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:
commit
8da49a33dd
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -67,7 +67,7 @@ static struct fb_info *get_fb_info(unsigned int idx)
|
|||
mutex_lock(®istration_lock);
|
||||
fb_info = registered_fb[idx];
|
||||
if (fb_info)
|
||||
atomic_inc(&fb_info->count);
|
||||
refcount_inc(&fb_info->count);
|
||||
mutex_unlock(®istration_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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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? */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
/*
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue