drm-misc-next for v5.15-rc1:

UAPI Changes:
 - Remove sysfs stats for dma-buf attachments, as it causes a performance regression.
   Previous merge is not in a rc kernel yet, so no userspace regression possible.
 
 Cross-subsystem Changes:
 - Sanitize user input in kyro's viewport ioctl.
 - Use refcount_t in fb_info->count
 - Assorted fixes to dma-buf.
 - Extend x86 efifb handling to all archs.
 - Fix neofb divide by 0.
 - Document corpro,gm7123 bridge dt bindings.
 
 Core Changes:
 - Slightly rework drm master handling.
 - Cleanup vgaarb handling.
 - Assorted fixes.
 
 Driver Changes:
 - Add support for ws2401 panel.
 - Assorted fixes to stm, ast, bochs.
 - Demidlayer ingenic irq.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmD5TGAACgkQ/lWMcqZw
 E8PNgxAApjTYQSfjIBbOZnNraxW6w7/bPea35E9A47EdBQsNGnYftNsFjbrn/mCJ
 D+0eRLjCMlg4FF1SHdh9cPJ35py+ygbDeupogboLITfU99eGBth3fM2Xdg9LPcBh
 dbni/JLG9R7gIvSlqdJuweN21trfVrV/9FQEilG5DvQcl27Wx5g8VMRZke1EqGKX
 7Id09Uq50ky18vhDjQRCveYhRqJAxV+XozBatzHyxpDVzjLQvRhlAAYdvrSMHZ5R
 jreGzOfR8awc6Om+w7wx3Jn1oEGmXVZB/VqxEqGtMOr3lpARPucxrqfHsqpam3rv
 yIoEKPrkG+k6fsU7Tbg59jNqe/PbCUW3AlpyuBxf55EbnVGgjLDbq4sRRMkehPfA
 fhC31ujOXQQnAgaxyeQAaAJFKNFJzA8Cq5ZPfG+zztzuomHCiUVQBRowP65hJMzR
 +ZlEDnhUD3STLz39zuO1reZR1ZoPIvKbsokHAA+ZrIwUd6U3D3ia8V51pq+lL5aS
 TGDkyMN9jyZ+SO8Z7+2FnJAv9FAOPU/WCLU/fWW46jAvuezwMIwVcjfSqDU2XbZD
 e7KgHpHhx3BGxI8TThHKlY7mf6IL2Bm7X1Cv1pdZs/eEn3Udh2ax942uTQZu/YOO
 0AT1XchpvYCBNRw05bVI3OlJ+w3I8uV+h+11jHOKeY6cbwdHeKE=
 =BUya
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2021-07-22' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for v5.15-rc1:

UAPI Changes:
- Remove sysfs stats for dma-buf attachments, as it causes a performance regression.
  Previous merge is not in a rc kernel yet, so no userspace regression possible.

Cross-subsystem Changes:
- Sanitize user input in kyro's viewport ioctl.
- Use refcount_t in fb_info->count
- Assorted fixes to dma-buf.
- Extend x86 efifb handling to all archs.
- Fix neofb divide by 0.
- Document corpro,gm7123 bridge dt bindings.

Core Changes:
- Slightly rework drm master handling.
- Cleanup vgaarb handling.
- Assorted fixes.

Driver Changes:
- Add support for ws2401 panel.
- Assorted fixes to stm, ast, bochs.
- Demidlayer ingenic irq.

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

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/2d0d2fe8-01fc-e216-c3fd-38db9e69944e@linux.intel.com
This commit is contained in:
Dave Airlie 2021-07-23 11:31:50 +10:00
commit 8da49a33dd
62 changed files with 1570 additions and 640 deletions

View File

@ -22,31 +22,3 @@ KernelVersion: v5.13
Contact: Hridya Valsaraju <hridya@google.com>
Description: This file is read-only and specifies the size of the DMA-BUF in
bytes.
What: /sys/kernel/dmabuf/buffers/<inode_number>/attachments
Date: May 2021
KernelVersion: v5.13
Contact: Hridya Valsaraju <hridya@google.com>
Description: This directory will contain subdirectories representing every
attachment of the DMA-BUF.
What: /sys/kernel/dmabuf/buffers/<inode_number>/attachments/<attachment_uid>
Date: May 2021
KernelVersion: v5.13
Contact: Hridya Valsaraju <hridya@google.com>
Description: This directory will contain information on the attached device
and the number of current distinct device mappings.
What: /sys/kernel/dmabuf/buffers/<inode_number>/attachments/<attachment_uid>/device
Date: May 2021
KernelVersion: v5.13
Contact: Hridya Valsaraju <hridya@google.com>
Description: This file is read-only and is a symlink to the attached device's
sysfs entry.
What: /sys/kernel/dmabuf/buffers/<inode_number>/attachments/<attachment_uid>/map_counter
Date: May 2021
KernelVersion: v5.13
Contact: Hridya Valsaraju <hridya@google.com>
Description: This file is read-only and contains a map_counter indicating the
number of distinct device mappings of the attachment.

View File

@ -22,6 +22,9 @@ properties:
- ti,ths8134a
- ti,ths8134b
- const: ti,ths8134
- items:
- const: corpro,gm7123
- const: adi,adv7123
- enum:
- adi,adv7123
- dumb-vga-dac

View File

@ -0,0 +1,99 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/samsung,lms380kf01.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung LMS380KF01 display panel
description: The LMS380KF01 is a 480x800 DPI display panel from Samsung Mobile
Displays (SMD) utilizing the WideChips WS2401 display controller. It can be
used with internal or external backlight control.
The panel must obey the rules for a SPI slave device as specified in
spi/spi-controller.yaml
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
const: samsung,lms380kf01
reg: true
interrupts:
description: provides an optional ESD (electrostatic discharge)
interrupt that signals abnormalities in the display hardware.
This can also be raised for other reasons like erroneous
configuration.
maxItems: 1
reset-gpios: true
vci-supply:
description: regulator that supplies the VCI analog voltage
usually around 3.0 V
vccio-supply:
description: regulator that supplies the VCCIO voltage usually
around 1.8 V
backlight: true
spi-cpha: true
spi-cpol: true
spi-max-frequency:
maximum: 1200000
port: true
required:
- compatible
- reg
- spi-cpha
- spi-cpol
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi {
compatible = "spi-gpio";
sck-gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
miso-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
mosi-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>;
cs-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>;
num-chipselects = <1>;
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "samsung,lms380kf01";
spi-max-frequency = <1200000>;
spi-cpha;
spi-cpol;
reg = <0>;
vci-supply = <&lcd_3v0_reg>;
vccio-supply = <&lcd_1v8_reg>;
reset-gpios = <&gpio 4 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio>;
interrupts = <5 IRQ_TYPE_EDGE_RISING>;
port {
panel_in: endpoint {
remote-endpoint = <&display_out>;
};
};
};
};
...

View File

@ -6067,6 +6067,13 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
F: drivers/gpu/drm/vmwgfx/
F: include/uapi/drm/vmwgfx_drm.h
DRM DRIVER FOR WIDECHIPS WS2401 PANELS
M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
F: Documentation/devicetree/bindings/display/panel/samsung,lms380kf01.yaml
F: drivers/gpu/drm/panel/panel-widechips-ws2401.c
DRM DRIVERS
M: David Airlie <airlied@linux.ie>
M: Daniel Vetter <daniel@ffwll.ch>

View File

@ -17,6 +17,7 @@
#ifdef CONFIG_EFI
void efi_init(void);
extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
@ -52,10 +53,6 @@ void efi_virtmap_unload(void);
struct screen_info *alloc_screen_info(void);
void free_screen_info(struct screen_info *si);
static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
{
}
/*
* A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
* so we will reserve that amount of memory. We have no easy way to tell what

View File

@ -14,6 +14,7 @@
#ifdef CONFIG_EFI
extern void efi_init(void);
extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
#else
#define efi_init()
#endif
@ -85,10 +86,6 @@ static inline void free_screen_info(struct screen_info *si)
{
}
static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
{
}
#define EFI_ALLOC_ALIGN SZ_64K
/*

View File

@ -13,6 +13,7 @@
#ifdef CONFIG_EFI
extern void efi_init(void);
extern void efifb_setup_from_dmi(struct screen_info *si, const char *opt);
#else
#define efi_init()
#endif
@ -39,10 +40,6 @@ static inline void free_screen_info(struct screen_info *si)
{
}
static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt)
{
}
void efi_virtmap_load(void);
void efi_virtmap_unload(void);

View File

@ -2767,32 +2767,6 @@ config AMD_NB
def_bool y
depends on CPU_SUP_AMD && PCI
config X86_SYSFB
bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
help
Firmwares often provide initial graphics framebuffers so the BIOS,
bootloader or kernel can show basic video-output during boot for
user-guidance and debugging. Historically, x86 used the VESA BIOS
Extensions and EFI-framebuffers for this, which are mostly limited
to x86.
This option, if enabled, marks VGA/VBE/EFI framebuffers as generic
framebuffers so the new generic system-framebuffer drivers can be
used on x86. If the framebuffer is not compatible with the generic
modes, it is advertised as fallback platform framebuffer so legacy
drivers like efifb, vesafb and uvesafb can pick it up.
If this option is not selected, all system framebuffers are always
marked as fallback platform framebuffers as usual.
Note: Legacy fbdev drivers, including vesafb, efifb, uvesafb, will
not be able to pick up generic system framebuffers if this option
is selected. You are highly encouraged to enable simplefb as
replacement if you select this option. simplefb can correctly deal
with generic system framebuffers. But you should still keep vesafb
and others enabled as fallback if a system framebuffer is
incompatible with simplefb.
If unsure, say Y.
endmenu

View File

@ -136,9 +136,6 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o
obj-$(CONFIG_OF) += devicetree.o
obj-$(CONFIG_UPROBES) += uprobes.o
obj-y += sysfb.o
obj-$(CONFIG_X86_SYSFB) += sysfb_simplefb.o
obj-$(CONFIG_EFI) += sysfb_efi.o
obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
obj-$(CONFIG_TRACING) += tracepoint.o

View File

@ -40,14 +40,11 @@
*
* * ``/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name``
* * ``/sys/kernel/dmabuf/buffers/<inode_number>/size``
* * ``/sys/kernel/dmabuf/buffers/<inode_number>/attachments/<attach_uid>/device``
* * ``/sys/kernel/dmabuf/buffers/<inode_number>/attachments/<attach_uid>/map_counter``
*
* The information in the interface can also be used to derive per-exporter and
* per-device usage statistics. The data from the interface can be gathered
* on error conditions or other important events to provide a snapshot of
* DMA-BUF usage. It can also be collected periodically by telemetry to monitor
* various metrics.
* The information in the interface can also be used to derive per-exporter
* statistics. The data from the interface can be gathered on error conditions
* or other important events to provide a snapshot of DMA-BUF usage.
* It can also be collected periodically by telemetry to monitor various metrics.
*
* Detailed documentation about the interface is present in
* Documentation/ABI/testing/sysfs-kernel-dmabuf-buffers.
@ -121,120 +118,6 @@ static struct kobj_type dma_buf_ktype = {
.default_groups = dma_buf_stats_default_groups,
};
#define to_dma_buf_attach_entry_from_kobj(x) container_of(x, struct dma_buf_attach_sysfs_entry, kobj)
struct dma_buf_attach_stats_attribute {
struct attribute attr;
ssize_t (*show)(struct dma_buf_attach_sysfs_entry *sysfs_entry,
struct dma_buf_attach_stats_attribute *attr, char *buf);
};
#define to_dma_buf_attach_stats_attr(x) container_of(x, struct dma_buf_attach_stats_attribute, attr)
static ssize_t dma_buf_attach_stats_attribute_show(struct kobject *kobj,
struct attribute *attr,
char *buf)
{
struct dma_buf_attach_stats_attribute *attribute;
struct dma_buf_attach_sysfs_entry *sysfs_entry;
attribute = to_dma_buf_attach_stats_attr(attr);
sysfs_entry = to_dma_buf_attach_entry_from_kobj(kobj);
if (!attribute->show)
return -EIO;
return attribute->show(sysfs_entry, attribute, buf);
}
static const struct sysfs_ops dma_buf_attach_stats_sysfs_ops = {
.show = dma_buf_attach_stats_attribute_show,
};
static ssize_t map_counter_show(struct dma_buf_attach_sysfs_entry *sysfs_entry,
struct dma_buf_attach_stats_attribute *attr,
char *buf)
{
return sysfs_emit(buf, "%u\n", sysfs_entry->map_counter);
}
static struct dma_buf_attach_stats_attribute map_counter_attribute =
__ATTR_RO(map_counter);
static struct attribute *dma_buf_attach_stats_default_attrs[] = {
&map_counter_attribute.attr,
NULL,
};
ATTRIBUTE_GROUPS(dma_buf_attach_stats_default);
static void dma_buf_attach_sysfs_release(struct kobject *kobj)
{
struct dma_buf_attach_sysfs_entry *sysfs_entry;
sysfs_entry = to_dma_buf_attach_entry_from_kobj(kobj);
kfree(sysfs_entry);
}
static struct kobj_type dma_buf_attach_ktype = {
.sysfs_ops = &dma_buf_attach_stats_sysfs_ops,
.release = dma_buf_attach_sysfs_release,
.default_groups = dma_buf_attach_stats_default_groups,
};
void dma_buf_attach_stats_teardown(struct dma_buf_attachment *attach)
{
struct dma_buf_attach_sysfs_entry *sysfs_entry;
sysfs_entry = attach->sysfs_entry;
if (!sysfs_entry)
return;
sysfs_delete_link(&sysfs_entry->kobj, &attach->dev->kobj, "device");
kobject_del(&sysfs_entry->kobj);
kobject_put(&sysfs_entry->kobj);
}
int dma_buf_attach_stats_setup(struct dma_buf_attachment *attach,
unsigned int uid)
{
struct dma_buf_attach_sysfs_entry *sysfs_entry;
int ret;
struct dma_buf *dmabuf;
if (!attach)
return -EINVAL;
dmabuf = attach->dmabuf;
sysfs_entry = kzalloc(sizeof(struct dma_buf_attach_sysfs_entry),
GFP_KERNEL);
if (!sysfs_entry)
return -ENOMEM;
sysfs_entry->kobj.kset = dmabuf->sysfs_entry->attach_stats_kset;
attach->sysfs_entry = sysfs_entry;
ret = kobject_init_and_add(&sysfs_entry->kobj, &dma_buf_attach_ktype,
NULL, "%u", uid);
if (ret)
goto kobj_err;
ret = sysfs_create_link(&sysfs_entry->kobj, &attach->dev->kobj,
"device");
if (ret)
goto link_err;
return 0;
link_err:
kobject_del(&sysfs_entry->kobj);
kobj_err:
kobject_put(&sysfs_entry->kobj);
attach->sysfs_entry = NULL;
return ret;
}
void dma_buf_stats_teardown(struct dma_buf *dmabuf)
{
struct dma_buf_sysfs_entry *sysfs_entry;
@ -243,7 +126,6 @@ void dma_buf_stats_teardown(struct dma_buf *dmabuf)
if (!sysfs_entry)
return;
kset_unregister(sysfs_entry->attach_stats_kset);
kobject_del(&sysfs_entry->kobj);
kobject_put(&sysfs_entry->kobj);
}
@ -290,7 +172,6 @@ int dma_buf_stats_setup(struct dma_buf *dmabuf)
{
struct dma_buf_sysfs_entry *sysfs_entry;
int ret;
struct kset *attach_stats_kset;
if (!dmabuf || !dmabuf->file)
return -EINVAL;
@ -315,21 +196,8 @@ int dma_buf_stats_setup(struct dma_buf *dmabuf)
if (ret)
goto err_sysfs_dmabuf;
/* create the directory for attachment stats */
attach_stats_kset = kset_create_and_add("attachments",
&dmabuf_sysfs_no_uevent_ops,
&sysfs_entry->kobj);
if (!attach_stats_kset) {
ret = -ENOMEM;
goto err_sysfs_attach;
}
sysfs_entry->attach_stats_kset = attach_stats_kset;
return 0;
err_sysfs_attach:
kobject_del(&sysfs_entry->kobj);
err_sysfs_dmabuf:
kobject_put(&sysfs_entry->kobj);
dmabuf->sysfs_entry = NULL;

