drm-misc-next for 6.5:
UAPI Changes: Cross-subsystem Changes: - arch: Consolidate <asm/fb.h> Core Changes: - aperture: Ignore firmware framebuffers with non-primary devices - fbdev: Use fbdev's I/O helpers - sysfs: Expose DRM connector ID - tests: More tests for drm_rect Driver Changes: - armada: Implement fbdev emulation as a client - bridge: - fsl-ldb: Support i.MX6SX - lt9211: Remove blanking packets - lt9611: Remove blanking packets - tc358768: Implement input bus formats reporting, fix various timings and clocks settings - ti-sn65dsi86: Implement wait_hpd_asserted - nouveau: Improve NULL pointer checks before dereference - panel: - nt36523: Support Lenovo J606F - st7703: Support Anbernic RG353V-V2 - new panels: InnoLux G070ACE-L01 - sun4i: Fix MIPI-DSI dotclock - vc4: RGB Range toggle property, BT601 and BT2020 support for HDMI - vkms: Convert to drmm helpers, Add reflection and rotation support -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRcEzekXsqa64kGDp7j7w1vZxhRxQUCZFyY2wAKCRDj7w1vZxhR xWfwAP47UUe2pd7DjVM3TZETgNDXAWxhMAiMhHDpDJIgHArVGgD+PNom4rm2efsr uiUt9yrwcIKUEfPPa+GfNIBFQ66hwg4= =HvL5 -----END PGP SIGNATURE----- Merge tag 'drm-misc-next-2023-05-11' of git://anongit.freedesktop.org/drm/drm-misc into drm-next drm-misc-next for 6.5: UAPI Changes: Cross-subsystem Changes: - arch: Consolidate <asm/fb.h> Core Changes: - aperture: Ignore firmware framebuffers with non-primary devices - fbdev: Use fbdev's I/O helpers - sysfs: Expose DRM connector ID - tests: More tests for drm_rect Driver Changes: - armada: Implement fbdev emulation as a client - bridge: - fsl-ldb: Support i.MX6SX - lt9211: Remove blanking packets - lt9611: Remove blanking packets - tc358768: Implement input bus formats reporting, fix various timings and clocks settings - ti-sn65dsi86: Implement wait_hpd_asserted - nouveau: Improve NULL pointer checks before dereference - panel: - nt36523: Support Lenovo J606F - st7703: Support Anbernic RG353V-V2 - new panels: InnoLux G070ACE-L01 - sun4i: Fix MIPI-DSI dotclock - vc4: RGB Range toggle property, BT601 and BT2020 support for HDMI - vkms: Convert to drmm helpers, Add reflection and rotation support Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <maxime@cerno.tech> Link: https://patchwork.freedesktop.org/patch/msgid/2pxmxdzsk2ekjy6xvbpj67zrhtwvkkhfspuvdm5pfm5i54hed6@sooct7yq6z4w
This commit is contained in:
commit
33a8617088
@ -17,6 +17,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx6sx-ldb
|
||||
- fsl,imx8mp-ldb
|
||||
- fsl,imx93-ldb
|
||||
|
||||
@ -64,7 +65,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fsl,imx93-ldb
|
||||
enum:
|
||||
- fsl,imx6sx-ldb
|
||||
- fsl,imx93-ldb
|
||||
then:
|
||||
properties:
|
||||
ports:
|
||||
|
@ -19,11 +19,16 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- xiaomi,elish-boe-nt36523
|
||||
- xiaomi,elish-csot-nt36523
|
||||
- const: novatek,nt36523
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- xiaomi,elish-boe-nt36523
|
||||
- xiaomi,elish-csot-nt36523
|
||||
- const: novatek,nt36523
|
||||
- items:
|
||||
- enum:
|
||||
- lenovo,j606f-boe-nt36523w
|
||||
- const: novatek,nt36523w
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
@ -34,6 +39,7 @@ properties:
|
||||
|
||||
reg: true
|
||||
ports: true
|
||||
rotation: true
|
||||
backlight: true
|
||||
|
||||
required:
|
||||
|
@ -174,6 +174,8 @@ properties:
|
||||
- innolux,at043tn24
|
||||
# Innolux AT070TN92 7.0" WQVGA TFT LCD panel
|
||||
- innolux,at070tn92
|
||||
# Innolux G070ACE-L01 7" WVGA (800x480) TFT LCD panel
|
||||
- innolux,g070ace-l01
|
||||
# Innolux G070Y2-L01 7" WVGA (800x480) TFT LCD panel
|
||||
- innolux,g070y2-l01
|
||||
# Innolux G070Y2-T02 7" WVGA (800x480) TFT LCD TTL panel
|
||||
|
@ -20,6 +20,8 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
# Anberic RG353V-V2 5.0" 640x480 TFT LCD panel
|
||||
- anbernic,rg353v-panel-v2
|
||||
# Rocktech JH057N00900 5.5" 720x1440 TFT LCD panel
|
||||
- rocktech,jh057n00900
|
||||
# Xingbangda XBD599 5.99" 720x1440 TFT LCD panel
|
||||
|
@ -31,3 +31,7 @@ host such documentation:
|
||||
.. toctree::
|
||||
|
||||
i915_vm_bind.rst
|
||||
|
||||
.. toctree::
|
||||
|
||||
xe.rst
|
||||
|
235
Documentation/gpu/rfc/xe.rst
Normal file
235
Documentation/gpu/rfc/xe.rst
Normal file
@ -0,0 +1,235 @@
|
||||
==========================
|
||||
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 driver will be protected with both STAGING Kconfig and force_probe. Changes in
|
||||
the uAPI are expected while the driver is behind these protections. STAGING will
|
||||
be removed when the driver uAPI gets to a mature state where we can guarantee the
|
||||
‘no regression’ rule. Then force_probe will be lifted only for future platforms
|
||||
that will be productized with Xe driver, but not with i915.
|
||||
|
||||
Xe – Pre-Merge Goals
|
||||
====================
|
||||
|
||||
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.
|
||||
|
||||
GPU VA
|
||||
------
|
||||
Two main goals of Xe are meeting together here:
|
||||
|
||||
1) Have an uAPI that aligns with modern UMD needs.
|
||||
|
||||
2) Early upstream engagement.
|
||||
|
||||
RedHat engineers working on Nouveau proposed a new DRM feature to handle keeping
|
||||
track of GPU virtual address mappings. This is still not merged upstream, but
|
||||
this aligns very well with our goals and with our VM_BIND. The engagement with
|
||||
upstream and the port of Xe towards GPUVA is already ongoing.
|
||||
|
||||
As a key measurable result, Xe needs to be aligned with the GPU VA and working in
|
||||
our tree. Missing Nouveau patches should *not* block Xe and any needed GPUVA
|
||||
related patch should be independent and present on dri-devel or acked by
|
||||
maintainers to go along with the first Xe pull request towards drm-next.
|
||||
|
||||
DRM_VM_BIND
|
||||
-----------
|
||||
Nouveau, and Xe are all implementing ‘VM_BIND’ and new ‘Exec’ uAPIs in order to
|
||||
fulfill the needs of the modern uAPI. Xe merge should *not* be blocked on the
|
||||
development of a common new drm_infrastructure. However, the Xe team needs to
|
||||
engage with the community to explore the options of a common API.
|
||||
|
||||
As a key measurable result, the DRM_VM_BIND needs to be documented in this file
|
||||
below, or this entire block deleted if the consensus is for independent drivers
|
||||
vm_bind ioctls.
|
||||
|
||||
Although having a common DRM level IOCTL for VM_BIND is not a requirement to get
|
||||
Xe merged, it is mandatory to enforce the overall locking scheme for all major
|
||||
structs and list (so vm and vma). So, a consensus is needed, and possibly some
|
||||
common helpers. If helpers are needed, they should be also documented in this
|
||||
document.
|
||||
|
||||
ASYNC VM_BIND
|
||||
-------------
|
||||
Although having a common DRM level IOCTL for VM_BIND is not a requirement to get
|
||||
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 a sample API should be documented here or in
|
||||
a separate document pointed to by this document.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
This is a non-blocker item since the driver without the support for the long
|
||||
running compute enabled is not a showstopper.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
@ -276,11 +276,8 @@ Various hold-ups:
|
||||
- Need to switch to drm_fbdev_generic_setup(), otherwise a lot of the custom fb
|
||||
setup code can't be deleted.
|
||||
|
||||
- Many drivers wrap drm_gem_fb_create() only to check for valid formats. For
|
||||
atomic drivers we could check for valid formats by calling
|
||||
drm_plane_check_pixel_format() against all planes, and pass if any plane
|
||||
supports the format. For non-atomic that's not possible since like the format
|
||||
list for the primary plane is fake and we'd therefor reject valid formats.
|
||||
- Need to switch to drm_gem_fb_create(), as now drm_gem_fb_create() checks for
|
||||
valid formats for atomic drivers.
|
||||
|
||||
- Many drivers subclass drm_framebuffer, we'd need a embedding compatible
|
||||
version of the varios drm_gem_fb_create functions. Maybe called
|
||||
|
@ -118,14 +118,9 @@ Add Plane Features
|
||||
|
||||
There's lots of plane features we could add support for:
|
||||
|
||||
- ARGB format on primary plane: blend the primary plane into background with
|
||||
translucent alpha.
|
||||
|
||||
- Add background color KMS property[Good to get started].
|
||||
|
||||
- Full alpha blending on all planes.
|
||||
|
||||
- Rotation, scaling.
|
||||
- Scaling.
|
||||
|
||||
- Additional buffer formats, especially YUV formats for video like NV12.
|
||||
Low/high bpp RGB formats would also be interesting.
|
||||
|
@ -6763,6 +6763,7 @@ F: drivers/gpu/drm/udl/
|
||||
DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS)
|
||||
M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
|
||||
M: Melissa Wen <melissa.srw@gmail.com>
|
||||
M: Maíra Canal <mairacanal@riseup.net>
|
||||
R: Haneen Mohammed <hamohammed.sa@gmail.com>
|
||||
R: Daniel Vetter <daniel@ffwll.ch>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
@ -6865,6 +6866,7 @@ S: Maintained
|
||||
T: git git://anongit.freedesktop.org/drm/drm-misc
|
||||
F: Documentation/devicetree/bindings/display/bridge/
|
||||
F: drivers/gpu/drm/bridge/
|
||||
F: drivers/gpu/drm/drm_bridge.c
|
||||
F: include/drm/drm_bridge.h
|
||||
|
||||
DRM DRIVERS FOR EXYNOS
|
||||
|
@ -1,20 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
@ -1,19 +1,6 @@
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
@ -5,19 +5,6 @@
|
||||
#ifndef __ASM_FB_H_
|
||||
#define __ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* __ASM_FB_H_ */
|
||||
|
@ -2,11 +2,12 @@
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/efi.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
struct file;
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
@ -15,10 +16,8 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
else
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
}
|
||||
#define fb_pgprotect fb_pgprotect
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
@ -5,19 +5,6 @@
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
@ -2,22 +2,18 @@
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
struct file;
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
#ifdef CONFIG_MMU
|
||||
#ifdef CONFIG_SUN3
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
|
||||
}
|
||||
#else
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
if (CPU_IS_020_OR_030)
|
||||
pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
|
||||
if (CPU_IS_040_OR_060) {
|
||||
@ -25,15 +21,11 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
/* Use no-cache mode, serialized */
|
||||
pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_SUN3 */
|
||||
#else
|
||||
#define fb_pgprotect(...) do {} while (0)
|
||||
#endif /* CONFIG_MMU */
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define fb_pgprotect fb_pgprotect
|
||||
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
@ -1,19 +1,17 @@
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
struct file;
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
}
|
||||
#define fb_pgprotect fb_pgprotect
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
@ -11,7 +11,7 @@
|
||||
# Copyright (C) 1994 by Linus Torvalds
|
||||
# Portions Copyright (C) 1999 The Puffin Group
|
||||
#
|
||||
# Modified for PA-RISC Linux by Paul Lahaie, Alex deVries,
|
||||
# Modified for PA-RISC Linux by Paul Lahaie, Alex deVries,
|
||||
# Mike Shaver, Helge Deller and Martin K. Petersen
|
||||
#
|
||||
|
||||
@ -119,6 +119,8 @@ export LIBGCC
|
||||
|
||||
libs-y += arch/parisc/lib/ $(LIBGCC)
|
||||
|
||||
drivers-y += arch/parisc/video/
|
||||
|
||||
boot := arch/parisc/boot
|
||||
|
||||
PALO := $(shell if (which palo 2>&1); then : ; \
|
||||
|
@ -2,23 +2,13 @@
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
struct fb_info;
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FB_STI)
|
||||
#if defined(CONFIG_STI_CORE)
|
||||
int fb_is_primary_device(struct fb_info *info);
|
||||
#else
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define fb_is_primary_device fb_is_primary_device
|
||||
#endif
|
||||
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
3
arch/parisc/video/Makefile
Normal file
3
arch/parisc/video/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-$(CONFIG_STI_CORE) += fbdev.o
|
27
arch/parisc/video/fbdev.c
Normal file
27
arch/parisc/video/fbdev.c
Normal file
@ -0,0 +1,27 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
|
||||
* Copyright (C) 2001-2020 Helge Deller <deller@gmx.de>
|
||||
* Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/fb.h>
|
||||
|
||||
#include <video/sticore.h>
|
||||
|
||||
int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
struct sti_struct *sti;
|
||||
|
||||
sti = sti_get_rom(0);
|
||||
|
||||
/* if no built-in graphics card found, allow any fb driver as default */
|
||||
if (!sti)
|
||||
return true;
|
||||
|
||||
/* return true if it's the default built-in framebuffer driver */
|
||||
return (sti->info == info);
|
||||
}
|
||||
EXPORT_SYMBOL(fb_is_primary_device);
|
@ -2,8 +2,8 @@
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
@ -13,10 +13,8 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
vma->vm_end - vma->vm_start,
|
||||
vma->vm_page_prot);
|
||||
}
|
||||
#define fb_pgprotect fb_pgprotect
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
@ -2,19 +2,6 @@
|
||||
#ifndef _ASM_FB_H_
|
||||
#define _ASM_FB_H_
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
}
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_FB_H_ */
|
||||
|
@ -60,6 +60,7 @@ libs-y += arch/sparc/prom/
|
||||
libs-y += arch/sparc/lib/
|
||||
|
||||
drivers-$(CONFIG_PM) += arch/sparc/power/
|
||||
drivers-$(CONFIG_FB) += arch/sparc/video/
|
||||
|
||||
boot := arch/sparc/boot
|
||||
|
||||
|
@ -1,34 +1,21 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _SPARC_FB_H_
|
||||
#define _SPARC_FB_H_
|
||||
#include <linux/console.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
struct fb_info;
|
||||
struct file;
|
||||
struct vm_area_struct;
|
||||
|
||||
#ifdef CONFIG_SPARC32
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
#ifdef CONFIG_SPARC64
|
||||
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||
{ }
|
||||
#define fb_pgprotect fb_pgprotect
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
struct device *dev = info->device;
|
||||
struct device_node *node;
|
||||
int fb_is_primary_device(struct fb_info *info);
|
||||
#define fb_is_primary_device fb_is_primary_device
|
||||
|
||||
if (console_set_on_cmdline)
|
||||
return 0;
|
||||
|
||||
node = dev->of_node;
|
||||
if (node &&
|
||||
node == of_console_device)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _SPARC_FB_H_ */
|
||||
|
3
arch/sparc/video/Makefile
Normal file
3
arch/sparc/video/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-$(CONFIG_FB) += fbdev.o
|
24
arch/sparc/video/fbdev.c
Normal file
24
arch/sparc/video/fbdev.c
Normal file
@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/fb.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
struct device *dev = info->device;
|
||||
struct device_node *node;
|
||||
|
||||
if (console_set_on_cmdline)
|
||||
return 0;
|
||||
|
||||
node = dev->of_node;
|
||||
if (node && node == of_console_device)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fb_is_primary_device);
|
@ -2,21 +2,16 @@
|
||||
#ifndef _ASM_X86_FB_H
|
||||
#define _ASM_X86_FB_H
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/fs.h>
|
||||
#include <asm/page.h>
|
||||
struct fb_info;
|
||||
struct file;
|
||||
struct vm_area_struct;
|
||||
|
||||
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
|
||||
unsigned long off)
|
||||
{
|
||||
unsigned long prot;
|
||||
void fb_pgprotect(struct file *file, struct vm_area_struct *vma, unsigned long off);
|
||||
#define fb_pgprotect fb_pgprotect
|
||||
|
||||
prot = pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK;
|
||||
if (boot_cpu_data.x86 > 3)
|
||||
pgprot_val(vma->vm_page_prot) =
|
||||
prot | cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS);
|
||||
}
|
||||
int fb_is_primary_device(struct fb_info *info);
|
||||
#define fb_is_primary_device fb_is_primary_device
|
||||
|
||||
extern int fb_is_primary_device(struct fb_info *info);
|
||||
#include <asm-generic/fb.h>
|
||||
|
||||
#endif /* _ASM_X86_FB_H */
|
||||
|
@ -6,35 +6,39 @@
|
||||
* for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <asm/fb.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/vgaarb.h>
|
||||
|
||||
void fb_pgprotect(struct file *file, struct vm_area_struct *vma, unsigned long off)
|
||||
{
|
||||
unsigned long prot;
|
||||
|
||||
prot = pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK;
|
||||
if (boot_cpu_data.x86 > 3)
|
||||
pgprot_val(vma->vm_page_prot) =
|
||||
prot | cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS);
|
||||
}
|
||||
EXPORT_SYMBOL(fb_pgprotect);
|
||||
|
||||
int fb_is_primary_device(struct fb_info *info)
|
||||
{
|
||||
struct device *device = info->device;
|
||||
struct pci_dev *default_device = vga_default_device();
|
||||
struct pci_dev *pci_dev;
|
||||
struct resource *res;
|
||||
|
||||
if (!device || !dev_is_pci(device))
|
||||
return 0;
|
||||
|
||||
pci_dev = to_pci_dev(device);
|
||||
|
||||
if (default_device) {
|
||||
if (pci_dev == default_device)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = pci_dev->resource + PCI_ROM_RESOURCE;
|
||||
|
||||
if (res->flags & IORESOURCE_ROM_SHADOW)
|
||||
if (pci_dev == vga_default_device())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fb_is_primary_device);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -72,7 +72,7 @@ static int cfag12864bfb_probe(struct platform_device *device)
|
||||
if (!info)
|
||||
goto none;
|
||||
|
||||
info->screen_base = (char __iomem *) cfag12864b_buffer;
|
||||
info->screen_buffer = cfag12864b_buffer;
|
||||
info->screen_size = CFAG12864B_SIZE;
|
||||
info->fbops = &cfag12864bfb_ops;
|
||||
info->fix = cfag12864bfb_fix;
|
||||
|
@ -640,7 +640,7 @@ static int ht16k33_fbdev_probe(struct device *dev, struct ht16k33_priv *priv,
|
||||
|
||||
INIT_DELAYED_WORK(&priv->work, ht16k33_fb_update);
|
||||
fbdev->info->fbops = &ht16k33_fb_ops;
|
||||
fbdev->info->screen_base = (char __iomem *) fbdev->buffer;
|
||||
fbdev->info->screen_buffer = fbdev->buffer;
|
||||
fbdev->info->screen_size = HT16K33_FB_SIZE;
|
||||
fbdev->info->fix = ht16k33_fb_fix;
|
||||
fbdev->info->var = ht16k33_fb_var;
|
||||
|
@ -660,7 +660,7 @@ EXPORT_SYMBOL_GPL(dma_resv_get_singleton);
|
||||
* dma_resv_lock() already
|
||||
* RETURNS
|
||||
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
|
||||
* greater than zer on success.
|
||||
* greater than zero on success.
|
||||
*/
|
||||
long dma_resv_wait_timeout(struct dma_resv *obj, enum dma_resv_usage usage,
|
||||
bool intr, unsigned long timeout)
|
||||
|
@ -285,7 +285,7 @@ static int hdlcd_drm_bind(struct device *dev)
|
||||
*/
|
||||
if (hdlcd_read(hdlcd, HDLCD_REG_COMMAND)) {
|
||||
hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
|
||||
drm_aperture_remove_framebuffers(false, &hdlcd_driver);
|
||||
drm_aperture_remove_framebuffers(&hdlcd_driver);
|
||||
}
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
@ -1,7 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
armada-y := armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \
|
||||
armada-y := armada_crtc.o armada_drv.o armada_fb.o \
|
||||
armada_gem.o armada_overlay.o armada_plane.o armada_trace.o
|
||||
armada-y += armada_510.o
|
||||
armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o
|
||||
armada-$(CONFIG_DRM_FBDEV_EMULATION) += armada_fbdev.o
|
||||
|
||||
obj-$(CONFIG_DRM_ARMADA) := armada.o
|
||||
|
@ -16,7 +16,6 @@ struct armada_crtc;
|
||||
struct armada_gem_object;
|
||||
struct clk;
|
||||
struct drm_display_mode;
|
||||
struct drm_fb_helper;
|
||||
|
||||
static inline void
|
||||
armada_updatel(uint32_t val, uint32_t mask, void __iomem *ptr)
|
||||
@ -55,7 +54,6 @@ extern const struct armada_variant armada510_ops;
|
||||
|
||||
struct armada_private {
|
||||
struct drm_device drm;
|
||||
struct drm_fb_helper *fbdev;
|
||||
struct armada_crtc *dcrtc[2];
|
||||
struct drm_mm linear; /* protected by linear_lock */
|
||||
struct mutex linear_lock;
|
||||
@ -75,8 +73,12 @@ struct armada_private {
|
||||
|
||||
#define drm_to_armada_dev(dev) container_of(dev, struct armada_private, drm)
|
||||
|
||||
int armada_fbdev_init(struct drm_device *);
|
||||
void armada_fbdev_fini(struct drm_device *);
|
||||
#if defined(CONFIG_DRM_FBDEV_EMULATION)
|
||||
void armada_fbdev_setup(struct drm_device *dev);
|
||||
#else
|
||||
static inline void armada_fbdev_setup(struct drm_device *dev)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
int armada_overlay_plane_create(struct drm_device *, unsigned long);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
@ -16,7 +17,6 @@
|
||||
#include <drm/drm_managed.h>
|
||||
#include <drm/drm_prime.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
@ -37,7 +37,6 @@ static const struct drm_ioctl_desc armada_ioctls[] = {
|
||||
DEFINE_DRM_GEM_FOPS(armada_drm_fops);
|
||||
|
||||
static const struct drm_driver armada_drm_driver = {
|
||||
.lastclose = drm_fb_helper_lastclose,
|
||||
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
|
||||
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
|
||||
.gem_prime_import = armada_gem_prime_import,
|
||||
@ -55,7 +54,6 @@ static const struct drm_driver armada_drm_driver = {
|
||||
|
||||
static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
|
||||
.fb_create = armada_fb_create,
|
||||
.output_poll_changed = drm_fb_helper_output_poll_changed,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_commit = drm_atomic_helper_commit,
|
||||
};
|
||||
@ -95,7 +93,7 @@ static int armada_drm_bind(struct device *dev)
|
||||
}
|
||||
|
||||
/* Remove early framebuffers */
|
||||
ret = drm_aperture_remove_framebuffers(false, &armada_drm_driver);
|
||||
ret = drm_aperture_remove_framebuffers(&armada_drm_driver);
|
||||
if (ret) {
|
||||
dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n",
|
||||
__func__, ret);
|
||||
@ -131,10 +129,6 @@ static int armada_drm_bind(struct device *dev)
|
||||
|
||||
drm_mode_config_reset(&priv->drm);
|
||||
|
||||
ret = armada_fbdev_init(&priv->drm);
|
||||
if (ret)
|
||||
goto err_comp;
|
||||
|
||||
drm_kms_helper_poll_init(&priv->drm);
|
||||
|
||||
ret = drm_dev_register(&priv->drm, 0);
|
||||
@ -145,11 +139,12 @@ static int armada_drm_bind(struct device *dev)
|
||||
armada_drm_debugfs_init(priv->drm.primary);
|
||||
#endif
|
||||
|
||||
armada_fbdev_setup(&priv->drm);
|
||||
|
||||
return 0;
|
||||
|
||||
err_poll:
|
||||
drm_kms_helper_poll_fini(&priv->drm);
|
||||
armada_fbdev_fini(&priv->drm);
|
||||
err_comp:
|
||||
component_unbind_all(dev, &priv->drm);
|
||||
err_kms:
|
||||
@ -164,7 +159,6 @@ static void armada_drm_unbind(struct device *dev)
|
||||
struct armada_private *priv = drm_to_armada_dev(drm);
|
||||
|
||||
drm_kms_helper_poll_fini(&priv->drm);
|
||||
armada_fbdev_fini(&priv->drm);
|
||||
|
||||
drm_dev_unregister(&priv->drm);
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
#include <drm/drm_modeset_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
@ -16,6 +18,19 @@
|
||||
#include "armada_fb.h"
|
||||
#include "armada_gem.h"
|
||||
|
||||
static void armada_fbdev_fb_destroy(struct fb_info *info)
|
||||
{
|
||||
struct drm_fb_helper *fbh = info->par;
|
||||
|
||||
drm_fb_helper_fini(fbh);
|
||||
|
||||
fbh->fb->funcs->destroy(fbh->fb);
|
||||
|
||||
drm_client_release(&fbh->client);
|
||||
drm_fb_helper_unprepare(fbh);
|
||||
kfree(fbh);
|
||||
}
|
||||
|
||||
static const struct fb_ops armada_fb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
DRM_FB_HELPER_DEFAULT_OPS,
|
||||
@ -24,6 +39,7 @@ static const struct fb_ops armada_fb_ops = {
|
||||
.fb_fillrect = drm_fb_helper_cfb_fillrect,
|
||||
.fb_copyarea = drm_fb_helper_cfb_copyarea,
|
||||
.fb_imageblit = drm_fb_helper_cfb_imageblit,
|
||||
.fb_destroy = armada_fbdev_fb_destroy,
|
||||
};
|
||||
|
||||
static int armada_fbdev_create(struct drm_fb_helper *fbh,
|
||||
@ -117,56 +133,95 @@ static const struct drm_fb_helper_funcs armada_fb_helper_funcs = {
|
||||
.fb_probe = armada_fb_probe,
|
||||
};
|
||||
|
||||
int armada_fbdev_init(struct drm_device *dev)
|
||||
/*
|
||||
* Fbdev client and struct drm_client_funcs
|
||||
*/
|
||||
|
||||
static void armada_fbdev_client_unregister(struct drm_client_dev *client)
|
||||
{
|
||||
struct armada_private *priv = drm_to_armada_dev(dev);
|
||||
struct drm_fb_helper *fbh;
|
||||
int ret;
|
||||
struct drm_fb_helper *fbh = drm_fb_helper_from_client(client);
|
||||
|
||||
fbh = devm_kzalloc(dev->dev, sizeof(*fbh), GFP_KERNEL);
|
||||
if (!fbh)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->fbdev = fbh;
|
||||
|
||||
drm_fb_helper_prepare(dev, fbh, 32, &armada_fb_helper_funcs);
|
||||
|
||||
ret = drm_fb_helper_init(dev, fbh);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize drm fb helper\n");
|
||||
goto err_fb_helper;
|
||||
if (fbh->info) {
|
||||
drm_fb_helper_unregister_info(fbh);
|
||||
} else {
|
||||
drm_client_release(&fbh->client);
|
||||
drm_fb_helper_unprepare(fbh);
|
||||
kfree(fbh);
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_fb_helper_initial_config(fbh);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to set initial config\n");
|
||||
goto err_fb_setup;
|
||||
}
|
||||
static int armada_fbdev_client_restore(struct drm_client_dev *client)
|
||||
{
|
||||
drm_fb_helper_lastclose(client->dev);
|
||||
|
||||
return 0;
|
||||
err_fb_setup:
|
||||
}
|
||||
|
||||
static int armada_fbdev_client_hotplug(struct drm_client_dev *client)
|
||||
{
|
||||
struct drm_fb_helper *fbh = drm_fb_helper_from_client(client);
|
||||
struct drm_device *dev = client->dev;
|
||||
int ret;
|
||||
|
||||
if (dev->fb_helper)
|
||||
return drm_fb_helper_hotplug_event(dev->fb_helper);
|
||||
|
||||
ret = drm_fb_helper_init(dev, fbh);
|
||||
if (ret)
|
||||
goto err_drm_err;
|
||||
|
||||
if (!drm_drv_uses_atomic_modeset(dev))
|
||||
drm_helper_disable_unused_functions(dev);
|
||||
|
||||
ret = drm_fb_helper_initial_config(fbh);
|
||||
if (ret)
|
||||
goto err_drm_fb_helper_fini;
|
||||
|
||||
return 0;
|
||||
|
||||
err_drm_fb_helper_fini:
|
||||
drm_fb_helper_fini(fbh);
|
||||
err_fb_helper:
|
||||
drm_fb_helper_unprepare(fbh);
|
||||
priv->fbdev = NULL;
|
||||
err_drm_err:
|
||||
drm_err(dev, "armada: Failed to setup fbdev emulation (ret=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void armada_fbdev_fini(struct drm_device *dev)
|
||||
static const struct drm_client_funcs armada_fbdev_client_funcs = {
|
||||
.owner = THIS_MODULE,
|
||||
.unregister = armada_fbdev_client_unregister,
|
||||
.restore = armada_fbdev_client_restore,
|
||||
.hotplug = armada_fbdev_client_hotplug,
|
||||
};
|
||||
|
||||
void armada_fbdev_setup(struct drm_device *dev)
|
||||
{
|
||||
struct armada_private *priv = drm_to_armada_dev(dev);
|
||||
struct drm_fb_helper *fbh = priv->fbdev;
|
||||
struct drm_fb_helper *fbh;
|
||||
int ret;
|
||||
|
||||
if (fbh) {
|
||||
drm_fb_helper_unregister_info(fbh);
|
||||
drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
|
||||
drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
|
||||
|
||||
drm_fb_helper_fini(fbh);
|
||||
fbh = kzalloc(sizeof(*fbh), GFP_KERNEL);
|
||||
if (!fbh)
|
||||
return;
|
||||
drm_fb_helper_prepare(dev, fbh, 32, &armada_fb_helper_funcs);
|
||||
|
||||
if (fbh->fb)
|
||||
fbh->fb->funcs->destroy(fbh->fb);
|
||||
|
||||
drm_fb_helper_unprepare(fbh);
|
||||
|
||||
priv->fbdev = NULL;
|
||||
ret = drm_client_init(dev, &fbh->client, "fbdev", &armada_fbdev_client_funcs);
|
||||
if (ret) {
|
||||
drm_err(dev, "Failed to register client: %d\n", ret);
|
||||
goto err_drm_client_init;
|
||||
}
|
||||
|
||||
ret = armada_fbdev_client_hotplug(&fbh->client);
|
||||
if (ret)
|
||||
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
|
||||
|
||||
drm_client_register(&fbh->client);
|
||||
|
||||
return;
|
||||
|
||||
err_drm_client_init:
|
||||
drm_fb_helper_unprepare(fbh);
|
||||
kfree(fbh);
|
||||
return;
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
||||
#define LVDS_CTRL_VBG_ADJ_MASK GENMASK(19, 17)
|
||||
|
||||
enum fsl_ldb_devtype {
|
||||
IMX6SX_LDB,
|
||||
IMX8MP_LDB,
|
||||
IMX93_LDB,
|
||||
};
|
||||
@ -64,9 +65,14 @@ struct fsl_ldb_devdata {
|
||||
u32 ldb_ctrl;
|
||||
u32 lvds_ctrl;
|
||||
bool lvds_en_bit;
|
||||
bool single_ctrl_reg;
|
||||
};
|
||||
|
||||
static const struct fsl_ldb_devdata fsl_ldb_devdata[] = {
|
||||
[IMX6SX_LDB] = {
|
||||
.ldb_ctrl = 0x18,
|
||||
.single_ctrl_reg = true,
|
||||
},
|
||||
[IMX8MP_LDB] = {
|
||||
.ldb_ctrl = 0x5c,
|
||||
.lvds_ctrl = 0x128,
|
||||
@ -201,6 +207,9 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
|
||||
|
||||
regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, reg);
|
||||
|
||||
if (fsl_ldb->devdata->single_ctrl_reg)
|
||||
return;
|
||||
|
||||
/* Program LVDS_CTRL */
|
||||
reg = LVDS_CTRL_CC_ADJ(2) | LVDS_CTRL_PRE_EMPH_EN |
|
||||
LVDS_CTRL_PRE_EMPH_ADJ(3) | LVDS_CTRL_VBG_EN;
|
||||
@ -226,7 +235,8 @@ static void fsl_ldb_atomic_disable(struct drm_bridge *bridge,
|
||||
regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl,
|
||||
LVDS_CTRL_LVDS_EN);
|
||||
else
|
||||
regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, 0);
|
||||
if (!fsl_ldb->devdata->single_ctrl_reg)
|
||||
regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->lvds_ctrl, 0);
|
||||
regmap_write(fsl_ldb->regmap, fsl_ldb->devdata->ldb_ctrl, 0);
|
||||
|
||||
clk_disable_unprepare(fsl_ldb->clk);
|
||||
@ -372,6 +382,8 @@ static void fsl_ldb_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id fsl_ldb_match[] = {
|
||||
{ .compatible = "fsl,imx6sx-ldb",
|
||||
.data = &fsl_ldb_devdata[IMX6SX_LDB], },
|
||||
{ .compatible = "fsl,imx8mp-ldb",
|
||||
.data = &fsl_ldb_devdata[IMX8MP_LDB], },
|
||||
{ .compatible = "fsl,imx93-ldb",
|
||||
|
@ -3207,7 +3207,7 @@ static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct it6505 *it6505 = file->private_data;
|
||||
struct drm_display_mode *vid = &it6505->video_info;
|
||||
struct drm_display_mode *vid;
|
||||
u8 read_buf[READ_BUFFER_SIZE];
|
||||
u8 *str = read_buf, *end = read_buf + READ_BUFFER_SIZE;
|
||||
ssize_t ret, count;
|
||||
@ -3216,6 +3216,7 @@ static ssize_t receive_timing_debugfs_show(struct file *file, char __user *buf,
|
||||
return -ENODEV;
|
||||
|
||||
it6505_calc_video_info(it6505);
|
||||
vid = &it6505->video_info;
|
||||
str += scnprintf(str, end - str, "---video timing---\n");
|
||||
str += scnprintf(str, end - str, "PCLK:%d.%03dMHz\n",
|
||||
vid->clock / 1000, vid->clock % 1000);
|
||||
|
@ -709,7 +709,9 @@ static int lt9211_host_attach(struct lt9211 *ctx)
|
||||
dsi->lanes = dsi_lanes;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
|
||||
MIPI_DSI_MODE_VIDEO_HSE;
|
||||
MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_NO_HSA |
|
||||
MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP |
|
||||
MIPI_DSI_MODE_NO_EOT_PACKET;
|
||||
|
||||
ret = devm_mipi_dsi_attach(dev, dsi);
|
||||
if (ret < 0) {
|
||||
|
@ -774,7 +774,9 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611,
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
|
||||
MIPI_DSI_MODE_VIDEO_HSE;
|
||||
MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_NO_HSA |
|
||||
MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP |
|
||||
MIPI_DSI_MODE_NO_EOT_PACKET;
|
||||
|
||||
ret = devm_mipi_dsi_attach(dev, dsi);
|
||||
if (ret < 0) {
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/media-bus-format.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@ -146,6 +148,7 @@ struct tc358768_priv {
|
||||
|
||||
u32 pd_lines; /* number of Parallel Port Input Data Lines */
|
||||
u32 dsi_lanes; /* number of DSI Lanes */
|
||||
u32 dsi_bpp; /* number of Bits Per Pixel over DSI */
|
||||
|
||||
/* Parameters for PLL programming */
|
||||
u32 fbd; /* PLL feedback divider */
|
||||
@ -284,12 +287,12 @@ static void tc358768_hw_disable(struct tc358768_priv *priv)
|
||||
|
||||
static u32 tc358768_pll_to_pclk(struct tc358768_priv *priv, u32 pll_clk)
|
||||
{
|
||||
return (u32)div_u64((u64)pll_clk * priv->dsi_lanes, priv->pd_lines);
|
||||
return (u32)div_u64((u64)pll_clk * priv->dsi_lanes, priv->dsi_bpp);
|
||||
}
|
||||
|
||||
static u32 tc358768_pclk_to_pll(struct tc358768_priv *priv, u32 pclk)
|
||||
{
|
||||
return (u32)div_u64((u64)pclk * priv->pd_lines, priv->dsi_lanes);
|
||||
return (u32)div_u64((u64)pclk * priv->dsi_bpp, priv->dsi_lanes);
|
||||
}
|
||||
|
||||
static int tc358768_calc_pll(struct tc358768_priv *priv,
|
||||
@ -334,13 +337,17 @@ static int tc358768_calc_pll(struct tc358768_priv *priv,
|
||||
u32 fbd;
|
||||
|
||||
for (fbd = 0; fbd < 512; ++fbd) {
|
||||
u32 pll, diff;
|
||||
u32 pll, diff, pll_in;
|
||||
|
||||
pll = (u32)div_u64((u64)refclk * (fbd + 1), divisor);
|
||||
|
||||
if (pll >= max_pll || pll < min_pll)
|
||||
continue;
|
||||
|
||||
pll_in = (u32)div_u64((u64)refclk, prd + 1);
|
||||
if (pll_in < 4000000)
|
||||
continue;
|
||||
|
||||
diff = max(pll, target_pll) - min(pll, target_pll);
|
||||
|
||||
if (diff < best_diff) {
|
||||
@ -422,6 +429,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
|
||||
priv->output.panel = panel;
|
||||
|
||||
priv->dsi_lanes = dev->lanes;
|
||||
priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format);
|
||||
|
||||
/* get input ep (port0/endpoint0) */
|
||||
ret = -EINVAL;
|
||||
@ -433,7 +441,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host,
|
||||
}
|
||||
|
||||
if (ret)
|
||||
priv->pd_lines = mipi_dsi_pixel_format_to_bpp(dev->format);
|
||||
priv->pd_lines = priv->dsi_bpp;
|
||||
|
||||
drm_bridge_add(&priv->bridge);
|
||||
|
||||
@ -632,8 +640,9 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
struct mipi_dsi_device *dsi_dev = priv->output.dev;
|
||||
unsigned long mode_flags = dsi_dev->mode_flags;
|
||||
u32 val, val2, lptxcnt, hact, data_type;
|
||||
s32 raw_val;
|
||||
const struct drm_display_mode *mode;
|
||||
u32 dsibclk_nsk, dsiclk_nsk, ui_nsk, phy_delay_nsk;
|
||||
u32 dsibclk_nsk, dsiclk_nsk, ui_nsk;
|
||||
u32 dsiclk, dsibclk, video_start;
|
||||
const u32 internal_delay = 40;
|
||||
int ret, i;
|
||||
@ -717,11 +726,9 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
dsibclk);
|
||||
dsiclk_nsk = (u32)div_u64((u64)1000000000 * TC358768_PRECISION, dsiclk);
|
||||
ui_nsk = dsiclk_nsk / 2;
|
||||
phy_delay_nsk = dsibclk_nsk + 2 * dsiclk_nsk;
|
||||
dev_dbg(priv->dev, "dsiclk_nsk: %u\n", dsiclk_nsk);
|
||||
dev_dbg(priv->dev, "ui_nsk: %u\n", ui_nsk);
|
||||
dev_dbg(priv->dev, "dsibclk_nsk: %u\n", dsibclk_nsk);
|
||||
dev_dbg(priv->dev, "phy_delay_nsk: %u\n", phy_delay_nsk);
|
||||
|
||||
/* LP11 > 100us for D-PHY Rx Init */
|
||||
val = tc358768_ns_to_cnt(100 * 1000, dsibclk_nsk) - 1;
|
||||
@ -736,25 +743,26 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
|
||||
/* 38ns < TCLK_PREPARE < 95ns */
|
||||
val = tc358768_ns_to_cnt(65, dsibclk_nsk) - 1;
|
||||
/* TCLK_PREPARE > 300ns */
|
||||
val2 = tc358768_ns_to_cnt(300 + tc358768_to_ns(3 * ui_nsk),
|
||||
dsibclk_nsk);
|
||||
val |= (val2 - tc358768_to_ns(phy_delay_nsk - dsibclk_nsk)) << 8;
|
||||
/* TCLK_PREPARE + TCLK_ZERO > 300ns */
|
||||
val2 = tc358768_ns_to_cnt(300 - tc358768_to_ns(2 * ui_nsk),
|
||||
dsibclk_nsk) - 2;
|
||||
val |= val2 << 8;
|
||||
dev_dbg(priv->dev, "TCLK_HEADERCNT: 0x%x\n", val);
|
||||
tc358768_write(priv, TC358768_TCLK_HEADERCNT, val);
|
||||
|
||||
/* TCLK_TRAIL > 60ns + 3*UI */
|
||||
val = 60 + tc358768_to_ns(3 * ui_nsk);
|
||||
val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 5;
|
||||
/* TCLK_TRAIL > 60ns AND TEOT <= 105 ns + 12*UI */
|
||||
raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(2 * ui_nsk), dsibclk_nsk) - 5;
|
||||
val = clamp(raw_val, 0, 127);
|
||||
dev_dbg(priv->dev, "TCLK_TRAILCNT: 0x%x\n", val);
|
||||
tc358768_write(priv, TC358768_TCLK_TRAILCNT, val);
|
||||
|
||||
/* 40ns + 4*UI < THS_PREPARE < 85ns + 6*UI */
|
||||
val = 50 + tc358768_to_ns(4 * ui_nsk);
|
||||
val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 1;
|
||||
/* THS_ZERO > 145ns + 10*UI */
|
||||
val2 = tc358768_ns_to_cnt(145 - tc358768_to_ns(ui_nsk), dsibclk_nsk);
|
||||
val |= (val2 - tc358768_to_ns(phy_delay_nsk)) << 8;
|
||||
/* THS_PREPARE + THS_ZERO > 145ns + 10*UI */
|
||||
raw_val = tc358768_ns_to_cnt(145 - tc358768_to_ns(3 * ui_nsk), dsibclk_nsk) - 10;
|
||||
val2 = clamp(raw_val, 0, 127);
|
||||
val |= val2 << 8;
|
||||
dev_dbg(priv->dev, "THS_HEADERCNT: 0x%x\n", val);
|
||||
tc358768_write(priv, TC358768_THS_HEADERCNT, val);
|
||||
|
||||
@ -770,9 +778,10 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
dev_dbg(priv->dev, "TCLK_POSTCNT: 0x%x\n", val);
|
||||
tc358768_write(priv, TC358768_TCLK_POSTCNT, val);
|
||||
|
||||
/* 60ns + 4*UI < THS_PREPARE < 105ns + 12*UI */
|
||||
val = tc358768_ns_to_cnt(60 + tc358768_to_ns(15 * ui_nsk),
|
||||
dsibclk_nsk) - 5;
|
||||
/* max(60ns + 4*UI, 8*UI) < THS_TRAILCNT < 105ns + 12*UI */
|
||||
raw_val = tc358768_ns_to_cnt(60 + tc358768_to_ns(18 * ui_nsk),
|
||||
dsibclk_nsk) - 4;
|
||||
val = clamp(raw_val, 0, 15);
|
||||
dev_dbg(priv->dev, "THS_TRAILCNT: 0x%x\n", val);
|
||||
tc358768_write(priv, TC358768_THS_TRAILCNT, val);
|
||||
|
||||
@ -786,7 +795,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
|
||||
/* TXTAGOCNT[26:16] RXTASURECNT[10:0] */
|
||||
val = tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk * 4);
|
||||
val = tc358768_ns_to_cnt(val, dsibclk_nsk) - 1;
|
||||
val = tc358768_ns_to_cnt(val, dsibclk_nsk) / 4 - 1;
|
||||
val2 = tc358768_ns_to_cnt(tc358768_to_ns((lptxcnt + 1) * dsibclk_nsk),
|
||||
dsibclk_nsk) - 2;
|
||||
val = val << 16 | val2;
|
||||
@ -866,8 +875,7 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
val = TC358768_DSI_CONFW_MODE_SET | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
|
||||
val |= (dsi_dev->lanes - 1) << 1;
|
||||
|
||||
if (!(dsi_dev->mode_flags & MIPI_DSI_MODE_LPM))
|
||||
val |= TC358768_DSI_CONTROL_TXMD;
|
||||
val |= TC358768_DSI_CONTROL_TXMD;
|
||||
|
||||
if (!(mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS))
|
||||
val |= TC358768_DSI_CONTROL_HSCKMD;
|
||||
@ -913,6 +921,44 @@ static void tc358768_bridge_enable(struct drm_bridge *bridge)
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_INPUT_SEL_FORMATS 1
|
||||
|
||||
static u32 *
|
||||
tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
|
||||
struct drm_bridge_state *bridge_state,
|
||||
struct drm_crtc_state *crtc_state,
|
||||
struct drm_connector_state *conn_state,
|
||||
u32 output_fmt,
|
||||
unsigned int *num_input_fmts)
|
||||
{
|
||||
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
|
||||
u32 *input_fmts;
|
||||
|
||||
*num_input_fmts = 0;
|
||||
|
||||
input_fmts = kcalloc(MAX_INPUT_SEL_FORMATS, sizeof(*input_fmts),
|
||||
GFP_KERNEL);
|
||||
if (!input_fmts)
|
||||
return NULL;
|
||||
|
||||
switch (priv->pd_lines) {
|
||||
case 16:
|
||||
input_fmts[0] = MEDIA_BUS_FMT_RGB565_1X16;
|
||||
break;
|
||||
case 18:
|
||||
input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X18;
|
||||
break;
|
||||
default:
|
||||
case 24:
|
||||
input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
|
||||
break;
|
||||
};
|
||||
|
||||
*num_input_fmts = MAX_INPUT_SEL_FORMATS;
|
||||
|
||||
return input_fmts;
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs tc358768_bridge_funcs = {
|
||||
.attach = tc358768_bridge_attach,
|
||||
.mode_valid = tc358768_bridge_mode_valid,
|
||||
@ -920,6 +966,11 @@ static const struct drm_bridge_funcs tc358768_bridge_funcs = {
|
||||
.enable = tc358768_bridge_enable,
|
||||
.disable = tc358768_bridge_disable,
|
||||
.post_disable = tc358768_bridge_post_disable,
|
||||
|
||||
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
|
||||
.atomic_reset = drm_atomic_helper_bridge_reset,
|
||||
.atomic_get_input_bus_fmts = tc358768_atomic_get_input_bus_fmts,
|
||||
};
|
||||
|
||||
static const struct drm_bridge_timings default_tc358768_timings = {
|
||||
|
@ -478,6 +478,7 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge,
|
||||
dev_err(ctx->dev, "failed to lock PLL, ret=%i\n", ret);
|
||||
/* On failure, disable PLL again and exit. */
|
||||
regmap_write(ctx->regmap, REG_RC_PLL_EN, 0x00);
|
||||
regulator_disable(ctx->vcc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -618,6 +618,24 @@ exit:
|
||||
return len;
|
||||
}
|
||||
|
||||
static int ti_sn_aux_wait_hpd_asserted(struct drm_dp_aux *aux, unsigned long wait_us)
|
||||
{
|
||||
/*
|
||||
* The HPD in this chip is a bit useless (See comment in
|
||||
* ti_sn65dsi86_enable_comms) so if our driver is expected to wait
|
||||
* for HPD, we just assume it's asserted after the wait_us delay.
|
||||
*
|
||||
* In case we are asked to wait forever (wait_us=0) take conservative
|
||||
* 500ms delay.
|
||||
*/
|
||||
if (wait_us == 0)
|
||||
wait_us = 500000;
|
||||
|
||||
usleep_range(wait_us, wait_us + 1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_sn_aux_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
@ -627,6 +645,7 @@ static int ti_sn_aux_probe(struct auxiliary_device *adev,
|
||||
pdata->aux.name = "ti-sn65dsi86-aux";
|
||||
pdata->aux.dev = &adev->dev;
|
||||
pdata->aux.transfer = ti_sn_aux_transfer;
|
||||
pdata->aux.wait_hpd_asserted = ti_sn_aux_wait_hpd_asserted;
|
||||
drm_dp_aux_init(&pdata->aux);
|
||||
|
||||
ret = devm_of_dp_aux_populate_ep_devices(&pdata->aux);
|
||||
|
@ -32,17 +32,13 @@
|
||||
*
|
||||
* static int remove_conflicting_framebuffers(struct pci_dev *pdev)
|
||||
* {
|
||||
* bool primary = false;
|
||||
* resource_size_t base, size;
|
||||
* int ret;
|
||||
*
|
||||
* base = pci_resource_start(pdev, 0);
|
||||
* size = pci_resource_len(pdev, 0);
|
||||
* #ifdef CONFIG_X86
|
||||
* primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
|
||||
* #endif
|
||||
*
|
||||
* return drm_aperture_remove_conflicting_framebuffers(base, size, primary,
|
||||
* return drm_aperture_remove_conflicting_framebuffers(base, size,
|
||||
* &example_driver);
|
||||
* }
|
||||
*
|
||||
@ -161,7 +157,6 @@ EXPORT_SYMBOL(devm_aperture_acquire_from_firmware);
|
||||
* drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range
|
||||
* @base: the aperture's base address in physical memory
|
||||
* @size: aperture size in bytes
|
||||
* @primary: also kick vga16fb if present
|
||||
* @req_driver: requesting DRM driver
|
||||
*
|
||||
* This function removes graphics device drivers which use the memory range described by
|
||||
@ -171,9 +166,9 @@ EXPORT_SYMBOL(devm_aperture_acquire_from_firmware);
|
||||
* 0 on success, or a negative errno code otherwise
|
||||
*/
|
||||
int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size,
|
||||
bool primary, const struct drm_driver *req_driver)
|
||||
const struct drm_driver *req_driver)
|
||||
{
|
||||
return aperture_remove_conflicting_devices(base, size, primary, req_driver->name);
|
||||
return aperture_remove_conflicting_devices(base, size, req_driver->name);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers);
|
||||
|
||||
|
@ -1209,7 +1209,16 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
|
||||
continue;
|
||||
|
||||
ret = drm_crtc_vblank_get(crtc);
|
||||
WARN_ONCE(ret != -EINVAL, "driver forgot to call drm_crtc_vblank_off()\n");
|
||||
/*
|
||||
* Self-refresh is not a true "disable"; ensure vblank remains
|
||||
* enabled.
|
||||
*/
|
||||
if (new_crtc_state->self_refresh_active)
|
||||
WARN_ONCE(ret != 0,
|
||||
"driver disabled vblank in self-refresh\n");
|
||||
else
|
||||
WARN_ONCE(ret != -EINVAL,
|
||||
"driver forgot to call drm_crtc_vblank_off()\n");
|
||||
if (ret == 0)
|
||||
drm_crtc_vblank_put(crtc);
|
||||
}
|
||||
|
@ -969,7 +969,9 @@ EXPORT_SYMBOL(drm_dev_register);
|
||||
*
|
||||
* Unregister the DRM device from the system. This does the reverse of
|
||||
* drm_dev_register() but does not deallocate the device. The caller must call
|
||||
* drm_dev_put() to drop their final reference.
|
||||
* drm_dev_put() to drop their final reference, unless it is managed with devres
|
||||
* (as devices allocated with devm_drm_dev_alloc() are), in which case there is
|
||||
* already an unwind action registered.
|
||||
*
|
||||
* A special form of unregistering for hotpluggable devices is drm_dev_unplug(),
|
||||
* which can be called while there are still open users of @dev.
|
||||
|
@ -714,95 +714,6 @@ void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagerefli
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_deferred_io);
|
||||
|
||||
typedef ssize_t (*drm_fb_helper_read_screen)(struct fb_info *info, char __user *buf,
|
||||
size_t count, loff_t pos);
|
||||
|
||||
static ssize_t __drm_fb_helper_read(struct fb_info *info, char __user *buf, size_t count,
|
||||
loff_t *ppos, drm_fb_helper_read_screen read_screen)
|
||||
{
|
||||
loff_t pos = *ppos;
|
||||
size_t total_size;
|
||||
ssize_t ret;
|
||||
|
||||
if (info->screen_size)
|
||||
total_size = info->screen_size;
|
||||
else
|
||||
total_size = info->fix.smem_len;
|
||||
|
||||
if (pos >= total_size)
|
||||
return 0;
|
||||
if (count >= total_size)
|
||||
count = total_size;
|
||||
if (total_size - count < pos)
|
||||
count = total_size - pos;
|
||||
|
||||
if (info->fbops->fb_sync)
|
||||
info->fbops->fb_sync(info);
|
||||
|
||||
ret = read_screen(info, buf, count, pos);
|
||||
if (ret > 0)
|
||||
*ppos += ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef ssize_t (*drm_fb_helper_write_screen)(struct fb_info *info, const char __user *buf,
|
||||
size_t count, loff_t pos);
|
||||
|
||||
static ssize_t __drm_fb_helper_write(struct fb_info *info, const char __user *buf, size_t count,
|
||||
loff_t *ppos, drm_fb_helper_write_screen write_screen)
|
||||
{
|
||||
loff_t pos = *ppos;
|
||||
size_t total_size;
|
||||
ssize_t ret;
|
||||
int err = 0;
|
||||
|
||||
if (info->screen_size)
|
||||
total_size = info->screen_size;
|
||||
else
|
||||
total_size = info->fix.smem_len;
|
||||
|
||||
if (pos > total_size)
|
||||
return -EFBIG;
|
||||
if (count > total_size) {
|
||||
err = -EFBIG;
|
||||
count = total_size;
|
||||
}
|
||||
if (total_size - count < pos) {
|
||||
if (!err)
|
||||
err = -ENOSPC;
|
||||
count = total_size - pos;
|
||||
}
|
||||
|
||||
if (info->fbops->fb_sync)
|
||||
info->fbops->fb_sync(info);
|
||||
|
||||
/*
|
||||
* Copy to framebuffer even if we already logged an error. Emulates
|
||||
* the behavior of the original fbdev implementation.
|
||||
*/
|
||||
ret = write_screen(info, buf, count, pos);
|
||||
if (ret < 0)
|
||||
return ret; /* return last error, if any */
|
||||
else if (!ret)
|
||||
return err; /* return previous error, if any */
|
||||
|
||||
*ppos += ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t drm_fb_helper_read_screen_buffer(struct fb_info *info, char __user *buf,
|
||||
size_t count, loff_t pos)
|
||||
{
|
||||
const char *src = info->screen_buffer + pos;
|
||||
|
||||
if (copy_to_user(buf, src, count))
|
||||
return -EFAULT;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_sys_read - Implements struct &fb_ops.fb_read for system memory
|
||||
* @info: fb_info struct pointer
|
||||
@ -816,21 +727,10 @@ static ssize_t drm_fb_helper_read_screen_buffer(struct fb_info *info, char __use
|
||||
ssize_t drm_fb_helper_sys_read(struct fb_info *info, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return __drm_fb_helper_read(info, buf, count, ppos, drm_fb_helper_read_screen_buffer);
|
||||
return fb_sys_read(info, buf, count, ppos);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_sys_read);
|
||||
|
||||
static ssize_t drm_fb_helper_write_screen_buffer(struct fb_info *info, const char __user *buf,
|
||||
size_t count, loff_t pos)
|
||||
{
|
||||
char *dst = info->screen_buffer + pos;
|
||||
|
||||
if (copy_from_user(dst, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_sys_write - Implements struct &fb_ops.fb_write for system memory
|
||||
* @info: fb_info struct pointer
|
||||
@ -849,7 +749,7 @@ ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
|
||||
ssize_t ret;
|
||||
struct drm_rect damage_area;
|
||||
|
||||
ret = __drm_fb_helper_write(info, buf, count, ppos, drm_fb_helper_write_screen_buffer);
|
||||
ret = fb_sys_write(info, buf, count, ppos);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
@ -921,39 +821,6 @@ void drm_fb_helper_sys_imageblit(struct fb_info *info,
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_sys_imageblit);
|
||||
|
||||
static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_t count,
|
||||
loff_t pos)
|
||||
{
|
||||
const char __iomem *src = info->screen_base + pos;
|
||||
size_t alloc_size = min_t(size_t, count, PAGE_SIZE);
|
||||
ssize_t ret = 0;
|
||||
int err = 0;
|
||||
char *tmp;
|
||||
|
||||
tmp = kmalloc(alloc_size, GFP_KERNEL);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
while (count) {
|
||||
size_t c = min_t(size_t, count, alloc_size);
|
||||
|
||||
memcpy_fromio(tmp, src, c);
|
||||
if (copy_to_user(buf, tmp, c)) {
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
src += c;
|
||||
buf += c;
|
||||
ret += c;
|
||||
count -= c;
|
||||
}
|
||||
|
||||
kfree(tmp);
|
||||
|
||||
return ret ? ret : err;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_cfb_read - Implements struct &fb_ops.fb_read for I/O memory
|
||||
* @info: fb_info struct pointer
|
||||
@ -967,43 +834,10 @@ static ssize_t fb_read_screen_base(struct fb_info *info, char __user *buf, size_
|
||||
ssize_t drm_fb_helper_cfb_read(struct fb_info *info, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return __drm_fb_helper_read(info, buf, count, ppos, fb_read_screen_base);
|
||||
return fb_io_read(info, buf, count, ppos);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_cfb_read);
|
||||
|
||||
static ssize_t fb_write_screen_base(struct fb_info *info, const char __user *buf, size_t count,
|
||||
loff_t pos)
|
||||
{
|
||||
char __iomem *dst = info->screen_base + pos;
|
||||
size_t alloc_size = min_t(size_t, count, PAGE_SIZE);
|
||||
ssize_t ret = 0;
|
||||
int err = 0;
|
||||
u8 *tmp;
|
||||
|
||||
tmp = kmalloc(alloc_size, GFP_KERNEL);
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
while (count) {
|
||||
size_t c = min_t(size_t, count, alloc_size);
|
||||
|
||||
if (copy_from_user(tmp, buf, c)) {
|
||||
err = -EFAULT;
|
||||
break;
|
||||
}
|
||||
memcpy_toio(dst, tmp, c);
|
||||
|
||||
dst += c;
|
||||
buf += c;
|
||||
ret += c;
|
||||
count -= c;
|
||||
}
|
||||
|
||||
kfree(tmp);
|
||||
|
||||
return ret ? ret : err;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_fb_helper_cfb_write - Implements struct &fb_ops.fb_write for I/O memory
|
||||
* @info: fb_info struct pointer
|
||||
@ -1022,7 +856,7 @@ ssize_t drm_fb_helper_cfb_write(struct fb_info *info, const char __user *buf,
|
||||
ssize_t ret;
|
||||
struct drm_rect damage_area;
|
||||
|
||||
ret = __drm_fb_helper_write(info, buf, count, ppos, fb_write_screen_base);
|
||||
ret = fb_io_write(info, buf, count, ppos);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/drm_damage_helper.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
#include <drm/drm_gem.h>
|
||||
@ -164,6 +165,14 @@ int drm_gem_fb_init_with_funcs(struct drm_device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (drm_drv_uses_atomic_modeset(dev) &&
|
||||
!drm_any_plane_has_format(dev, mode_cmd->pixel_format,
|
||||
mode_cmd->modifier[0])) {
|
||||
drm_dbg(dev, "Unsupported pixel format %p4cc / modifier 0x%llx\n",
|
||||
&mode_cmd->pixel_format, mode_cmd->modifier[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->num_planes; i++) {
|
||||
unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
|
||||
unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
|
||||
|
@ -45,7 +45,7 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;
|
||||
* the frame's scanout buffer or the cursor image. If there's no more space
|
||||
* left in VRAM, inactive GEM objects can be moved to system memory.
|
||||
*
|
||||
* To initialize the VRAM helper library call drmm_vram_helper_alloc_mm().
|
||||
* To initialize the VRAM helper library call drmm_vram_helper_init().
|
||||
* The function allocates and initializes an instance of &struct drm_vram_mm
|
||||
* in &struct drm_device.vram_mm . Use &DRM_GEM_VRAM_DRIVER to initialize
|
||||
* &struct drm_driver and &DRM_VRAM_MM_FILE_OPERATIONS to initialize
|
||||
@ -73,7 +73,7 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;
|
||||
* // setup device, vram base and size
|
||||
* // ...
|
||||
*
|
||||
* ret = drmm_vram_helper_alloc_mm(dev, vram_base, vram_size);
|
||||
* ret = drmm_vram_helper_init(dev, vram_base, vram_size);
|
||||
* if (ret)
|
||||
* return ret;
|
||||
* return 0;
|
||||
@ -86,7 +86,7 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs;
|
||||
* to userspace.
|
||||
*
|
||||
* You don't have to clean up the instance of VRAM MM.
|
||||
* drmm_vram_helper_alloc_mm() is a managed interface that installs a
|
||||
* drmm_vram_helper_init() is a managed interface that installs a
|
||||
* clean-up handler to run during the DRM device's release.
|
||||
*
|
||||
* For drawing or scanout operations, rsp. buffer objects have to be pinned
|
||||
|
@ -11,12 +11,14 @@
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/drm_accel.h>
|
||||
@ -96,6 +98,34 @@ static char *drm_devnode(const struct device *dev, umode_t *mode)
|
||||
return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
|
||||
}
|
||||
|
||||
static int typec_connector_bind(struct device *dev,
|
||||
struct device *typec_connector, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sysfs_create_link(&dev->kobj, &typec_connector->kobj, "typec_connector");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_link(&typec_connector->kobj, &dev->kobj, "drm_connector");
|
||||
if (ret)
|
||||
sysfs_remove_link(&dev->kobj, "typec_connector");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void typec_connector_unbind(struct device *dev,
|
||||
struct device *typec_connector, void *data)
|
||||
{
|
||||
sysfs_remove_link(&typec_connector->kobj, "drm_connector");
|
||||
sysfs_remove_link(&dev->kobj, "typec_connector");
|
||||
}
|
||||
|
||||
static const struct component_ops typec_connector_ops = {
|
||||
.bind = typec_connector_bind,
|
||||
.unbind = typec_connector_unbind,
|
||||
};
|
||||
|
||||
static CLASS_ATTR_STRING(version, S_IRUGO, "drm 1.1.0 20060810");
|
||||
|
||||
/**
|
||||
@ -282,16 +312,27 @@ static ssize_t modes_show(struct device *device,
|
||||
return written;
|
||||
}
|
||||
|
||||
static ssize_t connector_id_show(struct device *device,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct drm_connector *connector = to_drm_connector(device);
|
||||
|
||||
return sysfs_emit(buf, "%d\n", connector->base.id);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(status);
|
||||
static DEVICE_ATTR_RO(enabled);
|
||||
static DEVICE_ATTR_RO(dpms);
|
||||
static DEVICE_ATTR_RO(modes);
|
||||
static DEVICE_ATTR_RO(connector_id);
|
||||
|
||||
static struct attribute *connector_dev_attrs[] = {
|
||||
&dev_attr_status.attr,
|
||||
&dev_attr_enabled.attr,
|
||||
&dev_attr_dpms.attr,
|
||||
&dev_attr_modes.attr,
|
||||
&dev_attr_connector_id.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -353,9 +394,16 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
|
||||
|
||||
connector->kdev = kdev;
|
||||
|
||||
if (dev_fwnode(kdev)) {
|
||||
r = component_add(kdev, &typec_connector_ops);
|
||||
if (r)
|
||||
drm_err(dev, "failed to add component to create link to typec connector\n");
|
||||
}
|
||||
|
||||
if (connector->ddc)
|
||||
return sysfs_create_link(&connector->kdev->kobj,
|
||||
&connector->ddc->dev.kobj, "ddc");
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
@ -371,6 +419,9 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
|
||||
if (connector->ddc)
|
||||
sysfs_remove_link(&connector->kdev->kobj, "ddc");
|
||||
|
||||
if (dev_fwnode(connector->kdev))
|
||||
component_del(connector->kdev, &typec_connector_ops);
|
||||
|
||||
DRM_DEBUG("removing \"%s\" from sysfs\n",
|
||||
connector->name);
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include <linux/aperture.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/notifier.h>
|
||||
@ -19,7 +20,6 @@
|
||||
#include <acpi/video.h>
|
||||
|
||||
#include <drm/drm.h>
|
||||
#include <drm/drm_aperture.h>
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_ioctl.h>
|
||||
@ -414,20 +414,45 @@ out_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hardware for gma500 is a hybrid device, which both acts as a PCI
|
||||
* device (for legacy vga functionality) but also more like an
|
||||
* integrated display on a SoC where the framebuffer simply
|
||||
* resides in main memory and not in a special PCI bar (that
|
||||
* internally redirects to a stolen range of main memory) like all
|
||||
* other integrated PCI display devices implement it.
|
||||
*
|
||||
* To catch all cases we need to remove conflicting firmware devices
|
||||
* for the stolen system memory and for the VGA functionality. As we
|
||||
* currently cannot easily find the framebuffer's location in stolen
|
||||
* memory, we remove all framebuffers here.
|
||||
*
|
||||
* TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then
|
||||
* we might be able to read the framebuffer range from the
|
||||
* device.
|
||||
*/
|
||||
static int gma_remove_conflicting_framebuffers(struct pci_dev *pdev,
|
||||
const struct drm_driver *req_driver)
|
||||
{
|
||||
resource_size_t base = 0;
|
||||
resource_size_t size = U32_MAX; /* 4 GiB HW limit */
|
||||
const char *name = req_driver->name;
|
||||
int ret;
|
||||
|
||||
ret = aperture_remove_conflicting_devices(base, size, name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return __aperture_remove_legacy_vga_devices(pdev);
|
||||
}
|
||||
|
||||
static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
struct drm_psb_private *dev_priv;
|
||||
struct drm_device *dev;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We cannot yet easily find the framebuffer's location in memory. So
|
||||
* remove all framebuffers here.
|
||||
*
|
||||
* TODO: Refactor psb_driver_load() to map vdc_reg earlier. Then we
|
||||
* might be able to read the framebuffer range from the device.
|
||||
*/
|
||||
ret = drm_aperture_remove_framebuffers(true, &driver);
|
||||
ret = gma_remove_conflicting_framebuffers(pdev, &driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -74,7 +74,6 @@ static int hyperv_setup_vram(struct hyperv_drm_device *hv,
|
||||
|
||||
drm_aperture_remove_conflicting_framebuffers(screen_info.lfb_base,
|
||||
screen_info.lfb_size,
|
||||
false,
|
||||
&hyperv_driver);
|
||||
|
||||
hv->fb_size = (unsigned long)hv->mmio_megabytes * 1024 * 1024;
|
||||
|
@ -400,8 +400,8 @@ static int imx_lcdc_probe(struct platform_device *pdev)
|
||||
|
||||
lcdc = devm_drm_dev_alloc(dev, &imx_lcdc_drm_driver,
|
||||
struct imx_lcdc, drm);
|
||||
if (!lcdc)
|
||||
return -ENOMEM;
|
||||
if (IS_ERR(lcdc))
|
||||
return PTR_ERR(lcdc);
|
||||
|
||||
drm = &lcdc->drm;
|
||||
|
||||
|
@ -285,7 +285,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
|
||||
* Remove early framebuffers (ie. simplefb). The framebuffer can be
|
||||
* located anywhere in RAM
|
||||
*/
|
||||
ret = drm_aperture_remove_framebuffers(false, &meson_driver);
|
||||
ret = drm_aperture_remove_framebuffers(&meson_driver);
|
||||
if (ret)
|
||||
goto free_drm;
|
||||
|
||||
|
@ -186,7 +186,7 @@ union meson_hdmi_venc_mode {
|
||||
} encp;
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = {
|
||||
.enci = {
|
||||
.hso_begin = 5,
|
||||
.hso_end = 129,
|
||||
@ -206,7 +206,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = {
|
||||
.enci = {
|
||||
.hso_begin = 3,
|
||||
.hso_end = 129,
|
||||
@ -226,7 +226,7 @@ union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x21,
|
||||
.video_mode = 0x4000,
|
||||
@ -272,7 +272,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x21,
|
||||
.video_mode = 0x4000,
|
||||
@ -318,7 +318,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x2029,
|
||||
.video_mode = 0x4040,
|
||||
@ -360,7 +360,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x202d,
|
||||
.video_mode = 0x4040,
|
||||
@ -405,7 +405,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x2029,
|
||||
.video_mode = 0x5ffc,
|
||||
@ -454,7 +454,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x202d,
|
||||
.video_mode = 0x5ffc,
|
||||
@ -503,7 +503,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0xd,
|
||||
.video_mode = 0x4040,
|
||||
@ -552,7 +552,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x1,
|
||||
.video_mode = 0x4040,
|
||||
@ -596,7 +596,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0xd,
|
||||
.video_mode = 0x4040,
|
||||
@ -644,7 +644,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x1,
|
||||
.video_mode = 0x4040,
|
||||
@ -688,7 +688,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x1,
|
||||
.video_mode = 0x4040,
|
||||
@ -730,7 +730,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x1,
|
||||
.video_mode = 0x4040,
|
||||
@ -772,7 +772,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = {
|
||||
},
|
||||
};
|
||||
|
||||
union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = {
|
||||
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = {
|
||||
.encp = {
|
||||
.dvi_settings = 0x1,
|
||||
.video_mode = 0x4040,
|
||||
@ -814,7 +814,7 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = {
|
||||
},
|
||||
};
|
||||
|
||||
struct meson_hdmi_venc_vic_mode {
|
||||
static struct meson_hdmi_venc_vic_mode {
|
||||
unsigned int vic;
|
||||
union meson_hdmi_venc_mode *mode;
|
||||
} meson_hdmi_venc_vic_modes[] = {
|
||||
|
@ -455,7 +455,7 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
|
||||
goto err_deinit_vram;
|
||||
|
||||
/* the fw fb could be anywhere in memory */
|
||||
ret = drm_aperture_remove_framebuffers(false, drv);
|
||||
ret = drm_aperture_remove_framebuffers(drv);
|
||||
if (ret)
|
||||
goto err_msm_uninit;
|
||||
|
||||
|
@ -73,13 +73,14 @@ nouveau_debugfs_pstate_get(struct seq_file *m, void *data)
|
||||
{
|
||||
struct drm_device *drm = m->private;
|
||||
struct nouveau_debugfs *debugfs = nouveau_debugfs(drm);
|
||||
struct nvif_object *ctrl = &debugfs->ctrl;
|
||||
struct nvif_object *ctrl;
|
||||
struct nvif_control_pstate_info_v0 info = {};
|
||||
int ret, i;
|
||||
|
||||
if (!debugfs)
|
||||
return -ENODEV;
|
||||
|
||||
ctrl = &debugfs->ctrl;
|
||||
ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_INFO, &info, sizeof(info));
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -119,19 +120,19 @@ nouveau_debugfs_pstate_get(struct seq_file *m, void *data)
|
||||
|
||||
if (state >= 0) {
|
||||
if (info.ustate_ac == state)
|
||||
seq_printf(m, " AC");
|
||||
seq_puts(m, " AC");
|
||||
if (info.ustate_dc == state)
|
||||
seq_printf(m, " DC");
|
||||
seq_puts(m, " DC");
|
||||
if (info.pstate == state)
|
||||
seq_printf(m, " *");
|
||||
seq_puts(m, " *");
|
||||
} else {
|
||||
if (info.ustate_ac < -1)
|
||||
seq_printf(m, " AC");
|
||||
seq_puts(m, " AC");
|
||||
if (info.ustate_dc < -1)
|
||||
seq_printf(m, " DC");
|
||||
seq_puts(m, " DC");
|
||||
}
|
||||
|
||||
seq_printf(m, "\n");
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -144,7 +145,6 @@ nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf,
|
||||
struct seq_file *m = file->private_data;
|
||||
struct drm_device *drm = m->private;
|
||||
struct nouveau_debugfs *debugfs = nouveau_debugfs(drm);
|
||||
struct nvif_object *ctrl = &debugfs->ctrl;
|
||||
struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL };
|
||||
char buf[32] = {}, *tmp, *cur = buf;
|
||||
long value, ret;
|
||||
@ -188,7 +188,8 @@ nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args));
|
||||
ret = nvif_mthd(&debugfs->ctrl, NVIF_CONTROL_PSTATE_USER,
|
||||
&args, sizeof(args));
|
||||
pm_runtime_put_autosuspend(drm->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -59,7 +59,6 @@ int
|
||||
nvbios_power_budget_header(struct nvkm_bios *bios,
|
||||
struct nvbios_power_budget *budget)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &bios->subdev;
|
||||
u8 ver, hdr, cnt, len, cap_entry;
|
||||
u32 header;
|
||||
|
||||
@ -82,7 +81,7 @@ nvbios_power_budget_header(struct nvkm_bios *bios,
|
||||
}
|
||||
|
||||
if (cap_entry >= cnt && cap_entry != 0xff) {
|
||||
nvkm_warn(subdev,
|
||||
nvkm_warn(&bios->subdev,
|
||||
"invalid cap_entry in power budget table found\n");
|
||||
budget->cap_entry = 0xff;
|
||||
return -EINVAL;
|
||||
|
@ -417,7 +417,6 @@ nvkm_pstate_new(struct nvkm_clk *clk, int idx)
|
||||
return 0;
|
||||
|
||||
pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
|
||||
cstate = &pstate->base;
|
||||
if (!pstate)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -427,6 +426,7 @@ nvkm_pstate_new(struct nvkm_clk *clk, int idx)
|
||||
pstate->fanspeed = perfE.fanspeed;
|
||||
pstate->pcie_speed = perfE.pcie_speed;
|
||||
pstate->pcie_width = perfE.pcie_width;
|
||||
cstate = &pstate->base;
|
||||
cstate->voltage = perfE.voltage;
|
||||
cstate->domain[nv_clk_src_core] = perfE.core;
|
||||
cstate->domain[nv_clk_src_shader] = perfE.shader;
|
||||
|
@ -114,18 +114,17 @@ nvkm_pcie_init(struct nvkm_pci *pci)
|
||||
int
|
||||
nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
|
||||
{
|
||||
struct nvkm_subdev *subdev = &pci->subdev;
|
||||
struct nvkm_subdev *subdev;
|
||||
enum nvkm_pcie_speed cur_speed, max_speed;
|
||||
struct pci_bus *pbus;
|
||||
int ret;
|
||||
|
||||
if (!pci || !pci_is_pcie(pci->pdev))
|
||||
return 0;
|
||||
pbus = pci->pdev->bus;
|
||||
|
||||
if (!pci->func->pcie.set_link)
|
||||
return -ENOSYS;
|
||||
|
||||
subdev = &pci->subdev;
|
||||
nvkm_trace(subdev, "requested %s\n", nvkm_pcie_speeds[speed]);
|
||||
|
||||
if (pci->func->pcie.version(pci) < 2) {
|
||||
@ -134,7 +133,7 @@ nvkm_pcie_set_link(struct nvkm_pci *pci, enum nvkm_pcie_speed speed, u8 width)
|
||||
}
|
||||
|
||||
cur_speed = pci->func->pcie.cur_speed(pci);
|
||||
max_speed = min(nvkm_pcie_speed(pbus->max_bus_speed),
|
||||
max_speed = min(nvkm_pcie_speed(pci->pdev->bus->max_bus_speed),
|
||||
pci->func->pcie.max_speed(pci));
|
||||
|
||||
nvkm_trace(subdev, "current speed: %s\n", nvkm_pcie_speeds[cur_speed]);
|
||||
|
@ -98,10 +98,10 @@ nvkm_fanpwm_create(struct nvkm_therm *therm, struct dcb_gpio_func *func)
|
||||
return -ENODEV;
|
||||
|
||||
fan = kzalloc(sizeof(*fan), GFP_KERNEL);
|
||||
therm->fan = &fan->base;
|
||||
if (!fan)
|
||||
return -ENOMEM;
|
||||
|
||||
therm->fan = &fan->base;
|
||||
fan->base.type = "PWM";
|
||||
fan->base.get = nvkm_fanpwm_get;
|
||||
fan->base.set = nvkm_fanpwm_set;
|
||||
|
@ -100,10 +100,10 @@ nvkm_fantog_create(struct nvkm_therm *therm, struct dcb_gpio_func *func)
|
||||
}
|
||||
|
||||
fan = kzalloc(sizeof(*fan), GFP_KERNEL);
|
||||
therm->fan = &fan->base;
|
||||
if (!fan)
|
||||
return -ENOMEM;
|
||||
|
||||
therm->fan = &fan->base;
|
||||
fan->base.type = "toggle";
|
||||
fan->base.get = nvkm_fantog_get;
|
||||
fan->base.set = nvkm_fantog_set;
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright (c) 2022, 2023 Jianhua Lu <lujianhua000@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
@ -12,6 +13,8 @@
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
@ -30,6 +33,7 @@ struct panel_info {
|
||||
struct drm_panel panel;
|
||||
struct mipi_dsi_device *dsi[2];
|
||||
const struct panel_desc *desc;
|
||||
enum drm_panel_orientation orientation;
|
||||
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct backlight_device *backlight;
|
||||
@ -53,6 +57,7 @@ struct panel_desc {
|
||||
int (*init_sequence)(struct panel_info *pinfo);
|
||||
|
||||
bool is_dual_dsi;
|
||||
bool has_dcs_backlight;
|
||||
};
|
||||
|
||||
static inline struct panel_info *to_panel_info(struct drm_panel *panel)
|
||||
@ -478,6 +483,456 @@ static int elish_csot_init_sequence(struct panel_info *pinfo)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int j606f_boe_init_sequence(struct panel_info *pinfo)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = pinfo->dsi[0];
|
||||
struct device *dev = &dsi->dev;
|
||||
int ret;
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x05, 0xd9);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x07, 0x78);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x08, 0x5a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x63);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0e, 0x91);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x73);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x95, 0xeb);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x96, 0xeb);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x66);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x75, 0xa2);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x77, 0xb3);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00,
|
||||
0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01,
|
||||
0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03,
|
||||
0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03,
|
||||
0xfd, 0x03, 0xff);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00,
|
||||
0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01,
|
||||
0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03,
|
||||
0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03,
|
||||
0xfd, 0x03, 0xff);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x00, 0x08, 0x00, 0x23, 0x00, 0x4d, 0x00, 0x6d, 0x00,
|
||||
0x89, 0x00, 0xa1, 0x00, 0xb6, 0x00, 0xc9);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xda, 0x01, 0x13, 0x01, 0x3c, 0x01, 0x7e, 0x01,
|
||||
0xab, 0x01, 0xf7, 0x02, 0x2f, 0x02, 0x31);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xba, 0x02, 0x67, 0x02, 0xa6, 0x02, 0xd1, 0x03, 0x08, 0x03,
|
||||
0x2e, 0x03, 0x5b, 0x03, 0x6b, 0x03, 0x7b);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x03, 0x8e, 0x03, 0xa2, 0x03, 0xb7, 0x03, 0xe7, 0x03,
|
||||
0xfd, 0x03, 0xff);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x21);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00,
|
||||
0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01,
|
||||
0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03,
|
||||
0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb3, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03,
|
||||
0xf5, 0x03, 0xf7);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00,
|
||||
0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01,
|
||||
0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03,
|
||||
0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb7, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03,
|
||||
0xf5, 0x03, 0xf7);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb8, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x45, 0x00, 0x65, 0x00,
|
||||
0x81, 0x00, 0x99, 0x00, 0xae, 0x00, 0xc1);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0xd2, 0x01, 0x0b, 0x01, 0x34, 0x01, 0x76, 0x01,
|
||||
0xa3, 0x01, 0xef, 0x02, 0x27, 0x02, 0x29);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xba, 0x02, 0x5f, 0x02, 0x9e, 0x02, 0xc9, 0x03, 0x00, 0x03,
|
||||
0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x03, 0x86, 0x03, 0x9a, 0x03, 0xaf, 0x03, 0xdf, 0x03,
|
||||
0xf5, 0x03, 0xf7);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x23);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x00, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x07, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x11, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x12, 0x77);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x15, 0x07);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x16, 0x07);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x24);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x01, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x02, 0x1c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x03, 0x1c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x04, 0x1d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x05, 0x1d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x06, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x07, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x08, 0x0f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x09, 0x0f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0a, 0x0e);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0b, 0x0e);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x0d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x0d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0e, 0x0c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x0c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x10, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x11, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x12, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x13, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x14, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x15, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x16, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x17, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x18, 0x1c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x19, 0x1c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x1d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x1d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1c, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x0f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x0f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x20, 0x0e);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x21, 0x0e);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x22, 0x0d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x23, 0x0d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x24, 0x0c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x25, 0x0c);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x27, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x28, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x29, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_LUT, 0x20);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x0a);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x44);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x33, 0x0c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x34, 0x32);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x37, 0x44);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x38, 0x40);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x39, 0x00);
|
||||
|
||||
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x9a);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set pixel format: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x3b, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_3D_CONTROL, 0x42);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x3f, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x43, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x47, 0x66);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x4a, 0x9a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x4b, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x4c, 0x91);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x4d, 0x21);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x4e, 0x43);
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_brightness(dsi, 18);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set display brightness: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x52, 0x34);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x55, 0x82, 0x02);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x56, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x58, 0x21);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x59, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5a, 0xba);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5b, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x00, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5f, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x82);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x7e, 0x20);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x7f, 0x3c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x82, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x97, 0xc0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb6,
|
||||
0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
|
||||
0x05, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x92, 0xc4);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x93, 0x1a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x94, 0x5f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xd7, 0x55);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xda, 0x0a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xde, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xdb, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xdc, 0xc4);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x22);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe0, 0xc4);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe1, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe2, 0xc4);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe3, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe4, 0xc4);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe5, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe6, 0xc4);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x88);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x8d, 0x88);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x8e, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb5, 0x90);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x25);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x05, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x19, 0x07);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1f, 0xba);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x20, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0xba);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x27, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x33, 0xba);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x34, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x3f, 0xe0);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_VSYNC_TIMING, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x44, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_GET_SCANLINE, 0x40);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x48, 0xba);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x49, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0xd0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x61, 0xba);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x62, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf1, 0x10);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x64, 0x16);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x67, 0x16);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x6a, 0x16);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x70, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_READ_PPS_START, 0xf3);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xa3, 0xff);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xa4, 0xff);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xa5, 0xff);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xd6, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x26);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x00, 0xa1);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0a, 0xf2);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x04, 0x28);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x06, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0c, 0x13);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0d, 0x0a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0f, 0x0a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x11, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x12, 0x50);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x13, 0x51);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x14, 0x65);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x15, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x16, 0x10);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x17, 0xa0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x18, 0x86);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x19, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x7b);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x10);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1c, 0xbb);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x22, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x23, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x7b);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1d, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1e, 0xc3);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1f, 0xc3);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x24, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x25, 0xc3);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2f, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0xc3);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_COLUMNS, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x32, 0xc3);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x39, 0x00);
|
||||
|
||||
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0xc3);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set pixel format: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x20, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x33, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x34, 0x78);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x35, 0x16);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xc8, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xc9, 0x82);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xca, 0x4e);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xcb, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_READ_PPS_CONTINUE, 0x4c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xaa, 0x47);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x27);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x56, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x58, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x59, 0x53);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5a, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x14);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_CABC_MIN_BRIGHTNESS, 0x20);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5f, 0x10);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x60, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x61, 0x1d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x62, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x63, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x64, 0x24);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x1c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x66, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x67, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x68, 0x25);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x78, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xc3, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xd1, 0x24);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x22, 0x2f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x23, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x24, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x25, 0xc3);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0xf8);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x27, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x28, 0x1a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x29, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x1a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_LUT, 0x1a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0xe0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x14, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x16, 0xc0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0xf0);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
|
||||
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x08);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set pixel format: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x24);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
|
||||
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x5d);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set pixel format: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x3b, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x4a, 0x5d);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x4b, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5a, 0x70);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x91, 0x44);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x92, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xdb, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xdc, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xdd, 0x22);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xdf, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe0, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe1, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe2, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe3, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe4, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe5, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xe6, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5c, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5d, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x8d, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x8e, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x25);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x70);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x20, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_GAMMA_CURVE, 0x70);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x27, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x33, 0x70);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x34, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x48, 0x70);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x49, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5b, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x61, 0x70);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x62, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x26);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x02, 0x31);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x19, 0x0a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1a, 0x7f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1b, 0x0a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1c, 0x0c);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2a, 0x0a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2b, 0x7f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1e, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x1f, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x25, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_ROWS, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_PARTIAL_COLUMNS, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x32, 0x8d);
|
||||
|
||||
ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x75);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set pixel format: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x2a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x25, 0x75);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x20);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x18, 0x40);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x02);
|
||||
|
||||
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set tear on: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x13);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x3b, 0x03, 0x5f, 0x1a, 0x04, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x10);
|
||||
usleep_range(10000, 11000);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfb, 0x01);
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_brightness(dsi, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set display brightness: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x2c);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x68, 0x05, 0x01);
|
||||
|
||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(100);
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_on(dsi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set display on: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(30);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_display_mode elish_boe_modes[] = {
|
||||
{
|
||||
/* There is only one 120 Hz timing, but it doesn't work perfectly, 104 Hz preferred */
|
||||
@ -508,6 +963,22 @@ static const struct drm_display_mode elish_csot_modes[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode j606f_boe_modes[] = {
|
||||
{
|
||||
.clock = (1200 + 58 + 2 + 60) * (2000 + 26 + 2 + 93) * 60 / 1000,
|
||||
.hdisplay = 1200,
|
||||
.hsync_start = 1200 + 58,
|
||||
.hsync_end = 1200 + 58 + 2,
|
||||
.htotal = 1200 + 58 + 2 + 60,
|
||||
.vdisplay = 2000,
|
||||
.vsync_start = 2000 + 26,
|
||||
.vsync_end = 2000 + 26 + 2,
|
||||
.vtotal = 2000 + 26 + 2 + 93,
|
||||
.width_mm = 143,
|
||||
.height_mm = 235,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct panel_desc elish_boe_desc = {
|
||||
.modes = elish_boe_modes,
|
||||
.num_modes = ARRAY_SIZE(elish_boe_modes),
|
||||
@ -544,6 +1015,20 @@ static const struct panel_desc elish_csot_desc = {
|
||||
.is_dual_dsi = true,
|
||||
};
|
||||
|
||||
static const struct panel_desc j606f_boe_desc = {
|
||||
.modes = j606f_boe_modes,
|
||||
.num_modes = ARRAY_SIZE(j606f_boe_modes),
|
||||
.width_mm = 143,
|
||||
.height_mm = 235,
|
||||
.bpc = 8,
|
||||
.lanes = 4,
|
||||
.format = MIPI_DSI_FMT_RGB888,
|
||||
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM,
|
||||
.init_sequence = j606f_boe_init_sequence,
|
||||
.has_dcs_backlight = true,
|
||||
};
|
||||
|
||||
static void nt36523_reset(struct panel_info *pinfo)
|
||||
{
|
||||
gpiod_set_value_cansleep(pinfo->reset_gpio, 1);
|
||||
@ -672,13 +1157,74 @@ static int nt36523_get_modes(struct drm_panel *panel,
|
||||
return pinfo->desc->num_modes;
|
||||
}
|
||||
|
||||
static enum drm_panel_orientation nt36523_get_orientation(struct drm_panel *panel)
|
||||
{
|
||||
struct panel_info *pinfo = to_panel_info(panel);
|
||||
|
||||
return pinfo->orientation;
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs nt36523_panel_funcs = {
|
||||
.disable = nt36523_disable,
|
||||
.prepare = nt36523_prepare,
|
||||
.unprepare = nt36523_unprepare,
|
||||
.get_modes = nt36523_get_modes,
|
||||
.get_orientation = nt36523_get_orientation,
|
||||
};
|
||||
|
||||
static int nt36523_bl_update_status(struct backlight_device *bl)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = bl_get_data(bl);
|
||||
u16 brightness = backlight_get_brightness(bl);
|
||||
int ret;
|
||||
|
||||
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nt36523_bl_get_brightness(struct backlight_device *bl)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = bl_get_data(bl);
|
||||
u16 brightness;
|
||||
int ret;
|
||||
|
||||
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||
|
||||
ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
return brightness;
|
||||
}
|
||||
|
||||
static const struct backlight_ops nt36523_bl_ops = {
|
||||
.update_status = nt36523_bl_update_status,
|
||||
.get_brightness = nt36523_bl_get_brightness,
|
||||
};
|
||||
|
||||
static struct backlight_device *nt36523_create_backlight(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct device *dev = &dsi->dev;
|
||||
const struct backlight_properties props = {
|
||||
.type = BACKLIGHT_RAW,
|
||||
.brightness = 512,
|
||||
.max_brightness = 4095,
|
||||
.scale = BACKLIGHT_SCALE_NON_LINEAR,
|
||||
};
|
||||
|
||||
return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
|
||||
&nt36523_bl_ops, &props);
|
||||
}
|
||||
|
||||
static int nt36523_probe(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct device *dev = &dsi->dev;
|
||||
@ -730,9 +1276,22 @@ static int nt36523_probe(struct mipi_dsi_device *dsi)
|
||||
mipi_dsi_set_drvdata(dsi, pinfo);
|
||||
drm_panel_init(&pinfo->panel, dev, &nt36523_panel_funcs, DRM_MODE_CONNECTOR_DSI);
|
||||
|
||||
ret = drm_panel_of_backlight(&pinfo->panel);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to get backlight\n");
|
||||
ret = of_drm_get_panel_orientation(dev->of_node, &pinfo->orientation);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pinfo->desc->has_dcs_backlight) {
|
||||
pinfo->panel.backlight = nt36523_create_backlight(dsi);
|
||||
if (IS_ERR(pinfo->panel.backlight))
|
||||
return dev_err_probe(dev, PTR_ERR(pinfo->panel.backlight),
|
||||
"Failed to create backlight\n");
|
||||
} else {
|
||||
ret = drm_panel_of_backlight(&pinfo->panel);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to get backlight\n");
|
||||
}
|
||||
|
||||
drm_panel_add(&pinfo->panel);
|
||||
|
||||
@ -750,6 +1309,10 @@ static int nt36523_probe(struct mipi_dsi_device *dsi)
|
||||
}
|
||||
|
||||
static const struct of_device_id nt36523_of_match[] = {
|
||||
{
|
||||
.compatible = "lenovo,j606f-boe-nt36523w",
|
||||
.data = &j606f_boe_desc,
|
||||
},
|
||||
{
|
||||
.compatible = "xiaomi,elish-boe-nt36523",
|
||||
.data = &elish_boe_desc,
|
||||
|
@ -2142,6 +2142,38 @@ static const struct panel_desc innolux_at070tn92 = {
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
};
|
||||
|
||||
static const struct display_timing innolux_g070ace_l01_timing = {
|
||||
.pixelclock = { 25200000, 35000000, 35700000 },
|
||||
.hactive = { 800, 800, 800 },
|
||||
.hfront_porch = { 30, 32, 87 },
|
||||
.hback_porch = { 30, 32, 87 },
|
||||
.hsync_len = { 1, 1, 1 },
|
||||
.vactive = { 480, 480, 480 },
|
||||
.vfront_porch = { 3, 3, 3 },
|
||||
.vback_porch = { 13, 13, 13 },
|
||||
.vsync_len = { 1, 1, 4 },
|
||||
.flags = DISPLAY_FLAGS_DE_HIGH,
|
||||
};
|
||||
|
||||
static const struct panel_desc innolux_g070ace_l01 = {
|
||||
.timings = &innolux_g070ace_l01_timing,
|
||||
.num_timings = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 152,
|
||||
.height = 91,
|
||||
},
|
||||
.delay = {
|
||||
.prepare = 10,
|
||||
.enable = 50,
|
||||
.disable = 50,
|
||||
.unprepare = 500,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH,
|
||||
.connector_type = DRM_MODE_CONNECTOR_LVDS,
|
||||
};
|
||||
|
||||
static const struct display_timing innolux_g070y2_l01_timing = {
|
||||
.pixelclock = { 28000000, 29500000, 32000000 },
|
||||
.hactive = { 800, 800, 800 },
|
||||
@ -4098,6 +4130,9 @@ static const struct of_device_id platform_of_match[] = {
|
||||
}, {
|
||||
.compatible = "innolux,at070tn92",
|
||||
.data = &innolux_at070tn92,
|
||||
}, {
|
||||
.compatible = "innolux,g070ace-l01",
|
||||
.data = &innolux_g070ace_l01,
|
||||
}, {
|
||||
.compatible = "innolux,g070y2-l01",
|
||||
.data = &innolux_g070y2_l01,
|
||||
|
@ -28,6 +28,7 @@
|
||||
/* Manufacturer specific Commands send via DSI */
|
||||
#define ST7703_CMD_ALL_PIXEL_OFF 0x22
|
||||
#define ST7703_CMD_ALL_PIXEL_ON 0x23
|
||||
#define ST7703_CMD_SETAPID 0xB1
|
||||
#define ST7703_CMD_SETDISP 0xB2
|
||||
#define ST7703_CMD_SETRGBIF 0xB3
|
||||
#define ST7703_CMD_SETCYC 0xB4
|
||||
@ -41,12 +42,15 @@
|
||||
#define ST7703_CMD_UNKNOWN_BF 0xBF
|
||||
#define ST7703_CMD_SETSCR 0xC0
|
||||
#define ST7703_CMD_SETPOWER 0xC1
|
||||
#define ST7703_CMD_SETECO 0xC6
|
||||
#define ST7703_CMD_SETIO 0xC7
|
||||
#define ST7703_CMD_SETCABC 0xC8
|
||||
#define ST7703_CMD_SETPANEL 0xCC
|
||||
#define ST7703_CMD_UNKNOWN_C6 0xC6
|
||||
#define ST7703_CMD_SETGAMMA 0xE0
|
||||
#define ST7703_CMD_SETEQ 0xE3
|
||||
#define ST7703_CMD_SETGIP1 0xE9
|
||||
#define ST7703_CMD_SETGIP2 0xEA
|
||||
#define ST7703_CMD_UNKNOWN_EF 0xEF
|
||||
|
||||
struct st7703 {
|
||||
struct device *dev;
|
||||
@ -249,8 +253,7 @@ static int xbd599_init_sequence(struct st7703 *ctx)
|
||||
* ESD_DET_TIME_SEL = 0 frames
|
||||
*/);
|
||||
|
||||
/* Undocumented command. */
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
|
||||
0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
|
||||
@ -338,6 +341,98 @@ static const struct st7703_panel_desc xbd599_desc = {
|
||||
.init_sequence = xbd599_init_sequence,
|
||||
};
|
||||
|
||||
static int rg353v2_init_sequence(struct st7703 *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
|
||||
/*
|
||||
* Init sequence was supplied by the panel vendor.
|
||||
*/
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00,
|
||||
0xda, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
|
||||
0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x0a, 0x0a);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x92, 0x92);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22,
|
||||
0xf0, 0x63);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05,
|
||||
0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a,
|
||||
0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
|
||||
0x00, 0x00, 0x12, 0x50, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32,
|
||||
0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33,
|
||||
0x33);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
|
||||
0x00, 0xff);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
|
||||
0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
|
||||
0x02);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d,
|
||||
0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d,
|
||||
0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07,
|
||||
0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c,
|
||||
0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
|
||||
0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||||
0xc0, 0x10);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00,
|
||||
0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80,
|
||||
0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
|
||||
0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
|
||||
0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
|
||||
0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
|
||||
0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
|
||||
0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42,
|
||||
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
|
||||
0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_display_mode rg353v2_mode = {
|
||||
.hdisplay = 640,
|
||||
.hsync_start = 640 + 40,
|
||||
.hsync_end = 640 + 40 + 2,
|
||||
.htotal = 640 + 40 + 2 + 80,
|
||||
.vdisplay = 480,
|
||||
.vsync_start = 480 + 18,
|
||||
.vsync_end = 480 + 18 + 2,
|
||||
.vtotal = 480 + 18 + 2 + 28,
|
||||
.clock = 24150,
|
||||
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
|
||||
.width_mm = 70,
|
||||
.height_mm = 57,
|
||||
};
|
||||
|
||||
static const struct st7703_panel_desc rg353v2_desc = {
|
||||
.mode = &rg353v2_mode,
|
||||
.lanes = 4,
|
||||
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_NO_EOT_PACKET | MIPI_DSI_MODE_LPM,
|
||||
.format = MIPI_DSI_FMT_RGB888,
|
||||
.init_sequence = rg353v2_init_sequence,
|
||||
};
|
||||
|
||||
static int st7703_enable(struct drm_panel *panel)
|
||||
{
|
||||
struct st7703 *ctx = panel_to_st7703(panel);
|
||||
@ -598,6 +693,7 @@ static void st7703_remove(struct mipi_dsi_device *dsi)
|
||||
}
|
||||
|
||||
static const struct of_device_id st7703_of_match[] = {
|
||||
{ .compatible = "anbernic,rg353v-panel-v2", .data = &rg353v2_desc },
|
||||
{ .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
|
||||
{ .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
|
||||
{ /* sentinel */ }
|
||||
|
@ -273,10 +273,9 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector)
|
||||
edid->width_cm, edid->height_cm);
|
||||
|
||||
dp->sink_has_audio = drm_detect_monitor_audio(edid);
|
||||
|
||||
drm_connector_update_edid_property(connector, edid);
|
||||
ret = drm_add_edid_modes(connector, edid);
|
||||
if (ret)
|
||||
drm_connector_update_edid_property(connector,
|
||||
edid);
|
||||
}
|
||||
mutex_unlock(&dp->lock);
|
||||
|
||||
|
@ -140,7 +140,7 @@ static int rockchip_drm_bind(struct device *dev)
|
||||
int ret;
|
||||
|
||||
/* Remove existing drivers that may own the framebuffer memory. */
|
||||
ret = drm_aperture_remove_framebuffers(false, &rockchip_drm_driver);
|
||||
ret = drm_aperture_remove_framebuffers(&rockchip_drm_driver);
|
||||
if (ret) {
|
||||
DRM_DEV_ERROR(dev,
|
||||
"Failed to remove existing framebuffers - %d.\n",
|
||||
|
@ -714,13 +714,13 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
if (crtc->state->self_refresh_active)
|
||||
rockchip_drm_set_win_enabled(crtc, false);
|
||||
|
||||
if (crtc->state->self_refresh_active)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&vop->vop_lock);
|
||||
|
||||
drm_crtc_vblank_off(crtc);
|
||||
|
||||
if (crtc->state->self_refresh_active)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Vop standby will take effect at end of current frame,
|
||||
* if dsp hold valid irq happen, it means standby complete.
|
||||
@ -754,9 +754,9 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
vop_core_clks_disable(vop);
|
||||
pm_runtime_put(vop->dev);
|
||||
|
||||
out:
|
||||
mutex_unlock(&vop->vop_lock);
|
||||
|
||||
out:
|
||||
if (crtc->state->event && !crtc->state->active) {
|
||||
spin_lock_irq(&crtc->dev->event_lock);
|
||||
drm_crtc_send_vblank_event(crtc, crtc->state->event);
|
||||
|
@ -72,7 +72,7 @@ int drm_sched_entity_init(struct drm_sched_entity *entity,
|
||||
entity->num_sched_list = num_sched_list;
|
||||
entity->priority = priority;
|
||||
entity->sched_list = num_sched_list > 1 ? sched_list : NULL;
|
||||
entity->last_scheduled = NULL;
|
||||
RCU_INIT_POINTER(entity->last_scheduled, NULL);
|
||||
RB_CLEAR_NODE(&entity->rb_tree_node);
|
||||
|
||||
if(num_sched_list)
|
||||
@ -140,11 +140,32 @@ bool drm_sched_entity_is_ready(struct drm_sched_entity *entity)
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_sched_entity_error - return error of last scheduled job
|
||||
* @entity: scheduler entity to check
|
||||
*
|
||||
* Opportunistically return the error of the last scheduled job. Result can
|
||||
* change any time when new jobs are pushed to the hw.
|
||||
*/
|
||||
int drm_sched_entity_error(struct drm_sched_entity *entity)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
int r;
|
||||
|
||||
rcu_read_lock();
|
||||
fence = rcu_dereference(entity->last_scheduled);
|
||||
r = fence ? fence->error : 0;
|
||||
rcu_read_unlock();
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_sched_entity_error);
|
||||
|
||||
static void drm_sched_entity_kill_jobs_work(struct work_struct *wrk)
|
||||
{
|
||||
struct drm_sched_job *job = container_of(wrk, typeof(*job), work);
|
||||
|
||||
drm_sched_fence_finished(job->s_fence);
|
||||
drm_sched_fence_finished(job->s_fence, -ESRCH);
|
||||
WARN_ON(job->s_fence->parent);
|
||||
job->sched->ops->free_job(job);
|
||||
}
|
||||
@ -191,12 +212,12 @@ static void drm_sched_entity_kill(struct drm_sched_entity *entity)
|
||||
/* Make sure this entity is not used by the scheduler at the moment */
|
||||
wait_for_completion(&entity->entity_idle);
|
||||
|
||||
prev = dma_fence_get(entity->last_scheduled);
|
||||
/* The entity is guaranteed to not be used by the scheduler */
|
||||
prev = rcu_dereference_check(entity->last_scheduled, true);
|
||||
dma_fence_get(prev);
|
||||
while ((job = to_drm_sched_job(spsc_queue_pop(&entity->job_queue)))) {
|
||||
struct drm_sched_fence *s_fence = job->s_fence;
|
||||
|
||||
dma_fence_set_error(&s_fence->finished, -ESRCH);
|
||||
|
||||
dma_fence_get(&s_fence->finished);
|
||||
if (!prev || dma_fence_add_callback(prev, &job->finish_cb,
|
||||
drm_sched_entity_kill_jobs_cb))
|
||||
@ -280,8 +301,8 @@ void drm_sched_entity_fini(struct drm_sched_entity *entity)
|
||||
entity->dependency = NULL;
|
||||
}
|
||||
|
||||
dma_fence_put(entity->last_scheduled);
|
||||
entity->last_scheduled = NULL;
|
||||
dma_fence_put(rcu_dereference_check(entity->last_scheduled, true));
|
||||
RCU_INIT_POINTER(entity->last_scheduled, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_sched_entity_fini);
|
||||
|
||||
@ -423,9 +444,9 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
|
||||
if (entity->guilty && atomic_read(entity->guilty))
|
||||
dma_fence_set_error(&sched_job->s_fence->finished, -ECANCELED);
|
||||
|
||||
dma_fence_put(entity->last_scheduled);
|
||||
|
||||
entity->last_scheduled = dma_fence_get(&sched_job->s_fence->finished);
|
||||
dma_fence_put(rcu_dereference_check(entity->last_scheduled, true));
|
||||
rcu_assign_pointer(entity->last_scheduled,
|
||||
dma_fence_get(&sched_job->s_fence->finished));
|
||||
|
||||
/*
|
||||
* If the queue is empty we allow drm_sched_entity_select_rq() to
|
||||
@ -448,6 +469,12 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
|
||||
drm_sched_rq_update_fifo(entity, next->submit_ts);
|
||||
}
|
||||
|
||||
/* Jobs and entities might have different lifecycles. Since we're
|
||||
* removing the job from the entities queue, set the jobs entity pointer
|
||||
* to NULL to prevent any future access of the entity through this job.
|
||||
*/
|
||||
sched_job->entity = NULL;
|
||||
|
||||
return sched_job;
|
||||
}
|
||||
|
||||
@ -473,7 +500,7 @@ void drm_sched_entity_select_rq(struct drm_sched_entity *entity)
|
||||
*/
|
||||
smp_rmb();
|
||||
|
||||
fence = entity->last_scheduled;
|
||||
fence = rcu_dereference_check(entity->last_scheduled, true);
|
||||
|
||||
/* stay on the same engine if the previous job hasn't finished */
|
||||
if (fence && !dma_fence_is_signaled(fence))
|
||||
|
@ -53,8 +53,10 @@ void drm_sched_fence_scheduled(struct drm_sched_fence *fence)
|
||||
dma_fence_signal(&fence->scheduled);
|
||||
}
|
||||
|
||||
void drm_sched_fence_finished(struct drm_sched_fence *fence)
|
||||
void drm_sched_fence_finished(struct drm_sched_fence *fence, int result)
|
||||
{
|
||||
if (result)
|
||||
dma_fence_set_error(&fence->finished, result);
|
||||
dma_fence_signal(&fence->finished);
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,10 @@
|
||||
* the hardware.
|
||||
*
|
||||
* The jobs in a entity are always scheduled in the order that they were pushed.
|
||||
*
|
||||
* Note that once a job was taken from the entities queue and pushed to the
|
||||
* hardware, i.e. the pending queue, the entity must not be referenced anymore
|
||||
* through the jobs entity pointer.
|
||||
*/
|
||||
|
||||
#include <linux/kthread.h>
|
||||
@ -258,7 +262,7 @@ drm_sched_rq_select_entity_fifo(struct drm_sched_rq *rq)
|
||||
*
|
||||
* Finish the job's fence and wake up the worker thread.
|
||||
*/
|
||||
static void drm_sched_job_done(struct drm_sched_job *s_job)
|
||||
static void drm_sched_job_done(struct drm_sched_job *s_job, int result)
|
||||
{
|
||||
struct drm_sched_fence *s_fence = s_job->s_fence;
|
||||
struct drm_gpu_scheduler *sched = s_fence->sched;
|
||||
@ -269,7 +273,7 @@ static void drm_sched_job_done(struct drm_sched_job *s_job)
|
||||
trace_drm_sched_process_job(s_fence);
|
||||
|
||||
dma_fence_get(&s_fence->finished);
|
||||
drm_sched_fence_finished(s_fence);
|
||||
drm_sched_fence_finished(s_fence, result);
|
||||
dma_fence_put(&s_fence->finished);
|
||||
wake_up_interruptible(&sched->wake_up_worker);
|
||||
}
|
||||
@ -283,7 +287,7 @@ static void drm_sched_job_done_cb(struct dma_fence *f, struct dma_fence_cb *cb)
|
||||
{
|
||||
struct drm_sched_job *s_job = container_of(cb, struct drm_sched_job, cb);
|
||||
|
||||
drm_sched_job_done(s_job);
|
||||
drm_sched_job_done(s_job, f->error);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -534,12 +538,12 @@ void drm_sched_start(struct drm_gpu_scheduler *sched, bool full_recovery)
|
||||
r = dma_fence_add_callback(fence, &s_job->cb,
|
||||
drm_sched_job_done_cb);
|
||||
if (r == -ENOENT)
|
||||
drm_sched_job_done(s_job);
|
||||
drm_sched_job_done(s_job, fence->error);
|
||||
else if (r)
|
||||
DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n",
|
||||
r);
|
||||
} else
|
||||
drm_sched_job_done(s_job);
|
||||
drm_sched_job_done(s_job, -ECANCELED);
|
||||
}
|
||||
|
||||
if (full_recovery) {
|
||||
@ -1050,15 +1054,13 @@ static int drm_sched_main(void *param)
|
||||
r = dma_fence_add_callback(fence, &sched_job->cb,
|
||||
drm_sched_job_done_cb);
|
||||
if (r == -ENOENT)
|
||||
drm_sched_job_done(sched_job);
|
||||
drm_sched_job_done(sched_job, fence->error);
|
||||
else if (r)
|
||||
DRM_DEV_ERROR(sched->dev, "fence add callback failed (%d)\n",
|
||||
r);
|
||||
} else {
|
||||
if (IS_ERR(fence))
|
||||
dma_fence_set_error(&s_fence->finished, PTR_ERR(fence));
|
||||
|
||||
drm_sched_job_done(sched_job);
|
||||
drm_sched_job_done(sched_job, IS_ERR(fence) ?
|
||||
PTR_ERR(fence) : 0);
|
||||
}
|
||||
|
||||
wake_up(&sched->job_scheduled);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <linux/component.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
|
@ -266,6 +266,7 @@ static void hdmi_active_area(struct sti_hdmi *hdmi)
|
||||
*/
|
||||
static void hdmi_config(struct sti_hdmi *hdmi)
|
||||
{
|
||||
struct drm_connector *connector = hdmi->drm_connector;
|
||||
u32 conf;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
@ -275,7 +276,7 @@ static void hdmi_config(struct sti_hdmi *hdmi)
|
||||
|
||||
/* Select encryption type and the framing mode */
|
||||
conf |= HDMI_CFG_ESS_NOT_OESS;
|
||||
if (hdmi->hdmi_monitor)
|
||||
if (connector->display_info.is_hdmi)
|
||||
conf |= HDMI_CFG_HDMI_NOT_DVI;
|
||||
|
||||
/* Set Hsync polarity */
|
||||
@ -985,15 +986,15 @@ static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
if (!edid)
|
||||
goto fail;
|
||||
|
||||
hdmi->hdmi_monitor = drm_detect_hdmi_monitor(edid);
|
||||
DRM_DEBUG_KMS("%s : %dx%d cm\n",
|
||||
(hdmi->hdmi_monitor ? "hdmi monitor" : "dvi monitor"),
|
||||
edid->width_cm, edid->height_cm);
|
||||
cec_notifier_set_phys_addr_from_edid(hdmi->notifier, edid);
|
||||
|
||||
count = drm_add_edid_modes(connector, edid);
|
||||
drm_connector_update_edid_property(connector, edid);
|
||||
|
||||
DRM_DEBUG_KMS("%s : %dx%d cm\n",
|
||||
(connector->display_info.is_hdmi ? "hdmi monitor" : "dvi monitor"),
|
||||
edid->width_cm, edid->height_cm);
|
||||
|
||||
kfree(edid);
|
||||
return count;
|
||||
|
||||
|
@ -57,7 +57,6 @@ struct hdmi_audio_params {
|
||||
* @reset: reset control of the hdmi phy
|
||||
* @ddc_adapt: i2c ddc adapter
|
||||
* @colorspace: current colorspace selected
|
||||
* @hdmi_monitor: true if HDMI monitor detected else DVI monitor assumed
|
||||
* @audio_pdev: ASoC hdmi-codec platform device
|
||||
* @audio: hdmi audio parameters.
|
||||
* @drm_connector: hdmi connector
|
||||
@ -83,7 +82,6 @@ struct sti_hdmi {
|
||||
struct reset_control *reset;
|
||||
struct i2c_adapter *ddc_adapt;
|
||||
enum hdmi_colorspace colorspace;
|
||||
bool hdmi_monitor;
|
||||
struct platform_device *audio_pdev;
|
||||
struct hdmi_audio_params audio;
|
||||
struct drm_connector *drm_connector;
|
||||
|
@ -185,7 +185,7 @@ static int stm_drm_platform_probe(struct platform_device *pdev)
|
||||
|
||||
DRM_DEBUG("%s\n", __func__);
|
||||
|
||||
ret = drm_aperture_remove_framebuffers(false, &drv_driver);
|
||||
ret = drm_aperture_remove_framebuffers(&drv_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -19,7 +19,7 @@ sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
|
||||
sun8i_vi_scaler.o sun8i_csc.o
|
||||
|
||||
sun4i-tcon-y += sun4i_crtc.o
|
||||
sun4i-tcon-y += sun4i_dotclock.o
|
||||
sun4i-tcon-y += sun4i_tcon_dclk.o
|
||||
sun4i-tcon-y += sun4i_lvds.o
|
||||
sun4i-tcon-y += sun4i_tcon.o
|
||||
sun4i-tcon-y += sun4i_rgb.o
|
||||
|
@ -98,7 +98,7 @@ static int sun4i_drv_bind(struct device *dev)
|
||||
goto unbind_all;
|
||||
|
||||
/* Remove early framebuffers (ie. simplefb) */
|
||||
ret = drm_aperture_remove_framebuffers(false, &sun4i_drv_driver);
|
||||
ret = drm_aperture_remove_framebuffers(&sun4i_drv_driver);
|
||||
if (ret)
|
||||
goto unbind_all;
|
||||
|
||||
|
@ -31,12 +31,12 @@
|
||||
#include <uapi/drm/drm_mode.h>
|
||||
|
||||
#include "sun4i_crtc.h"
|
||||
#include "sun4i_dotclock.h"
|
||||
#include "sun4i_drv.h"
|
||||
#include "sun4i_lvds.h"
|
||||
#include "sun4i_rgb.h"
|
||||
#include "sun4i_tcon.h"
|
||||
#include "sun6i_mipi_dsi.h"
|
||||
#include "sun4i_tcon_dclk.h"
|
||||
#include "sun8i_tcon_top.h"
|
||||
#include "sunxi_engine.h"
|
||||
|
||||
@ -291,18 +291,6 @@ static int sun4i_tcon_get_clk_delay(const struct drm_display_mode *mode,
|
||||
return delay;
|
||||
}
|
||||
|
||||
static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
/* Configure the dot clock */
|
||||
clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
|
||||
|
||||
/* Set the resolution */
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
|
||||
SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
|
||||
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
|
||||
}
|
||||
|
||||
static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon,
|
||||
const struct drm_connector *connector)
|
||||
{
|
||||
@ -367,10 +355,18 @@ static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
|
||||
u32 block_space, start_delay;
|
||||
u32 tcon_div;
|
||||
|
||||
/*
|
||||
* dclk is required to run at 1/4 the DSI per-lane bit rate.
|
||||
*/
|
||||
tcon->dclk_min_div = SUN6I_DSI_TCON_DIV;
|
||||
tcon->dclk_max_div = SUN6I_DSI_TCON_DIV;
|
||||
clk_set_rate(tcon->dclk, mode->crtc_clock * 1000 * (bpp / lanes)
|
||||
/ SUN6I_DSI_TCON_DIV);
|
||||
|
||||
sun4i_tcon0_mode_set_common(tcon, mode);
|
||||
/* Set the resolution */
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
|
||||
SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
|
||||
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
|
||||
|
||||
/* Set dithering if needed */
|
||||
sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));
|
||||
@ -438,7 +434,12 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
|
||||
|
||||
tcon->dclk_min_div = 7;
|
||||
tcon->dclk_max_div = 7;
|
||||
sun4i_tcon0_mode_set_common(tcon, mode);
|
||||
clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
|
||||
|
||||
/* Set the resolution */
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
|
||||
SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
|
||||
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
|
||||
|
||||
/* Set dithering if needed */
|
||||
sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));
|
||||
@ -515,7 +516,12 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
|
||||
|
||||
tcon->dclk_min_div = tcon->quirks->dclk_min_div;
|
||||
tcon->dclk_max_div = 127;
|
||||
sun4i_tcon0_mode_set_common(tcon, mode);
|
||||
clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
|
||||
|
||||
/* Set the resolution */
|
||||
regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
|
||||
SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
|
||||
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
|
||||
|
||||
/* Set dithering if needed */
|
||||
sun4i_tcon0_mode_set_dithering(tcon, connector);
|
||||
@ -1237,14 +1243,14 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
|
||||
ret = sun4i_tcon_init_irq(dev, tcon);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't init our TCON interrupts\n");
|
||||
goto err_free_dotclock;
|
||||
goto err_free_dclk;
|
||||
}
|
||||
|
||||
tcon->crtc = sun4i_crtc_init(drm, engine, tcon);
|
||||
if (IS_ERR(tcon->crtc)) {
|
||||
dev_err(dev, "Couldn't create our CRTC\n");
|
||||
ret = PTR_ERR(tcon->crtc);
|
||||
goto err_free_dotclock;
|
||||
goto err_free_dclk;
|
||||
}
|
||||
|
||||
if (tcon->quirks->has_channel_0) {
|
||||
@ -1264,7 +1270,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
|
||||
of_node_put(remote);
|
||||
|
||||
if (ret < 0)
|
||||
goto err_free_dotclock;
|
||||
goto err_free_dclk;
|
||||
}
|
||||
|
||||
if (tcon->quirks->needs_de_be_mux) {
|
||||
@ -1290,7 +1296,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_dotclock:
|
||||
err_free_dclk:
|
||||
if (tcon->quirks->has_channel_0)
|
||||
sun4i_dclk_free(tcon);
|
||||
err_free_clocks:
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "sun4i_tcon.h"
|
||||
#include "sun4i_dotclock.h"
|
||||
#include "sun4i_tcon_dclk.h"
|
||||
|
||||
struct sun4i_dclk {
|
||||
struct clk_hw hw;
|
@ -1244,7 +1244,7 @@ static int host1x_drm_probe(struct host1x_device *dev)
|
||||
|
||||
drm_mode_config_reset(drm);
|
||||
|
||||
err = drm_aperture_remove_framebuffers(false, &tegra_drm_driver);
|
||||
err = drm_aperture_remove_framebuffers(&tegra_drm_driver);
|
||||
if (err < 0)
|
||||
goto hub;
|
||||
|
||||
|
@ -8,6 +8,19 @@
|
||||
#include <kunit/test.h>
|
||||
|
||||
#include <drm/drm_rect.h>
|
||||
#include <drm/drm_mode.h>
|
||||
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
static void drm_rect_compare(struct kunit *test, const struct drm_rect *r,
|
||||
const struct drm_rect *expected)
|
||||
{
|
||||
KUNIT_EXPECT_EQ(test, r->x1, expected->x1);
|
||||
KUNIT_EXPECT_EQ(test, r->y1, expected->y1);
|
||||
KUNIT_EXPECT_EQ(test, drm_rect_width(r), drm_rect_width(expected));
|
||||
KUNIT_EXPECT_EQ(test, drm_rect_height(r), drm_rect_height(expected));
|
||||
}
|
||||
|
||||
static void drm_test_rect_clip_scaled_div_by_zero(struct kunit *test)
|
||||
{
|
||||
@ -196,11 +209,313 @@ static void drm_test_rect_clip_scaled_signed_vs_unsigned(struct kunit *test)
|
||||
KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
|
||||
}
|
||||
|
||||
struct drm_rect_intersect_case {
|
||||
const char *description;
|
||||
struct drm_rect r1, r2;
|
||||
bool should_be_visible;
|
||||
struct drm_rect expected_intersection;
|
||||
};
|
||||
|
||||
static const struct drm_rect_intersect_case drm_rect_intersect_cases[] = {
|
||||
{
|
||||
.description = "top-left x bottom-right",
|
||||
.r1 = DRM_RECT_INIT(1, 1, 2, 2),
|
||||
.r2 = DRM_RECT_INIT(0, 0, 2, 2),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
|
||||
},
|
||||
{
|
||||
.description = "top-right x bottom-left",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 2, 2),
|
||||
.r2 = DRM_RECT_INIT(1, -1, 2, 2),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
|
||||
},
|
||||
{
|
||||
.description = "bottom-left x top-right",
|
||||
.r1 = DRM_RECT_INIT(1, -1, 2, 2),
|
||||
.r2 = DRM_RECT_INIT(0, 0, 2, 2),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
|
||||
},
|
||||
{
|
||||
.description = "bottom-right x top-left",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 2, 2),
|
||||
.r2 = DRM_RECT_INIT(1, 1, 2, 2),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
|
||||
},
|
||||
{
|
||||
.description = "right x left",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 2, 1),
|
||||
.r2 = DRM_RECT_INIT(1, 0, 3, 1),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
|
||||
},
|
||||
{
|
||||
.description = "left x right",
|
||||
.r1 = DRM_RECT_INIT(1, 0, 3, 1),
|
||||
.r2 = DRM_RECT_INIT(0, 0, 2, 1),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
|
||||
},
|
||||
{
|
||||
.description = "up x bottom",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 1, 2),
|
||||
.r2 = DRM_RECT_INIT(0, -1, 1, 3),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(0, 0, 1, 2),
|
||||
},
|
||||
{
|
||||
.description = "bottom x up",
|
||||
.r1 = DRM_RECT_INIT(0, -1, 1, 3),
|
||||
.r2 = DRM_RECT_INIT(0, 0, 1, 2),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(0, 0, 1, 2),
|
||||
},
|
||||
{
|
||||
.description = "touching corner",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 1, 1),
|
||||
.r2 = DRM_RECT_INIT(1, 1, 2, 2),
|
||||
.should_be_visible = false,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 1, 0, 0),
|
||||
},
|
||||
{
|
||||
.description = "touching side",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 1, 1),
|
||||
.r2 = DRM_RECT_INIT(1, 0, 1, 1),
|
||||
.should_be_visible = false,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 0, 0, 1),
|
||||
},
|
||||
{
|
||||
.description = "equal rects",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 2, 2),
|
||||
.r2 = DRM_RECT_INIT(0, 0, 2, 2),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(0, 0, 2, 2),
|
||||
},
|
||||
{
|
||||
.description = "inside another",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 2, 2),
|
||||
.r2 = DRM_RECT_INIT(1, 1, 1, 1),
|
||||
.should_be_visible = true,
|
||||
.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
|
||||
},
|
||||
{
|
||||
.description = "far away",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 1, 1),
|
||||
.r2 = DRM_RECT_INIT(3, 6, 1, 1),
|
||||
.should_be_visible = false,
|
||||
.expected_intersection = DRM_RECT_INIT(3, 6, -2, -5),
|
||||
},
|
||||
{
|
||||
.description = "points intersecting",
|
||||
.r1 = DRM_RECT_INIT(5, 10, 0, 0),
|
||||
.r2 = DRM_RECT_INIT(5, 10, 0, 0),
|
||||
.should_be_visible = false,
|
||||
.expected_intersection = DRM_RECT_INIT(5, 10, 0, 0),
|
||||
},
|
||||
{
|
||||
.description = "points not intersecting",
|
||||
.r1 = DRM_RECT_INIT(0, 0, 0, 0),
|
||||
.r2 = DRM_RECT_INIT(5, 10, 0, 0),
|
||||
.should_be_visible = false,
|
||||
.expected_intersection = DRM_RECT_INIT(5, 10, -5, -10),
|
||||
},
|
||||
};
|
||||
|
||||
static void drm_rect_intersect_case_desc(const struct drm_rect_intersect_case *t, char *desc)
|
||||
{
|
||||
snprintf(desc, KUNIT_PARAM_DESC_SIZE,
|
||||
"%s: " DRM_RECT_FMT " x " DRM_RECT_FMT,
|
||||
t->description, DRM_RECT_ARG(&t->r1), DRM_RECT_ARG(&t->r2));
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(drm_rect_intersect, drm_rect_intersect_cases, drm_rect_intersect_case_desc);
|
||||
|
||||
static void drm_test_rect_intersect(struct kunit *test)
|
||||
{
|
||||
const struct drm_rect_intersect_case *params = test->param_value;
|
||||
struct drm_rect r1_aux = params->r1;
|
||||
bool visible;
|
||||
|
||||
visible = drm_rect_intersect(&r1_aux, ¶ms->r2);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, visible, params->should_be_visible);
|
||||
drm_rect_compare(test, &r1_aux, ¶ms->expected_intersection);
|
||||
}
|
||||
|
||||
struct drm_rect_scale_case {
|
||||
const char *name;
|
||||
struct drm_rect src, dst;
|
||||
int min_range, max_range;
|
||||
int expected_scaling_factor;
|
||||
};
|
||||
|
||||
static const struct drm_rect_scale_case drm_rect_scale_cases[] = {
|
||||
{
|
||||
.name = "normal use",
|
||||
.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
|
||||
.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
|
||||
.min_range = 0, .max_range = INT_MAX,
|
||||
.expected_scaling_factor = 2,
|
||||
},
|
||||
{
|
||||
.name = "out of max range",
|
||||
.src = DRM_RECT_INIT(0, 0, 10 << 16, 10 << 16),
|
||||
.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
|
||||
.min_range = 3, .max_range = 5,
|
||||
.expected_scaling_factor = -ERANGE,
|
||||
},
|
||||
{
|
||||
.name = "out of min range",
|
||||
.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
|
||||
.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
|
||||
.min_range = 3, .max_range = 5,
|
||||
.expected_scaling_factor = -ERANGE,
|
||||
},
|
||||
{
|
||||
.name = "zero dst",
|
||||
.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
|
||||
.dst = DRM_RECT_INIT(0, 0, 0 << 16, 0 << 16),
|
||||
.min_range = 0, .max_range = INT_MAX,
|
||||
.expected_scaling_factor = 0,
|
||||
},
|
||||
{
|
||||
.name = "negative src",
|
||||
.src = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)),
|
||||
.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
|
||||
.min_range = 0, .max_range = INT_MAX,
|
||||
.expected_scaling_factor = -EINVAL,
|
||||
},
|
||||
{
|
||||
.name = "negative dst",
|
||||
.src = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
|
||||
.dst = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)),
|
||||
.min_range = 0, .max_range = INT_MAX,
|
||||
.expected_scaling_factor = -EINVAL,
|
||||
},
|
||||
};
|
||||
|
||||
static void drm_rect_scale_case_desc(const struct drm_rect_scale_case *t, char *desc)
|
||||
{
|
||||
strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(drm_rect_scale, drm_rect_scale_cases, drm_rect_scale_case_desc);
|
||||
|
||||
static void drm_test_rect_calc_hscale(struct kunit *test)
|
||||
{
|
||||
const struct drm_rect_scale_case *params = test->param_value;
|
||||
int scaling_factor;
|
||||
|
||||
scaling_factor = drm_rect_calc_hscale(¶ms->src, ¶ms->dst,
|
||||
params->min_range, params->max_range);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
|
||||
}
|
||||
|
||||
static void drm_test_rect_calc_vscale(struct kunit *test)
|
||||
{
|
||||
const struct drm_rect_scale_case *params = test->param_value;
|
||||
int scaling_factor;
|
||||
|
||||
scaling_factor = drm_rect_calc_vscale(¶ms->src, ¶ms->dst,
|
||||
params->min_range, params->max_range);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
|
||||
}
|
||||
|
||||
struct drm_rect_rotate_case {
|
||||
const char *name;
|
||||
unsigned int rotation;
|
||||
struct drm_rect rect;
|
||||
int width, height;
|
||||
struct drm_rect expected;
|
||||
};
|
||||
|
||||
static const struct drm_rect_rotate_case drm_rect_rotate_cases[] = {
|
||||
{
|
||||
.name = "reflect-x",
|
||||
.rotation = DRM_MODE_REFLECT_X,
|
||||
.rect = DRM_RECT_INIT(0, 0, 5, 5),
|
||||
.width = 5, .height = 10,
|
||||
.expected = DRM_RECT_INIT(0, 0, 5, 5),
|
||||
},
|
||||
{
|
||||
.name = "reflect-y",
|
||||
.rotation = DRM_MODE_REFLECT_Y,
|
||||
.rect = DRM_RECT_INIT(2, 0, 5, 5),
|
||||
.width = 5, .height = 10,
|
||||
.expected = DRM_RECT_INIT(2, 5, 5, 5),
|
||||
},
|
||||
{
|
||||
.name = "rotate-0",
|
||||
.rotation = DRM_MODE_ROTATE_0,
|
||||
.rect = DRM_RECT_INIT(0, 2, 5, 5),
|
||||
.width = 5, .height = 10,
|
||||
.expected = DRM_RECT_INIT(0, 2, 5, 5),
|
||||
},
|
||||
{
|
||||
.name = "rotate-90",
|
||||
.rotation = DRM_MODE_ROTATE_90,
|
||||
.rect = DRM_RECT_INIT(0, 0, 5, 10),
|
||||
.width = 5, .height = 10,
|
||||
.expected = DRM_RECT_INIT(0, 0, 10, 5),
|
||||
},
|
||||
{
|
||||
.name = "rotate-180",
|
||||
.rotation = DRM_MODE_ROTATE_180,
|
||||
.rect = DRM_RECT_INIT(11, 3, 5, 10),
|
||||
.width = 5, .height = 10,
|
||||
.expected = DRM_RECT_INIT(-11, -3, 5, 10),
|
||||
},
|
||||
{
|
||||
.name = "rotate-270",
|
||||
.rotation = DRM_MODE_ROTATE_270,
|
||||
.rect = DRM_RECT_INIT(6, 3, 5, 10),
|
||||
.width = 5, .height = 10,
|
||||
.expected = DRM_RECT_INIT(-3, 6, 10, 5),
|
||||
},
|
||||
};
|
||||
|
||||
static void drm_rect_rotate_case_desc(const struct drm_rect_rotate_case *t, char *desc)
|
||||
{
|
||||
strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
|
||||
}
|
||||
|
||||
KUNIT_ARRAY_PARAM(drm_rect_rotate, drm_rect_rotate_cases, drm_rect_rotate_case_desc);
|
||||
|
||||
static void drm_test_rect_rotate(struct kunit *test)
|
||||
{
|
||||
const struct drm_rect_rotate_case *params = test->param_value;
|
||||
struct drm_rect r = params->rect;
|
||||
|
||||
drm_rect_rotate(&r, params->width, params->height, params->rotation);
|
||||
|
||||
drm_rect_compare(test, &r, ¶ms->expected);
|
||||
}
|
||||
|
||||
static void drm_test_rect_rotate_inv(struct kunit *test)
|
||||
{
|
||||
const struct drm_rect_rotate_case *params = test->param_value;
|
||||
struct drm_rect r = params->expected;
|
||||
|
||||
drm_rect_rotate_inv(&r, params->width, params->height, params->rotation);
|
||||
|
||||
drm_rect_compare(test, &r, ¶ms->rect);
|
||||
}
|
||||
|
||||
static struct kunit_case drm_rect_tests[] = {
|
||||
KUNIT_CASE(drm_test_rect_clip_scaled_div_by_zero),
|
||||
KUNIT_CASE(drm_test_rect_clip_scaled_not_clipped),
|
||||
KUNIT_CASE(drm_test_rect_clip_scaled_clipped),
|
||||
KUNIT_CASE(drm_test_rect_clip_scaled_signed_vs_unsigned),
|
||||
KUNIT_CASE_PARAM(drm_test_rect_intersect, drm_rect_intersect_gen_params),
|
||||
KUNIT_CASE_PARAM(drm_test_rect_calc_hscale, drm_rect_scale_gen_params),
|
||||
KUNIT_CASE_PARAM(drm_test_rect_calc_vscale, drm_rect_scale_gen_params),
|
||||
KUNIT_CASE_PARAM(drm_test_rect_rotate, drm_rect_rotate_gen_params),
|
||||
KUNIT_CASE_PARAM(drm_test_rect_rotate_inv, drm_rect_rotate_gen_params),
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -156,7 +156,6 @@ static int tve200_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct tve200_drm_dev_private *priv;
|
||||
struct drm_device *drm;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
@ -192,8 +191,7 @@ static int tve200_probe(struct platform_device *pdev)
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->regs = devm_ioremap_resource(dev, res);
|
||||
priv->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->regs)) {
|
||||
dev_err(dev, "%s failed mmio\n", __func__);
|
||||
ret = -EINVAL;
|
||||
|
@ -255,7 +255,7 @@ static struct urb *udl_get_urb_locked(struct udl_device *udl, long timeout)
|
||||
list_del_init(&unode->entry);
|
||||
udl->urbs.available--;
|
||||
|
||||
return unode ? unode->urb : NULL;
|
||||
return unode->urb;
|
||||
}
|
||||
|
||||
#define GET_URB_TIMEOUT HZ
|
||||
|
@ -43,6 +43,9 @@ struct vc4_dummy_output {
|
||||
struct drm_connector connector;
|
||||
};
|
||||
|
||||
#define encoder_to_vc4_dummy_output(_enc) \
|
||||
container_of_const(_enc, struct vc4_dummy_output, encoder.base)
|
||||
|
||||
struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
|
||||
struct drm_device *drm,
|
||||
struct drm_crtc *crtc,
|
||||
|
@ -80,7 +80,7 @@ int vc4_mock_atomic_add_output(struct kunit *test,
|
||||
crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
|
||||
|
||||
output = container_of(encoder, struct vc4_dummy_output, encoder.base);
|
||||
output = encoder_to_vc4_dummy_output(encoder);
|
||||
conn = &output->connector;
|
||||
conn_state = drm_atomic_get_connector_state(state, conn);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
||||
@ -126,7 +126,7 @@ int vc4_mock_atomic_del_output(struct kunit *test,
|
||||
ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
|
||||
output = container_of(encoder, struct vc4_dummy_output, encoder.base);
|
||||
output = encoder_to_vc4_dummy_output(encoder);
|
||||
conn = &output->connector;
|
||||
conn_state = drm_atomic_get_connector_state(state, conn);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
|
||||
|
@ -97,11 +97,8 @@ struct vc4_dpi {
|
||||
struct debugfs_regset32 regset;
|
||||
};
|
||||
|
||||
static inline struct vc4_dpi *
|
||||
to_vc4_dpi(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct vc4_dpi, encoder.base);
|
||||
}
|
||||
#define to_vc4_dpi(_encoder) \
|
||||
container_of_const(_encoder, struct vc4_dpi, encoder.base)
|
||||
|
||||
#define DPI_READ(offset) \
|
||||
({ \
|
||||
|
@ -350,7 +350,7 @@ static int vc4_drm_bind(struct device *dev)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ret = drm_aperture_remove_framebuffers(false, driver);
|
||||
ret = drm_aperture_remove_framebuffers(driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -232,11 +232,8 @@ struct vc4_dev {
|
||||
struct kref bin_bo_kref;
|
||||
};
|
||||
|
||||
static inline struct vc4_dev *
|
||||
to_vc4_dev(const struct drm_device *dev)
|
||||
{
|
||||
return container_of(dev, struct vc4_dev, base);
|
||||
}
|
||||
#define to_vc4_dev(_dev) \
|
||||
container_of_const(_dev, struct vc4_dev, base)
|
||||
|
||||
struct vc4_bo {
|
||||
struct drm_gem_dma_object base;
|
||||
@ -285,11 +282,8 @@ struct vc4_bo {
|
||||
struct mutex madv_lock;
|
||||
};
|
||||
|
||||
static inline struct vc4_bo *
|
||||
to_vc4_bo(const struct drm_gem_object *bo)
|
||||
{
|
||||
return container_of(to_drm_gem_dma_obj(bo), struct vc4_bo, base);
|
||||
}
|
||||
#define to_vc4_bo(_bo) \
|
||||
container_of_const(to_drm_gem_dma_obj(_bo), struct vc4_bo, base)
|
||||
|
||||
struct vc4_fence {
|
||||
struct dma_fence base;
|
||||
@ -298,11 +292,8 @@ struct vc4_fence {
|
||||
uint64_t seqno;
|
||||
};
|
||||
|
||||
static inline struct vc4_fence *
|
||||
to_vc4_fence(const struct dma_fence *fence)
|
||||
{
|
||||
return container_of(fence, struct vc4_fence, base);
|
||||
}
|
||||
#define to_vc4_fence(_fence) \
|
||||
container_of_const(_fence, struct vc4_fence, base)
|
||||
|
||||
struct vc4_seqno_cb {
|
||||
struct work_struct work;
|
||||
@ -368,11 +359,8 @@ struct vc4_hvs_state {
|
||||
} fifo_state[HVS_NUM_CHANNELS];
|
||||
};
|
||||
|
||||
static inline struct vc4_hvs_state *
|
||||
to_vc4_hvs_state(const struct drm_private_state *priv)
|
||||
{
|
||||
return container_of(priv, struct vc4_hvs_state, base);
|
||||
}
|
||||
#define to_vc4_hvs_state(_state) \
|
||||
container_of_const(_state, struct vc4_hvs_state, base)
|
||||
|
||||
struct vc4_hvs_state *vc4_hvs_get_global_state(struct drm_atomic_state *state);
|
||||
struct vc4_hvs_state *vc4_hvs_get_old_global_state(const struct drm_atomic_state *state);
|
||||
@ -382,11 +370,8 @@ struct vc4_plane {
|
||||
struct drm_plane base;
|
||||
};
|
||||
|
||||
static inline struct vc4_plane *
|
||||
to_vc4_plane(const struct drm_plane *plane)
|
||||
{
|
||||
return container_of(plane, struct vc4_plane, base);
|
||||
}
|
||||
#define to_vc4_plane(_plane) \
|
||||
container_of_const(_plane, struct vc4_plane, base)
|
||||
|
||||
enum vc4_scaling_mode {
|
||||
VC4_SCALING_NONE,
|
||||
@ -458,11 +443,8 @@ struct vc4_plane_state {
|
||||
u64 membus_load;
|
||||
};
|
||||
|
||||
static inline struct vc4_plane_state *
|
||||
to_vc4_plane_state(const struct drm_plane_state *state)
|
||||
{
|
||||
return container_of(state, struct vc4_plane_state, base);
|
||||
}
|
||||
#define to_vc4_plane_state(_state) \
|
||||
container_of_const(_state, struct vc4_plane_state, base)
|
||||
|
||||
enum vc4_encoder_type {
|
||||
VC4_ENCODER_TYPE_NONE,
|
||||
@ -489,11 +471,8 @@ struct vc4_encoder {
|
||||
void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state);
|
||||
};
|
||||
|
||||
static inline struct vc4_encoder *
|
||||
to_vc4_encoder(const struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct vc4_encoder, base);
|
||||
}
|
||||
#define to_vc4_encoder(_encoder) \
|
||||
container_of_const(_encoder, struct vc4_encoder, base)
|
||||
|
||||
static inline
|
||||
struct drm_encoder *vc4_find_encoder_by_type(struct drm_device *drm,
|
||||
@ -591,11 +570,8 @@ struct vc4_crtc {
|
||||
unsigned int current_hvs_channel;
|
||||
};
|
||||
|
||||
static inline struct vc4_crtc *
|
||||
to_vc4_crtc(const struct drm_crtc *crtc)
|
||||
{
|
||||
return container_of(crtc, struct vc4_crtc, base);
|
||||
}
|
||||
#define to_vc4_crtc(_crtc) \
|
||||
container_of_const(_crtc, struct vc4_crtc, base)
|
||||
|
||||
static inline const struct vc4_crtc_data *
|
||||
vc4_crtc_to_vc4_crtc_data(const struct vc4_crtc *crtc)
|
||||
@ -608,7 +584,7 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc)
|
||||
{
|
||||
const struct vc4_crtc_data *data = vc4_crtc_to_vc4_crtc_data(crtc);
|
||||
|
||||
return container_of(data, struct vc4_pv_data, base);
|
||||
return container_of_const(data, struct vc4_pv_data, base);
|
||||
}
|
||||
|
||||
struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc,
|
||||
@ -636,11 +612,8 @@ struct vc4_crtc_state {
|
||||
|
||||
#define VC4_HVS_CHANNEL_DISABLED ((unsigned int)-1)
|
||||
|
||||
static inline struct vc4_crtc_state *
|
||||
to_vc4_crtc_state(const struct drm_crtc_state *crtc_state)
|
||||
{
|
||||
return container_of(crtc_state, struct vc4_crtc_state, base);
|
||||
}
|
||||
#define to_vc4_crtc_state(_state) \
|
||||
container_of_const(_state, struct vc4_crtc_state, base)
|
||||
|
||||
#define V3D_READ(offset) \
|
||||
({ \
|
||||
|
@ -600,19 +600,14 @@ struct vc4_dsi {
|
||||
struct debugfs_regset32 regset;
|
||||
};
|
||||
|
||||
#define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host)
|
||||
#define host_to_dsi(host) \
|
||||
container_of_const(host, struct vc4_dsi, dsi_host)
|
||||
|
||||
static inline struct vc4_dsi *
|
||||
to_vc4_dsi(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct vc4_dsi, encoder.base);
|
||||
}
|
||||
#define to_vc4_dsi(_encoder) \
|
||||
container_of_const(_encoder, struct vc4_dsi, encoder.base)
|
||||
|
||||
static inline struct vc4_dsi *
|
||||
bridge_to_vc4_dsi(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct vc4_dsi, bridge);
|
||||
}
|
||||
#define bridge_to_vc4_dsi(_bridge) \
|
||||
container_of_const(_bridge, struct vc4_dsi, bridge)
|
||||
|
||||
static inline void
|
||||
dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
|
||||
|
@ -153,11 +153,17 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
|
||||
return clock > HDMI_14_MAX_TMDS_CLK;
|
||||
}
|
||||
|
||||
static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi,
|
||||
const struct drm_display_mode *mode)
|
||||
static bool vc4_hdmi_is_full_range(struct vc4_hdmi *vc4_hdmi,
|
||||
struct vc4_hdmi_connector_state *vc4_state)
|
||||
{
|
||||
const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
|
||||
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
|
||||
|
||||
if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED)
|
||||
return false;
|
||||
else if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL)
|
||||
return true;
|
||||
|
||||
return !display->is_hdmi ||
|
||||
drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL;
|
||||
}
|
||||
@ -528,14 +534,45 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector,
|
||||
{
|
||||
struct drm_connector_state *old_state =
|
||||
drm_atomic_get_old_connector_state(state, connector);
|
||||
struct vc4_hdmi_connector_state *old_vc4_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(old_state);
|
||||
struct drm_connector_state *new_state =
|
||||
drm_atomic_get_new_connector_state(state, connector);
|
||||
struct vc4_hdmi_connector_state *new_vc4_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(new_state);
|
||||
struct drm_crtc *crtc = new_state->crtc;
|
||||
|
||||
if (!crtc)
|
||||
return 0;
|
||||
|
||||
if (old_state->tv.margins.left != new_state->tv.margins.left ||
|
||||
old_state->tv.margins.right != new_state->tv.margins.right ||
|
||||
old_state->tv.margins.top != new_state->tv.margins.top ||
|
||||
old_state->tv.margins.bottom != new_state->tv.margins.bottom) {
|
||||
struct drm_crtc_state *crtc_state;
|
||||
int ret;
|
||||
|
||||
crtc_state = drm_atomic_get_crtc_state(state, crtc);
|
||||
if (IS_ERR(crtc_state))
|
||||
return PTR_ERR(crtc_state);
|
||||
|
||||
/*
|
||||
* Strictly speaking, we should be calling
|
||||
* drm_atomic_helper_check_planes() after our call to
|
||||
* drm_atomic_add_affected_planes(). However, the
|
||||
* connector atomic_check is called as part of
|
||||
* drm_atomic_helper_check_modeset() that already
|
||||
* happens before a call to
|
||||
* drm_atomic_helper_check_planes() in
|
||||
* drm_atomic_helper_check().
|
||||
*/
|
||||
ret = drm_atomic_add_affected_planes(state, crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (old_state->colorspace != new_state->colorspace ||
|
||||
old_vc4_state->broadcast_rgb != new_vc4_state->broadcast_rgb ||
|
||||
!drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) {
|
||||
struct drm_crtc_state *crtc_state;
|
||||
|
||||
@ -549,6 +586,49 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc4_hdmi_connector_get_property(struct drm_connector *connector,
|
||||
const struct drm_connector_state *state,
|
||||
struct drm_property *property,
|
||||
uint64_t *val)
|
||||
{
|
||||
struct drm_device *drm = connector->dev;
|
||||
struct vc4_hdmi *vc4_hdmi =
|
||||
connector_to_vc4_hdmi(connector);
|
||||
const struct vc4_hdmi_connector_state *vc4_conn_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(state);
|
||||
|
||||
if (property == vc4_hdmi->broadcast_rgb_property) {
|
||||
*val = vc4_conn_state->broadcast_rgb;
|
||||
} else {
|
||||
drm_dbg(drm, "Unknown property [PROP:%d:%s]\n",
|
||||
property->base.id, property->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vc4_hdmi_connector_set_property(struct drm_connector *connector,
|
||||
struct drm_connector_state *state,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct drm_device *drm = connector->dev;
|
||||
struct vc4_hdmi *vc4_hdmi =
|
||||
connector_to_vc4_hdmi(connector);
|
||||
struct vc4_hdmi_connector_state *vc4_conn_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(state);
|
||||
|
||||
if (property == vc4_hdmi->broadcast_rgb_property) {
|
||||
vc4_conn_state->broadcast_rgb = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
drm_dbg(drm, "Unknown property [PROP:%d:%s]\n",
|
||||
property->base.id, property->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void vc4_hdmi_connector_reset(struct drm_connector *connector)
|
||||
{
|
||||
struct vc4_hdmi_connector_state *old_state =
|
||||
@ -568,6 +648,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
|
||||
new_state->base.max_bpc = 8;
|
||||
new_state->base.max_requested_bpc = 8;
|
||||
new_state->output_format = VC4_HDMI_OUTPUT_RGB;
|
||||
new_state->broadcast_rgb = VC4_HDMI_BROADCAST_RGB_AUTO;
|
||||
drm_atomic_helper_connector_tv_margins_reset(connector);
|
||||
}
|
||||
|
||||
@ -585,6 +666,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector)
|
||||
new_state->tmds_char_rate = vc4_state->tmds_char_rate;
|
||||
new_state->output_bpc = vc4_state->output_bpc;
|
||||
new_state->output_format = vc4_state->output_format;
|
||||
new_state->broadcast_rgb = vc4_state->broadcast_rgb;
|
||||
__drm_atomic_helper_connector_duplicate_state(connector, &new_state->base);
|
||||
|
||||
return &new_state->base;
|
||||
@ -595,6 +677,8 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
|
||||
.reset = vc4_hdmi_connector_reset,
|
||||
.atomic_duplicate_state = vc4_hdmi_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
.atomic_get_property = vc4_hdmi_connector_get_property,
|
||||
.atomic_set_property = vc4_hdmi_connector_set_property,
|
||||
};
|
||||
|
||||
static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
|
||||
@ -603,6 +687,33 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs =
|
||||
.atomic_check = vc4_hdmi_connector_atomic_check,
|
||||
};
|
||||
|
||||
static const struct drm_prop_enum_list broadcast_rgb_names[] = {
|
||||
{ VC4_HDMI_BROADCAST_RGB_AUTO, "Automatic" },
|
||||
{ VC4_HDMI_BROADCAST_RGB_FULL, "Full" },
|
||||
{ VC4_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235" },
|
||||
};
|
||||
|
||||
static void
|
||||
vc4_hdmi_attach_broadcast_rgb_property(struct drm_device *dev,
|
||||
struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
struct drm_property *prop = vc4_hdmi->broadcast_rgb_property;
|
||||
|
||||
if (!prop) {
|
||||
prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM,
|
||||
"Broadcast RGB",
|
||||
broadcast_rgb_names,
|
||||
ARRAY_SIZE(broadcast_rgb_names));
|
||||
if (!prop)
|
||||
return;
|
||||
|
||||
vc4_hdmi->broadcast_rgb_property = prop;
|
||||
}
|
||||
|
||||
drm_object_attach_property(&vc4_hdmi->connector.base, prop,
|
||||
VC4_HDMI_BROADCAST_RGB_AUTO);
|
||||
}
|
||||
|
||||
static int vc4_hdmi_connector_init(struct drm_device *dev,
|
||||
struct vc4_hdmi *vc4_hdmi)
|
||||
{
|
||||
@ -649,6 +760,8 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
|
||||
if (vc4_hdmi->variant->supports_hdr)
|
||||
drm_connector_attach_hdr_output_metadata_property(connector);
|
||||
|
||||
vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi);
|
||||
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
|
||||
return 0;
|
||||
@ -803,7 +916,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
|
||||
|
||||
drm_hdmi_avi_infoframe_quant_range(&frame.avi,
|
||||
connector, mode,
|
||||
vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ?
|
||||
vc4_hdmi_is_full_range(vc4_hdmi, vc4_state) ?
|
||||
HDMI_QUANTIZATION_RANGE_FULL :
|
||||
HDMI_QUANTIZATION_RANGE_LIMITED);
|
||||
drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate);
|
||||
@ -1046,6 +1159,8 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
|
||||
struct drm_connector_state *state,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct vc4_hdmi_connector_state *vc4_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(state);
|
||||
struct drm_device *drm = vc4_hdmi->connector.dev;
|
||||
unsigned long flags;
|
||||
u32 csc_ctl;
|
||||
@ -1059,7 +1174,7 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
|
||||
csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
|
||||
VC4_HD_CSC_CTL_ORDER);
|
||||
|
||||
if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) {
|
||||
if (!vc4_hdmi_is_full_range(vc4_hdmi, vc4_state)) {
|
||||
/* CEA VICs other than #1 requre limited range RGB
|
||||
* output unless overridden by an AVI infoframe.
|
||||
* Apply a colorspace conversion to squash 0-255 down
|
||||
@ -1092,68 +1207,134 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
|
||||
}
|
||||
|
||||
/*
|
||||
* If we need to output Full Range RGB, then use the unity matrix
|
||||
* Matrices for (internal) RGB to RGB output.
|
||||
*
|
||||
* [ 1 0 0 0]
|
||||
* [ 0 1 0 0]
|
||||
* [ 0 0 1 0]
|
||||
*
|
||||
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
||||
* Matrices are signed 2p13 fixed point, with signed 9p6 offsets
|
||||
*/
|
||||
static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = {
|
||||
{ 0x2000, 0x0000, 0x0000, 0x0000 },
|
||||
{ 0x0000, 0x2000, 0x0000, 0x0000 },
|
||||
{ 0x0000, 0x0000, 0x2000, 0x0000 },
|
||||
static const u16 vc5_hdmi_csc_full_rgb_to_rgb[2][3][4] = {
|
||||
{
|
||||
/*
|
||||
* Full range - unity
|
||||
*
|
||||
* [ 1 0 0 0]
|
||||
* [ 0 1 0 0]
|
||||
* [ 0 0 1 0]
|
||||
*/
|
||||
{ 0x2000, 0x0000, 0x0000, 0x0000 },
|
||||
{ 0x0000, 0x2000, 0x0000, 0x0000 },
|
||||
{ 0x0000, 0x0000, 0x2000, 0x0000 },
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Limited range
|
||||
*
|
||||
* CEA VICs other than #1 require limited range RGB
|
||||
* output unless overridden by an AVI infoframe. Apply a
|
||||
* colorspace conversion to squash 0-255 down to 16-235.
|
||||
* The matrix here is:
|
||||
*
|
||||
* [ 0.8594 0 0 16]
|
||||
* [ 0 0.8594 0 16]
|
||||
* [ 0 0 0.8594 16]
|
||||
*/
|
||||
{ 0x1b80, 0x0000, 0x0000, 0x0400 },
|
||||
{ 0x0000, 0x1b80, 0x0000, 0x0400 },
|
||||
{ 0x0000, 0x0000, 0x1b80, 0x0400 },
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* CEA VICs other than #1 require limited range RGB output unless
|
||||
* overridden by an AVI infoframe. Apply a colorspace conversion to
|
||||
* squash 0-255 down to 16-235. The matrix here is:
|
||||
* Conversion between Full Range RGB and YUV using the BT.601 Colorspace
|
||||
*
|
||||
* [ 0.8594 0 0 16]
|
||||
* [ 0 0.8594 0 16]
|
||||
* [ 0 0 0.8594 16]
|
||||
*
|
||||
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
||||
* Matrices are signed 2p13 fixed point, with signed 9p6 offsets
|
||||
*/
|
||||
static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = {
|
||||
{ 0x1b80, 0x0000, 0x0000, 0x0400 },
|
||||
{ 0x0000, 0x1b80, 0x0000, 0x0400 },
|
||||
{ 0x0000, 0x0000, 0x1b80, 0x0400 },
|
||||
static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt601[2][3][4] = {
|
||||
{
|
||||
/*
|
||||
* Full Range
|
||||
*
|
||||
* [ 0.299000 0.587000 0.114000 0 ]
|
||||
* [ -0.168736 -0.331264 0.500000 128 ]
|
||||
* [ 0.500000 -0.418688 -0.081312 128 ]
|
||||
*/
|
||||
{ 0x0991, 0x12c9, 0x03a6, 0x0000 },
|
||||
{ 0xfa9b, 0xf567, 0x1000, 0x2000 },
|
||||
{ 0x1000, 0xf29b, 0xfd67, 0x2000 },
|
||||
},
|
||||
{
|
||||
/* Limited Range
|
||||
*
|
||||
* [ 0.255785 0.502160 0.097523 16 ]
|
||||
* [ -0.147644 -0.289856 0.437500 128 ]
|
||||
* [ 0.437500 -0.366352 -0.071148 128 ]
|
||||
*/
|
||||
{ 0x082f, 0x1012, 0x031f, 0x0400 },
|
||||
{ 0xfb48, 0xf6ba, 0x0e00, 0x2000 },
|
||||
{ 0x0e00, 0xf448, 0xfdba, 0x2000 },
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Conversion between Full Range RGB and Full Range YUV422 using the
|
||||
* BT.709 Colorspace
|
||||
* Conversion between Full Range RGB and YUV using the BT.709 Colorspace
|
||||
*
|
||||
*
|
||||
* [ 0.181906 0.611804 0.061758 16 ]
|
||||
* [ -0.100268 -0.337232 0.437500 128 ]
|
||||
* [ 0.437500 -0.397386 -0.040114 128 ]
|
||||
*
|
||||
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
||||
* Matrices are signed 2p13 fixed point, with signed 9p6 offsets
|
||||
*/
|
||||
static const u16 vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709[3][4] = {
|
||||
{ 0x05d2, 0x1394, 0x01fa, 0x0400 },
|
||||
{ 0xfccc, 0xf536, 0x0e00, 0x2000 },
|
||||
{ 0x0e00, 0xf34a, 0xfeb8, 0x2000 },
|
||||
static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt709[2][3][4] = {
|
||||
{
|
||||
/*
|
||||
* Full Range
|
||||
*
|
||||
* [ 0.212600 0.715200 0.072200 0 ]
|
||||
* [ -0.114572 -0.385428 0.500000 128 ]
|
||||
* [ 0.500000 -0.454153 -0.045847 128 ]
|
||||
*/
|
||||
{ 0x06ce, 0x16e3, 0x024f, 0x0000 },
|
||||
{ 0xfc56, 0xf3ac, 0x1000, 0x2000 },
|
||||
{ 0x1000, 0xf179, 0xfe89, 0x2000 },
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Limited Range
|
||||
*
|
||||
* [ 0.181906 0.611804 0.061758 16 ]
|
||||
* [ -0.100268 -0.337232 0.437500 128 ]
|
||||
* [ 0.437500 -0.397386 -0.040114 128 ]
|
||||
*/
|
||||
{ 0x05d2, 0x1394, 0x01fa, 0x0400 },
|
||||
{ 0xfccc, 0xf536, 0x0e00, 0x2000 },
|
||||
{ 0x0e00, 0xf34a, 0xfeb8, 0x2000 },
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Conversion between Full Range RGB and Full Range YUV444 using the
|
||||
* BT.709 Colorspace
|
||||
* Conversion between Full Range RGB and YUV using the BT.2020 Colorspace
|
||||
*
|
||||
* [ -0.100268 -0.337232 0.437500 128 ]
|
||||
* [ 0.437500 -0.397386 -0.040114 128 ]
|
||||
* [ 0.181906 0.611804 0.061758 16 ]
|
||||
*
|
||||
* Matrix is signed 2p13 fixed point, with signed 9p6 offsets
|
||||
* Matrices are signed 2p13 fixed point, with signed 9p6 offsets
|
||||
*/
|
||||
static const u16 vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709[3][4] = {
|
||||
{ 0xfccc, 0xf536, 0x0e00, 0x2000 },
|
||||
{ 0x0e00, 0xf34a, 0xfeb8, 0x2000 },
|
||||
{ 0x05d2, 0x1394, 0x01fa, 0x0400 },
|
||||
static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt2020[2][3][4] = {
|
||||
{
|
||||
/*
|
||||
* Full Range
|
||||
*
|
||||
* [ 0.262700 0.678000 0.059300 0 ]
|
||||
* [ -0.139630 -0.360370 0.500000 128 ]
|
||||
* [ 0.500000 -0.459786 -0.040214 128 ]
|
||||
*/
|
||||
{ 0x0868, 0x15b2, 0x01e6, 0x0000 },
|
||||
{ 0xfb89, 0xf479, 0x1000, 0x2000 },
|
||||
{ 0x1000, 0xf14a, 0xfeb8, 0x2000 },
|
||||
},
|
||||
{
|
||||
/* Limited Range
|
||||
*
|
||||
* [ 0.224732 0.580008 0.050729 16 ]
|
||||
* [ -0.122176 -0.315324 0.437500 128 ]
|
||||
* [ 0.437500 -0.402312 -0.035188 128 ]
|
||||
*/
|
||||
{ 0x082f, 0x1012, 0x031f, 0x0400 },
|
||||
{ 0xfb48, 0xf6ba, 0x0e00, 0x2000 },
|
||||
{ 0x0e00, 0xf448, 0xfdba, 0x2000 },
|
||||
},
|
||||
};
|
||||
|
||||
static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi,
|
||||
@ -1169,6 +1350,48 @@ static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi,
|
||||
HDMI_WRITE(HDMI_CSC_34_33, (coeffs[2][3] << 16) | coeffs[2][2]);
|
||||
}
|
||||
|
||||
static void vc5_hdmi_set_csc_coeffs_swap(struct vc4_hdmi *vc4_hdmi,
|
||||
const u16 coeffs[3][4])
|
||||
{
|
||||
lockdep_assert_held(&vc4_hdmi->hw_lock);
|
||||
|
||||
/* YUV444 needs the CSC matrices using the channels in a different order */
|
||||
HDMI_WRITE(HDMI_CSC_12_11, (coeffs[1][1] << 16) | coeffs[1][0]);
|
||||
HDMI_WRITE(HDMI_CSC_14_13, (coeffs[1][3] << 16) | coeffs[1][2]);
|
||||
HDMI_WRITE(HDMI_CSC_22_21, (coeffs[2][1] << 16) | coeffs[2][0]);
|
||||
HDMI_WRITE(HDMI_CSC_24_23, (coeffs[2][3] << 16) | coeffs[2][2]);
|
||||
HDMI_WRITE(HDMI_CSC_32_31, (coeffs[0][1] << 16) | coeffs[0][0]);
|
||||
HDMI_WRITE(HDMI_CSC_34_33, (coeffs[0][3] << 16) | coeffs[0][2]);
|
||||
}
|
||||
|
||||
static const u16
|
||||
(*vc5_hdmi_find_yuv_csc_coeffs(struct vc4_hdmi *vc4_hdmi, u32 colorspace, bool limited))[4]
|
||||
{
|
||||
switch (colorspace) {
|
||||
case DRM_MODE_COLORIMETRY_SMPTE_170M_YCC:
|
||||
case DRM_MODE_COLORIMETRY_XVYCC_601:
|
||||
case DRM_MODE_COLORIMETRY_SYCC_601:
|
||||
case DRM_MODE_COLORIMETRY_OPYCC_601:
|
||||
case DRM_MODE_COLORIMETRY_BT601_YCC:
|
||||
return vc5_hdmi_csc_full_rgb_to_yuv_bt601[limited];
|
||||
|
||||
default:
|
||||
case DRM_MODE_COLORIMETRY_NO_DATA:
|
||||
case DRM_MODE_COLORIMETRY_BT709_YCC:
|
||||
case DRM_MODE_COLORIMETRY_XVYCC_709:
|
||||
case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED:
|
||||
case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT:
|
||||
return vc5_hdmi_csc_full_rgb_to_yuv_bt709[limited];
|
||||
|
||||
case DRM_MODE_COLORIMETRY_BT2020_CYCC:
|
||||
case DRM_MODE_COLORIMETRY_BT2020_YCC:
|
||||
case DRM_MODE_COLORIMETRY_BT2020_RGB:
|
||||
case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65:
|
||||
case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER:
|
||||
return vc5_hdmi_csc_full_rgb_to_yuv_bt2020[limited];
|
||||
}
|
||||
}
|
||||
|
||||
static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
|
||||
struct drm_connector_state *state,
|
||||
const struct drm_display_mode *mode)
|
||||
@ -1176,7 +1399,9 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
|
||||
struct drm_device *drm = vc4_hdmi->connector.dev;
|
||||
struct vc4_hdmi_connector_state *vc4_state =
|
||||
conn_state_to_vc4_hdmi_conn_state(state);
|
||||
unsigned int lim_range = vc4_hdmi_is_full_range(vc4_hdmi, vc4_state) ? 0 : 1;
|
||||
unsigned long flags;
|
||||
const u16 (*csc)[4];
|
||||
u32 if_cfg = 0;
|
||||
u32 if_xbar = 0x543210;
|
||||
u32 csc_chan_ctl = 0;
|
||||
@ -1191,10 +1416,14 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
|
||||
|
||||
switch (vc4_state->output_format) {
|
||||
case VC4_HDMI_OUTPUT_YUV444:
|
||||
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709);
|
||||
csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range);
|
||||
|
||||
vc5_hdmi_set_csc_coeffs_swap(vc4_hdmi, csc);
|
||||
break;
|
||||
|
||||
case VC4_HDMI_OUTPUT_YUV422:
|
||||
csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range);
|
||||
|
||||
csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD,
|
||||
VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) |
|
||||
VC5_MT_CP_CSC_CTL_USE_444_TO_422 |
|
||||
@ -1206,16 +1435,13 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi,
|
||||
if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY,
|
||||
VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422);
|
||||
|
||||
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709);
|
||||
vc5_hdmi_set_csc_coeffs(vc4_hdmi, csc);
|
||||
break;
|
||||
|
||||
case VC4_HDMI_OUTPUT_RGB:
|
||||
if_xbar = 0x354021;
|
||||
|
||||
if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode))
|
||||
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb);
|
||||
else
|
||||
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity);
|
||||
vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_rgb[lim_range]);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -117,6 +117,12 @@ enum vc4_hdmi_output_format {
|
||||
VC4_HDMI_OUTPUT_YUV420,
|
||||
};
|
||||
|
||||
enum vc4_hdmi_broadcast_rgb {
|
||||
VC4_HDMI_BROADCAST_RGB_AUTO,
|
||||
VC4_HDMI_BROADCAST_RGB_FULL,
|
||||
VC4_HDMI_BROADCAST_RGB_LIMITED,
|
||||
};
|
||||
|
||||
/* General HDMI hardware state. */
|
||||
struct vc4_hdmi {
|
||||
struct vc4_hdmi_audio audio;
|
||||
@ -129,6 +135,8 @@ struct vc4_hdmi {
|
||||
|
||||
struct delayed_work scrambling_work;
|
||||
|
||||
struct drm_property *broadcast_rgb_property;
|
||||
|
||||
struct i2c_adapter *ddc;
|
||||
void __iomem *hdmicore_regs;
|
||||
void __iomem *hd_regs;
|
||||
@ -222,17 +230,14 @@ struct vc4_hdmi {
|
||||
enum vc4_hdmi_output_format output_format;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
connector_to_vc4_hdmi(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct vc4_hdmi, connector);
|
||||
}
|
||||
#define connector_to_vc4_hdmi(_connector) \
|
||||
container_of_const(_connector, struct vc4_hdmi, connector)
|
||||
|
||||
static inline struct vc4_hdmi *
|
||||
encoder_to_vc4_hdmi(struct drm_encoder *encoder)
|
||||
{
|
||||
struct vc4_encoder *_encoder = to_vc4_encoder(encoder);
|
||||
return container_of(_encoder, struct vc4_hdmi, encoder);
|
||||
return container_of_const(_encoder, struct vc4_hdmi, encoder);
|
||||
}
|
||||
|
||||
struct vc4_hdmi_connector_state {
|
||||
@ -240,13 +245,11 @@ struct vc4_hdmi_connector_state {
|
||||
unsigned long long tmds_char_rate;
|
||||
unsigned int output_bpc;
|
||||
enum vc4_hdmi_output_format output_format;
|
||||
enum vc4_hdmi_broadcast_rgb broadcast_rgb;
|
||||
};
|
||||
|
||||
static inline struct vc4_hdmi_connector_state *
|
||||
conn_state_to_vc4_hdmi_conn_state(struct drm_connector_state *conn_state)
|
||||
{
|
||||
return container_of(conn_state, struct vc4_hdmi_connector_state, base);
|
||||
}
|
||||
#define conn_state_to_vc4_hdmi_conn_state(_state) \
|
||||
container_of_const(_state, struct vc4_hdmi_connector_state, base)
|
||||
|
||||
void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi,
|
||||
struct vc4_hdmi_connector_state *vc4_conn_state);
|
||||
|
@ -31,11 +31,8 @@ struct vc4_ctm_state {
|
||||
int fifo;
|
||||
};
|
||||
|
||||
static struct vc4_ctm_state *
|
||||
to_vc4_ctm_state(const struct drm_private_state *priv)
|
||||
{
|
||||
return container_of(priv, struct vc4_ctm_state, base);
|
||||
}
|
||||
#define to_vc4_ctm_state(_state) \
|
||||
container_of_const(_state, struct vc4_ctm_state, base)
|
||||
|
||||
struct vc4_load_tracker_state {
|
||||
struct drm_private_state base;
|
||||
@ -43,11 +40,8 @@ struct vc4_load_tracker_state {
|
||||
u64 membus_load;
|
||||
};
|
||||
|
||||
static struct vc4_load_tracker_state *
|
||||
to_vc4_load_tracker_state(const struct drm_private_state *priv)
|
||||
{
|
||||
return container_of(priv, struct vc4_load_tracker_state, base);
|
||||
}
|
||||
#define to_vc4_load_tracker_state(_state) \
|
||||
container_of_const(_state, struct vc4_load_tracker_state, base)
|
||||
|
||||
static struct vc4_ctm_state *vc4_get_ctm_state(struct drm_atomic_state *state,
|
||||
struct drm_private_obj *manager)
|
||||
@ -717,7 +711,7 @@ static void vc4_hvs_channels_destroy_state(struct drm_private_obj *obj,
|
||||
static void vc4_hvs_channels_print_state(struct drm_printer *p,
|
||||
const struct drm_private_state *state)
|
||||
{
|
||||
struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state);
|
||||
const struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state);
|
||||
unsigned int i;
|
||||
|
||||
drm_printf(p, "HVS State\n");
|
||||
|
@ -1334,8 +1334,7 @@ out:
|
||||
|
||||
u32 vc4_plane_dlist_size(const struct drm_plane_state *state)
|
||||
{
|
||||
const struct vc4_plane_state *vc4_state =
|
||||
container_of(state, typeof(*vc4_state), base);
|
||||
const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
|
||||
|
||||
return vc4_state->dlist_count;
|
||||
}
|
||||
|
@ -168,15 +168,11 @@ struct vc4_txp {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct vc4_txp, encoder.base);
|
||||
}
|
||||
#define encoder_to_vc4_txp(_encoder) \
|
||||
container_of_const(_encoder, struct vc4_txp, encoder.base)
|
||||
|
||||
static inline struct vc4_txp *connector_to_vc4_txp(struct drm_connector *conn)
|
||||
{
|
||||
return container_of(conn, struct vc4_txp, connector.base);
|
||||
}
|
||||
#define connector_to_vc4_txp(_connector) \
|
||||
container_of_const(_connector, struct vc4_txp, connector.base)
|
||||
|
||||
static const struct debugfs_reg32 txp_regs[] = {
|
||||
VC4_REG32(TXP_DST_PTR),
|
||||
|
@ -219,17 +219,11 @@ struct vc4_vec {
|
||||
writel(val, vec->regs + (offset)); \
|
||||
} while (0)
|
||||
|
||||
static inline struct vc4_vec *
|
||||
encoder_to_vc4_vec(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct vc4_vec, encoder.base);
|
||||
}
|
||||
#define encoder_to_vc4_vec(_encoder) \
|
||||
container_of_const(_encoder, struct vc4_vec, encoder.base)
|
||||
|
||||
static inline struct vc4_vec *
|
||||
connector_to_vc4_vec(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct vc4_vec, connector);
|
||||
}
|
||||
#define connector_to_vc4_vec(_connector) \
|
||||
container_of_const(_connector, struct vc4_vec, connector)
|
||||
|
||||
enum vc4_vec_tv_mode_id {
|
||||
VC4_VEC_TV_MODE_NTSC,
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_blend.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
@ -53,10 +54,30 @@ static void pre_mul_alpha_blend(struct vkms_frame_info *frame_info,
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_y_limit(struct vkms_frame_info *frame_info, int y)
|
||||
static int get_y_pos(struct vkms_frame_info *frame_info, int y)
|
||||
{
|
||||
if (y >= frame_info->dst.y1 && y < frame_info->dst.y2)
|
||||
return true;
|
||||
if (frame_info->rotation & DRM_MODE_REFLECT_Y)
|
||||
return drm_rect_height(&frame_info->rotated) - y - 1;
|
||||
|
||||
switch (frame_info->rotation & DRM_MODE_ROTATE_MASK) {
|
||||
case DRM_MODE_ROTATE_90:
|
||||
return frame_info->rotated.x2 - y - 1;
|
||||
case DRM_MODE_ROTATE_270:
|
||||
return y + frame_info->rotated.x1;
|
||||
default:
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_limit(struct vkms_frame_info *frame_info, int pos)
|
||||
{
|
||||
if (drm_rotation_90_or_270(frame_info->rotation)) {
|
||||
if (pos >= 0 && pos < drm_rect_width(&frame_info->rotated))
|
||||
return true;
|
||||
} else {
|
||||
if (pos >= frame_info->rotated.y1 && pos < frame_info->rotated.y2)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -86,6 +107,7 @@ static void blend(struct vkms_writeback_job *wb,
|
||||
{
|
||||
struct vkms_plane_state **plane = crtc_state->active_planes;
|
||||
u32 n_active_planes = crtc_state->num_active_planes;
|
||||
int y_pos;
|
||||
|
||||
const struct pixel_argb_u16 background_color = { .a = 0xffff };
|
||||
|
||||
@ -96,10 +118,12 @@ static void blend(struct vkms_writeback_job *wb,
|
||||
|
||||
/* The active planes are composed associatively in z-order. */
|
||||
for (size_t i = 0; i < n_active_planes; i++) {
|
||||
if (!check_y_limit(plane[i]->frame_info, y))
|
||||
y_pos = get_y_pos(plane[i]->frame_info, y);
|
||||
|
||||
if (!check_limit(plane[i]->frame_info, y_pos))
|
||||
continue;
|
||||
|
||||
plane[i]->plane_read(stage_buffer, plane[i]->frame_info, y);
|
||||
vkms_compose_row(stage_buffer, plane[i], y_pos);
|
||||
pre_mul_alpha_blend(plane[i]->frame_info, stage_buffer,
|
||||
output_buffer);
|
||||
}
|
||||
@ -107,7 +131,7 @@ static void blend(struct vkms_writeback_job *wb,
|
||||
*crc32 = crc32_le(*crc32, (void *)output_buffer->pixels, row_size);
|
||||
|
||||
if (wb)
|
||||
wb->wb_write(&wb->wb_frame_info, output_buffer, y);
|
||||
wb->wb_write(&wb->wb_frame_info, output_buffer, y_pos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +142,7 @@ static int check_format_funcs(struct vkms_crtc_state *crtc_state,
|
||||
u32 n_active_planes = crtc_state->num_active_planes;
|
||||
|
||||
for (size_t i = 0; i < n_active_planes; i++)
|
||||
if (!planes[i]->plane_read)
|
||||
if (!planes[i]->pixel_read)
|
||||
return -1;
|
||||
|
||||
if (active_wb && !active_wb->wb_write)
|
||||
|
@ -161,7 +161,6 @@ static void vkms_atomic_crtc_reset(struct drm_crtc *crtc)
|
||||
|
||||
static const struct drm_crtc_funcs vkms_crtc_funcs = {
|
||||
.set_config = drm_atomic_helper_set_config,
|
||||
.destroy = drm_crtc_cleanup,
|
||||
.page_flip = drm_atomic_helper_page_flip,
|
||||
.reset = vkms_atomic_crtc_reset,
|
||||
.atomic_duplicate_state = vkms_atomic_crtc_duplicate_state,
|
||||
@ -282,8 +281,8 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
|
||||
struct vkms_output *vkms_out = drm_crtc_to_vkms_output(crtc);
|
||||
int ret;
|
||||
|
||||
ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor,
|
||||
&vkms_crtc_funcs, NULL);
|
||||
ret = drmm_crtc_init_with_planes(dev, crtc, primary, cursor,
|
||||
&vkms_crtc_funcs, NULL);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to init CRTC\n");
|
||||
return ret;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user