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:
Dave Airlie 2023-05-19 11:37:52 +10:00
commit 33a8617088
144 changed files with 2763 additions and 1166 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -31,3 +31,7 @@ host such documentation:
.. toctree::
i915_vm_bind.rst
.. toctree::
xe.rst

View 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 ARMs 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 whats 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.

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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 : ; \

View File

@ -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_ */

View 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
View 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);

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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

View File

@ -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_ */

View 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
View 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);

View File

@ -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 */

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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>

View File

@ -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;
}

View File

@ -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>

View File

@ -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",

View File

@ -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);

View File

@ -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) {

View File

@ -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) {

View File

@ -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 = {

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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[] = {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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]);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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 */ }

View File

@ -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);

View File

@ -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",

View File

@ -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);

View File

@ -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))

View File

@ -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);
}

View File

@ -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);

View File

@ -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>

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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, &params->r2);
KUNIT_EXPECT_EQ(test, visible, params->should_be_visible);
drm_rect_compare(test, &r1_aux, &params->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(&params->src, &params->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(&params->src, &params->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, &params->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, &params->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),
{ }
};

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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) \
({ \

View File

@ -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;

View File

@ -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) \
({ \

View File

@ -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)

View File

@ -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:

View File

@ -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);

View File

@ -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");

View File

@ -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;
}

View File

@ -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),

View File

@ -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,

View File

@ -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)

View File

@ -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