View File

@ -14,23 +14,8 @@ int dma_buf_init_sysfs_statistics(void);
void dma_buf_uninit_sysfs_statistics(void);
int dma_buf_stats_setup(struct dma_buf *dmabuf);
int dma_buf_attach_stats_setup(struct dma_buf_attachment *attach,
unsigned int uid);
static inline void dma_buf_update_attachment_map_count(struct dma_buf_attachment *attach,
int delta)
{
struct dma_buf_attach_sysfs_entry *entry = attach->sysfs_entry;
entry->map_counter += delta;
}
void dma_buf_stats_teardown(struct dma_buf *dmabuf);
void dma_buf_attach_stats_teardown(struct dma_buf_attachment *attach);
static inline unsigned int dma_buf_update_attach_uid(struct dma_buf *dmabuf)
{
struct dma_buf_sysfs_entry *entry = dmabuf->sysfs_entry;
return entry->attachment_uid++;
}
#else
static inline int dma_buf_init_sysfs_statistics(void)
@ -44,19 +29,7 @@ static inline int dma_buf_stats_setup(struct dma_buf *dmabuf)
{
return 0;
}
static inline int dma_buf_attach_stats_setup(struct dma_buf_attachment *attach,
unsigned int uid)
{
return 0;
}
static inline void dma_buf_stats_teardown(struct dma_buf *dmabuf) {}
static inline void dma_buf_attach_stats_teardown(struct dma_buf_attachment *attach) {}
static inline void dma_buf_update_attachment_map_count(struct dma_buf_attachment *attach,
int delta) {}
static inline unsigned int dma_buf_update_attach_uid(struct dma_buf *dmabuf)
{
return 0;
}
#endif
#endif // _DMA_BUF_SYSFS_STATS_H

View File

@ -76,12 +76,12 @@ static void dma_buf_release(struct dentry *dentry)
*/
BUG_ON(dmabuf->cb_shared.active || dmabuf->cb_excl.active);
dma_buf_stats_teardown(dmabuf);
dmabuf->ops->release(dmabuf);
if (dmabuf->resv == (struct dma_resv *)&dmabuf[1])
dma_resv_fini(dmabuf->resv);
dma_buf_stats_teardown(dmabuf);
module_put(dmabuf->owner);
kfree(dmabuf->name);
kfree(dmabuf);
@ -738,7 +738,6 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
{
struct dma_buf_attachment *attach;
int ret;
unsigned int attach_uid;
if (WARN_ON(!dmabuf || !dev))
return ERR_PTR(-EINVAL);
@ -764,13 +763,8 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
}
dma_resv_lock(dmabuf->resv, NULL);
list_add(&attach->node, &dmabuf->attachments);
attach_uid = dma_buf_update_attach_uid(dmabuf);
dma_resv_unlock(dmabuf->resv);
ret = dma_buf_attach_stats_setup(attach, attach_uid);
if (ret)
goto err_sysfs;
/* When either the importer or the exporter can't handle dynamic
* mappings we cache the mapping here to avoid issues with the
* reservation object lock.
@ -797,7 +791,6 @@ dma_buf_dynamic_attach(struct dma_buf *dmabuf, struct device *dev,
dma_resv_unlock(attach->dmabuf->resv);
attach->sgt = sgt;
attach->dir = DMA_BIDIRECTIONAL;
dma_buf_update_attachment_map_count(attach, 1 /* delta */);
}
return attach;
@ -814,7 +807,6 @@ err_unlock:
if (dma_buf_is_dynamic(attach->dmabuf))
dma_resv_unlock(attach->dmabuf->resv);
err_sysfs:
dma_buf_detach(dmabuf, attach);
return ERR_PTR(ret);
}
@ -864,7 +856,6 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
dma_resv_lock(attach->dmabuf->resv, NULL);
__unmap_dma_buf(attach, attach->sgt, attach->dir);
dma_buf_update_attachment_map_count(attach, -1 /* delta */);
if (dma_buf_is_dynamic(attach->dmabuf)) {
dmabuf->ops->unpin(attach);
@ -878,7 +869,6 @@ void dma_buf_detach(struct dma_buf *dmabuf, struct dma_buf_attachment *attach)
if (dmabuf->ops->detach)
dmabuf->ops->detach(dmabuf, attach);
dma_buf_attach_stats_teardown(attach);
kfree(attach);
}
EXPORT_SYMBOL_GPL(dma_buf_detach);
@ -1020,10 +1010,6 @@ struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach,
}
}
#endif /* CONFIG_DMA_API_DEBUG */
if (!IS_ERR(sg_table))
dma_buf_update_attachment_map_count(attach, 1 /* delta */);
return sg_table;
}
EXPORT_SYMBOL_GPL(dma_buf_map_attachment);
@ -1061,8 +1047,6 @@ void dma_buf_unmap_attachment(struct dma_buf_attachment *attach,
if (dma_buf_is_dynamic(attach->dmabuf) &&
!IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY))
dma_buf_unpin(attach);
dma_buf_update_attachment_map_count(attach, -1 /* delta */);
}
EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);

View File

@ -251,6 +251,38 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
Say Y here to enable "download mode" by default.
config SYSFB
bool
default y
depends on X86 || ARM || ARM64 || RISCV || COMPILE_TEST
config SYSFB_SIMPLEFB
bool "Mark VGA/VBE/EFI FB as generic system framebuffer"
depends on SYSFB
help
Firmwares often provide initial graphics framebuffers so the BIOS,
bootloader or kernel can show basic video-output during boot for
user-guidance and debugging. Historically, x86 used the VESA BIOS
Extensions and EFI-framebuffers for this, which are mostly limited
to x86 BIOS or EFI systems.
This option, if enabled, marks VGA/VBE/EFI framebuffers as generic
framebuffers so the new generic system-framebuffer drivers can be
used instead. If the framebuffer is not compatible with the generic
modes, it is advertised as fallback platform framebuffer so legacy
drivers like efifb, vesafb and uvesafb can pick it up.
If this option is not selected, all system framebuffers are always
marked as fallback platform framebuffers as usual.
Note: Legacy fbdev drivers, including vesafb, efifb, uvesafb, will
not be able to pick up generic system framebuffers if this option
is selected. You are highly encouraged to enable simplefb as
replacement if you select this option. simplefb can correctly deal
with generic system framebuffers. But you should still keep vesafb
and others enabled as fallback if a system framebuffer is
incompatible with simplefb.
If unsure, say Y.
config TI_SCI_PROTOCOL
tristate "TI System Control Interface (TISCI) Message Protocol"
depends on TI_MESSAGE_MANAGER

View File

@ -18,6 +18,8 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_SYSFB) += sysfb.o
obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o

View File

@ -36,6 +36,8 @@ obj-$(CONFIG_LOAD_UEFI_KEYS) += mokvar-table.o
fake_map-y += fake_mem.o
fake_map-$(CONFIG_X86) += x86_fake_mem.o
obj-$(CONFIG_SYSFB) += sysfb_efi.o
arm-obj-$(CONFIG_EFI) := efi-init.o arm-runtime.o
obj-$(CONFIG_ARM) += $(arm-obj-y)
obj-$(CONFIG_ARM64) += $(arm-obj-y)

View File

@ -275,93 +275,3 @@ void __init efi_init(void)
}
#endif
}
static bool efifb_overlaps_pci_range(const struct of_pci_range *range)
{
u64 fb_base = screen_info.lfb_base;
if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32;
return fb_base >= range->cpu_addr &&
fb_base < (range->cpu_addr + range->size);
}
static struct device_node *find_pci_overlap_node(void)
{
struct device_node *np;
for_each_node_by_type(np, "pci") {
struct of_pci_range_parser parser;
struct of_pci_range range;
int err;
err = of_pci_range_parser_init(&parser, np);
if (err) {
pr_warn("of_pci_range_parser_init() failed: %d\n", err);
continue;
}
for_each_of_pci_range(&parser, &range)
if (efifb_overlaps_pci_range(&range))
return np;
}
return NULL;
}
/*
* If the efifb framebuffer is backed by a PCI graphics controller, we have
* to ensure that this relation is expressed using a device link when
* running in DT mode, or the probe order may be reversed, resulting in a
* resource reservation conflict on the memory window that the efifb
* framebuffer steals from the PCIe host bridge.
*/
static int efifb_add_links(struct fwnode_handle *fwnode)
{
struct device_node *sup_np;
sup_np = find_pci_overlap_node();
/*
* If there's no PCI graphics controller backing the efifb, we are
* done here.
*/
if (!sup_np)
return 0;
fwnode_link_add(fwnode, of_fwnode_handle(sup_np));
of_node_put(sup_np);
return 0;
}
static const struct fwnode_operations efifb_fwnode_ops = {
.add_links = efifb_add_links,
};
static struct fwnode_handle efifb_fwnode;
static int __init register_gop_device(void)
{
struct platform_device *pd;
int err;
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
return 0;
pd = platform_device_alloc("efi-framebuffer", 0);
if (!pd)
return -ENOMEM;
if (IS_ENABLED(CONFIG_PCI)) {
fwnode_init(&efifb_fwnode, &efifb_fwnode_ops);
pd->dev.fwnode = &efifb_fwnode;
}
err = platform_device_add_data(pd, &screen_info, sizeof(screen_info));
if (err)
return err;
return platform_device_add(pd);
}
subsys_initcall(register_gop_device);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Generic System Framebuffers on x86
* Generic System Framebuffers
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
*
* EFI Quirks Copyright (c) 2006 Edgar Hucek <gimli@dark-green.com>
@ -19,12 +19,14 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/of_address.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/screen_info.h>
#include <linux/sysfb.h>
#include <video/vga.h>
#include <asm/efi.h>
#include <asm/sysfb.h>
enum {
OVERRIDE_NONE = 0x0,
@ -267,7 +269,72 @@ static const struct dmi_system_id efifb_dmi_swap_width_height[] __initconst = {
{},
};
__init void sysfb_apply_efi_quirks(void)
static bool efifb_overlaps_pci_range(const struct of_pci_range *range)
{
u64 fb_base = screen_info.lfb_base;
if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE)
fb_base |= (u64)(unsigned long)screen_info.ext_lfb_base << 32;
return fb_base >= range->cpu_addr &&
fb_base < (range->cpu_addr + range->size);
}
static struct device_node *find_pci_overlap_node(void)
{
struct device_node *np;
for_each_node_by_type(np, "pci") {
struct of_pci_range_parser parser;
struct of_pci_range range;
int err;
err = of_pci_range_parser_init(&parser, np);
if (err) {
pr_warn("of_pci_range_parser_init() failed: %d\n", err);
continue;
}
for_each_of_pci_range(&parser, &range)
if (efifb_overlaps_pci_range(&range))
return np;
}
return NULL;
}
/*
* If the efifb framebuffer is backed by a PCI graphics controller, we have
* to ensure that this relation is expressed using a device link when
* running in DT mode, or the probe order may be reversed, resulting in a
* resource reservation conflict on the memory window that the efifb
* framebuffer steals from the PCIe host bridge.
*/
static int efifb_add_links(struct fwnode_handle *fwnode)
{
struct device_node *sup_np;
sup_np = find_pci_overlap_node();
/*
* If there's no PCI graphics controller backing the efifb, we are
* done here.
*/
if (!sup_np)
return 0;
fwnode_link_add(fwnode, of_fwnode_handle(sup_np));
of_node_put(sup_np);
return 0;
}
static const struct fwnode_operations efifb_fwnode_ops = {
.add_links = efifb_add_links,
};
static struct fwnode_handle efifb_fwnode;
__init void sysfb_apply_efi_quirks(struct platform_device *pd)
{
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI ||
!(screen_info.capabilities & VIDEO_CAPABILITY_SKIP_QUIRKS))
@ -281,4 +348,9 @@ __init void sysfb_apply_efi_quirks(void)
screen_info.lfb_height = temp;
screen_info.lfb_linelength = 4 * screen_info.lfb_width;
}
if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI && IS_ENABLED(CONFIG_PCI)) {
fwnode_init(&efifb_fwnode, &efifb_fwnode_ops);
pd->dev.fwnode = &efifb_fwnode;
}
}

View File

@ -1,11 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Generic System Framebuffers on x86
* Generic System Framebuffers
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
*/
/*
* Simple-Framebuffer support for x86 systems
* Simple-Framebuffer support
* Create a platform-device for any available boot framebuffer. The
* simple-framebuffer platform device is already available on DT systems, so
* this module parses the global "screen_info" object and creates a suitable
@ -16,12 +16,12 @@
* to pick these devices up without messing with simple-framebuffer drivers.
* The global "screen_info" is still valid at all times.
*
* If CONFIG_X86_SYSFB is not selected, we never register "simple-framebuffer"
* If CONFIG_SYSFB_SIMPLEFB is not selected, never register "simple-framebuffer"
* platform devices, but only use legacy framebuffer devices for
* backwards compatibility.
*
* TODO: We set the dev_id field of all platform-devices to 0. This allows
* other x86 OF/DT parsers to create such devices, too. However, they must
* other OF/DT parsers to create such devices, too. However, they must
* start at offset 1 for this to work.
*/
@ -32,7 +32,7 @@
#include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h>
#include <linux/screen_info.h>
#include <asm/sysfb.h>
#include <linux/sysfb.h>
static __init int sysfb_init(void)
{
@ -43,12 +43,10 @@ static __init int sysfb_init(void)
bool compatible;
int ret;
sysfb_apply_efi_quirks();
/* try to create a simple-framebuffer device */
compatible = parse_mode(si, &mode);
compatible = sysfb_parse_mode(si, &mode);
if (compatible) {
ret = create_simplefb(si, &mode);
ret = sysfb_create_simplefb(si, &mode);
if (!ret)
return 0;
}
@ -61,9 +59,24 @@ static __init int sysfb_init(void)
else
name = "platform-framebuffer";
pd = platform_device_register_resndata(NULL, name, 0,
NULL, 0, si, sizeof(*si));
return PTR_ERR_OR_ZERO(pd);
pd = platform_device_alloc(name, 0);
if (!pd)
return -ENOMEM;
sysfb_apply_efi_quirks(pd);
ret = platform_device_add_data(pd, si, sizeof(*si));
if (ret)
goto err;
ret = platform_device_add(pd);
if (ret)
goto err;
return 0;
err:
platform_device_put(pd);
return ret;
}
/* must execute after PCI subsystem for EFI quirks */

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Generic System Framebuffers on x86
* Generic System Framebuffers
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
*/
@ -18,14 +18,14 @@
#include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h>
#include <linux/screen_info.h>
#include <asm/sysfb.h>
#include <linux/sysfb.h>
static const char simplefb_resname[] = "BOOTFB";
static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
/* try parsing x86 screen_info into a simple-framebuffer mode struct */
__init bool parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode)
/* try parsing screen_info into a simple-framebuffer mode struct */
__init bool sysfb_parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode)
{
const struct simplefb_format *f;
__u8 type;
@ -57,13 +57,14 @@ __init bool parse_mode(const struct screen_info *si,
return false;
}
__init int create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode)
__init int sysfb_create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode)
{
struct platform_device *pd;
struct resource res;
u64 base, size;
u32 length;
int ret;
/*
* If the 64BIT_BASE capability is set, ext_lfb_base will contain the
@ -105,7 +106,19 @@ __init int create_simplefb(const struct screen_info *si,
if (res.end <= res.start)
return -EINVAL;
pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0,
&res, 1, mode, sizeof(*mode));
return PTR_ERR_OR_ZERO(pd);
pd = platform_device_alloc("simple-framebuffer", 0);
if (!pd)
return -ENOMEM;
sysfb_apply_efi_quirks(pd);
ret = platform_device_add_resources(pd, &res, 1);
if (ret)
return ret;
ret = platform_device_add_data(pd, mode, sizeof(*mode));
if (ret)
return ret;
return platform_device_add(pd);
}

View File

@ -1266,15 +1266,16 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev)
/**
* amdgpu_device_vga_set_decode - enable/disable vga decode
*
* @cookie: amdgpu_device pointer
* @pdev: PCI device pointer
* @state: enable/disable vga decode
*
* Enable/disable vga decode (all asics).
* Returns VGA resource flags.
*/
static unsigned int amdgpu_device_vga_set_decode(void *cookie, bool state)
static unsigned int amdgpu_device_vga_set_decode(struct pci_dev *pdev,
bool state)
{
struct amdgpu_device *adev = cookie;
struct amdgpu_device *adev = drm_to_adev(pci_get_drvdata(pdev));
amdgpu_asic_set_vga_state(adev, state);
if (state)
return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
@ -3715,7 +3716,7 @@ fence_driver_init:
/* this will fail for cards that aren't VGA class devices, just
* ignore it */
if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
vga_client_register(adev->pdev, adev, NULL, amdgpu_device_vga_set_decode);
vga_client_register(adev->pdev, amdgpu_device_vga_set_decode);
if (amdgpu_device_supports_px(ddev)) {
px = true;
@ -3838,7 +3839,7 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev)
vga_switcheroo_fini_domain_pm_ops(adev->dev);
}
if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
vga_client_register(adev->pdev, NULL, NULL, NULL);
vga_client_unregister(adev->pdev);
if (IS_ENABLED(CONFIG_PERF_EVENTS))
amdgpu_pmu_fini(adev);

View File

@ -337,6 +337,11 @@ int ast_mode_config_init(struct ast_private *ast);
#define AST_DP501_LINKRATE 0xf014
#define AST_DP501_EDID_DATA 0xf020
/* Define for Soc scratched reg */
#define AST_VRAM_INIT_STATUS_MASK GENMASK(7, 6)
//#define AST_VRAM_INIT_BY_BMC BIT(7)
//#define AST_VRAM_INIT_READY BIT(6)
int ast_mm_init(struct ast_private *ast);
/* ast post */
@ -346,6 +351,7 @@ bool ast_is_vga_enabled(struct drm_device *dev);
void ast_post_gpu(struct drm_device *dev);
u32 ast_mindwm(struct ast_private *ast, u32 r);
void ast_moutdwm(struct ast_private *ast, u32 r, u32 v);
void ast_patch_ahb_2500(struct ast_private *ast);
/* ast dp501 */
void ast_set_dp501_video_output(struct drm_device *dev, u8 mode);
bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);

View File

@ -97,6 +97,11 @@ static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev)
jregd0 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
jregd1 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff);
if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) {
/* Patch AST2500 */
if (((pdev->revision & 0xF0) == 0x40)
&& ((jregd0 & AST_VRAM_INIT_STATUS_MASK) == 0))
ast_patch_ahb_2500(ast);
/* Double check it's actually working */
data = ast_read32(ast, 0xf004);
if ((data != 0xFFFFFFFF) && (data != 0x00)) {

View File

@ -1298,7 +1298,7 @@ static enum drm_connector_status ast_connector_detect(struct drm_connector
int r;
r = ast_get_modes(connector);
if (r < 0)
if (r <= 0)
return connector_status_disconnected;
return connector_status_connected;

View File

@ -2028,6 +2028,40 @@ static bool ast_dram_init_2500(struct ast_private *ast)
return true;
}
void ast_patch_ahb_2500(struct ast_private *ast)
{
u32 data;
/* Clear bus lock condition */
ast_moutdwm(ast, 0x1e600000, 0xAEED1A03);
ast_moutdwm(ast, 0x1e600084, 0x00010000);
ast_moutdwm(ast, 0x1e600088, 0x00000000);
ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8);
data = ast_mindwm(ast, 0x1e6e2070);
if (data & 0x08000000) { /* check fast reset */
/*
* If "Fast restet" is enabled for ARM-ICE debugger,
* then WDT needs to enable, that
* WDT04 is WDT#1 Reload reg.
* WDT08 is WDT#1 counter restart reg to avoid system deadlock
* WDT0C is WDT#1 control reg
* [6:5]:= 01:Full chip
* [4]:= 1:1MHz clock source
* [1]:= 1:WDT will be cleeared and disabled after timeout occurs
* [0]:= 1:WDT enable
*/
ast_moutdwm(ast, 0x1E785004, 0x00000010);
ast_moutdwm(ast, 0x1E785008, 0x00004755);
ast_moutdwm(ast, 0x1E78500c, 0x00000033);
udelay(1000);
}
do {
ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8);
data = ast_mindwm(ast, 0x1e6e2000);
} while (data != 1);
ast_moutdwm(ast, 0x1e6e207c, 0x08000000); /* clear fast reset */
}
void ast_post_chip_2500(struct drm_device *dev)
{
struct ast_private *ast = to_ast_private(dev);
@ -2035,39 +2069,44 @@ void ast_post_chip_2500(struct drm_device *dev)
u8 reg;
reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
if ((reg & 0x80) == 0) {/* vga only */
if ((reg & AST_VRAM_INIT_STATUS_MASK) == 0) {/* vga only */
/* Clear bus lock condition */
ast_moutdwm(ast, 0x1e600000, 0xAEED1A03);
ast_moutdwm(ast, 0x1e600084, 0x00010000);
ast_moutdwm(ast, 0x1e600088, 0x00000000);
ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8);
ast_write32(ast, 0xf004, 0x1e6e0000);
ast_write32(ast, 0xf000, 0x1);
ast_write32(ast, 0x12000, 0x1688a8a8);
while (ast_read32(ast, 0x12000) != 0x1)
;
ast_patch_ahb_2500(ast);
ast_write32(ast, 0x10000, 0xfc600309);
while (ast_read32(ast, 0x10000) != 0x1)
;
/* Disable watchdog */
ast_moutdwm(ast, 0x1E78502C, 0x00000000);
ast_moutdwm(ast, 0x1E78504C, 0x00000000);
/*
* Reset USB port to patch USB unknown device issue
* SCU90 is Multi-function Pin Control #5
* [29]:= 1:Enable USB2.0 Host port#1 (that the mutually shared USB2.0 Hub
* port).
* SCU94 is Multi-function Pin Control #6
* [14:13]:= 1x:USB2.0 Host2 controller
* SCU70 is Hardware Strap reg
* [23]:= 1:CLKIN is 25MHz and USBCK1 = 24/48 MHz (determined by
* [18]: 0(24)/1(48) MHz)
* SCU7C is Write clear reg to SCU70
* [23]:= write 1 and then SCU70[23] will be clear as 0b.
*/
ast_moutdwm(ast, 0x1E6E2090, 0x20000000);
ast_moutdwm(ast, 0x1E6E2094, 0x00004000);
if (ast_mindwm(ast, 0x1E6E2070) & 0x00800000) {
ast_moutdwm(ast, 0x1E6E207C, 0x00800000);
mdelay(100);
ast_moutdwm(ast, 0x1E6E2070, 0x00800000);
}
/* Modify eSPI reset pin */
temp = ast_mindwm(ast, 0x1E6E2070);
if (temp & 0x02000000)
ast_moutdwm(ast, 0x1E6E207C, 0x00004000);
/* Slow down CPU/AHB CLK in VGA only mode */
temp = ast_read32(ast, 0x12008);
temp |= 0x73;
ast_write32(ast, 0x12008, temp);
/* Reset USB port to patch USB unknown device issue */
ast_moutdwm(ast, 0x1e6e2090, 0x20000000);
temp = ast_mindwm(ast, 0x1e6e2094);
temp |= 0x00004000;
ast_moutdwm(ast, 0x1e6e2094, temp);
temp = ast_mindwm(ast, 0x1e6e2070);
if (temp & 0x00800000) {
ast_moutdwm(ast, 0x1e6e207c, 0x00800000);
mdelay(100);
ast_moutdwm(ast, 0x1e6e2070, 0x00800000);
}
if (!ast_dram_init_2500(ast))
drm_err(dev, "DRAM init failed !\n");

View File

@ -61,6 +61,35 @@
* trusted clients.
*/
static bool drm_is_current_master_locked(struct drm_file *fpriv)
{
lockdep_assert_held_once(&fpriv->minor->dev->master_mutex);
return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
}
/**
* drm_is_current_master - checks whether @priv is the current master
* @fpriv: DRM file private
*
* Checks whether @fpriv is current master on its device. This decides whether a
* client is allowed to run DRM_MASTER IOCTLs.
*
* Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting
* - the current master is assumed to own the non-shareable display hardware.
*/
bool drm_is_current_master(struct drm_file *fpriv)
{
bool ret;
mutex_lock(&fpriv->minor->dev->master_mutex);
ret = drm_is_current_master_locked(fpriv);
mutex_unlock(&fpriv->minor->dev->master_mutex);
return ret;
}
EXPORT_SYMBOL(drm_is_current_master);
int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_auth *auth = data;
@ -135,16 +164,18 @@ static void drm_set_master(struct drm_device *dev, struct drm_file *fpriv,
static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
{
struct drm_master *old_master;
struct drm_master *new_master;
lockdep_assert_held_once(&dev->master_mutex);
WARN_ON(fpriv->is_master);
old_master = fpriv->master;
fpriv->master = drm_master_create(dev);
if (!fpriv->master) {
fpriv->master = old_master;
new_master = drm_master_create(dev);
if (!new_master)
return -ENOMEM;
}
spin_lock(&fpriv->master_lookup_lock);
fpriv->master = new_master;
spin_unlock(&fpriv->master_lookup_lock);
fpriv->is_master = 1;
fpriv->authenticated = 1;
@ -223,7 +254,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
if (ret)
goto out_unlock;
if (drm_is_current_master(file_priv))
if (drm_is_current_master_locked(file_priv))
goto out_unlock;
if (dev->master) {
@ -272,7 +303,7 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
if (ret)
goto out_unlock;
if (!drm_is_current_master(file_priv)) {
if (!drm_is_current_master_locked(file_priv)) {
ret = -EINVAL;
goto out_unlock;
}
@ -303,10 +334,13 @@ int drm_master_open(struct drm_file *file_priv)
* any master object for render clients
*/
mutex_lock(&dev->master_mutex);
if (!dev->master)
if (!dev->master) {
ret = drm_new_set_master(dev, file_priv);
else
} else {
spin_lock(&file_priv->master_lookup_lock);
file_priv->master = drm_master_get(dev->master);
spin_unlock(&file_priv->master_lookup_lock);
}
mutex_unlock(&dev->master_mutex);
return ret;
@ -322,7 +356,7 @@ void drm_master_release(struct drm_file *file_priv)
if (file_priv->magic)
idr_remove(&file_priv->master->magic_map, file_priv->magic);
if (!drm_is_current_master(file_priv))
if (!drm_is_current_master_locked(file_priv))
goto out;
drm_legacy_lock_master_cleanup(dev, master);
@ -343,22 +377,6 @@ out:
mutex_unlock(&dev->master_mutex);
}
/**
* drm_is_current_master - checks whether @priv is the current master
* @fpriv: DRM file private
*
* Checks whether @fpriv is current master on its device. This decides whether a
* client is allowed to run DRM_MASTER IOCTLs.
*
* Most of the modern IOCTL which require DRM_MASTER are for kernel modesetting
* - the current master is assumed to own the non-shareable display hardware.
*/
bool drm_is_current_master(struct drm_file *fpriv)
{
return fpriv->is_master && drm_lease_owner(fpriv->master) == fpriv->minor->dev->master;
}
EXPORT_SYMBOL(drm_is_current_master);
/**
* drm_master_get - reference a master pointer
* @master: &struct drm_master
@ -372,6 +390,31 @@ struct drm_master *drm_master_get(struct drm_master *master)
}
EXPORT_SYMBOL(drm_master_get);
/**
* drm_file_get_master - reference &drm_file.master of @file_priv
* @file_priv: DRM file private
*
* Increments the reference count of @file_priv's &drm_file.master and returns
* the &drm_file.master. If @file_priv has no &drm_file.master, returns NULL.
*
* Master pointers returned from this function should be unreferenced using
* drm_master_put().
*/
struct drm_master *drm_file_get_master(struct drm_file *file_priv)
{
struct drm_master *master = NULL;
spin_lock(&file_priv->master_lookup_lock);
if (!file_priv->master)
goto unlock;
master = drm_master_get(file_priv->master);
unlock:
spin_unlock(&file_priv->master_lookup_lock);
return master;
}
EXPORT_SYMBOL(drm_file_get_master);
static void drm_master_destroy(struct kref *kref)
{
struct drm_master *master = container_of(kref, struct drm_master, refcount);

View File

@ -2414,6 +2414,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
struct drm_mode_modeinfo u_mode;
struct drm_mode_modeinfo __user *mode_ptr;
uint32_t __user *encoder_ptr;
bool is_current_master;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EOPNOTSUPP;
@ -2444,9 +2445,11 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
out_resp->connector_type = connector->connector_type;
out_resp->connector_type_id = connector->connector_type_id;
is_current_master = drm_is_current_master(file_priv);
mutex_lock(&dev->mode_config.mutex);
if (out_resp->count_modes == 0) {
if (drm_is_current_master(file_priv))
if (is_current_master)
connector->funcs->fill_modes(connector,
dev->mode_config.max_width,
dev->mode_config.max_height);

View File

@ -91,6 +91,7 @@ static int drm_clients_info(struct seq_file *m, void *data)
mutex_lock(&dev->filelist_mutex);
list_for_each_entry_reverse(priv, &dev->filelist, lhead) {
struct task_struct *task;
bool is_current_master = drm_is_current_master(priv);
rcu_read_lock(); /* locks pid_task()->comm */
task = pid_task(priv->pid, PIDTYPE_PID);
@ -99,7 +100,7 @@ static int drm_clients_info(struct seq_file *m, void *data)
task ? task->comm : "<unknown>",
pid_vnr(priv->pid),
priv->minor->index,
drm_is_current_master(priv) ? 'y' : 'n',
is_current_master ? 'y' : 'n',
priv->authenticated ? 'y' : 'n',
from_kuid_munged(seq_user_ns(m), uid),
priv->magic);

View File

@ -176,6 +176,7 @@ struct drm_file *drm_file_alloc(struct drm_minor *minor)
init_waitqueue_head(&file->event_wait);
file->event_space = 4096; /* set aside 4k for event buffer */
spin_lock_init(&file->master_lookup_lock);
mutex_init(&file->event_read_lock);
if (drm_core_check_feature(dev, DRIVER_GEM))

View File

@ -136,7 +136,7 @@ int drm_irq_install(struct drm_device *dev, int irq)
if (ret < 0) {
dev->irq_enabled = false;
if (drm_core_check_feature(dev, DRIVER_LEGACY))
vga_client_register(to_pci_dev(dev->dev), NULL, NULL, NULL);
vga_client_unregister(to_pci_dev(dev->dev));
free_irq(irq, dev);
} else {
dev->irq = irq;
@ -198,7 +198,7 @@ int drm_irq_uninstall(struct drm_device *dev)
DRM_DEBUG("irq=%d\n", dev->irq);
if (drm_core_check_feature(dev, DRIVER_LEGACY))
vga_client_register(to_pci_dev(dev->dev), NULL, NULL, NULL);
vga_client_unregister(to_pci_dev(dev->dev));
if (dev->driver->irq_uninstall)
dev->driver->irq_uninstall(dev);

View File

@ -106,10 +106,19 @@ static bool _drm_has_leased(struct drm_master *master, int id)
*/
bool _drm_lease_held(struct drm_file *file_priv, int id)
{
if (!file_priv || !file_priv->master)
bool ret;
struct drm_master *master;
if (!file_priv)
return true;
return _drm_lease_held_master(file_priv->master, id);
master = drm_file_get_master(file_priv);
if (!master)
return true;
ret = _drm_lease_held_master(master, id);
drm_master_put(&master);
return ret;
}
/**
@ -128,13 +137,22 @@ bool drm_lease_held(struct drm_file *file_priv, int id)
struct drm_master *master;
bool ret;
if (!file_priv || !file_priv->master || !file_priv->master->lessor)
if (!file_priv)
return true;
master = file_priv->master;
master = drm_file_get_master(file_priv);
if (!master)
return true;
if (!master->lessor) {
ret = true;
goto out;
}
mutex_lock(&master->dev->mode_config.idr_mutex);
ret = _drm_lease_held_master(master, id);
mutex_unlock(&master->dev->mode_config.idr_mutex);
out:
drm_master_put(&master);
return ret;
}
@ -154,10 +172,16 @@ uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
int count_in, count_out;
uint32_t crtcs_out = 0;
if (!file_priv || !file_priv->master || !file_priv->master->lessor)
if (!file_priv)
return crtcs_in;
master = file_priv->master;
master = drm_file_get_master(file_priv);
if (!master)
return crtcs_in;
if (!master->lessor) {
crtcs_out = crtcs_in;
goto out;
}
dev = master->dev;
count_in = count_out = 0;
@ -176,6 +200,9 @@ uint32_t drm_lease_filter_crtcs(struct drm_file *file_priv, uint32_t crtcs_in)
count_in++;
}
mutex_unlock(&master->dev->mode_config.idr_mutex);
out:
drm_master_put(&master);
return crtcs_out;
}
@ -489,7 +516,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
size_t object_count;
int ret = 0;
struct idr leases;
struct drm_master *lessor = lessor_priv->master;
struct drm_master *lessor;
struct drm_master *lessee = NULL;
struct file *lessee_file = NULL;
struct file *lessor_file = lessor_priv->filp;
@ -501,12 +528,6 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EOPNOTSUPP;
/* Do not allow sub-leases */
if (lessor->lessor) {
DRM_DEBUG_LEASE("recursive leasing not allowed\n");
return -EINVAL;
}
/* need some objects */
if (cl->object_count == 0) {
DRM_DEBUG_LEASE("no objects in lease\n");
@ -518,12 +539,22 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
return -EINVAL;
}
lessor = drm_file_get_master(lessor_priv);
/* Do not allow sub-leases */
if (lessor->lessor) {
DRM_DEBUG_LEASE("recursive leasing not allowed\n");
ret = -EINVAL;
goto out_lessor;
}
object_count = cl->object_count;
object_ids = memdup_user(u64_to_user_ptr(cl->object_ids),
array_size(object_count, sizeof(__u32)));
if (IS_ERR(object_ids))
return PTR_ERR(object_ids);
if (IS_ERR(object_ids)) {
ret = PTR_ERR(object_ids);
goto out_lessor;
}
idr_init(&leases);
@ -534,14 +565,15 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
if (ret) {
DRM_DEBUG_LEASE("lease object lookup failed: %i\n", ret);
idr_destroy(&leases);
return ret;
goto out_lessor;
}
/* Allocate a file descriptor for the lease */
fd = get_unused_fd_flags(cl->flags & (O_CLOEXEC | O_NONBLOCK));
if (fd < 0) {
idr_destroy(&leases);
return fd;
ret = fd;
goto out_lessor;
}
DRM_DEBUG_LEASE("Creating lease\n");
@ -577,6 +609,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,
/* Hook up the fd */
fd_install(fd, lessee_file);
drm_master_put(&lessor);
DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl succeeded\n");
return 0;
@ -586,6 +619,8 @@ out_lessee:
out_leases:
put_unused_fd(fd);
out_lessor:
drm_master_put(&lessor);
DRM_DEBUG_LEASE("drm_mode_create_lease_ioctl failed: %d\n", ret);
return ret;
}
@ -608,7 +643,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
struct drm_mode_list_lessees *arg = data;
__u32 __user *lessee_ids = (__u32 __user *) (uintptr_t) (arg->lessees_ptr);
__u32 count_lessees = arg->count_lessees;
struct drm_master *lessor = lessor_priv->master, *lessee;
struct drm_master *lessor, *lessee;
int count;
int ret = 0;
@ -619,6 +654,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EOPNOTSUPP;
lessor = drm_file_get_master(lessor_priv);
DRM_DEBUG_LEASE("List lessees for %d\n", lessor->lessee_id);
mutex_lock(&dev->mode_config.idr_mutex);
@ -642,6 +678,7 @@ int drm_mode_list_lessees_ioctl(struct drm_device *dev,
arg->count_lessees = count;
mutex_unlock(&dev->mode_config.idr_mutex);
drm_master_put(&lessor);
return ret;
}
@ -661,7 +698,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
struct drm_mode_get_lease *arg = data;
__u32 __user *object_ids = (__u32 __user *) (uintptr_t) (arg->objects_ptr);
__u32 count_objects = arg->count_objects;
struct drm_master *lessee = lessee_priv->master;
struct drm_master *lessee;
struct idr *object_idr;
int count;
void *entry;
@ -675,6 +712,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EOPNOTSUPP;
lessee = drm_file_get_master(lessee_priv);
DRM_DEBUG_LEASE("get lease for %d\n", lessee->lessee_id);
mutex_lock(&dev->mode_config.idr_mutex);
@ -702,6 +740,7 @@ int drm_mode_get_lease_ioctl(struct drm_device *dev,
arg->count_objects = count;
mutex_unlock(&dev->mode_config.idr_mutex);
drm_master_put(&lessee);
return ret;
}
@ -720,7 +759,7 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
void *data, struct drm_file *lessor_priv)
{
struct drm_mode_revoke_lease *arg = data;
struct drm_master *lessor = lessor_priv->master;
struct drm_master *lessor;
struct drm_master *lessee;
int ret = 0;
@ -730,6 +769,7 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EOPNOTSUPP;
lessor = drm_file_get_master(lessor_priv);
mutex_lock(&dev->mode_config.idr_mutex);
lessee = _drm_find_lessee(lessor, arg->lessee_id);
@ -750,6 +790,7 @@ int drm_mode_revoke_lease_ioctl(struct drm_device *dev,
fail:
mutex_unlock(&dev->mode_config.idr_mutex);
drm_master_put(&lessor);
return ret;
}

View File

@ -124,9 +124,9 @@ intel_vga_set_state(struct drm_i915_private *i915, bool enable_decode)
}
static unsigned int
intel_vga_set_decode(void *cookie, bool enable_decode)
intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode)
{
struct drm_i915_private *i915 = cookie;
struct drm_i915_private *i915 = pdev_to_i915(pdev);
intel_vga_set_state(i915, enable_decode);
@ -139,6 +139,7 @@ intel_vga_set_decode(void *cookie, bool enable_decode)
int intel_vga_register(struct drm_i915_private *i915)
{
struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
int ret;
@ -150,7 +151,7 @@ int intel_vga_register(struct drm_i915_private *i915)
* then we do not take part in VGA arbitration and the
* vga_client_register() fails with -ENODEV.
*/
ret = vga_client_register(pdev, i915, NULL, intel_vga_set_decode);
ret = vga_client_register(pdev, intel_vga_set_decode);
if (ret && ret != -ENODEV)
return ret;
@ -161,5 +162,5 @@ void intel_vga_unregister(struct drm_i915_private *i915)
{
struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
vga_client_register(pdev, NULL, NULL, NULL);
vga_client_unregister(pdev);
}

View File

@ -33,7 +33,6 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_irq.h>
#include <drm/drm_managed.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@ -799,8 +798,6 @@ static const struct drm_driver ingenic_drm_driver_data = {
.fops = &ingenic_drm_fops,
.gem_create_object = ingenic_drm_gem_create_object,
DRM_GEM_CMA_DRIVER_OPS,
.irq_handler = ingenic_drm_irq_handler,
};
static const struct drm_plane_funcs ingenic_drm_primary_plane_funcs = {
@ -1098,7 +1095,7 @@ static int ingenic_drm_bind(struct device *dev, bool has_components)
encoder->possible_clones = clone_mask;
}
ret = drm_irq_install(drm, irq);
ret = devm_request_irq(dev, irq, ingenic_drm_irq_handler, 0, drm->driver->name, drm);
if (ret) {
dev_err(dev, "Unable to install IRQ handler\n");
return ret;

View File

@ -11,9 +11,9 @@
#include "nouveau_vga.h"
static unsigned int
nouveau_vga_set_decode(void *priv, bool state)
nouveau_vga_set_decode(struct pci_dev *pdev, bool state)
{
struct nouveau_drm *drm = nouveau_drm(priv);
struct nouveau_drm *drm = nouveau_drm(pci_get_drvdata(pdev));
struct nvif_object *device = &drm->client.device.object;
if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CURIE &&
@ -94,7 +94,7 @@ nouveau_vga_init(struct nouveau_drm *drm)
return;
pdev = to_pci_dev(dev->dev);
vga_client_register(pdev, dev, NULL, nouveau_vga_set_decode);
vga_client_register(pdev, nouveau_vga_set_decode);
/* don't register Thunderbolt eGPU with vga_switcheroo */
if (pci_is_thunderbolt_attached(pdev))
@ -118,7 +118,7 @@ nouveau_vga_fini(struct nouveau_drm *drm)
return;
pdev = to_pci_dev(dev->dev);
vga_client_register(pdev, NULL, NULL, NULL);
vga_client_unregister(pdev);
if (pci_is_thunderbolt_attached(pdev))
return;

View File

@ -574,6 +574,16 @@ config DRM_PANEL_VISIONOX_RM69299
Say Y here if you want to enable support for Visionox
RM69299 DSI Video Mode panel.
config DRM_PANEL_WIDECHIPS_WS2401
tristate "Widechips WS2401 DPI panel driver"
depends on SPI && GPIOLIB
depends on BACKLIGHT_CLASS_DEVICE
select DRM_MIPI_DBI
help
Say Y here if you want to enable support for the Widechips WS2401 DPI
480x800 display controller used in panels such as Samsung LMS380KF01.
This display is used in the Samsung Galaxy Ace 2 GT-I8160 (Codina).
config DRM_PANEL_XINPENG_XPP055C272
tristate "Xinpeng XPP055C272 panel driver"
depends on OF

View File

@ -60,4 +60,5 @@ obj-$(CONFIG_DRM_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
obj-$(CONFIG_DRM_PANEL_TPO_TPG110) += panel-tpo-tpg110.o
obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o
obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o

View File

@ -0,0 +1,441 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Panel driver for the WideChips WS2401 480x800 DPI RGB panel, used in
* the Samsung Mobile Display (SMD) LMS380KF01.
* Found in the Samsung Galaxy Ace 2 GT-I8160 mobile phone.
* Linus Walleij <linus.walleij@linaro.org>
* Inspired by code and know-how in the vendor driver by Gareth Phillips.
*/
#include <drm/drm_mipi_dbi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/media-bus-format.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <video/mipi_display.h>
#define WS2401_RESCTL 0xb8 /* Resolution select control */
#define WS2401_PSMPS 0xbd /* SMPS positive control */
#define WS2401_NSMPS 0xbe /* SMPS negative control */
#define WS2401_SMPS 0xbf
#define WS2401_BCMODE 0xc1 /* Backlight control mode */
#define WS2401_WRBLCTL 0xc3 /* Backlight control */
#define WS2401_WRDISBV 0xc4 /* Write manual brightness */
#define WS2401_WRCTRLD 0xc6 /* Write BL control */
#define WS2401_WRMIE 0xc7 /* Write MIE mode */
#define WS2401_READ_ID1 0xda /* Read panel ID 1 */
#define WS2401_READ_ID2 0xdb /* Read panel ID 2 */
#define WS2401_READ_ID3 0xdc /* Read panel ID 3 */
#define WS2401_GAMMA_R1 0xe7 /* Gamma red 1 */
#define WS2401_GAMMA_G1 0xe8 /* Gamma green 1 */
#define WS2401_GAMMA_B1 0xe9 /* Gamma blue 1 */
#define WS2401_GAMMA_R2 0xea /* Gamma red 2 */
#define WS2401_GAMMA_G2 0xeb /* Gamma green 2 */
#define WS2401_GAMMA_B2 0xec /* Gamma blue 2 */
#define WS2401_PASSWD1 0xf0 /* Password command for level 2 */
#define WS2401_DISCTL 0xf2 /* Display control */
#define WS2401_PWRCTL 0xf3 /* Power control */
#define WS2401_VCOMCTL 0xf4 /* VCOM control */
#define WS2401_SRCCTL 0xf5 /* Source control */
#define WS2401_PANELCTL 0xf6 /* Panel control */
static const u8 ws2401_dbi_read_commands[] = {
WS2401_READ_ID1,
WS2401_READ_ID2,
WS2401_READ_ID3,
0, /* sentinel */
};
/**
* struct ws2401 - state container for a panel controlled by the WS2401
* controller
*/
struct ws2401 {
/** @dev: the container device */
struct device *dev;
/** @dbi: the DBI bus abstraction handle */
struct mipi_dbi dbi;
/** @panel: the DRM panel instance for this device */
struct drm_panel panel;
/** @width: the width of this panel in mm */
u32 width;
/** @height: the height of this panel in mm */
u32 height;
/** @reset: reset GPIO line */
struct gpio_desc *reset;
/** @regulators: VCCIO and VIO supply regulators */
struct regulator_bulk_data regulators[2];
/** @internal_bl: If using internal backlight */
bool internal_bl;
};
static const struct drm_display_mode lms380kf01_480_800_mode = {
/*
* The vendor driver states that the "SMD panel" has a clock
* frequency of 49920000 Hz / 2 = 24960000 Hz.
*/
.clock = 24960,
.hdisplay = 480,
.hsync_start = 480 + 8,
.hsync_end = 480 + 8 + 10,
.htotal = 480 + 8 + 10 + 8,
.vdisplay = 800,
.vsync_start = 800 + 8,
.vsync_end = 800 + 8 + 2,
.vtotal = 800 + 8 + 2 + 18,
.width_mm = 50,
.height_mm = 84,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static inline struct ws2401 *to_ws2401(struct drm_panel *panel)
{
return container_of(panel, struct ws2401, panel);
}
static void ws2401_read_mtp_id(struct ws2401 *ws)
{
struct mipi_dbi *dbi = &ws->dbi;
u8 id1, id2, id3;
int ret;
ret = mipi_dbi_command_read(dbi, WS2401_READ_ID1, &id1);
if (ret) {
dev_err(ws->dev, "unable to read MTP ID 1\n");
return;
}
ret = mipi_dbi_command_read(dbi, WS2401_READ_ID2, &id2);
if (ret) {
dev_err(ws->dev, "unable to read MTP ID 2\n");
return;
}
ret = mipi_dbi_command_read(dbi, WS2401_READ_ID3, &id3);
if (ret) {
dev_err(ws->dev, "unable to read MTP ID 3\n");
return;
}
dev_info(ws->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
}
static int ws2401_power_on(struct ws2401 *ws)
{
struct mipi_dbi *dbi = &ws->dbi;
int ret;
/* Power up */
ret = regulator_bulk_enable(ARRAY_SIZE(ws->regulators),
ws->regulators);
if (ret) {
dev_err(ws->dev, "failed to enable regulators: %d\n", ret);
return ret;
}
msleep(10);
/* Assert reset >=1 ms */
gpiod_set_value_cansleep(ws->reset, 1);
usleep_range(1000, 5000);
/* De-assert reset */
gpiod_set_value_cansleep(ws->reset, 0);
/* Wait >= 10 ms */
msleep(10);
dev_dbg(ws->dev, "de-asserted RESET\n");
/*
* Exit sleep mode and initialize display - some hammering is
* necessary.
*/
mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
mipi_dbi_command(dbi, MIPI_DCS_EXIT_SLEEP_MODE);
msleep(50);
/* Magic to unlock level 2 control of the display */
mipi_dbi_command(dbi, WS2401_PASSWD1, 0x5a, 0x5a);
/* Configure resolution to 480RGBx800 */
mipi_dbi_command(dbi, WS2401_RESCTL, 0x12);
/* Set addressing mode Flip V(d0), Flip H(d1) RGB/BGR(d3) */
mipi_dbi_command(dbi, MIPI_DCS_SET_ADDRESS_MODE, 0x01);
/* Set pixel format: 24 bpp */
mipi_dbi_command(dbi, MIPI_DCS_SET_PIXEL_FORMAT, 0x70);
mipi_dbi_command(dbi, WS2401_SMPS, 0x00, 0x0f);
mipi_dbi_command(dbi, WS2401_PSMPS, 0x06, 0x03, /* DDVDH: 4.6v */
0x7e, 0x03, 0x12, 0x37);
mipi_dbi_command(dbi, WS2401_NSMPS, 0x06, 0x03, /* DDVDH: -4.6v */
0x7e, 0x02, 0x15, 0x37);
mipi_dbi_command(dbi, WS2401_SMPS, 0x02, 0x0f);
mipi_dbi_command(dbi, WS2401_PWRCTL, 0x10, 0xA9, 0x00, 0x01, 0x44,
0xb4, /* VGH:16.1v, VGL:-13.8v */
0x50, /* GREFP:4.2v (default) */
0x50, /* GREFN:-4.2v (default) */
0x00,
0x44); /* VOUTL:-10v (default) */
mipi_dbi_command(dbi, WS2401_DISCTL, 0x01, 0x00, 0x00, 0x00, 0x14,
0x16);
mipi_dbi_command(dbi, WS2401_VCOMCTL, 0x30, 0x53, 0x53);
mipi_dbi_command(dbi, WS2401_SRCCTL, 0x03, 0x0C, 0x00, 0x00, 0x00,
0x01, /* 2 dot inversion */
0x01, 0x06, 0x03);
mipi_dbi_command(dbi, WS2401_PANELCTL, 0x14, 0x00, 0x80, 0x00);
mipi_dbi_command(dbi, WS2401_WRMIE, 0x01);
/* Set up gamma, probably these are P-gamma and N-gamma for each color */
mipi_dbi_command(dbi, WS2401_GAMMA_R1, 0x00,
0x5b, 0x42, 0x41, 0x3f, 0x42, 0x3d, 0x38, 0x2e,
0x2b, 0x2a, 0x27, 0x22, 0x27, 0x0f, 0x00, 0x00);
mipi_dbi_command(dbi, WS2401_GAMMA_R2, 0x00,
0x5b, 0x42, 0x41, 0x3f, 0x42, 0x3d, 0x38, 0x2e,
0x2b, 0x2a, 0x27, 0x22, 0x27, 0x0f, 0x00, 0x00);
mipi_dbi_command(dbi, WS2401_GAMMA_G1, 0x00,
0x59, 0x40, 0x3f, 0x3e, 0x41, 0x3d, 0x39, 0x2f,
0x2c, 0x2b, 0x29, 0x25, 0x29, 0x19, 0x08, 0x00);
mipi_dbi_command(dbi, WS2401_GAMMA_G2, 0x00,
0x59, 0x40, 0x3f, 0x3e, 0x41, 0x3d, 0x39, 0x2f,
0x2c, 0x2b, 0x29, 0x25, 0x29, 0x19, 0x08, 0x00);
mipi_dbi_command(dbi, WS2401_GAMMA_B1, 0x00,
0x57, 0x3b, 0x3a, 0x3b, 0x3f, 0x3b, 0x38, 0x27,
0x38, 0x2a, 0x26, 0x22, 0x34, 0x0c, 0x09, 0x00);
mipi_dbi_command(dbi, WS2401_GAMMA_B2, 0x00,
0x57, 0x3b, 0x3a, 0x3b, 0x3f, 0x3b, 0x38, 0x27,
0x38, 0x2a, 0x26, 0x22, 0x34, 0x0c, 0x09, 0x00);
if (ws->internal_bl) {
mipi_dbi_command(dbi, WS2401_WRCTRLD, 0x2c);
} else {
mipi_dbi_command(dbi, WS2401_WRCTRLD, 0x00);
/*
* When not using internal backlight we do not need any further
* L2 accesses to the panel so we close the door on our way out.
* Otherwise we need to leave the L2 door open.
*/
mipi_dbi_command(dbi, WS2401_PASSWD1, 0xa5, 0xa5);
}
return 0;
}
static int ws2401_power_off(struct ws2401 *ws)
{
/* Go into RESET and disable regulators */
gpiod_set_value_cansleep(ws->reset, 1);
return regulator_bulk_disable(ARRAY_SIZE(ws->regulators),
ws->regulators);
}
static int ws2401_unprepare(struct drm_panel *panel)
{
struct ws2401 *ws = to_ws2401(panel);
struct mipi_dbi *dbi = &ws->dbi;
/* Make sure we disable backlight, if any */
if (ws->internal_bl)
mipi_dbi_command(dbi, WS2401_WRCTRLD, 0x00);
mipi_dbi_command(dbi, MIPI_DCS_ENTER_SLEEP_MODE);
msleep(120);
return ws2401_power_off(to_ws2401(panel));
}
static int ws2401_disable(struct drm_panel *panel)
{
struct ws2401 *ws = to_ws2401(panel);
struct mipi_dbi *dbi = &ws->dbi;
mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_OFF);
msleep(25);
return 0;
}
static int ws2401_prepare(struct drm_panel *panel)
{
return ws2401_power_on(to_ws2401(panel));
}
static int ws2401_enable(struct drm_panel *panel)
{
struct ws2401 *ws = to_ws2401(panel);
struct mipi_dbi *dbi = &ws->dbi;
mipi_dbi_command(dbi, MIPI_DCS_SET_DISPLAY_ON);
return 0;
}
/**
* ws2401_get_modes() - return the mode
* @panel: the panel to get the mode for
* @connector: reference to the central DRM connector control structure
*/
static int ws2401_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct ws2401 *ws = to_ws2401(panel);
struct drm_display_mode *mode;
static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
/*
* We just support the LMS380KF01 so far, if we implement more panels
* this mode, the following connector display_info settings and
* probably the custom DCS sequences needs to selected based on what
* the target panel needs.
*/
mode = drm_mode_duplicate(connector->dev, &lms380kf01_480_800_mode);
if (!mode) {
dev_err(ws->dev, "failed to add mode\n");
return -ENOMEM;
}
connector->display_info.bpc = 8;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
connector->display_info.bus_flags =
DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
drm_display_info_set_bus_formats(&connector->display_info,
&bus_format, 1);
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
return 1;
}
static const struct drm_panel_funcs ws2401_drm_funcs = {
.disable = ws2401_disable,
.unprepare = ws2401_unprepare,
.prepare = ws2401_prepare,
.enable = ws2401_enable,
.get_modes = ws2401_get_modes,
};
static int ws2401_set_brightness(struct backlight_device *bl)
{
struct ws2401 *ws = bl_get_data(bl);
struct mipi_dbi *dbi = &ws->dbi;
u8 brightness = backlight_get_brightness(bl);
if (backlight_is_blank(bl)) {
mipi_dbi_command(dbi, WS2401_WRCTRLD, 0x00);
} else {
mipi_dbi_command(dbi, WS2401_WRCTRLD, 0x2c);
mipi_dbi_command(dbi, WS2401_WRDISBV, brightness);
}
return 0;
}
static const struct backlight_ops ws2401_bl_ops = {
.update_status = ws2401_set_brightness,
};
static const struct backlight_properties ws2401_bl_props = {
.type = BACKLIGHT_PLATFORM,
.brightness = 120,
.max_brightness = U8_MAX,
};
static int ws2401_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct ws2401 *ws;
int ret;
ws = devm_kzalloc(dev, sizeof(*ws), GFP_KERNEL);
if (!ws)
return -ENOMEM;
ws->dev = dev;
/*
* VCI is the analog voltage supply
* VCCIO is the digital I/O voltage supply
*/
ws->regulators[0].supply = "vci";
ws->regulators[1].supply = "vccio";
ret = devm_regulator_bulk_get(dev,
ARRAY_SIZE(ws->regulators),
ws->regulators);
if (ret)
return dev_err_probe(dev, ret, "failed to get regulators\n");
ws->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ws->reset)) {
ret = PTR_ERR(ws->reset);
return dev_err_probe(dev, ret, "no RESET GPIO\n");
}
ret = mipi_dbi_spi_init(spi, &ws->dbi, NULL);
if (ret)
return dev_err_probe(dev, ret, "MIPI DBI init failed\n");
ws->dbi.read_commands = ws2401_dbi_read_commands;
ws2401_power_on(ws);
ws2401_read_mtp_id(ws);
ws2401_power_off(ws);
drm_panel_init(&ws->panel, dev, &ws2401_drm_funcs,
DRM_MODE_CONNECTOR_DPI);
ret = drm_panel_of_backlight(&ws->panel);
if (ret)
return dev_err_probe(dev, ret,
"failed to get external backlight device\n");
if (!ws->panel.backlight) {
dev_dbg(dev, "no external backlight, using internal backlight\n");
ws->panel.backlight =
devm_backlight_device_register(dev, "ws2401", dev, ws,
&ws2401_bl_ops, &ws2401_bl_props);
if (IS_ERR(ws->panel.backlight))
return dev_err_probe(dev, PTR_ERR(ws->panel.backlight),
"failed to register backlight device\n");
} else {
dev_dbg(dev, "using external backlight\n");
}
spi_set_drvdata(spi, ws);
drm_panel_add(&ws->panel);
dev_dbg(dev, "added panel\n");
return 0;
}
static int ws2401_remove(struct spi_device *spi)
{
struct ws2401 *ws = spi_get_drvdata(spi);
drm_panel_remove(&ws->panel);
return 0;
}
/*
* Samsung LMS380KF01 is the one instance of this display controller that we
* know about, but if more are found, the controller can be parameterized
* here and used for other configurations.
*/
static const struct of_device_id ws2401_match[] = {
{ .compatible = "samsung,lms380kf01", },
{},
};
MODULE_DEVICE_TABLE(of, ws2401_match);
static struct spi_driver ws2401_driver = {
.probe = ws2401_probe,
.remove = ws2401_remove,
.driver = {
.name = "ws2401-panel",
.of_match_table = ws2401_match,
},
};
module_spi_driver(ws2401_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("Samsung WS2401 panel driver");
MODULE_LICENSE("GPL v2");

View File

@ -1067,15 +1067,16 @@ void radeon_combios_fini(struct radeon_device *rdev)
/**
* radeon_vga_set_decode - enable/disable vga decode
*
* @cookie: radeon_device pointer
* @pdev: PCI device
* @state: enable/disable vga decode
*
* Enable/disable vga decode (all asics).
* Returns VGA resource flags.
*/
static unsigned int radeon_vga_set_decode(void *cookie, bool state)
static unsigned int radeon_vga_set_decode(struct pci_dev *pdev, bool state)
{
struct radeon_device *rdev = cookie;
struct drm_device *dev = pci_get_drvdata(pdev);
struct radeon_device *rdev = dev->dev_private;
radeon_vga_set_state(rdev, state);
if (state)
return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
@ -1434,7 +1435,7 @@ int radeon_device_init(struct radeon_device *rdev,
/* if we have > 1 VGA cards, then disable the radeon VGA resources */
/* this will fail for cards that aren't VGA class devices, just
* ignore it */
vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
vga_client_register(rdev->pdev, radeon_vga_set_decode);
if (rdev->flags & RADEON_IS_PX)
runtime = true;
@ -1530,7 +1531,7 @@ void radeon_device_fini(struct radeon_device *rdev)
vga_switcheroo_unregister_client(rdev->pdev);
if (rdev->flags & RADEON_IS_PX)
vga_switcheroo_fini_domain_pm_ops(rdev->dev);
vga_client_register(rdev->pdev, NULL, NULL, NULL);
vga_client_unregister(rdev->pdev);
if (rdev->rio_mem)
pci_iounmap(rdev->pdev, rdev->rio_mem);
rdev->rio_mem = NULL;

View File

@ -309,14 +309,23 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
return 0;
}
#define DSI_PHY_DELAY(fp, vp, mbps) DIV_ROUND_UP((fp) * (mbps) + 1000 * (vp), 8000)
static int
dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
struct dw_mipi_dsi_dphy_timing *timing)
{
timing->clk_hs2lp = 0x40;
timing->clk_lp2hs = 0x40;
timing->data_hs2lp = 0x40;
timing->data_lp2hs = 0x40;
/*
* From STM32MP157 datasheet, valid for STM32F469, STM32F7x9, STM32H747
* phy_clkhs2lp_time = (272+136*UI)/(8*UI)
* phy_clklp2hs_time = (512+40*UI)/(8*UI)
* phy_hs2lp_time = (192+64*UI)/(8*UI)
* phy_lp2hs_time = (256+32*UI)/(8*UI)
*/
timing->clk_hs2lp = DSI_PHY_DELAY(272, 136, lane_mbps);
timing->clk_lp2hs = DSI_PHY_DELAY(512, 40, lane_mbps);
timing->data_hs2lp = DSI_PHY_DELAY(192, 64, lane_mbps);
timing->data_lp2hs = DSI_PHY_DELAY(256, 32, lane_mbps);
return 0;
}

View File

@ -1121,8 +1121,9 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
ret = drm_bridge_attach(encoder, bridge, NULL, 0);
if (ret) {
drm_encoder_cleanup(encoder);
return -EINVAL;
if (ret != -EPROBE_DEFER)
drm_encoder_cleanup(encoder);
return ret;
}
DRM_DEBUG_DRIVER("Bridge encoder:%d created\n", encoder->base.id);
@ -1265,7 +1266,8 @@ int ltdc_load(struct drm_device *ddev)
if (bridge) {
ret = ltdc_encoder_init(ddev, bridge);
if (ret) {
DRM_ERROR("init encoder endpoint %d\n", i);
if (ret != -EPROBE_DEFER)
DRM_ERROR("init encoder endpoint %d\n", i);
goto err;
}
}

View File

@ -64,8 +64,8 @@ config DRM_SIMPLEDRM
buffer, size, and display format must be provided via device tree,
UEFI, VESA, etc.
On x86 and compatible, you should also select CONFIG_X86_SYSFB to
use UEFI and VESA framebuffers.
On x86 BIOS or UEFI systems, you should also select SYSFB_SIMPLEFB
to use UEFI and VESA framebuffers.
config TINYDRM_HX8357D
tristate "DRM support for HX8357D display panels"

View File

@ -648,7 +648,7 @@ static int bochs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent
if (IS_ERR(dev))
return PTR_ERR(dev);
ret = pci_enable_device(pdev);
ret = pcim_enable_device(pdev);
if (ret)
goto err_free_dev;

View File

@ -9,6 +9,7 @@ v3d-y := \
v3d_gem.o \
v3d_irq.o \
v3d_mmu.o \
v3d_perfmon.o \
v3d_trace_points.o \
v3d_sched.o

View File

@ -94,6 +94,9 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
case DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH:
args->value = 1;
return 0;
case DRM_V3D_PARAM_SUPPORTS_PERFMON:
args->value = (v3d->ver >= 40);
return 0;
default:
DRM_DEBUG("Unknown parameter %d\n", args->param);
return -EINVAL;
@ -121,6 +124,7 @@ v3d_open(struct drm_device *dev, struct drm_file *file)
1, NULL);
}
v3d_perfmon_open_file(v3d_priv);
file->driver_priv = v3d_priv;
return 0;
@ -136,6 +140,7 @@ v3d_postclose(struct drm_device *dev, struct drm_file *file)
drm_sched_entity_destroy(&v3d_priv->sched_entity[q]);
}
v3d_perfmon_close_file(v3d_priv);
kfree(v3d_priv);
}
@ -156,6 +161,9 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(V3D_GET_BO_OFFSET, v3d_get_bo_offset_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(V3D_SUBMIT_TFU, v3d_submit_tfu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CSD, v3d_submit_csd_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
DRM_IOCTL_DEF_DRV(V3D_PERFMON_CREATE, v3d_perfmon_create_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(V3D_PERFMON_DESTROY, v3d_perfmon_destroy_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_VALUES, v3d_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
};
static const struct drm_driver v3d_drm_driver = {

View File

@ -37,6 +37,40 @@ struct v3d_queue_state {
u64 emit_seqno;
};
/* Performance monitor object. The perform lifetime is controlled by userspace
* using perfmon related ioctls. A perfmon can be attached to a submit_cl
* request, and when this is the case, HW perf counters will be activated just
* before the submit_cl is submitted to the GPU and disabled when the job is
* done. This way, only events related to a specific job will be counted.
*/
struct v3d_perfmon {
/* Tracks the number of users of the perfmon, when this counter reaches
* zero the perfmon is destroyed.
*/
refcount_t refcnt;
/* Protects perfmon stop, as it can be invoked from multiple places. */
struct mutex lock;
/* Number of counters activated in this perfmon instance
* (should be less than DRM_V3D_MAX_PERF_COUNTERS).
*/
u8 ncounters;
/* Events counted by the HW perf counters. */
u8 counters[DRM_V3D_MAX_PERF_COUNTERS];
/* Storage for counter values. Counters are incremented by the
* HW perf counter values every time the perfmon is attached
* to a GPU job. This way, perfmon users don't have to
* retrieve the results after each job if they want to track
* events covering several submissions. Note that counter
* values can't be reset, but you can fake a reset by
* destroying the perfmon and creating a new one.
*/
u64 values[];
};
struct v3d_dev {
struct drm_device drm;
@ -89,6 +123,9 @@ struct v3d_dev {
*/
spinlock_t job_lock;
/* Used to track the active perfmon if any. */
struct v3d_perfmon *active_perfmon;
/* Protects bo_stats */
struct mutex bo_lock;
@ -133,6 +170,11 @@ v3d_has_csd(struct v3d_dev *v3d)
struct v3d_file_priv {
struct v3d_dev *v3d;
struct {
struct idr idr;
struct mutex lock;
} perfmon;
struct drm_sched_entity sched_entity[V3D_MAX_QUEUES];
};
@ -205,6 +247,11 @@ struct v3d_job {
*/
struct dma_fence *done_fence;
/* Pointer to a performance monitor object if the user requested it,
* NULL otherwise.
*/
struct v3d_perfmon *perfmon;
/* Callback for the freeing of the job on refcount going to 0. */
void (*free)(struct kref *ref);
};
@ -353,3 +400,19 @@ void v3d_mmu_remove_ptes(struct v3d_bo *bo);
/* v3d_sched.c */
int v3d_sched_init(struct v3d_dev *v3d);
void v3d_sched_fini(struct v3d_dev *v3d);
/* v3d_perfmon.c */
void v3d_perfmon_get(struct v3d_perfmon *perfmon);
void v3d_perfmon_put(struct v3d_perfmon *perfmon);
void v3d_perfmon_start(struct v3d_dev *v3d, struct v3d_perfmon *perfmon);
void v3d_perfmon_stop(struct v3d_dev *v3d, struct v3d_perfmon *perfmon,
bool capture);
struct v3d_perfmon *v3d_perfmon_find(struct v3d_file_priv *v3d_priv, int id);
void v3d_perfmon_open_file(struct v3d_file_priv *v3d_priv);
void v3d_perfmon_close_file(struct v3d_file_priv *v3d_priv);
int v3d_perfmon_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int v3d_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int v3d_perfmon_get_values_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);

View File

@ -126,6 +126,8 @@ v3d_reset(struct v3d_dev *v3d)
v3d_mmu_set_page_table(v3d);
v3d_irq_reset(v3d);
v3d_perfmon_stop(v3d, v3d->active_perfmon, false);
trace_v3d_reset_end(dev);
}
@ -375,6 +377,9 @@ v3d_job_free(struct kref *ref)
pm_runtime_mark_last_busy(job->v3d->drm.dev);
pm_runtime_put_autosuspend(job->v3d->drm.dev);
if (job->perfmon)
v3d_perfmon_put(job->perfmon);
kfree(job);
}
@ -539,6 +544,9 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
trace_v3d_submit_cl_ioctl(&v3d->drm, args->rcl_start, args->rcl_end);
if (args->pad != 0)
return -EINVAL;
if (args->flags != 0 &&
args->flags != DRM_V3D_SUBMIT_CL_FLUSH_CACHE) {
DRM_INFO("invalid flags: %d\n", args->flags);
@ -611,8 +619,20 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
if (ret)
goto fail;
if (args->perfmon_id) {
render->base.perfmon = v3d_perfmon_find(v3d_priv,
args->perfmon_id);
if (!render->base.perfmon) {
ret = -ENOENT;
goto fail;
}
}
mutex_lock(&v3d->sched_lock);
if (bin) {
bin->base.perfmon = render->base.perfmon;
v3d_perfmon_get(bin->base.perfmon);
ret = v3d_push_job(v3d_priv, &bin->base, V3D_BIN);
if (ret)
goto fail_unreserve;
@ -633,6 +653,8 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
ret = drm_gem_fence_array_add(&clean_job->deps, render_fence);
if (ret)
goto fail_unreserve;
clean_job->perfmon = render->base.perfmon;
v3d_perfmon_get(clean_job->perfmon);
ret = v3d_push_job(v3d_priv, clean_job, V3D_CACHE_CLEAN);
if (ret)
goto fail_unreserve;
@ -827,6 +849,15 @@ v3d_submit_csd_ioctl(struct drm_device *dev, void *data,
if (ret)
goto fail;
if (args->perfmon_id) {
job->base.perfmon = v3d_perfmon_find(v3d_priv,
args->perfmon_id);
if (!job->base.perfmon) {
ret = -ENOENT;
goto fail;
}
}
mutex_lock(&v3d->sched_lock);
ret = v3d_push_job(v3d_priv, &job->base, V3D_CSD);
if (ret)

View File

@ -0,0 +1,213 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Raspberry Pi
*/
#include "v3d_drv.h"
#include "v3d_regs.h"
#define V3D_PERFMONID_MIN 1
#define V3D_PERFMONID_MAX U32_MAX
void v3d_perfmon_get(struct v3d_perfmon *perfmon)
{
if (perfmon)
refcount_inc(&perfmon->refcnt);
}
void v3d_perfmon_put(struct v3d_perfmon *perfmon)
{
if (perfmon && refcount_dec_and_test(&perfmon->refcnt))
kfree(perfmon);
}
void v3d_perfmon_start(struct v3d_dev *v3d, struct v3d_perfmon *perfmon)
{
unsigned int i;
u32 mask;
u8 ncounters = perfmon->ncounters;
if (WARN_ON_ONCE(!perfmon || v3d->active_perfmon))
return;
mask = GENMASK(ncounters - 1, 0);
for (i = 0; i < ncounters; i++) {
u32 source = i / 4;
u32 channel = V3D_SET_FIELD(perfmon->counters[i], V3D_PCTR_S0);
i++;
channel |= V3D_SET_FIELD(i < ncounters ? perfmon->counters[i] : 0,
V3D_PCTR_S1);
i++;
channel |= V3D_SET_FIELD(i < ncounters ? perfmon->counters[i] : 0,
V3D_PCTR_S2);
i++;
channel |= V3D_SET_FIELD(i < ncounters ? perfmon->counters[i] : 0,
V3D_PCTR_S3);
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_SRC_X(source), channel);
}
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_CLR, mask);
V3D_CORE_WRITE(0, V3D_PCTR_0_OVERFLOW, mask);
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, mask);
v3d->active_perfmon = perfmon;
}
void v3d_perfmon_stop(struct v3d_dev *v3d, struct v3d_perfmon *perfmon,
bool capture)
{
unsigned int i;
if (!perfmon || !v3d->active_perfmon)
return;
mutex_lock(&perfmon->lock);
if (perfmon != v3d->active_perfmon) {
mutex_unlock(&perfmon->lock);
return;
}
if (capture)
for (i = 0; i < perfmon->ncounters; i++)
perfmon->values[i] += V3D_CORE_READ(0, V3D_PCTR_0_PCTRX(i));
V3D_CORE_WRITE(0, V3D_V4_PCTR_0_EN, 0);
v3d->active_perfmon = NULL;
mutex_unlock(&perfmon->lock);
}
struct v3d_perfmon *v3d_perfmon_find(struct v3d_file_priv *v3d_priv, int id)
{
struct v3d_perfmon *perfmon;
mutex_lock(&v3d_priv->perfmon.lock);
perfmon = idr_find(&v3d_priv->perfmon.idr, id);
v3d_perfmon_get(perfmon);
mutex_unlock(&v3d_priv->perfmon.lock);
return perfmon;
}
void v3d_perfmon_open_file(struct v3d_file_priv *v3d_priv)
{
mutex_init(&v3d_priv->perfmon.lock);
idr_init(&v3d_priv->perfmon.idr);
}
static int v3d_perfmon_idr_del(int id, void *elem, void *data)
{
struct v3d_perfmon *perfmon = elem;
v3d_perfmon_put(perfmon);
return 0;
}
void v3d_perfmon_close_file(struct v3d_file_priv *v3d_priv)
{
mutex_lock(&v3d_priv->perfmon.lock);
idr_for_each(&v3d_priv->perfmon.idr, v3d_perfmon_idr_del, NULL);
idr_destroy(&v3d_priv->perfmon.idr);
mutex_unlock(&v3d_priv->perfmon.lock);
}
int v3d_perfmon_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
struct drm_v3d_perfmon_create *req = data;
struct v3d_perfmon *perfmon;
unsigned int i;
int ret;
/* Number of monitored counters cannot exceed HW limits. */
if (req->ncounters > DRM_V3D_MAX_PERF_COUNTERS ||
!req->ncounters)
return -EINVAL;
/* Make sure all counters are valid. */
for (i = 0; i < req->ncounters; i++) {
if (req->counters[i] >= V3D_PERFCNT_NUM)
return -EINVAL;
}
perfmon = kzalloc(struct_size(perfmon, values, req->ncounters),
GFP_KERNEL);
if (!perfmon)
return -ENOMEM;
for (i = 0; i < req->ncounters; i++)
perfmon->counters[i] = req->counters[i];
perfmon->ncounters = req->ncounters;
refcount_set(&perfmon->refcnt, 1);
mutex_init(&perfmon->lock);
mutex_lock(&v3d_priv->perfmon.lock);
ret = idr_alloc(&v3d_priv->perfmon.idr, perfmon, V3D_PERFMONID_MIN,
V3D_PERFMONID_MAX, GFP_KERNEL);
mutex_unlock(&v3d_priv->perfmon.lock);
if (ret < 0) {
kfree(perfmon);
return ret;
}
req->id = ret;
return 0;
}
int v3d_perfmon_destroy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
struct drm_v3d_perfmon_destroy *req = data;
struct v3d_perfmon *perfmon;
mutex_lock(&v3d_priv->perfmon.lock);
perfmon = idr_remove(&v3d_priv->perfmon.idr, req->id);
mutex_unlock(&v3d_priv->perfmon.lock);
if (!perfmon)
return -EINVAL;
v3d_perfmon_put(perfmon);
return 0;
}
int v3d_perfmon_get_values_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct v3d_dev *v3d = to_v3d_dev(dev);
struct v3d_file_priv *v3d_priv = file_priv->driver_priv;
struct drm_v3d_perfmon_get_values *req = data;
struct v3d_perfmon *perfmon;
int ret = 0;
if (req->pad != 0)
return -EINVAL;
mutex_lock(&v3d_priv->perfmon.lock);
perfmon = idr_find(&v3d_priv->perfmon.idr, req->id);
v3d_perfmon_get(perfmon);
mutex_unlock(&v3d_priv->perfmon.lock);
if (!perfmon)
return -EINVAL;
v3d_perfmon_stop(v3d, perfmon, true);
if (copy_to_user(u64_to_user_ptr(req->values_ptr), perfmon->values,
perfmon->ncounters * sizeof(u64)))
ret = -EFAULT;
v3d_perfmon_put(perfmon);
return ret;
}

View File

@ -347,6 +347,8 @@
/* Each src reg muxes four counters each. */
#define V3D_V4_PCTR_0_SRC_0_3 0x00660
#define V3D_V4_PCTR_0_SRC_28_31 0x0067c
#define V3D_V4_PCTR_0_SRC_X(x) (V3D_V4_PCTR_0_SRC_0_3 + \
4 * (x))
# define V3D_PCTR_S0_MASK V3D_MASK(6, 0)
# define V3D_PCTR_S0_SHIFT 0
# define V3D_PCTR_S1_MASK V3D_MASK(14, 8)

View File

@ -63,6 +63,16 @@ v3d_job_free(struct drm_sched_job *sched_job)
v3d_job_put(job);
}
static void
v3d_switch_perfmon(struct v3d_dev *v3d, struct v3d_job *job)
{
if (job->perfmon != v3d->active_perfmon)
v3d_perfmon_stop(v3d, v3d->active_perfmon, true);
if (job->perfmon && v3d->active_perfmon != job->perfmon)
v3d_perfmon_start(v3d, job->perfmon);
}
/*
* Returns the fences that the job depends on, one by one.
*
@ -120,6 +130,8 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno,
job->start, job->end);
v3d_switch_perfmon(v3d, &job->base);
/* Set the current and end address of the control list.
* Writing the end register is what starts the job.
*/
@ -169,6 +181,8 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno,
job->start, job->end);
v3d_switch_perfmon(v3d, &job->base);
/* XXX: Set the QCFG */
/* Set the current and end address of the control list.
@ -240,6 +254,8 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno);
v3d_switch_perfmon(v3d, &job->base);
for (i = 1; i <= 6; i++)
V3D_CORE_WRITE(0, V3D_CSD_QUEUED_CFG0 + 4 * i, job->args.cfg[i]);
/* CFG0 write kicks off the job. */

View File

@ -72,10 +72,7 @@ struct vga_device {
unsigned int io_norm_cnt; /* normal IO count */
unsigned int mem_norm_cnt; /* normal MEM count */
bool bridge_has_one_vga;
/* allow IRQ enable/disable hook */
void *cookie;
void (*irq_set_state)(void *cookie, bool enable);
unsigned int (*set_vga_decode)(void *cookie, bool decode);
unsigned int (*set_decode)(struct pci_dev *pdev, bool decode);
};
static LIST_HEAD(vga_list);
@ -218,13 +215,6 @@ int vga_remove_vgacon(struct pci_dev *pdev)
#endif
EXPORT_SYMBOL(vga_remove_vgacon);
static inline void vga_irq_set_state(struct vga_device *vgadev, bool state)
{
if (vgadev->irq_set_state)
vgadev->irq_set_state(vgadev->cookie, state);
}
/* If we don't ever use VGA arb we should avoid
turning off anything anywhere due to old X servers getting
confused about the boot device not being VGA */
@ -284,12 +274,6 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
if (vgadev == conflict)
continue;
/* Check if the architecture allows a conflict between those
* 2 devices or if they are on separate domains
*/
if (!vga_conflicts(vgadev->pdev, conflict->pdev))
continue;
/* We have a possible conflict. before we go further, we must
* check if we sit on the same bus as the conflicting device.
* if we don't, then we must tie both IO and MEM resources
@ -331,10 +315,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
if ((match & conflict->decodes) & VGA_RSRC_LEGACY_IO)
pci_bits |= PCI_COMMAND_IO;
if (pci_bits) {
vga_irq_set_state(conflict, false);
if (pci_bits)
flags |= PCI_VGA_STATE_CHANGE_DECODES;
}
}
if (change_bridge)
@ -371,9 +353,6 @@ enable_them:
pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
if (!vgadev->bridge_has_one_vga)
vga_irq_set_state(vgadev, true);
vgadev->owns |= wants;
lock_them:
vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
@ -826,7 +805,7 @@ static void __vga_set_legacy_decoding(struct pci_dev *pdev,
goto bail;
/* don't let userspace futz with kernel driver decodes */
if (userspace && vgadev->set_vga_decode)
if (userspace && vgadev->set_decode)
goto bail;
/* update the device decodes + counter */
@ -840,6 +819,17 @@ bail:
spin_unlock_irqrestore(&vga_lock, flags);
}
/**
* vga_set_legacy_decoding
* @pdev: pci device of the VGA card
* @decodes: bit mask of what legacy regions the card decodes
*
* Indicates to the arbiter if the card decodes legacy VGA IOs, legacy VGA
* Memory, both, or none. All cards default to both, the card driver (fbdev for
* example) should tell the arbiter if it has disabled legacy decoding, so the
* card can be left out of the arbitration process (and can be safe to take
* interrupts at any time.
*/
void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes)
{
__vga_set_legacy_decoding(pdev, decodes, false);
@ -849,17 +839,11 @@ EXPORT_SYMBOL(vga_set_legacy_decoding);
/**
* vga_client_register - register or unregister a VGA arbitration client
* @pdev: pci device of the VGA client
* @cookie: client cookie to be used in callbacks
* @irq_set_state: irq state change callback
* @set_vga_decode: vga decode change callback
* @set_decode: vga decode change callback
*
* Clients have two callback mechanisms they can use.
*
* @irq_set_state callback: If a client can't disable its GPUs VGA
* resources, then we need to be able to ask it to turn off its irqs when we
* turn off its mem and io decoding.
*
* @set_vga_decode callback: If a client can disable its GPU VGA resource, it
* @set_decode callback: If a client can disable its GPU VGA resource, it
* will get a callback from this to set the encode/decode state.
*
* Rationale: we cannot disable VGA decode resources unconditionally some single
@ -872,15 +856,12 @@ EXPORT_SYMBOL(vga_set_legacy_decoding);
* This function does not check whether a client for @pdev has been registered
* already.
*
* To unregister just call this function with @irq_set_state and @set_vga_decode
* both set to NULL for the same @pdev as originally used to register them.
* To unregister just call vga_client_unregister().
*
* Returns: 0 on success, -1 on failure
*/
int vga_client_register(struct pci_dev *pdev, void *cookie,
void (*irq_set_state)(void *cookie, bool state),
unsigned int (*set_vga_decode)(void *cookie,
bool decode))
int vga_client_register(struct pci_dev *pdev,
unsigned int (*set_decode)(struct pci_dev *pdev, bool decode))
{
int ret = -ENODEV;
struct vga_device *vgadev;
@ -891,9 +872,7 @@ int vga_client_register(struct pci_dev *pdev, void *cookie,
if (!vgadev)
goto bail;
vgadev->irq_set_state = irq_set_state;
vgadev->set_vga_decode = set_vga_decode;
vgadev->cookie = cookie;
vgadev->set_decode = set_decode;
ret = 0;
bail:
@ -1403,9 +1382,9 @@ static void vga_arbiter_notify_clients(void)
new_state = false;
else
new_state = true;
if (vgadev->set_vga_decode) {
new_decodes = vgadev->set_vga_decode(vgadev->cookie,
new_state);
if (vgadev->set_decode) {
new_decodes = vgadev->set_decode(vgadev->pdev,
new_state);
vga_update_device_decodes(vgadev, new_decodes);
}
}

View File

@ -119,10 +119,9 @@ static bool vfio_pci_is_denylisted(struct pci_dev *pdev)
* has no way to get to it and routing can be disabled externally at the
* bridge.
*/
static unsigned int vfio_pci_set_vga_decode(void *opaque, bool single_vga)
static unsigned int vfio_pci_set_decode(struct pci_dev *pdev, bool single_vga)
{
struct vfio_pci_device *vdev = opaque;
struct pci_dev *tmp = NULL, *pdev = vdev->pdev;
struct pci_dev *tmp = NULL;
unsigned char max_busnr;
unsigned int decodes;
@ -1954,10 +1953,10 @@ static int vfio_pci_vga_init(struct vfio_pci_device *vdev)
if (!vfio_pci_is_vga(pdev))
return 0;
ret = vga_client_register(pdev, vdev, NULL, vfio_pci_set_vga_decode);
ret = vga_client_register(pdev, vfio_pci_set_decode);
if (ret)
return ret;
vga_set_legacy_decoding(pdev, vfio_pci_set_vga_decode(vdev, false));
vga_set_legacy_decoding(pdev, vfio_pci_set_decode(pdev, false));
return 0;
}
@ -1967,7 +1966,7 @@ static void vfio_pci_vga_uninit(struct vfio_pci_device *vdev)
if (!vfio_pci_is_vga(pdev))
return;
vga_client_register(pdev, NULL, NULL, NULL);
vga_client_unregister(pdev);
vga_set_legacy_decoding(pdev, VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM |
VGA_RSRC_LEGACY_IO |
VGA_RSRC_LEGACY_MEM);

View File

@ -446,7 +446,7 @@ static ssize_t arcfb_write(struct fb_info *info, const char __user *buf,
/* modded from epson 1355 */
unsigned long p;
int err=-EINVAL;
int err;
unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount;
struct arcfb_par *par;
unsigned int xres;

View File

@ -67,7 +67,7 @@ static struct fb_info *get_fb_info(unsigned int idx)
mutex_lock(&registration_lock);
fb_info = registered_fb[idx];
if (fb_info)
atomic_inc(&fb_info->count);
refcount_inc(&fb_info->count);
mutex_unlock(&registration_lock);
return fb_info;
@ -75,7 +75,7 @@ static struct fb_info *get_fb_info(unsigned int idx)
static void put_fb_info(struct fb_info *fb_info)
{
if (!atomic_dec_and_test(&fb_info->count))
if (!refcount_dec_and_test(&fb_info->count))
return;
if (fb_info->fbops->fb_destroy)
fb_info->fbops->fb_destroy(fb_info);
@ -1592,7 +1592,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
if (!registered_fb[i])
break;
fb_info->node = i;
atomic_set(&fb_info->count, 1);
refcount_set(&fb_info->count, 1);
mutex_init(&fb_info->lock);
mutex_init(&fb_info->mm_lock);

View File

@ -372,6 +372,11 @@ static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight
/* probably haven't called CreateOverlay yet */
return -EINVAL;
if (ulWidth == 0 || ulWidth == 0xffffffff ||
ulHeight == 0 || ulHeight == 0xffffffff ||
(x < 2 && ulWidth + 2 == 0))
return -EINVAL;
/* Stop Ramdac Output */
DisableRamdacOutput(deviceInfo.pSTGReg);

View File

@ -585,7 +585,7 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
DBG("neofb_check_var");
if (PICOS2KHZ(var->pixclock) > par->maxClock)
if (var->pixclock && PICOS2KHZ(var->pixclock) > par->maxClock)
return -EINVAL;
/* Is the mode larger than the LCD panel? */

View File

@ -107,6 +107,7 @@ struct drm_master {
};
struct drm_master *drm_master_get(struct drm_master *master);
struct drm_master *drm_file_get_master(struct drm_file *file_priv);
void drm_master_put(struct drm_master **master);
bool drm_is_current_master(struct drm_file *fpriv);

View File

@ -226,15 +226,27 @@ struct drm_file {
/**
* @master:
*
* Master this node is currently associated with. Only relevant if
* drm_is_primary_client() returns true. Note that this only
* matches &drm_device.master if the master is the currently active one.
* Master this node is currently associated with. Protected by struct
* &drm_device.master_mutex, and serialized by @master_lookup_lock.
*
* Only relevant if drm_is_primary_client() returns true. Note that
* this only matches &drm_device.master if the master is the currently
* active one.
*
* When dereferencing this pointer, either hold struct
* &drm_device.master_mutex for the duration of the pointer's use, or
* use drm_file_get_master() if struct &drm_device.master_mutex is not
* currently held and there is no other need to hold it. This prevents
* @master from being freed during use.
*
* See also @authentication and @is_master and the :ref:`section on
* primary nodes and authentication <drm_primary_node>`.
*/
struct drm_master *master;
/** @master_lock: Serializes @master. */
spinlock_t master_lookup_lock;
/** @pid: Process that opened this file. */
struct pid *pid;

View File

@ -327,7 +327,7 @@ static inline bool drm_debug_enabled(enum drm_debug_category category)
/*
* struct device based logging
*
* Prefer drm_device based logging over device or prink based logging.
* Prefer drm_device based logging over device or printk based logging.
*/
__printf(3, 4)

View File

@ -444,15 +444,6 @@ struct dma_buf {
struct dma_buf_sysfs_entry {
struct kobject kobj;
struct dma_buf *dmabuf;
/**
* @sysfs_entry.attachment_uid:
*
* This is protected by the dma_resv_lock() on @resv and is
* incremented on each attach.
*/
unsigned int attachment_uid;
struct kset *attach_stats_kset;
} *sysfs_entry;
#endif
};
@ -504,7 +495,6 @@ struct dma_buf_attach_ops {
* @importer_ops: importer operations for this attachment, if provided
* dma_buf_map/unmap_attachment() must be called with the dma_resv lock held.
* @importer_priv: importer specific attachment data.
* @sysfs_entry: For exposing information about this attachment in sysfs.
*
* This structure holds the attachment information between the dma_buf buffer
* and its user device(s). The list contains one attachment struct per device
@ -525,13 +515,6 @@ struct dma_buf_attachment {
const struct dma_buf_attach_ops *importer_ops;
void *importer_priv;
void *priv;
#ifdef CONFIG_DMABUF_SYSFS_STATS
/* for sysfs stats */
struct dma_buf_attach_sysfs_entry {
struct kobject kobj;
unsigned int map_counter;
} *sysfs_entry;
#endif
};
/**

View File

@ -2,6 +2,7 @@
#ifndef _LINUX_FB_H
#define _LINUX_FB_H
#include <linux/refcount.h>
#include <linux/kgdb.h>
#include <uapi/linux/fb.h>
@ -435,7 +436,7 @@ struct fb_tile_ops {
struct fb_info {
atomic_t count;
refcount_t count;
int node;
int flags;
/*

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _ARCH_X86_KERNEL_SYSFB_H
#define _ARCH_X86_KERNEL_SYSFB_H
#ifndef _LINUX_SYSFB_H
#define _LINUX_SYSFB_H
/*
* Generic System Framebuffers on x86
@ -58,37 +58,37 @@ struct efifb_dmi_info {
#ifdef CONFIG_EFI
extern struct efifb_dmi_info efifb_dmi_list[];
void sysfb_apply_efi_quirks(void);
void sysfb_apply_efi_quirks(struct platform_device *pd);
#else /* CONFIG_EFI */
static inline void sysfb_apply_efi_quirks(void)
static inline void sysfb_apply_efi_quirks(struct platform_device *pd)
{
}
#endif /* CONFIG_EFI */
#ifdef CONFIG_X86_SYSFB
#ifdef CONFIG_SYSFB_SIMPLEFB
bool parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode);
int create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode);
bool sysfb_parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode);
int sysfb_create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode);
#else /* CONFIG_X86_SYSFB */
#else /* CONFIG_SYSFB_SIMPLE */
static inline bool parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode)
static inline bool sysfb_parse_mode(const struct screen_info *si,
struct simplefb_platform_data *mode)
{
return false;
}
static inline int create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode)
static inline int sysfb_create_simplefb(const struct screen_info *si,
const struct simplefb_platform_data *mode)
{
return -EINVAL;
}
#endif /* CONFIG_X86_SYSFB */
#endif /* CONFIG_SYSFB_SIMPLE */
#endif /* _ARCH_X86_KERNEL_SYSFB_H */
#endif /* _LINUX_SYSFB_H */

View File

@ -33,6 +33,8 @@
#include <video/vga.h>
struct pci_dev;
/* Legacy VGA regions */
#define VGA_RSRC_NONE 0x00
#define VGA_RSRC_LEGACY_IO 0x01
@ -42,42 +44,45 @@
#define VGA_RSRC_NORMAL_IO 0x04
#define VGA_RSRC_NORMAL_MEM 0x08
/* Passing that instead of a pci_dev to use the system "default"
* device, that is the one used by vgacon. Archs will probably
* have to provide their own vga_default_device();
*/
#define VGA_DEFAULT_DEVICE (NULL)
struct pci_dev;
/* For use by clients */
/**
* vga_set_legacy_decoding
*
* @pdev: pci device of the VGA card
* @decodes: bit mask of what legacy regions the card decodes
*
* Indicates to the arbiter if the card decodes legacy VGA IOs,
* legacy VGA Memory, both, or none. All cards default to both,
* the card driver (fbdev for example) should tell the arbiter
* if it has disabled legacy decoding, so the card can be left
* out of the arbitration process (and can be safe to take
* interrupts at any time.
*/
#if defined(CONFIG_VGA_ARB)
extern void vga_set_legacy_decoding(struct pci_dev *pdev,
unsigned int decodes);
#else
#ifdef CONFIG_VGA_ARB
void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes);
int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible);
void vga_put(struct pci_dev *pdev, unsigned int rsrc);
struct pci_dev *vga_default_device(void);
void vga_set_default_device(struct pci_dev *pdev);
int vga_remove_vgacon(struct pci_dev *pdev);
int vga_client_register(struct pci_dev *pdev,
unsigned int (*set_decode)(struct pci_dev *pdev, bool state));
#else /* CONFIG_VGA_ARB */
static inline void vga_set_legacy_decoding(struct pci_dev *pdev,
unsigned int decodes) { };
#endif
#if defined(CONFIG_VGA_ARB)
extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible);
#else
static inline int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) { return 0; }
#endif
unsigned int decodes)
{
};
static inline int vga_get(struct pci_dev *pdev, unsigned int rsrc,
int interruptible)
{
return 0;
}
static inline void vga_put(struct pci_dev *pdev, unsigned int rsrc)
{
}
static inline struct pci_dev *vga_default_device(void)
{
return NULL;
}
static inline void vga_set_default_device(struct pci_dev *pdev)
{
}
static inline int vga_remove_vgacon(struct pci_dev *pdev)
{
return 0;
}
static inline int vga_client_register(struct pci_dev *pdev,
unsigned int (*set_decode)(struct pci_dev *pdev, bool state))
{
return 0;
}
#endif /* CONFIG_VGA_ARB */
/**
* vga_get_interruptible
@ -109,48 +114,9 @@ static inline int vga_get_uninterruptible(struct pci_dev *pdev,
return vga_get(pdev, rsrc, 0);
}
#if defined(CONFIG_VGA_ARB)
extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);
#else
static inline void vga_put(struct pci_dev *pdev, unsigned int rsrc)
static inline void vga_client_unregister(struct pci_dev *pdev)
{
vga_client_register(pdev, NULL);
}
#endif
#ifdef CONFIG_VGA_ARB
extern struct pci_dev *vga_default_device(void);
extern void vga_set_default_device(struct pci_dev *pdev);
extern int vga_remove_vgacon(struct pci_dev *pdev);
#else
static inline struct pci_dev *vga_default_device(void) { return NULL; }
static inline void vga_set_default_device(struct pci_dev *pdev) { }
static inline int vga_remove_vgacon(struct pci_dev *pdev) { return 0; }
#endif
/*
* Architectures should define this if they have several
* independent PCI domains that can afford concurrent VGA
* decoding
*/
#ifndef __ARCH_HAS_VGA_CONFLICT
static inline int vga_conflicts(struct pci_dev *p1, struct pci_dev *p2)
{
return 1;
}
#endif
#if defined(CONFIG_VGA_ARB)
int vga_client_register(struct pci_dev *pdev, void *cookie,
void (*irq_set_state)(void *cookie, bool state),
unsigned int (*set_vga_decode)(void *cookie, bool state));
#else
static inline int vga_client_register(struct pci_dev *pdev, void *cookie,
void (*irq_set_state)(void *cookie, bool state),
unsigned int (*set_vga_decode)(void *cookie, bool state))
{
return 0;
}
#endif
#endif /* LINUX_VGA_H */

View File

@ -38,6 +38,9 @@ extern "C" {
#define DRM_V3D_GET_BO_OFFSET 0x05
#define DRM_V3D_SUBMIT_TFU 0x06
#define DRM_V3D_SUBMIT_CSD 0x07
#define DRM_V3D_PERFMON_CREATE 0x08
#define DRM_V3D_PERFMON_DESTROY 0x09
#define DRM_V3D_PERFMON_GET_VALUES 0x0a
#define DRM_IOCTL_V3D_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CL, struct drm_v3d_submit_cl)
#define DRM_IOCTL_V3D_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_WAIT_BO, struct drm_v3d_wait_bo)
@ -47,6 +50,12 @@ extern "C" {
#define DRM_IOCTL_V3D_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_GET_BO_OFFSET, struct drm_v3d_get_bo_offset)
#define DRM_IOCTL_V3D_SUBMIT_TFU DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_TFU, struct drm_v3d_submit_tfu)
#define DRM_IOCTL_V3D_SUBMIT_CSD DRM_IOW(DRM_COMMAND_BASE + DRM_V3D_SUBMIT_CSD, struct drm_v3d_submit_csd)
#define DRM_IOCTL_V3D_PERFMON_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_PERFMON_CREATE, \
struct drm_v3d_perfmon_create)
#define DRM_IOCTL_V3D_PERFMON_DESTROY DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_PERFMON_DESTROY, \
struct drm_v3d_perfmon_destroy)
#define DRM_IOCTL_V3D_PERFMON_GET_VALUES DRM_IOWR(DRM_COMMAND_BASE + DRM_V3D_PERFMON_GET_VALUES, \
struct drm_v3d_perfmon_get_values)
#define DRM_V3D_SUBMIT_CL_FLUSH_CACHE 0x01
@ -127,6 +136,11 @@ struct drm_v3d_submit_cl {
__u32 bo_handle_count;
__u32 flags;
/* ID of the perfmon to attach to this job. 0 means no perfmon. */
__u32 perfmon_id;
__u32 pad;
};
/**
@ -195,6 +209,7 @@ enum drm_v3d_param {
DRM_V3D_PARAM_SUPPORTS_TFU,
DRM_V3D_PARAM_SUPPORTS_CSD,
DRM_V3D_PARAM_SUPPORTS_CACHE_FLUSH,
DRM_V3D_PARAM_SUPPORTS_PERFMON,
};
struct drm_v3d_get_param {
@ -258,6 +273,127 @@ struct drm_v3d_submit_csd {
__u32 in_sync;
/* Sync object to signal when the CSD job is done. */
__u32 out_sync;
/* ID of the perfmon to attach to this job. 0 means no perfmon. */
__u32 perfmon_id;
};
enum {
V3D_PERFCNT_FEP_VALID_PRIMTS_NO_PIXELS,
V3D_PERFCNT_FEP_VALID_PRIMS,
V3D_PERFCNT_FEP_EZ_NFCLIP_QUADS,
V3D_PERFCNT_FEP_VALID_QUADS,
V3D_PERFCNT_TLB_QUADS_STENCIL_FAIL,
V3D_PERFCNT_TLB_QUADS_STENCILZ_FAIL,
V3D_PERFCNT_TLB_QUADS_STENCILZ_PASS,
V3D_PERFCNT_TLB_QUADS_ZERO_COV,
V3D_PERFCNT_TLB_QUADS_NONZERO_COV,
V3D_PERFCNT_TLB_QUADS_WRITTEN,
V3D_PERFCNT_PTB_PRIM_VIEWPOINT_DISCARD,
V3D_PERFCNT_PTB_PRIM_CLIP,
V3D_PERFCNT_PTB_PRIM_REV,
V3D_PERFCNT_QPU_IDLE_CYCLES,
V3D_PERFCNT_QPU_ACTIVE_CYCLES_VERTEX_COORD_USER,
V3D_PERFCNT_QPU_ACTIVE_CYCLES_FRAG,
V3D_PERFCNT_QPU_CYCLES_VALID_INSTR,
V3D_PERFCNT_QPU_CYCLES_TMU_STALL,
V3D_PERFCNT_QPU_CYCLES_SCOREBOARD_STALL,
V3D_PERFCNT_QPU_CYCLES_VARYINGS_STALL,
V3D_PERFCNT_QPU_IC_HIT,
V3D_PERFCNT_QPU_IC_MISS,
V3D_PERFCNT_QPU_UC_HIT,
V3D_PERFCNT_QPU_UC_MISS,
V3D_PERFCNT_TMU_TCACHE_ACCESS,
V3D_PERFCNT_TMU_TCACHE_MISS,
V3D_PERFCNT_VPM_VDW_STALL,
V3D_PERFCNT_VPM_VCD_STALL,
V3D_PERFCNT_BIN_ACTIVE,
V3D_PERFCNT_RDR_ACTIVE,
V3D_PERFCNT_L2T_HITS,
V3D_PERFCNT_L2T_MISSES,
V3D_PERFCNT_CYCLE_COUNT,
V3D_PERFCNT_QPU_CYCLES_STALLED_VERTEX_COORD_USER,
V3D_PERFCNT_QPU_CYCLES_STALLED_FRAGMENT,
V3D_PERFCNT_PTB_PRIMS_BINNED,
V3D_PERFCNT_AXI_WRITES_WATCH_0,
V3D_PERFCNT_AXI_READS_WATCH_0,
V3D_PERFCNT_AXI_WRITE_STALLS_WATCH_0,
V3D_PERFCNT_AXI_READ_STALLS_WATCH_0,
V3D_PERFCNT_AXI_WRITE_BYTES_WATCH_0,
V3D_PERFCNT_AXI_READ_BYTES_WATCH_0,
V3D_PERFCNT_AXI_WRITES_WATCH_1,
V3D_PERFCNT_AXI_READS_WATCH_1,
V3D_PERFCNT_AXI_WRITE_STALLS_WATCH_1,
V3D_PERFCNT_AXI_READ_STALLS_WATCH_1,
V3D_PERFCNT_AXI_WRITE_BYTES_WATCH_1,
V3D_PERFCNT_AXI_READ_BYTES_WATCH_1,
V3D_PERFCNT_TLB_PARTIAL_QUADS,
V3D_PERFCNT_TMU_CONFIG_ACCESSES,
V3D_PERFCNT_L2T_NO_ID_STALL,
V3D_PERFCNT_L2T_COM_QUE_STALL,
V3D_PERFCNT_L2T_TMU_WRITES,
V3D_PERFCNT_TMU_ACTIVE_CYCLES,
V3D_PERFCNT_TMU_STALLED_CYCLES,
V3D_PERFCNT_CLE_ACTIVE,
V3D_PERFCNT_L2T_TMU_READS,
V3D_PERFCNT_L2T_CLE_READS,
V3D_PERFCNT_L2T_VCD_READS,
V3D_PERFCNT_L2T_TMUCFG_READS,
V3D_PERFCNT_L2T_SLC0_READS,
V3D_PERFCNT_L2T_SLC1_READS,
V3D_PERFCNT_L2T_SLC2_READS,
V3D_PERFCNT_L2T_TMU_W_MISSES,
V3D_PERFCNT_L2T_TMU_R_MISSES,
V3D_PERFCNT_L2T_CLE_MISSES,
V3D_PERFCNT_L2T_VCD_MISSES,
V3D_PERFCNT_L2T_TMUCFG_MISSES,
V3D_PERFCNT_L2T_SLC0_MISSES,
V3D_PERFCNT_L2T_SLC1_MISSES,
V3D_PERFCNT_L2T_SLC2_MISSES,
V3D_PERFCNT_CORE_MEM_WRITES,
V3D_PERFCNT_L2T_MEM_WRITES,
V3D_PERFCNT_PTB_MEM_WRITES,
V3D_PERFCNT_TLB_MEM_WRITES,
V3D_PERFCNT_CORE_MEM_READS,
V3D_PERFCNT_L2T_MEM_READS,
V3D_PERFCNT_PTB_MEM_READS,
V3D_PERFCNT_PSE_MEM_READS,
V3D_PERFCNT_TLB_MEM_READS,
V3D_PERFCNT_GMP_MEM_READS,
V3D_PERFCNT_PTB_W_MEM_WORDS,
V3D_PERFCNT_TLB_W_MEM_WORDS,
V3D_PERFCNT_PSE_R_MEM_WORDS,
V3D_PERFCNT_TLB_R_MEM_WORDS,
V3D_PERFCNT_TMU_MRU_HITS,
V3D_PERFCNT_COMPUTE_ACTIVE,
V3D_PERFCNT_NUM,
};
#define DRM_V3D_MAX_PERF_COUNTERS 32
struct drm_v3d_perfmon_create {
__u32 id;
__u32 ncounters;
__u8 counters[DRM_V3D_MAX_PERF_COUNTERS];
};
struct drm_v3d_perfmon_destroy {
__u32 id;
};
/*
* Returns the values of the performance counters tracked by this
* perfmon (as an array of ncounters u64 values).
*
* No implicit synchronization is performed, so the user has to
* guarantee that any jobs using this perfmon have already been
* completed (probably by blocking on the seqno returned by the
* last exec that used the perfmon).
*/
struct drm_v3d_perfmon_get_values {
__u32 id;
__u32 pad;
__u64 values_ptr;
};
#if defined(__cplusplus)