Merge drm/drm-next into drm-intel-next
Sync with drm-xe-next so we can continue with display clean-up. Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/display/panel/boe,tv101wum-ll2.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: BOE TV101WUM-LL2 DSI Display Panel
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <neil.armstrong@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: panel-common.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: boe,tv101wum-ll2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
description: DSI virtual channel
|
||||
|
||||
backlight: true
|
||||
reset-gpios: true
|
||||
vsp-supply: true
|
||||
vsn-supply: true
|
||||
port: true
|
||||
rotation: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reset-gpios
|
||||
- vsp-supply
|
||||
- vsn-supply
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
dsi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
panel@0 {
|
||||
compatible = "boe,tv101wum-ll2";
|
||||
reg = <0>;
|
||||
|
||||
vsn-supply = <&vsn_lcd>;
|
||||
vsp-supply = <&vsp_lcd>;
|
||||
|
||||
reset-gpios = <&pio 45 GPIO_ACTIVE_LOW>;
|
||||
|
||||
port {
|
||||
panel_in: endpoint {
|
||||
remote-endpoint = <&dsi_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -18,6 +18,7 @@ properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- renesas,r9a07g043u-du # RZ/G2UL
|
||||
- renesas,r9a07g044-du # RZ/G2{L,LC}
|
||||
- items:
|
||||
- enum:
|
||||
@@ -60,9 +61,6 @@ properties:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- port@0
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
renesas,vsps:
|
||||
@@ -88,6 +86,34 @@ required:
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r9a07g043u-du
|
||||
then:
|
||||
properties:
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DPI
|
||||
|
||||
required:
|
||||
- port@0
|
||||
else:
|
||||
properties:
|
||||
ports:
|
||||
properties:
|
||||
port@0:
|
||||
description: DSI
|
||||
port@1:
|
||||
description: DPI
|
||||
|
||||
required:
|
||||
- port@0
|
||||
- port@1
|
||||
|
||||
examples:
|
||||
# RZ/G2L DU
|
||||
- |
|
||||
|
||||
@@ -7,6 +7,21 @@ Memory Management
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/xe_bo_doc.h
|
||||
:doc: Buffer Objects (BO)
|
||||
|
||||
GGTT
|
||||
====
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/xe_ggtt.c
|
||||
:doc: Global Graphics Translation Table (GGTT)
|
||||
|
||||
GGTT Internal API
|
||||
-----------------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/xe_ggtt_types.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/xe/xe_ggtt.c
|
||||
:internal:
|
||||
|
||||
Pagetable building
|
||||
==================
|
||||
|
||||
|
||||
@@ -7343,10 +7343,10 @@ F: drivers/gpu/drm/udl/
|
||||
|
||||
DRM DRIVER FOR VIRTUAL KERNEL MODESETTING (VKMS)
|
||||
M: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
|
||||
M: Melissa Wen <melissa.srw@gmail.com>
|
||||
M: Maíra Canal <mairacanal@riseup.net>
|
||||
R: Haneen Mohammed <hamohammed.sa@gmail.com>
|
||||
R: Daniel Vetter <daniel@ffwll.ch>
|
||||
R: Melissa Wen <melissa.srw@gmail.com>
|
||||
L: dri-devel@lists.freedesktop.org
|
||||
S: Maintained
|
||||
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
#include <drm/drm_accel.h>
|
||||
#include <drm/drm_auth.h>
|
||||
@@ -18,8 +18,7 @@
|
||||
#include <drm/drm_ioctl.h>
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
static DEFINE_SPINLOCK(accel_minor_lock);
|
||||
static struct idr accel_minors_idr;
|
||||
DEFINE_XARRAY_ALLOC(accel_minors_xa);
|
||||
|
||||
static struct dentry *accel_debugfs_root;
|
||||
|
||||
@@ -117,99 +116,6 @@ void accel_set_device_instance_params(struct device *kdev, int index)
|
||||
kdev->type = &accel_sysfs_device_minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_minor_alloc() - Allocates a new accel minor
|
||||
*
|
||||
* This function access the accel minors idr and allocates from it
|
||||
* a new id to represent a new accel minor
|
||||
*
|
||||
* Return: A new id on success or error code in case idr_alloc failed
|
||||
*/
|
||||
int accel_minor_alloc(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
spin_lock_irqsave(&accel_minor_lock, flags);
|
||||
r = idr_alloc(&accel_minors_idr, NULL, 0, ACCEL_MAX_MINORS, GFP_NOWAIT);
|
||||
spin_unlock_irqrestore(&accel_minor_lock, flags);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_minor_remove() - Remove an accel minor
|
||||
* @index: The minor id to remove.
|
||||
*
|
||||
* This function access the accel minors idr and removes from
|
||||
* it the member with the id that is passed to this function.
|
||||
*/
|
||||
void accel_minor_remove(int index)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&accel_minor_lock, flags);
|
||||
idr_remove(&accel_minors_idr, index);
|
||||
spin_unlock_irqrestore(&accel_minor_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_minor_replace() - Replace minor pointer in accel minors idr.
|
||||
* @minor: Pointer to the new minor.
|
||||
* @index: The minor id to replace.
|
||||
*
|
||||
* This function access the accel minors idr structure and replaces the pointer
|
||||
* that is associated with an existing id. Because the minor pointer can be
|
||||
* NULL, we need to explicitly pass the index.
|
||||
*
|
||||
* Return: 0 for success, negative value for error
|
||||
*/
|
||||
void accel_minor_replace(struct drm_minor *minor, int index)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&accel_minor_lock, flags);
|
||||
idr_replace(&accel_minors_idr, minor, index);
|
||||
spin_unlock_irqrestore(&accel_minor_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up the given minor-ID and returns the respective DRM-minor object. The
|
||||
* refence-count of the underlying device is increased so you must release this
|
||||
* object with accel_minor_release().
|
||||
*
|
||||
* The object can be only a drm_minor that represents an accel device.
|
||||
*
|
||||
* As long as you hold this minor, it is guaranteed that the object and the
|
||||
* minor->dev pointer will stay valid! However, the device may get unplugged and
|
||||
* unregistered while you hold the minor.
|
||||
*/
|
||||
static struct drm_minor *accel_minor_acquire(unsigned int minor_id)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&accel_minor_lock, flags);
|
||||
minor = idr_find(&accel_minors_idr, minor_id);
|
||||
if (minor)
|
||||
drm_dev_get(minor->dev);
|
||||
spin_unlock_irqrestore(&accel_minor_lock, flags);
|
||||
|
||||
if (!minor) {
|
||||
return ERR_PTR(-ENODEV);
|
||||
} else if (drm_dev_is_unplugged(minor->dev)) {
|
||||
drm_dev_put(minor->dev);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
return minor;
|
||||
}
|
||||
|
||||
static void accel_minor_release(struct drm_minor *minor)
|
||||
{
|
||||
drm_dev_put(minor->dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* accel_open - open method for ACCEL file
|
||||
* @inode: device inode
|
||||
@@ -227,7 +133,7 @@ int accel_open(struct inode *inode, struct file *filp)
|
||||
struct drm_minor *minor;
|
||||
int retcode;
|
||||
|
||||
minor = accel_minor_acquire(iminor(inode));
|
||||
minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
@@ -246,7 +152,7 @@ int accel_open(struct inode *inode, struct file *filp)
|
||||
|
||||
err_undo:
|
||||
atomic_dec(&dev->open_count);
|
||||
accel_minor_release(minor);
|
||||
drm_minor_release(minor);
|
||||
return retcode;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(accel_open);
|
||||
@@ -257,7 +163,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp)
|
||||
struct drm_minor *minor;
|
||||
int err;
|
||||
|
||||
minor = accel_minor_acquire(iminor(inode));
|
||||
minor = drm_minor_acquire(&accel_minors_xa, iminor(inode));
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
@@ -274,7 +180,7 @@ static int accel_stub_open(struct inode *inode, struct file *filp)
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
accel_minor_release(minor);
|
||||
drm_minor_release(minor);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -290,15 +196,13 @@ void accel_core_exit(void)
|
||||
unregister_chrdev(ACCEL_MAJOR, "accel");
|
||||
debugfs_remove(accel_debugfs_root);
|
||||
accel_sysfs_destroy();
|
||||
idr_destroy(&accel_minors_idr);
|
||||
WARN_ON(!xa_empty(&accel_minors_xa));
|
||||
}
|
||||
|
||||
int __init accel_core_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
idr_init(&accel_minors_idr);
|
||||
|
||||
ret = accel_sysfs_init();
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("Cannot create ACCEL class: %d\n", ret);
|
||||
|
||||
@@ -149,6 +149,37 @@ config DRM_PANIC_SCREEN
|
||||
or by writing to /sys/module/drm/parameters/panic_screen sysfs entry
|
||||
Default is "user"
|
||||
|
||||
config DRM_PANIC_SCREEN_QR_CODE
|
||||
bool "Add a panic screen with a QR code"
|
||||
depends on DRM_PANIC && RUST
|
||||
help
|
||||
This option adds a QR code generator, and a panic screen with a QR
|
||||
code. The QR code will contain the last lines of kmsg and other debug
|
||||
information. This should be easier for the user to report a kernel
|
||||
panic, with all debug information available.
|
||||
To use this panic screen, also set DRM_PANIC_SCREEN to "qr_code"
|
||||
|
||||
config DRM_PANIC_SCREEN_QR_CODE_URL
|
||||
string "Base URL of the QR code in the panic screen"
|
||||
depends on DRM_PANIC_SCREEN_QR_CODE
|
||||
help
|
||||
This option sets the base URL to report the kernel panic. If it's set
|
||||
the QR code will contain the URL and the kmsg compressed with zlib as
|
||||
a URL parameter. If it's empty, the QR code will contain the kmsg as
|
||||
uncompressed text only.
|
||||
There is a demo code in javascript, to decode and uncompress the kmsg
|
||||
data from the URL parameter at https://github.com/kdj0c/panic_report
|
||||
|
||||
config DRM_PANIC_SCREEN_QR_VERSION
|
||||
int "Maximum version (size) of the QR code."
|
||||
depends on DRM_PANIC_SCREEN_QR_CODE
|
||||
default 40
|
||||
help
|
||||
This option limits the version (or size) of the QR code. QR code
|
||||
version ranges from Version 1 (21x21) to Version 40 (177x177).
|
||||
Smaller QR code are easier to read, but will contain less debugging
|
||||
data. Default is 40.
|
||||
|
||||
config DRM_DEBUG_DP_MST_TOPOLOGY_REFS
|
||||
bool "Enable refcount backtrace history in the DP MST helpers"
|
||||
depends on STACKTRACE_SUPPORT
|
||||
|
||||
@@ -89,6 +89,7 @@ drm-$(CONFIG_DRM_PRIVACY_SCREEN) += \
|
||||
drm_privacy_screen_x86.o
|
||||
drm-$(CONFIG_DRM_ACCEL) += ../../accel/drm_accel.o
|
||||
drm-$(CONFIG_DRM_PANIC) += drm_panic.o
|
||||
drm-$(CONFIG_DRM_PANIC_SCREEN_QR_CODE) += drm_panic_qr.o
|
||||
obj-$(CONFIG_DRM) += drm.o
|
||||
|
||||
obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o
|
||||
|
||||
@@ -2579,9 +2579,9 @@ static int dm_late_init(void *handle)
|
||||
|
||||
static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
|
||||
{
|
||||
u8 buf[UUID_SIZE];
|
||||
guid_t guid;
|
||||
int ret;
|
||||
u8 guid[16];
|
||||
u64 tmp64;
|
||||
|
||||
mutex_lock(&mgr->lock);
|
||||
if (!mgr->mst_primary)
|
||||
@@ -2602,26 +2602,27 @@ static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr)
|
||||
}
|
||||
|
||||
/* Some hubs forget their guids after they resume */
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16);
|
||||
if (ret != 16) {
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, buf, sizeof(buf));
|
||||
if (ret != sizeof(buf)) {
|
||||
drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n");
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
if (memchr_inv(guid, 0, 16) == NULL) {
|
||||
tmp64 = get_jiffies_64();
|
||||
memcpy(&guid[0], &tmp64, sizeof(u64));
|
||||
memcpy(&guid[8], &tmp64, sizeof(u64));
|
||||
import_guid(&guid, buf);
|
||||
|
||||
ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, guid, 16);
|
||||
if (guid_is_null(&guid)) {
|
||||
guid_gen(&guid);
|
||||
export_guid(buf, &guid);
|
||||
|
||||
if (ret != 16) {
|
||||
ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, buf, sizeof(buf));
|
||||
|
||||
if (ret != sizeof(buf)) {
|
||||
drm_dbg_kms(mgr->dev, "check mstb guid failed - undocked during suspend?\n");
|
||||
goto out_fail;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(mgr->mst_primary->guid, guid, 16);
|
||||
guid_copy(&mgr->mst_primary->guid, &guid);
|
||||
|
||||
out_fail:
|
||||
mutex_unlock(&mgr->lock);
|
||||
@@ -4947,12 +4948,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
|
||||
|
||||
if (psr_feature_enabled)
|
||||
amdgpu_dm_set_psr_caps(link);
|
||||
|
||||
/* TODO: Fix vblank control helpers to delay PSR entry to allow this when
|
||||
* PSR is also supported.
|
||||
*/
|
||||
if (link->psr_settings.psr_feature_enabled)
|
||||
adev_to_drm(adev)->vblank_disable_immediate = false;
|
||||
}
|
||||
}
|
||||
amdgpu_set_panel_orientation(&aconnector->base);
|
||||
@@ -8248,12 +8243,66 @@ static int amdgpu_dm_encoder_init(struct drm_device *dev,
|
||||
|
||||
static void manage_dm_interrupts(struct amdgpu_device *adev,
|
||||
struct amdgpu_crtc *acrtc,
|
||||
bool enable)
|
||||
struct dm_crtc_state *acrtc_state)
|
||||
{
|
||||
if (enable)
|
||||
drm_crtc_vblank_on(&acrtc->base);
|
||||
else
|
||||
/*
|
||||
* We have no guarantee that the frontend index maps to the same
|
||||
* backend index - some even map to more than one.
|
||||
*
|
||||
* TODO: Use a different interrupt or check DC itself for the mapping.
|
||||
*/
|
||||
int irq_type =
|
||||
amdgpu_display_crtc_idx_to_irq_type(
|
||||
adev,
|
||||
acrtc->crtc_id);
|
||||
struct drm_vblank_crtc_config config = {0};
|
||||
struct dc_crtc_timing *timing;
|
||||
int offdelay;
|
||||
|
||||
if (acrtc_state) {
|
||||
if (amdgpu_ip_version(adev, DCE_HWIP, 0) <
|
||||
IP_VERSION(3, 5, 0) ||
|
||||
acrtc_state->stream->link->psr_settings.psr_version <
|
||||
DC_PSR_VERSION_UNSUPPORTED) {
|
||||
timing = &acrtc_state->stream->timing;
|
||||
|
||||
/* at least 2 frames */
|
||||
offdelay = DIV64_U64_ROUND_UP((u64)20 *
|
||||
timing->v_total *
|
||||
timing->h_total,
|
||||
timing->pix_clk_100hz);
|
||||
|
||||
config.offdelay_ms = offdelay ?: 30;
|
||||
} else {
|
||||
config.disable_immediate = true;
|
||||
}
|
||||
|
||||
drm_crtc_vblank_on_config(&acrtc->base,
|
||||
&config);
|
||||
|
||||
amdgpu_irq_get(
|
||||
adev,
|
||||
&adev->pageflip_irq,
|
||||
irq_type);
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
amdgpu_irq_get(
|
||||
adev,
|
||||
&adev->vline0_irq,
|
||||
irq_type);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
|
||||
amdgpu_irq_put(
|
||||
adev,
|
||||
&adev->vline0_irq,
|
||||
irq_type);
|
||||
#endif
|
||||
amdgpu_irq_put(
|
||||
adev,
|
||||
&adev->pageflip_irq,
|
||||
irq_type);
|
||||
drm_crtc_vblank_off(&acrtc->base);
|
||||
}
|
||||
}
|
||||
|
||||
static void dm_update_pflip_irq_state(struct amdgpu_device *adev,
|
||||
@@ -9305,7 +9354,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state,
|
||||
if (old_crtc_state->active &&
|
||||
(!new_crtc_state->active ||
|
||||
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
|
||||
manage_dm_interrupts(adev, acrtc, false);
|
||||
manage_dm_interrupts(adev, acrtc, NULL);
|
||||
dc_stream_release(dm_old_crtc_state->stream);
|
||||
}
|
||||
}
|
||||
@@ -9821,7 +9870,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
|
||||
drm_atomic_crtc_needs_modeset(new_crtc_state))) {
|
||||
dc_stream_retain(dm_new_crtc_state->stream);
|
||||
acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;
|
||||
manage_dm_interrupts(adev, acrtc, true);
|
||||
manage_dm_interrupts(adev, acrtc, dm_new_crtc_state);
|
||||
}
|
||||
/* Handle vrr on->off / off->on transitions */
|
||||
amdgpu_dm_handle_vrr_transition(dm_old_crtc_state, dm_new_crtc_state);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
.lava-test:
|
||||
extends:
|
||||
- .test-rules
|
||||
timeout: "1h30m"
|
||||
script:
|
||||
# Note: Build dir (and thus install) may be dirty due to GIT_STRATEGY
|
||||
- rm -rf install
|
||||
@@ -71,6 +72,7 @@
|
||||
- .baremetal-test-arm64
|
||||
- .use-debian/baremetal_arm64_test
|
||||
- .test-rules
|
||||
timeout: "1h30m"
|
||||
variables:
|
||||
FDO_CI_CONCURRENT: 10
|
||||
HWCI_TEST_SCRIPT: "/install/igt_runner.sh"
|
||||
@@ -215,7 +217,6 @@ panfrost:rk3399:
|
||||
extends:
|
||||
- .lava-igt:x86_64
|
||||
stage: i915
|
||||
timeout: "1h30m"
|
||||
variables:
|
||||
DRIVER_NAME: i915
|
||||
DTB: ""
|
||||
@@ -414,6 +415,7 @@ panfrost:g12b:
|
||||
|
||||
virtio_gpu:none:
|
||||
stage: software-driver
|
||||
timeout: "1h30m"
|
||||
variables:
|
||||
CROSVM_GALLIUM_DRIVER: llvmpipe
|
||||
DRIVER_NAME: virtio_gpu
|
||||
@@ -436,6 +438,7 @@ virtio_gpu:none:
|
||||
|
||||
vkms:none:
|
||||
stage: software-driver
|
||||
timeout: "1h30m"
|
||||
variables:
|
||||
DRIVER_NAME: vkms
|
||||
GPU_VERSION: none
|
||||
|
||||
@@ -89,7 +89,7 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
|
||||
struct drm_dp_mst_branch *mstb,
|
||||
struct drm_dp_mst_port *port);
|
||||
static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
|
||||
u8 *guid);
|
||||
guid_t *guid);
|
||||
|
||||
static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port);
|
||||
static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port);
|
||||
@@ -801,7 +801,7 @@ static bool drm_dp_sideband_parse_link_address(const struct drm_dp_mst_topology_
|
||||
int idx = 1;
|
||||
int i;
|
||||
|
||||
memcpy(repmsg->u.link_addr.guid, &raw->msg[idx], 16);
|
||||
import_guid(&repmsg->u.link_addr.guid, &raw->msg[idx]);
|
||||
idx += 16;
|
||||
repmsg->u.link_addr.nports = raw->msg[idx] & 0xf;
|
||||
idx++;
|
||||
@@ -829,7 +829,7 @@ static bool drm_dp_sideband_parse_link_address(const struct drm_dp_mst_topology_
|
||||
idx++;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
memcpy(repmsg->u.link_addr.ports[i].peer_guid, &raw->msg[idx], 16);
|
||||
import_guid(&repmsg->u.link_addr.ports[i].peer_guid, &raw->msg[idx]);
|
||||
idx += 16;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
@@ -1029,7 +1029,7 @@ static bool drm_dp_sideband_parse_reply(const struct drm_dp_mst_topology_mgr *mg
|
||||
msg->req_type = (raw->msg[0] & 0x7f);
|
||||
|
||||
if (msg->reply_type == DP_SIDEBAND_REPLY_NAK) {
|
||||
memcpy(msg->u.nak.guid, &raw->msg[1], 16);
|
||||
import_guid(&msg->u.nak.guid, &raw->msg[1]);
|
||||
msg->u.nak.reason = raw->msg[17];
|
||||
msg->u.nak.nak_data = raw->msg[18];
|
||||
return false;
|
||||
@@ -1078,7 +1078,7 @@ drm_dp_sideband_parse_connection_status_notify(const struct drm_dp_mst_topology_
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
|
||||
memcpy(msg->u.conn_stat.guid, &raw->msg[idx], 16);
|
||||
import_guid(&msg->u.conn_stat.guid, &raw->msg[idx]);
|
||||
idx += 16;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
@@ -1107,7 +1107,7 @@ static bool drm_dp_sideband_parse_resource_status_notify(const struct drm_dp_mst
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
|
||||
memcpy(msg->u.resource_stat.guid, &raw->msg[idx], 16);
|
||||
import_guid(&msg->u.resource_stat.guid, &raw->msg[idx]);
|
||||
idx += 16;
|
||||
if (idx > raw->curlen)
|
||||
goto fail_len;
|
||||
@@ -2174,20 +2174,24 @@ ssize_t drm_dp_mst_dpcd_write(struct drm_dp_aux *aux,
|
||||
offset, size, buffer);
|
||||
}
|
||||
|
||||
static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, u8 *guid)
|
||||
static int drm_dp_check_mstb_guid(struct drm_dp_mst_branch *mstb, guid_t *guid)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
memcpy(mstb->guid, guid, 16);
|
||||
guid_copy(&mstb->guid, guid);
|
||||
|
||||
if (!drm_dp_validate_guid(mstb->mgr, &mstb->guid)) {
|
||||
u8 buf[UUID_SIZE];
|
||||
|
||||
export_guid(buf, &mstb->guid);
|
||||
|
||||
if (!drm_dp_validate_guid(mstb->mgr, mstb->guid)) {
|
||||
if (mstb->port_parent) {
|
||||
ret = drm_dp_send_dpcd_write(mstb->mgr,
|
||||
mstb->port_parent,
|
||||
DP_GUID, 16, mstb->guid);
|
||||
DP_GUID, sizeof(buf), buf);
|
||||
} else {
|
||||
ret = drm_dp_dpcd_write(mstb->mgr->aux,
|
||||
DP_GUID, mstb->guid, 16);
|
||||
DP_GUID, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2567,9 +2571,9 @@ out:
|
||||
return mstb;
|
||||
}
|
||||
|
||||
static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
|
||||
struct drm_dp_mst_branch *mstb,
|
||||
const uint8_t *guid)
|
||||
static struct drm_dp_mst_branch *
|
||||
get_mst_branch_device_by_guid_helper(struct drm_dp_mst_branch *mstb,
|
||||
const guid_t *guid)
|
||||
{
|
||||
struct drm_dp_mst_branch *found_mstb;
|
||||
struct drm_dp_mst_port *port;
|
||||
@@ -2577,10 +2581,9 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
|
||||
if (!mstb)
|
||||
return NULL;
|
||||
|
||||
if (memcmp(mstb->guid, guid, 16) == 0)
|
||||
if (guid_equal(&mstb->guid, guid))
|
||||
return mstb;
|
||||
|
||||
|
||||
list_for_each_entry(port, &mstb->ports, next) {
|
||||
found_mstb = get_mst_branch_device_by_guid_helper(port->mstb, guid);
|
||||
|
||||
@@ -2593,7 +2596,7 @@ static struct drm_dp_mst_branch *get_mst_branch_device_by_guid_helper(
|
||||
|
||||
static struct drm_dp_mst_branch *
|
||||
drm_dp_get_mst_branch_device_by_guid(struct drm_dp_mst_topology_mgr *mgr,
|
||||
const uint8_t *guid)
|
||||
const guid_t *guid)
|
||||
{
|
||||
struct drm_dp_mst_branch *mstb;
|
||||
int ret;
|
||||
@@ -2695,17 +2698,12 @@ static void drm_dp_mst_queue_probe_work(struct drm_dp_mst_topology_mgr *mgr)
|
||||
}
|
||||
|
||||
static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
|
||||
u8 *guid)
|
||||
guid_t *guid)
|
||||
{
|
||||
u64 salt;
|
||||
|
||||
if (memchr_inv(guid, 0, 16))
|
||||
if (!guid_is_null(guid))
|
||||
return true;
|
||||
|
||||
salt = get_jiffies_64();
|
||||
|
||||
memcpy(&guid[0], &salt, sizeof(u64));
|
||||
memcpy(&guid[8], &salt, sizeof(u64));
|
||||
guid_gen(guid);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -2945,7 +2943,7 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
|
||||
drm_dbg_kms(mgr->dev, "link address reply: %d\n", reply->nports);
|
||||
drm_dp_dump_link_address(mgr, reply);
|
||||
|
||||
ret = drm_dp_check_mstb_guid(mstb, reply->guid);
|
||||
ret = drm_dp_check_mstb_guid(mstb, &reply->guid);
|
||||
if (ret) {
|
||||
char buf[64];
|
||||
|
||||
@@ -3799,8 +3797,9 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_suspend);
|
||||
int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr,
|
||||
bool sync)
|
||||
{
|
||||
u8 buf[UUID_SIZE];
|
||||
guid_t guid;
|
||||
int ret;
|
||||
u8 guid[16];
|
||||
|
||||
mutex_lock(&mgr->lock);
|
||||
if (!mgr->mst_primary)
|
||||
@@ -3821,13 +3820,15 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr,
|
||||
}
|
||||
|
||||
/* Some hubs forget their guids after they resume */
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16);
|
||||
if (ret != 16) {
|
||||
ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, buf, sizeof(buf));
|
||||
if (ret != sizeof(buf)) {
|
||||
drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n");
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
ret = drm_dp_check_mstb_guid(mgr->mst_primary, guid);
|
||||
import_guid(&guid, buf);
|
||||
|
||||
ret = drm_dp_check_mstb_guid(mgr->mst_primary, &guid);
|
||||
if (ret) {
|
||||
drm_dbg_kms(mgr->dev, "check mstb failed - undocked during suspend?\n");
|
||||
goto out_fail;
|
||||
@@ -4005,12 +4006,12 @@ drm_dp_mst_process_up_req(struct drm_dp_mst_topology_mgr *mgr,
|
||||
bool hotplug = false, dowork = false;
|
||||
|
||||
if (hdr->broadcast) {
|
||||
const u8 *guid = NULL;
|
||||
const guid_t *guid = NULL;
|
||||
|
||||
if (msg->req_type == DP_CONNECTION_STATUS_NOTIFY)
|
||||
guid = msg->u.conn_stat.guid;
|
||||
guid = &msg->u.conn_stat.guid;
|
||||
else if (msg->req_type == DP_RESOURCE_STATUS_NOTIFY)
|
||||
guid = msg->u.resource_stat.guid;
|
||||
guid = &msg->u.resource_stat.guid;
|
||||
|
||||
if (guid)
|
||||
mstb = drm_dp_get_mst_branch_device_by_guid(mgr, guid);
|
||||
@@ -5598,7 +5599,6 @@ EXPORT_SYMBOL(drm_dp_mst_atomic_check_mgr);
|
||||
* drm_dp_atomic_release_time_slots()
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 0 if the new state is valid, negative error code otherwise.
|
||||
*/
|
||||
int drm_dp_mst_atomic_check(struct drm_atomic_state *state)
|
||||
@@ -5635,7 +5635,6 @@ EXPORT_SYMBOL(drm_dp_mst_topology_state_funcs);
|
||||
* topology object.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* The MST topology state or error pointer.
|
||||
*/
|
||||
struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state,
|
||||
@@ -5655,7 +5654,6 @@ EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
|
||||
* topology object.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* The old MST topology state, or NULL if there's no topology state for this MST mgr
|
||||
* in the global atomic state
|
||||
*/
|
||||
@@ -5680,7 +5678,6 @@ EXPORT_SYMBOL(drm_atomic_get_old_mst_topology_state);
|
||||
* topology object.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* The new MST topology state, or NULL if there's no topology state for this MST mgr
|
||||
* in the global atomic state
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,6 @@ EXPORT_SYMBOL(__drm_crtc_commit_free);
|
||||
* hardware and flipped to.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
int drm_crtc_commit_wait(struct drm_crtc_commit *commit)
|
||||
@@ -337,7 +336,6 @@ EXPORT_SYMBOL(__drm_atomic_state_free);
|
||||
* not created by userspace through an IOCTL call.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into the pointer. When
|
||||
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
* entire atomic sequence must be restarted. All other errors are fatal.
|
||||
@@ -518,7 +516,6 @@ static int drm_atomic_connector_check(struct drm_connector *connector,
|
||||
* is consistent.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into the pointer. When
|
||||
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
* entire atomic sequence must be restarted. All other errors are fatal.
|
||||
@@ -828,7 +825,6 @@ EXPORT_SYMBOL(drm_atomic_private_obj_fini);
|
||||
* object lock to make sure that the state is consistent.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into a pointer.
|
||||
*/
|
||||
struct drm_private_state *
|
||||
@@ -1061,7 +1057,6 @@ EXPORT_SYMBOL(drm_atomic_get_new_crtc_for_encoder);
|
||||
* make sure that the state is consistent.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into the pointer. When
|
||||
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
* entire atomic sequence must be restarted. All other errors are fatal.
|
||||
@@ -1169,7 +1164,6 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
|
||||
* state is consistent.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Either the allocated state or the error code encoded into the pointer. When
|
||||
* the error is EDEADLK then the w/w mutex code has detected a deadlock and the
|
||||
* entire atomic sequence must be restarted.
|
||||
|
||||
@@ -2266,7 +2266,6 @@ crtc_or_fake_commit(struct drm_atomic_state *state, struct drm_crtc *crtc)
|
||||
* automatically.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 0 on success. -EBUSY when userspace schedules nonblocking commits too fast,
|
||||
* -ENOMEM on allocation failures and -EINTR when a signal is pending.
|
||||
*/
|
||||
@@ -3009,7 +3008,6 @@ EXPORT_SYMBOL(drm_atomic_helper_cleanup_planes);
|
||||
* don't pass the right state structures to the callbacks.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Returns 0 on success. Can return -ERESTARTSYS when @stall is true and the
|
||||
* waiting for the previous commits has been interrupted.
|
||||
*/
|
||||
|
||||
@@ -320,10 +320,14 @@ drm_edid_load_firmware(struct drm_connector *connector)
|
||||
bool drm_panic_is_enabled(struct drm_device *dev);
|
||||
void drm_panic_register(struct drm_device *dev);
|
||||
void drm_panic_unregister(struct drm_device *dev);
|
||||
void drm_panic_init(void);
|
||||
void drm_panic_exit(void);
|
||||
#else
|
||||
static inline bool drm_panic_is_enabled(struct drm_device *dev) { return false; }
|
||||
static inline void drm_panic_register(struct drm_device *dev) {}
|
||||
static inline void drm_panic_unregister(struct drm_device *dev) {}
|
||||
static inline void drm_panic_init(void) {}
|
||||
static inline void drm_panic_exit(void) {}
|
||||
#endif
|
||||
|
||||
#endif /* __DRM_CRTC_INTERNAL_H__ */
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <linux/pseudo_fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/srcu.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
#include <drm/drm_accel.h>
|
||||
#include <drm/drm_cache.h>
|
||||
@@ -54,8 +55,7 @@ MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl");
|
||||
MODULE_DESCRIPTION("DRM shared core routines");
|
||||
MODULE_LICENSE("GPL and additional rights");
|
||||
|
||||
static DEFINE_SPINLOCK(drm_minor_lock);
|
||||
static struct idr drm_minors_idr;
|
||||
DEFINE_XARRAY_ALLOC(drm_minors_xa);
|
||||
|
||||
/*
|
||||
* If the drm core fails to init for whatever reason,
|
||||
@@ -83,6 +83,18 @@ DEFINE_STATIC_SRCU(drm_unplug_srcu);
|
||||
* registered and unregistered dynamically according to device-state.
|
||||
*/
|
||||
|
||||
static struct xarray *drm_minor_get_xa(enum drm_minor_type type)
|
||||
{
|
||||
if (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER)
|
||||
return &drm_minors_xa;
|
||||
#if IS_ENABLED(CONFIG_DRM_ACCEL)
|
||||
else if (type == DRM_MINOR_ACCEL)
|
||||
return &accel_minors_xa;
|
||||
#endif
|
||||
else
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
|
||||
enum drm_minor_type type)
|
||||
{
|
||||
@@ -101,25 +113,31 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
|
||||
static void drm_minor_alloc_release(struct drm_device *dev, void *data)
|
||||
{
|
||||
struct drm_minor *minor = data;
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON(dev != minor->dev);
|
||||
|
||||
put_device(minor->kdev);
|
||||
|
||||
if (minor->type == DRM_MINOR_ACCEL) {
|
||||
accel_minor_remove(minor->index);
|
||||
} else {
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
idr_remove(&drm_minors_idr, minor->index);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
}
|
||||
xa_erase(drm_minor_get_xa(minor->type), minor->index);
|
||||
}
|
||||
|
||||
/*
|
||||
* DRM used to support 64 devices, for backwards compatibility we need to maintain the
|
||||
* minor allocation scheme where minors 0-63 are primary nodes, 64-127 are control nodes,
|
||||
* and 128-191 are render nodes.
|
||||
* After reaching the limit, we're allocating minors dynamically - first-come, first-serve.
|
||||
* Accel nodes are using a distinct major, so the minors are allocated in continuous 0-MAX
|
||||
* range.
|
||||
*/
|
||||
#define DRM_MINOR_LIMIT(t) ({ \
|
||||
typeof(t) _t = (t); \
|
||||
_t == DRM_MINOR_ACCEL ? XA_LIMIT(0, ACCEL_MAX_MINORS) : XA_LIMIT(64 * _t, 64 * _t + 63); \
|
||||
})
|
||||
#define DRM_EXTENDED_MINOR_LIMIT XA_LIMIT(192, (1 << MINORBITS) - 1)
|
||||
|
||||
static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
int r;
|
||||
|
||||
minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL);
|
||||
@@ -129,25 +147,14 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
|
||||
minor->type = type;
|
||||
minor->dev = dev;
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
if (type == DRM_MINOR_ACCEL) {
|
||||
r = accel_minor_alloc();
|
||||
} else {
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
r = idr_alloc(&drm_minors_idr,
|
||||
NULL,
|
||||
64 * type,
|
||||
64 * (type + 1),
|
||||
GFP_NOWAIT);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
}
|
||||
idr_preload_end();
|
||||
|
||||
r = xa_alloc(drm_minor_get_xa(type), &minor->index,
|
||||
NULL, DRM_MINOR_LIMIT(type), GFP_KERNEL);
|
||||
if (r == -EBUSY && (type == DRM_MINOR_PRIMARY || type == DRM_MINOR_RENDER))
|
||||
r = xa_alloc(&drm_minors_xa, &minor->index,
|
||||
NULL, DRM_EXTENDED_MINOR_LIMIT, GFP_KERNEL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
minor->index = r;
|
||||
|
||||
r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor);
|
||||
if (r)
|
||||
return r;
|
||||
@@ -163,7 +170,7 @@ static int drm_minor_alloc(struct drm_device *dev, enum drm_minor_type type)
|
||||
static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
void *entry;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
@@ -186,13 +193,12 @@ static int drm_minor_register(struct drm_device *dev, enum drm_minor_type type)
|
||||
goto err_debugfs;
|
||||
|
||||
/* replace NULL with @minor so lookups will succeed from now on */
|
||||
if (minor->type == DRM_MINOR_ACCEL) {
|
||||
accel_minor_replace(minor, minor->index);
|
||||
} else {
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
idr_replace(&drm_minors_idr, minor, minor->index);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
entry = xa_store(drm_minor_get_xa(type), minor->index, minor, GFP_KERNEL);
|
||||
if (xa_is_err(entry)) {
|
||||
ret = xa_err(entry);
|
||||
goto err_debugfs;
|
||||
}
|
||||
WARN_ON(entry);
|
||||
|
||||
DRM_DEBUG("new minor registered %d\n", minor->index);
|
||||
return 0;
|
||||
@@ -205,20 +211,13 @@ err_debugfs:
|
||||
static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type type)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
|
||||
minor = *drm_minor_get_slot(dev, type);
|
||||
if (!minor || !device_is_registered(minor->kdev))
|
||||
return;
|
||||
|
||||
/* replace @minor with NULL so lookups will fail from now on */
|
||||
if (minor->type == DRM_MINOR_ACCEL) {
|
||||
accel_minor_replace(NULL, minor->index);
|
||||
} else {
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
idr_replace(&drm_minors_idr, NULL, minor->index);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
}
|
||||
xa_store(drm_minor_get_xa(type), minor->index, NULL, GFP_KERNEL);
|
||||
|
||||
device_del(minor->kdev);
|
||||
dev_set_drvdata(minor->kdev, NULL); /* safety belt */
|
||||
@@ -234,16 +233,15 @@ static void drm_minor_unregister(struct drm_device *dev, enum drm_minor_type typ
|
||||
* minor->dev pointer will stay valid! However, the device may get unplugged and
|
||||
* unregistered while you hold the minor.
|
||||
*/
|
||||
struct drm_minor *drm_minor_acquire(unsigned int minor_id)
|
||||
struct drm_minor *drm_minor_acquire(struct xarray *minor_xa, unsigned int minor_id)
|
||||
{
|
||||
struct drm_minor *minor;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&drm_minor_lock, flags);
|
||||
minor = idr_find(&drm_minors_idr, minor_id);
|
||||
xa_lock(minor_xa);
|
||||
minor = xa_load(minor_xa, minor_id);
|
||||
if (minor)
|
||||
drm_dev_get(minor->dev);
|
||||
spin_unlock_irqrestore(&drm_minor_lock, flags);
|
||||
xa_unlock(minor_xa);
|
||||
|
||||
if (!minor) {
|
||||
return ERR_PTR(-ENODEV);
|
||||
@@ -1036,7 +1034,7 @@ static int drm_stub_open(struct inode *inode, struct file *filp)
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
minor = drm_minor_acquire(iminor(inode));
|
||||
minor = drm_minor_acquire(&drm_minors_xa, iminor(inode));
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
@@ -1067,11 +1065,12 @@ static const struct file_operations drm_stub_fops = {
|
||||
static void drm_core_exit(void)
|
||||
{
|
||||
drm_privacy_screen_lookup_exit();
|
||||
drm_panic_exit();
|
||||
accel_core_exit();
|
||||
unregister_chrdev(DRM_MAJOR, "drm");
|
||||
debugfs_remove(drm_debugfs_root);
|
||||
drm_sysfs_destroy();
|
||||
idr_destroy(&drm_minors_idr);
|
||||
WARN_ON(!xa_empty(&drm_minors_xa));
|
||||
drm_connector_ida_destroy();
|
||||
}
|
||||
|
||||
@@ -1080,7 +1079,6 @@ static int __init drm_core_init(void)
|
||||
int ret;
|
||||
|
||||
drm_connector_ida_init();
|
||||
idr_init(&drm_minors_idr);
|
||||
drm_memcpy_init_early();
|
||||
|
||||
ret = drm_sysfs_init();
|
||||
@@ -1099,6 +1097,8 @@ static int __init drm_core_init(void)
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
drm_panic_init();
|
||||
|
||||
drm_privacy_screen_lookup_init();
|
||||
|
||||
drm_core_init_complete = true;
|
||||
|
||||
@@ -347,7 +347,6 @@ int drm_open_helper(struct file *filp, struct drm_minor *minor)
|
||||
* resources for it. It also calls the &drm_driver.open driver callback.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* 0 on success or negative errno value on failure.
|
||||
*/
|
||||
int drm_open(struct inode *inode, struct file *filp)
|
||||
@@ -356,7 +355,7 @@ int drm_open(struct inode *inode, struct file *filp)
|
||||
struct drm_minor *minor;
|
||||
int retcode;
|
||||
|
||||
minor = drm_minor_acquire(iminor(inode));
|
||||
minor = drm_minor_acquire(&drm_minors_xa, iminor(inode));
|
||||
if (IS_ERR(minor))
|
||||
return PTR_ERR(minor);
|
||||
|
||||
@@ -406,7 +405,6 @@ static void drm_lastclose(struct drm_device *dev)
|
||||
* in-kernel DRM client.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Always succeeds and returns 0.
|
||||
*/
|
||||
int drm_release(struct inode *inode, struct file *filp)
|
||||
@@ -477,7 +475,6 @@ void drm_file_update_pid(struct drm_file *filp)
|
||||
* then restores the active in-kernel DRM client.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Always succeeds and returns 0.
|
||||
*/
|
||||
int drm_release_noglobal(struct inode *inode, struct file *filp)
|
||||
@@ -520,7 +517,6 @@ EXPORT_SYMBOL(drm_release_noglobal);
|
||||
* safety.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Number of bytes read (always aligned to full events, and can be 0) or a
|
||||
* negative error code on failure.
|
||||
*/
|
||||
@@ -606,7 +602,6 @@ EXPORT_SYMBOL(drm_read);
|
||||
* See also drm_read().
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* Mask of POLL flags indicating the current status of the file.
|
||||
*/
|
||||
__poll_t drm_poll(struct file *filp, struct poll_table_struct *wait)
|
||||
@@ -644,7 +639,6 @@ EXPORT_SYMBOL(drm_poll);
|
||||
* already hold &drm_device.event_lock.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_event_reserve_init_locked(struct drm_device *dev,
|
||||
@@ -686,7 +680,6 @@ EXPORT_SYMBOL(drm_event_reserve_init_locked);
|
||||
* drm_event_reserve_init_locked() instead.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int drm_event_reserve_init(struct drm_device *dev,
|
||||
|
||||
@@ -689,7 +689,6 @@ static int objects_lookup(struct drm_file *filp, u32 *handle, int count,
|
||||
* For a single handle lookup, use drm_gem_object_lookup().
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* @objs filled in with GEM object pointers. Returned GEM objects need to be
|
||||
* released with drm_gem_object_put(). -ENOENT is returned on a lookup
|
||||
* failure. 0 is returned on success.
|
||||
@@ -737,12 +736,11 @@ EXPORT_SYMBOL(drm_gem_objects_lookup);
|
||||
* @filp: DRM file private date
|
||||
* @handle: userspace handle
|
||||
*
|
||||
* Returns:
|
||||
* If looking up an array of handles, use drm_gem_objects_lookup().
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the object named by the handle if such exists on @filp, NULL
|
||||
* otherwise.
|
||||
*
|
||||
* If looking up an array of handles, use drm_gem_objects_lookup().
|
||||
*/
|
||||
struct drm_gem_object *
|
||||
drm_gem_object_lookup(struct drm_file *filp, u32 handle)
|
||||
@@ -763,7 +761,6 @@ EXPORT_SYMBOL(drm_gem_object_lookup);
|
||||
* @timeout: timeout value in jiffies or zero to return immediately
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or
|
||||
* greater than 0 on success.
|
||||
*/
|
||||
|
||||
@@ -80,10 +80,6 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv);
|
||||
void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv,
|
||||
uint32_t handle);
|
||||
|
||||
/* drm_drv.c */
|
||||
struct drm_minor *drm_minor_acquire(unsigned int minor_id);
|
||||
void drm_minor_release(struct drm_minor *minor);
|
||||
|
||||
/* drm_managed.c */
|
||||
void drm_managed_release(struct drm_device *dev);
|
||||
void drmm_add_final_kfree(struct drm_device *dev, void *container);
|
||||
|
||||
@@ -539,7 +539,6 @@ static int fill_analog_mode(struct drm_device *dev,
|
||||
* to reach those resolutions.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* A pointer to the mode, allocated with drm_mode_create(). Returns NULL
|
||||
* on error.
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/zlib.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
@@ -26,6 +28,7 @@
|
||||
#include <drm/drm_panic.h>
|
||||
#include <drm/drm_plane.h>
|
||||
#include <drm/drm_print.h>
|
||||
#include <drm/drm_rect.h>
|
||||
|
||||
#include "drm_crtc_internal.h"
|
||||
|
||||
@@ -85,7 +88,7 @@ static struct drm_panic_line panic_msg[] = {
|
||||
PANIC_LINE(""), /* will be replaced by the panic description */
|
||||
};
|
||||
|
||||
#define PANIC_MSG_LINES ARRAY_SIZE(panic_msg)
|
||||
static const size_t panic_msg_lines = ARRAY_SIZE(panic_msg);
|
||||
|
||||
static const struct drm_panic_line logo_ascii[] = {
|
||||
PANIC_LINE(" .--. _"),
|
||||
@@ -97,7 +100,7 @@ static const struct drm_panic_line logo_ascii[] = {
|
||||
PANIC_LINE(" \\___)=(___/"),
|
||||
};
|
||||
|
||||
#define PANIC_LOGO_LINES ARRAY_SIZE(logo_ascii)
|
||||
static const size_t logo_ascii_lines = ARRAY_SIZE(logo_ascii);
|
||||
|
||||
#if defined(CONFIG_LOGO) && !defined(MODULE)
|
||||
static const struct linux_logo *logo_mono;
|
||||
@@ -257,20 +260,20 @@ static bool drm_panic_is_pixel_fg(const u8 *sbuf8, unsigned int spitch, int x, i
|
||||
static void drm_panic_blit16(struct iosys_map *dmap, unsigned int dpitch,
|
||||
const u8 *sbuf8, unsigned int spitch,
|
||||
unsigned int height, unsigned int width,
|
||||
u16 fg16)
|
||||
unsigned int scale, u16 fg16)
|
||||
{
|
||||
unsigned int y, x;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
|
||||
iosys_map_wr(dmap, y * dpitch + x * sizeof(u16), u16, fg16);
|
||||
}
|
||||
|
||||
static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
|
||||
const u8 *sbuf8, unsigned int spitch,
|
||||
unsigned int height, unsigned int width,
|
||||
u32 fg32)
|
||||
unsigned int scale, u32 fg32)
|
||||
{
|
||||
unsigned int y, x;
|
||||
|
||||
@@ -278,7 +281,7 @@ static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
|
||||
for (x = 0; x < width; x++) {
|
||||
u32 off = y * dpitch + x * 3;
|
||||
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y)) {
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) {
|
||||
/* write blue-green-red to output in little endianness */
|
||||
iosys_map_wr(dmap, off, u8, (fg32 & 0x000000FF) >> 0);
|
||||
iosys_map_wr(dmap, off + 1, u8, (fg32 & 0x0000FF00) >> 8);
|
||||
@@ -291,24 +294,25 @@ static void drm_panic_blit24(struct iosys_map *dmap, unsigned int dpitch,
|
||||
static void drm_panic_blit32(struct iosys_map *dmap, unsigned int dpitch,
|
||||
const u8 *sbuf8, unsigned int spitch,
|
||||
unsigned int height, unsigned int width,
|
||||
u32 fg32)
|
||||
unsigned int scale, u32 fg32)
|
||||
{
|
||||
unsigned int y, x;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
for (x = 0; x < width; x++)
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
|
||||
iosys_map_wr(dmap, y * dpitch + x * sizeof(u32), u32, fg32);
|
||||
}
|
||||
|
||||
static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect *clip,
|
||||
const u8 *sbuf8, unsigned int spitch, u32 fg_color)
|
||||
const u8 *sbuf8, unsigned int spitch, unsigned int scale,
|
||||
u32 fg_color)
|
||||
{
|
||||
unsigned int y, x;
|
||||
|
||||
for (y = 0; y < drm_rect_height(clip); y++)
|
||||
for (x = 0; x < drm_rect_width(clip); x++)
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x, y))
|
||||
if (drm_panic_is_pixel_fg(sbuf8, spitch, x / scale, y / scale))
|
||||
sb->set_pixel(sb, clip->x1 + x, clip->y1 + y, fg_color);
|
||||
}
|
||||
|
||||
@@ -318,18 +322,22 @@ static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect
|
||||
* @clip: destination rectangle
|
||||
* @sbuf8: source buffer, in monochrome format, 8 pixels per byte.
|
||||
* @spitch: source pitch in bytes
|
||||
* @scale: integer scale, source buffer is scale time smaller than destination
|
||||
* rectangle
|
||||
* @fg_color: foreground color, in destination format
|
||||
*
|
||||
* This can be used to draw a font character, which is a monochrome image, to a
|
||||
* framebuffer in other supported format.
|
||||
*/
|
||||
static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip,
|
||||
const u8 *sbuf8, unsigned int spitch, u32 fg_color)
|
||||
const u8 *sbuf8, unsigned int spitch,
|
||||
unsigned int scale, u32 fg_color)
|
||||
|
||||
{
|
||||
struct iosys_map map;
|
||||
|
||||
if (sb->set_pixel)
|
||||
return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, fg_color);
|
||||
return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, scale, fg_color);
|
||||
|
||||
map = sb->map[0];
|
||||
iosys_map_incr(&map, clip->y1 * sb->pitch[0] + clip->x1 * sb->format->cpp[0]);
|
||||
@@ -337,15 +345,15 @@ static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip,
|
||||
switch (sb->format->cpp[0]) {
|
||||
case 2:
|
||||
drm_panic_blit16(&map, sb->pitch[0], sbuf8, spitch,
|
||||
drm_rect_height(clip), drm_rect_width(clip), fg_color);
|
||||
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
|
||||
break;
|
||||
case 3:
|
||||
drm_panic_blit24(&map, sb->pitch[0], sbuf8, spitch,
|
||||
drm_rect_height(clip), drm_rect_width(clip), fg_color);
|
||||
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
|
||||
break;
|
||||
case 4:
|
||||
drm_panic_blit32(&map, sb->pitch[0], sbuf8, spitch,
|
||||
drm_rect_height(clip), drm_rect_width(clip), fg_color);
|
||||
drm_rect_height(clip), drm_rect_width(clip), scale, fg_color);
|
||||
break;
|
||||
default:
|
||||
WARN_ONCE(1, "Can't blit with pixel width %d\n", sb->format->cpp[0]);
|
||||
@@ -485,37 +493,50 @@ static void draw_txt_rectangle(struct drm_scanout_buffer *sb,
|
||||
for (j = 0; j < line_len; j++) {
|
||||
src = get_char_bitmap(font, msg[i].txt[j], font_pitch);
|
||||
rec.x2 = rec.x1 + font->width;
|
||||
drm_panic_blit(sb, &rec, src, font_pitch, color);
|
||||
drm_panic_blit(sb, &rec, src, font_pitch, 1, color);
|
||||
rec.x1 += font->width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_panic_logo_rect(struct drm_rect *rect, const struct font_desc *font)
|
||||
{
|
||||
if (logo_mono) {
|
||||
drm_rect_init(rect, 0, 0, logo_mono->width, logo_mono->height);
|
||||
} else {
|
||||
int logo_width = get_max_line_len(logo_ascii, logo_ascii_lines) * font->width;
|
||||
|
||||
drm_rect_init(rect, 0, 0, logo_width, logo_ascii_lines * font->height);
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_panic_logo_draw(struct drm_scanout_buffer *sb, struct drm_rect *rect,
|
||||
const struct font_desc *font, u32 fg_color)
|
||||
{
|
||||
if (logo_mono)
|
||||
drm_panic_blit(sb, rect, logo_mono->data,
|
||||
DIV_ROUND_UP(drm_rect_width(rect), 8), 1, fg_color);
|
||||
else
|
||||
draw_txt_rectangle(sb, font, logo_ascii, logo_ascii_lines, false, rect,
|
||||
fg_color);
|
||||
}
|
||||
|
||||
static void draw_panic_static_user(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
|
||||
u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
|
||||
const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
|
||||
struct drm_rect r_screen, r_logo, r_msg;
|
||||
unsigned int logo_width, logo_height;
|
||||
unsigned int msg_width, msg_height;
|
||||
|
||||
if (!font)
|
||||
return;
|
||||
|
||||
r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
|
||||
drm_panic_logo_rect(&r_logo, font);
|
||||
|
||||
if (logo_mono) {
|
||||
logo_width = logo_mono->width;
|
||||
logo_height = logo_mono->height;
|
||||
} else {
|
||||
logo_width = get_max_line_len(logo_ascii, PANIC_LOGO_LINES) * font->width;
|
||||
logo_height = PANIC_LOGO_LINES * font->height;
|
||||
}
|
||||
r_logo = DRM_RECT_INIT(0, 0, logo_width, logo_height);
|
||||
|
||||
msg_width = min(get_max_line_len(panic_msg, PANIC_MSG_LINES) * font->width, sb->width);
|
||||
msg_height = min(PANIC_MSG_LINES * font->height, sb->height);
|
||||
msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width);
|
||||
msg_height = min(panic_msg_lines * font->height, sb->height);
|
||||
r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height);
|
||||
|
||||
/* Center the panic message */
|
||||
@@ -524,16 +545,10 @@ static void draw_panic_static_user(struct drm_scanout_buffer *sb)
|
||||
/* Fill with the background color, and draw text on top */
|
||||
drm_panic_fill(sb, &r_screen, bg_color);
|
||||
|
||||
if ((r_msg.x1 >= logo_width || r_msg.y1 >= logo_height) &&
|
||||
logo_width <= sb->width && logo_height <= sb->height) {
|
||||
if (logo_mono)
|
||||
drm_panic_blit(sb, &r_logo, logo_mono->data, DIV_ROUND_UP(logo_width, 8),
|
||||
fg_color);
|
||||
else
|
||||
draw_txt_rectangle(sb, font, logo_ascii, PANIC_LOGO_LINES, false, &r_logo,
|
||||
fg_color);
|
||||
}
|
||||
draw_txt_rectangle(sb, font, panic_msg, PANIC_MSG_LINES, true, &r_msg, fg_color);
|
||||
if (!drm_rect_overlap(&r_logo, &r_msg))
|
||||
drm_panic_logo_draw(sb, &r_logo, font, fg_color);
|
||||
|
||||
draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -615,6 +630,233 @@ static void draw_panic_static_kmsg(struct drm_scanout_buffer *sb)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
|
||||
/*
|
||||
* It is unwise to allocate memory in the panic callback, so the buffers are
|
||||
* pre-allocated. Only 2 buffers and the zlib workspace are needed.
|
||||
* Two buffers are enough, using the following buffer usage:
|
||||
* 1) kmsg messages are dumped in buffer1
|
||||
* 2) kmsg is zlib-compressed into buffer2
|
||||
* 3) compressed kmsg is encoded as QR-code Numeric stream in buffer1
|
||||
* 4) QR-code image is generated in buffer2
|
||||
* The Max QR code size is V40, 177x177, 4071 bytes for image, 2956 bytes for
|
||||
* data segments.
|
||||
*
|
||||
* Typically, ~7500 bytes of kmsg, are compressed into 2800 bytes, which fits in
|
||||
* a V40 QR-code (177x177).
|
||||
*
|
||||
* If CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL is not set, the kmsg data will be put
|
||||
* directly in the QR code.
|
||||
* 1) kmsg messages are dumped in buffer1
|
||||
* 2) kmsg message is encoded as byte stream in buffer2
|
||||
* 3) QR-code image is generated in buffer1
|
||||
*/
|
||||
|
||||
static uint panic_qr_version = CONFIG_DRM_PANIC_SCREEN_QR_VERSION;
|
||||
module_param(panic_qr_version, uint, 0644);
|
||||
MODULE_PARM_DESC(panic_qr_version, "maximum version (size) of the QR code");
|
||||
|
||||
#define MAX_QR_DATA 2956
|
||||
#define MAX_ZLIB_RATIO 3
|
||||
#define QR_BUFFER1_SIZE (MAX_ZLIB_RATIO * MAX_QR_DATA) /* Must also be > 4071 */
|
||||
#define QR_BUFFER2_SIZE 4096
|
||||
#define QR_MARGIN 4 /* 4 modules of foreground color around the qr code */
|
||||
|
||||
/* Compression parameters */
|
||||
#define COMPR_LEVEL 6
|
||||
#define WINDOW_BITS 12
|
||||
#define MEM_LEVEL 4
|
||||
|
||||
static char *qrbuf1;
|
||||
static char *qrbuf2;
|
||||
static struct z_stream_s stream;
|
||||
|
||||
static void __init drm_panic_qr_init(void)
|
||||
{
|
||||
qrbuf1 = kmalloc(QR_BUFFER1_SIZE, GFP_KERNEL);
|
||||
qrbuf2 = kmalloc(QR_BUFFER2_SIZE, GFP_KERNEL);
|
||||
stream.workspace = kmalloc(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
|
||||
GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void drm_panic_qr_exit(void)
|
||||
{
|
||||
kfree(qrbuf1);
|
||||
qrbuf1 = NULL;
|
||||
kfree(qrbuf2);
|
||||
qrbuf2 = NULL;
|
||||
kfree(stream.workspace);
|
||||
stream.workspace = NULL;
|
||||
}
|
||||
|
||||
extern size_t drm_panic_qr_max_data_size(u8 version, size_t url_len);
|
||||
|
||||
extern u8 drm_panic_qr_generate(const char *url, u8 *data, size_t data_len, size_t data_size,
|
||||
u8 *tmp, size_t tmp_size);
|
||||
|
||||
static int drm_panic_get_qr_code_url(u8 **qr_image)
|
||||
{
|
||||
struct kmsg_dump_iter iter;
|
||||
char url[256];
|
||||
size_t kmsg_len, max_kmsg_size;
|
||||
char *kmsg;
|
||||
int max_qr_data_size, url_len;
|
||||
|
||||
url_len = snprintf(url, sizeof(url), CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL "?a=%s&v=%s&zl=",
|
||||
utsname()->machine, utsname()->release);
|
||||
|
||||
max_qr_data_size = drm_panic_qr_max_data_size(panic_qr_version, url_len);
|
||||
max_kmsg_size = min(MAX_ZLIB_RATIO * max_qr_data_size, QR_BUFFER1_SIZE);
|
||||
|
||||
/* get kmsg to buffer 1 */
|
||||
kmsg_dump_rewind(&iter);
|
||||
kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len);
|
||||
|
||||
if (!kmsg_len)
|
||||
return -ENODATA;
|
||||
kmsg = qrbuf1;
|
||||
|
||||
try_again:
|
||||
if (zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
|
||||
MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||
return -EINVAL;
|
||||
|
||||
stream.next_in = kmsg;
|
||||
stream.avail_in = kmsg_len;
|
||||
stream.total_in = 0;
|
||||
stream.next_out = qrbuf2;
|
||||
stream.avail_out = QR_BUFFER2_SIZE;
|
||||
stream.total_out = 0;
|
||||
|
||||
if (zlib_deflate(&stream, Z_FINISH) != Z_STREAM_END)
|
||||
return -EINVAL;
|
||||
|
||||
if (zlib_deflateEnd(&stream) != Z_OK)
|
||||
return -EINVAL;
|
||||
|
||||
if (stream.total_out > max_qr_data_size) {
|
||||
/* too much data for the QR code, so skip the first line and try again */
|
||||
kmsg = strchr(kmsg, '\n');
|
||||
if (!kmsg)
|
||||
return -EINVAL;
|
||||
/* skip the first \n */
|
||||
kmsg += 1;
|
||||
kmsg_len = strlen(kmsg);
|
||||
goto try_again;
|
||||
}
|
||||
*qr_image = qrbuf2;
|
||||
|
||||
/* generate qr code image in buffer2 */
|
||||
return drm_panic_qr_generate(url, qrbuf2, stream.total_out, QR_BUFFER2_SIZE,
|
||||
qrbuf1, QR_BUFFER1_SIZE);
|
||||
}
|
||||
|
||||
static int drm_panic_get_qr_code_raw(u8 **qr_image)
|
||||
{
|
||||
struct kmsg_dump_iter iter;
|
||||
size_t kmsg_len;
|
||||
size_t max_kmsg_size = min(drm_panic_qr_max_data_size(panic_qr_version, 0),
|
||||
QR_BUFFER1_SIZE);
|
||||
|
||||
kmsg_dump_rewind(&iter);
|
||||
kmsg_dump_get_buffer(&iter, false, qrbuf1, max_kmsg_size, &kmsg_len);
|
||||
if (!kmsg_len)
|
||||
return -ENODATA;
|
||||
|
||||
*qr_image = qrbuf1;
|
||||
return drm_panic_qr_generate(NULL, qrbuf1, kmsg_len, QR_BUFFER1_SIZE,
|
||||
qrbuf2, QR_BUFFER2_SIZE);
|
||||
}
|
||||
|
||||
static int drm_panic_get_qr_code(u8 **qr_image)
|
||||
{
|
||||
if (strlen(CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL) > 0)
|
||||
return drm_panic_get_qr_code_url(qr_image);
|
||||
else
|
||||
return drm_panic_get_qr_code_raw(qr_image);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw the panic message at the center of the screen, with a QR Code
|
||||
*/
|
||||
static int _draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
|
||||
u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
|
||||
const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
|
||||
struct drm_rect r_screen, r_logo, r_msg, r_qr, r_qr_canvas;
|
||||
unsigned int max_qr_size, scale;
|
||||
unsigned int msg_width, msg_height;
|
||||
int qr_width, qr_canvas_width, qr_pitch, v_margin;
|
||||
u8 *qr_image;
|
||||
|
||||
if (!font || !qrbuf1 || !qrbuf2 || !stream.workspace)
|
||||
return -ENOMEM;
|
||||
|
||||
r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
|
||||
|
||||
drm_panic_logo_rect(&r_logo, font);
|
||||
|
||||
msg_width = min(get_max_line_len(panic_msg, panic_msg_lines) * font->width, sb->width);
|
||||
msg_height = min(panic_msg_lines * font->height, sb->height);
|
||||
r_msg = DRM_RECT_INIT(0, 0, msg_width, msg_height);
|
||||
|
||||
max_qr_size = min(3 * sb->width / 4, 3 * sb->height / 4);
|
||||
|
||||
qr_width = drm_panic_get_qr_code(&qr_image);
|
||||
if (qr_width <= 0)
|
||||
return -ENOSPC;
|
||||
|
||||
qr_canvas_width = qr_width + QR_MARGIN * 2;
|
||||
scale = max_qr_size / qr_canvas_width;
|
||||
/* QR code is not readable if not scaled at least by 2 */
|
||||
if (scale < 2)
|
||||
return -ENOSPC;
|
||||
|
||||
pr_debug("QR width %d and scale %d\n", qr_width, scale);
|
||||
r_qr_canvas = DRM_RECT_INIT(0, 0, qr_canvas_width * scale, qr_canvas_width * scale);
|
||||
|
||||
v_margin = (sb->height - drm_rect_height(&r_qr_canvas) - drm_rect_height(&r_msg)) / 5;
|
||||
|
||||
drm_rect_translate(&r_qr_canvas, (sb->width - r_qr_canvas.x2) / 2, 2 * v_margin);
|
||||
r_qr = DRM_RECT_INIT(r_qr_canvas.x1 + QR_MARGIN * scale, r_qr_canvas.y1 + QR_MARGIN * scale,
|
||||
qr_width * scale, qr_width * scale);
|
||||
|
||||
/* Center the panic message */
|
||||
drm_rect_translate(&r_msg, (sb->width - r_msg.x2) / 2,
|
||||
3 * v_margin + drm_rect_height(&r_qr_canvas));
|
||||
|
||||
/* Fill with the background color, and draw text on top */
|
||||
drm_panic_fill(sb, &r_screen, bg_color);
|
||||
|
||||
if (!drm_rect_overlap(&r_logo, &r_msg) && !drm_rect_overlap(&r_logo, &r_qr))
|
||||
drm_panic_logo_draw(sb, &r_logo, font, fg_color);
|
||||
|
||||
draw_txt_rectangle(sb, font, panic_msg, panic_msg_lines, true, &r_msg, fg_color);
|
||||
|
||||
/* Draw the qr code */
|
||||
qr_pitch = DIV_ROUND_UP(qr_width, 8);
|
||||
drm_panic_fill(sb, &r_qr_canvas, fg_color);
|
||||
drm_panic_fill(sb, &r_qr, bg_color);
|
||||
drm_panic_blit(sb, &r_qr, qr_image, qr_pitch, scale, fg_color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
if (_draw_panic_static_qr_code(sb))
|
||||
draw_panic_static_user(sb);
|
||||
}
|
||||
#else
|
||||
static void draw_panic_static_qr_code(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
draw_panic_static_user(sb);
|
||||
}
|
||||
|
||||
static void drm_panic_qr_init(void) {};
|
||||
static void drm_panic_qr_exit(void) {};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* drm_panic_is_format_supported()
|
||||
* @format: a fourcc color code
|
||||
@@ -633,6 +875,8 @@ static void draw_panic_dispatch(struct drm_scanout_buffer *sb)
|
||||
{
|
||||
if (!strcmp(drm_panic_screen, "kmsg")) {
|
||||
draw_panic_static_kmsg(sb);
|
||||
} else if (!strcmp(drm_panic_screen, "qr_code")) {
|
||||
draw_panic_static_qr_code(sb);
|
||||
} else {
|
||||
draw_panic_static_user(sb);
|
||||
}
|
||||
@@ -643,7 +887,7 @@ static void drm_panic_set_description(const char *description)
|
||||
u32 len;
|
||||
|
||||
if (description) {
|
||||
struct drm_panic_line *desc_line = &panic_msg[PANIC_MSG_LINES - 1];
|
||||
struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1];
|
||||
|
||||
desc_line->txt = description;
|
||||
len = strlen(description);
|
||||
@@ -656,7 +900,7 @@ static void drm_panic_set_description(const char *description)
|
||||
|
||||
static void drm_panic_clear_description(void)
|
||||
{
|
||||
struct drm_panic_line *desc_line = &panic_msg[PANIC_MSG_LINES - 1];
|
||||
struct drm_panic_line *desc_line = &panic_msg[panic_msg_lines - 1];
|
||||
|
||||
desc_line->len = 0;
|
||||
desc_line->txt = NULL;
|
||||
@@ -802,3 +1046,19 @@ void drm_panic_unregister(struct drm_device *dev)
|
||||
kmsg_dump_unregister(&plane->kmsg_panic);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_panic_init() - initialize DRM panic.
|
||||
*/
|
||||
void __init drm_panic_init(void)
|
||||
{
|
||||
drm_panic_qr_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_panic_exit() - Free the resources taken by drm_panic_exit()
|
||||
*/
|
||||
void drm_panic_exit(void)
|
||||
{
|
||||
drm_panic_qr_exit();
|
||||
}
|
||||
|
||||
1003
drivers/gpu/drm/drm_panic_qr.rs
Normal file
1003
drivers/gpu/drm/drm_panic_qr.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -100,8 +100,9 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str)
|
||||
copy = iterator->remain;
|
||||
|
||||
/* Copy out the bit of the string that we need */
|
||||
memcpy(iterator->data,
|
||||
str + (iterator->start - iterator->offset), copy);
|
||||
if (iterator->data)
|
||||
memcpy(iterator->data,
|
||||
str + (iterator->start - iterator->offset), copy);
|
||||
|
||||
iterator->offset = iterator->start + copy;
|
||||
iterator->remain -= copy;
|
||||
@@ -110,7 +111,8 @@ void __drm_puts_coredump(struct drm_printer *p, const char *str)
|
||||
|
||||
len = min_t(ssize_t, strlen(str), iterator->remain);
|
||||
|
||||
memcpy(iterator->data + pos, str, len);
|
||||
if (iterator->data)
|
||||
memcpy(iterator->data + pos, str, len);
|
||||
|
||||
iterator->offset += len;
|
||||
iterator->remain -= len;
|
||||
@@ -140,8 +142,9 @@ void __drm_printfn_coredump(struct drm_printer *p, struct va_format *vaf)
|
||||
if ((iterator->offset >= iterator->start) && (len < iterator->remain)) {
|
||||
ssize_t pos = iterator->offset - iterator->start;
|
||||
|
||||
snprintf(((char *) iterator->data) + pos,
|
||||
iterator->remain, "%pV", vaf);
|
||||
if (iterator->data)
|
||||
snprintf(((char *) iterator->data) + pos,
|
||||
iterator->remain, "%pV", vaf);
|
||||
|
||||
iterator->offset += len;
|
||||
iterator->remain -= len;
|
||||
|
||||
@@ -85,7 +85,6 @@ static u32 clip_scaled(int src, int dst, int *clip)
|
||||
* factors from @src to @dst.
|
||||
*
|
||||
* RETURNS:
|
||||
*
|
||||
* %true if rectangle @dst is still visible after being clipped,
|
||||
* %false otherwise.
|
||||
*/
|
||||
|
||||
@@ -686,7 +686,6 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
||||
* drm_atomic_helper_calc_timestamping_constants().
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Returns true on success, and false on failure, i.e. when no accurate
|
||||
* timestamp could be acquired.
|
||||
*/
|
||||
@@ -831,7 +830,6 @@ EXPORT_SYMBOL(drm_crtc_vblank_helper_get_vblank_timestamp_internal);
|
||||
* drm_atomic_helper_calc_timestamping_constants().
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* Returns true on success, and false on failure, i.e. when no accurate
|
||||
* timestamp could be acquired.
|
||||
*/
|
||||
|
||||
@@ -317,3 +317,7 @@ void intel_dpt_destroy(struct i915_address_space *vm)
|
||||
i915_vm_put(&dpt->vm);
|
||||
}
|
||||
|
||||
u64 intel_dpt_offset(struct i915_vma *dpt_vma)
|
||||
{
|
||||
return dpt_vma->node.start;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef __INTEL_DPT_H__
|
||||
#define __INTEL_DPT_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct drm_i915_private;
|
||||
|
||||
struct i915_address_space;
|
||||
@@ -20,5 +22,6 @@ void intel_dpt_suspend(struct drm_i915_private *i915);
|
||||
void intel_dpt_resume(struct drm_i915_private *i915);
|
||||
struct i915_address_space *
|
||||
intel_dpt_create(struct intel_framebuffer *fb);
|
||||
u64 intel_dpt_offset(struct i915_vma *dpt_vma);
|
||||
|
||||
#endif /* __INTEL_DPT_H__ */
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "intel_de.h"
|
||||
#include "intel_display_irq.h"
|
||||
#include "intel_display_types.h"
|
||||
#include "intel_dpt.h"
|
||||
#include "intel_fb.h"
|
||||
#include "intel_fbc.h"
|
||||
#include "intel_frontbuffer.h"
|
||||
@@ -1162,7 +1163,7 @@ static u32 skl_surf_address(const struct intel_plane_state *plane_state,
|
||||
* within the DPT is always 0.
|
||||
*/
|
||||
drm_WARN_ON(&i915->drm, plane_state->dpt_vma &&
|
||||
plane_state->dpt_vma->node.start);
|
||||
intel_dpt_offset(plane_state->dpt_vma));
|
||||
drm_WARN_ON(&i915->drm, offset & 0x1fffff);
|
||||
return offset >> 9;
|
||||
} else {
|
||||
|
||||
@@ -89,7 +89,6 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj);
|
||||
* @handle: userspace handle
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* A pointer to the object named by the handle if such exists on @filp, NULL
|
||||
* otherwise. This object is only valid whilst under the RCU read lock, and
|
||||
* note carefully the object may be in the process of being destroyed.
|
||||
|
||||
@@ -418,7 +418,6 @@ out_unpin:
|
||||
* For an untiled surface, this removes any existing fence.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* 0 on success, negative error code on failure.
|
||||
*/
|
||||
int i915_vma_pin_fence(struct i915_vma *vma)
|
||||
|
||||
@@ -389,7 +389,6 @@ void i915_vma_unpin_iomap(struct i915_vma *vma);
|
||||
* i915_vma_unpin_fence().
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* True if the vma has a fence, false otherwise.
|
||||
*/
|
||||
int __must_check i915_vma_pin_fence(struct i915_vma *vma);
|
||||
|
||||
@@ -34,7 +34,7 @@ struct imx_parallel_display_encoder {
|
||||
|
||||
struct imx_parallel_display {
|
||||
struct device *dev;
|
||||
void *edid;
|
||||
const struct drm_edid *drm_edid;
|
||||
u32 bus_format;
|
||||
u32 bus_flags;
|
||||
struct drm_display_mode mode;
|
||||
@@ -62,9 +62,9 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
|
||||
if (num_modes > 0)
|
||||
return num_modes;
|
||||
|
||||
if (imxpd->edid) {
|
||||
drm_connector_update_edid_property(connector, imxpd->edid);
|
||||
num_modes = drm_add_edid_modes(connector, imxpd->edid);
|
||||
if (imxpd->drm_edid) {
|
||||
drm_edid_connector_update(connector, imxpd->drm_edid);
|
||||
num_modes = drm_edid_connector_add_modes(connector);
|
||||
}
|
||||
|
||||
if (np) {
|
||||
@@ -331,7 +331,7 @@ static int imx_pd_probe(struct platform_device *pdev)
|
||||
|
||||
edidp = of_get_property(np, "edid", &edid_len);
|
||||
if (edidp)
|
||||
imxpd->edid = devm_kmemdup(dev, edidp, edid_len, GFP_KERNEL);
|
||||
imxpd->drm_edid = drm_edid_alloc(edidp, edid_len);
|
||||
|
||||
ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
|
||||
if (!ret) {
|
||||
@@ -355,7 +355,11 @@ static int imx_pd_probe(struct platform_device *pdev)
|
||||
|
||||
static void imx_pd_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
|
||||
|
||||
component_del(&pdev->dev, &imx_pd_ops);
|
||||
|
||||
drm_edid_free(imxpd->drm_edid);
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_pd_dt_ids[] = {
|
||||
|
||||
@@ -695,6 +695,10 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
|
||||
soc = soc_device_match(omapdrm_soc_devices);
|
||||
priv->omaprev = soc ? (uintptr_t)soc->data : 0;
|
||||
priv->wq = alloc_ordered_workqueue("omapdrm", 0);
|
||||
if (!priv->wq) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_workqueue;
|
||||
}
|
||||
|
||||
mutex_init(&priv->list_lock);
|
||||
INIT_LIST_HEAD(&priv->obj_list);
|
||||
@@ -753,6 +757,7 @@ err_gem_deinit:
|
||||
drm_mode_config_cleanup(ddev);
|
||||
omap_gem_deinit(ddev);
|
||||
destroy_workqueue(priv->wq);
|
||||
err_alloc_workqueue:
|
||||
omap_disconnect_pipelines(ddev);
|
||||
drm_dev_put(ddev);
|
||||
return ret;
|
||||
|
||||
@@ -87,6 +87,15 @@ config DRM_PANEL_BOE_TV101WUM_NL6
|
||||
Say Y here if you want to support for BOE TV101WUM and AUO KD101N80
|
||||
45NA WUXGA PANEL DSI Video Mode panel
|
||||
|
||||
config DRM_PANEL_BOE_TV101WUM_LL2
|
||||
tristate "BOE TV101WUM LL2 1200x1920 panel"
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
Say Y here if you want to support for BOE TV101WUM-LL2
|
||||
WUXGA PANEL DSI Video Mode panel
|
||||
|
||||
config DRM_PANEL_EBBG_FT8719
|
||||
tristate "EBBG FT8719 panel driver"
|
||||
depends on OF
|
||||
|
||||
@@ -6,6 +6,7 @@ obj-$(CONFIG_DRM_PANEL_AUO_A030JTN01) += panel-auo-a030jtn01.o
|
||||
obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o
|
||||
obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o
|
||||
obj-$(CONFIG_DRM_PANEL_BOE_TH101MB31UIG002_28A) += panel-boe-th101mb31ig002-28a.o
|
||||
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_LL2) += panel-boe-tv101wum-ll2.o
|
||||
obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o
|
||||
obj-$(CONFIG_DRM_PANEL_DSI_CM) += panel-dsi-cm.o
|
||||
obj-$(CONFIG_DRM_PANEL_LVDS) += panel-lvds.o
|
||||
|
||||
241
drivers/gpu/drm/panel/panel-boe-tv101wum-ll2.c
Normal file
241
drivers/gpu/drm/panel/panel-boe-tv101wum-ll2.c
Normal file
@@ -0,0 +1,241 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
|
||||
// Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
||||
// Copyright (c) 2024, Neil Armstrong <neil.armstrong@linaro.org>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
struct boe_tv101wum_ll2 {
|
||||
struct drm_panel panel;
|
||||
struct mipi_dsi_device *dsi;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator_bulk_data *supplies;
|
||||
};
|
||||
|
||||
static const struct regulator_bulk_data boe_tv101wum_ll2_supplies[] = {
|
||||
{ .supply = "vsp" },
|
||||
{ .supply = "vsn" },
|
||||
};
|
||||
|
||||
static inline struct boe_tv101wum_ll2 *to_boe_tv101wum_ll2(struct drm_panel *panel)
|
||||
{
|
||||
return container_of(panel, struct boe_tv101wum_ll2, panel);
|
||||
}
|
||||
|
||||
static void boe_tv101wum_ll2_reset(struct boe_tv101wum_ll2 *ctx)
|
||||
{
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||
usleep_range(5000, 6000);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
usleep_range(5000, 6000);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
|
||||
|
||||
msleep(120);
|
||||
}
|
||||
|
||||
static int boe_tv101wum_ll2_on(struct boe_tv101wum_ll2 *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
|
||||
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
|
||||
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0e);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0xff, 0x81, 0x68, 0x6c, 0x22,
|
||||
0x6d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x23);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x94, 0x2c, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x19);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa2, 0x38);
|
||||
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0c);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0xfd);
|
||||
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x00);
|
||||
|
||||
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
|
||||
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static void boe_tv101wum_ll2_off(struct boe_tv101wum_ll2 *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
|
||||
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||
|
||||
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
|
||||
|
||||
mipi_dsi_msleep(&dsi_ctx, 70);
|
||||
|
||||
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
|
||||
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x5a);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x5a);
|
||||
|
||||
mipi_dsi_msleep(&dsi_ctx, 150);
|
||||
}
|
||||
|
||||
static int boe_tv101wum_ll2_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel);
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(boe_tv101wum_ll2_supplies),
|
||||
ctx->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
boe_tv101wum_ll2_reset(ctx);
|
||||
|
||||
ret = boe_tv101wum_ll2_on(ctx);
|
||||
if (ret < 0) {
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies),
|
||||
ctx->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int boe_tv101wum_ll2_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel);
|
||||
|
||||
/* Ignore errors on failure, in any case set gpio and disable regulators */
|
||||
boe_tv101wum_ll2_off(ctx);
|
||||
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies),
|
||||
ctx->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_display_mode boe_tv101wum_ll2_mode = {
|
||||
.clock = (1200 + 27 + 8 + 12) * (1920 + 155 + 8 + 32) * 60 / 1000,
|
||||
.hdisplay = 1200,
|
||||
.hsync_start = 1200 + 27,
|
||||
.hsync_end = 1200 + 27 + 8,
|
||||
.htotal = 1200 + 27 + 8 + 12,
|
||||
.vdisplay = 1920,
|
||||
.vsync_start = 1920 + 155,
|
||||
.vsync_end = 1920 + 155 + 8,
|
||||
.vtotal = 1920 + 155 + 8 + 32,
|
||||
.width_mm = 136,
|
||||
.height_mm = 217,
|
||||
.type = DRM_MODE_TYPE_DRIVER,
|
||||
};
|
||||
|
||||
static int boe_tv101wum_ll2_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
/* We do not set display_info.bpc since unset value is bpc=8 by default */
|
||||
return drm_connector_helper_get_modes_fixed(connector, &boe_tv101wum_ll2_mode);
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs boe_tv101wum_ll2_panel_funcs = {
|
||||
.prepare = boe_tv101wum_ll2_prepare,
|
||||
.unprepare = boe_tv101wum_ll2_unprepare,
|
||||
.get_modes = boe_tv101wum_ll2_get_modes,
|
||||
};
|
||||
|
||||
static int boe_tv101wum_ll2_probe(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct device *dev = &dsi->dev;
|
||||
struct boe_tv101wum_ll2 *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_regulator_bulk_get_const(&dsi->dev,
|
||||
ARRAY_SIZE(boe_tv101wum_ll2_supplies),
|
||||
boe_tv101wum_ll2_supplies,
|
||||
&ctx->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ctx->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
|
||||
"Failed to get reset-gpios\n");
|
||||
|
||||
ctx->dsi = dsi;
|
||||
mipi_dsi_set_drvdata(dsi, ctx);
|
||||
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_VIDEO_HSE;
|
||||
|
||||
drm_panel_init(&ctx->panel, dev, &boe_tv101wum_ll2_panel_funcs,
|
||||
DRM_MODE_CONNECTOR_DSI);
|
||||
ctx->panel.prepare_prev_first = true;
|
||||
|
||||
ret = drm_panel_of_backlight(&ctx->panel);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to get backlight\n");
|
||||
|
||||
drm_panel_add(&ctx->panel);
|
||||
|
||||
ret = mipi_dsi_attach(dsi);
|
||||
if (ret < 0) {
|
||||
drm_panel_remove(&ctx->panel);
|
||||
return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void boe_tv101wum_ll2_remove(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct boe_tv101wum_ll2 *ctx = mipi_dsi_get_drvdata(dsi);
|
||||
int ret;
|
||||
|
||||
ret = mipi_dsi_detach(dsi);
|
||||
if (ret < 0)
|
||||
dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
|
||||
|
||||
drm_panel_remove(&ctx->panel);
|
||||
}
|
||||
|
||||
static const struct of_device_id boe_tv101wum_ll2_of_match[] = {
|
||||
{ .compatible = "boe,tv101wum-ll2" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, boe_tv101wum_ll2_of_match);
|
||||
|
||||
static struct mipi_dsi_driver boe_tv101wum_ll2_driver = {
|
||||
.probe = boe_tv101wum_ll2_probe,
|
||||
.remove = boe_tv101wum_ll2_remove,
|
||||
.driver = {
|
||||
.name = "panel-boe-tv101wum_ll2",
|
||||
.of_match_table = boe_tv101wum_ll2_of_match,
|
||||
},
|
||||
};
|
||||
module_mipi_dsi_driver(boe_tv101wum_ll2_driver);
|
||||
|
||||
MODULE_DESCRIPTION("DRM driver for BOE TV101WUM-LL2 Panel");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1911,6 +1911,7 @@ static const struct edp_panel_entry edp_panels[] = {
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b34, &delay_200_500_e80, "NV122WUM-N41"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b66, &delay_200_500_e80, "NE140WUM-N6G"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cb6, &delay_200_500_e200, "NT116WHM-N44"),
|
||||
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0cfa, &delay_200_500_e50, "NV116WHM-A4D"),
|
||||
@@ -1977,8 +1978,6 @@ static const struct edp_panel_entry edp_panels[] = {
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x05af, &delay_200_500_e200_d200, "Unknown"),
|
||||
EDP_PANEL_ENTRY('L', 'G', 'D', 0x05f1, &delay_200_500_e200_d200, "Unknown"),
|
||||
|
||||
EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"),
|
||||
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"),
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &delay_80_500_e50, "LQ140M1JW46"),
|
||||
EDP_PANEL_ENTRY('S', 'H', 'P', 0x153a, &delay_200_500_e50, "LQ140T1JH01"),
|
||||
|
||||
@@ -47,195 +47,196 @@ static inline struct panel_nv3051d *panel_to_panelnv3051d(struct drm_panel *pane
|
||||
static int panel_nv3051d_init_sequence(struct panel_nv3051d *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
|
||||
|
||||
/*
|
||||
* Init sequence was supplied by device vendor with no
|
||||
* documentation.
|
||||
*/
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xE3, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x03, 0x40);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x04, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x05, 0x03);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x24, 0x12);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x25, 0x1E);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x26, 0x28);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x27, 0x52);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x28, 0x57);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x29, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x2A, 0xDF);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x38, 0x9C);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x39, 0xA7);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x53);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x44, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x49, 0x3C);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x59, 0xFE);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x5C, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x91, 0x77);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x92, 0x77);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x55);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xA1, 0x50);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xA4, 0x9C);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xA7, 0x02);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xA8, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xA9, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xAA, 0xFC);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xAB, 0x28);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xAC, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xAD, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xAE, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xAF, 0x03);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x26);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x28);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x33);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x26);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x26);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x0E);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD1, 0x0E);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x29);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD4, 0x2B);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB2, 0x0C);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD2, 0x0A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB3, 0x28);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD3, 0x28);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD6, 0x0D);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x32);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD7, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xC1, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xE1, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x0A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD8, 0x0A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD9, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xBD, 0x13);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xDD, 0x13);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xBC, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xDC, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xBB, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xDB, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xDA, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xBE, 0x18);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xDE, 0x18);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xBF, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xDF, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xC0, 0x17);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x17);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x3B);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD5, 0x3C);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB0, 0x0B);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0C);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x03);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x00, 0x2A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x01, 0x2A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x02, 0x2A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x03, 0x2A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x04, 0x61);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x05, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x06, 0xC7);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x07, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x08, 0x82);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x09, 0x83);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x30, 0x2A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x31, 0x2A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x32, 0x2A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x33, 0x2A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x34, 0x61);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x35, 0xC5);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x36, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x37, 0x23);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x40, 0x82);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x41, 0x83);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x42, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x43, 0x81);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x44, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x45, 0xF2);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x46, 0xF1);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x47, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x48, 0xF4);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x49, 0xF3);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x50, 0x02);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x51, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x52, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x53, 0x03);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x54, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x55, 0xF6);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x56, 0xF5);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x57, 0x11);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x58, 0xF8);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x59, 0xF7);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x7E, 0x02);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x7F, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xE0, 0x5A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB1, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB4, 0x0E);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB5, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB6, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB7, 0x07);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB8, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xB9, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xBA, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xC7, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xCA, 0x0E);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xCB, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xCC, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xCD, 0x07);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xCE, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xCF, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xD0, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x81, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x84, 0x0E);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x85, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x86, 0x07);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x87, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x88, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x89, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x8A, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x97, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x9A, 0x0E);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x9B, 0x0F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x9C, 0x07);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x9D, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x9E, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x9F, 0x06);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xA0, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x02);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x01, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x02, 0xDA);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x03, 0xBA);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x04, 0xA8);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x05, 0x9A);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x06, 0x70);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x07, 0xFF);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x08, 0x91);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x09, 0x90);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0A, 0xFF);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0B, 0x8F);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0C, 0x60);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0D, 0x58);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0E, 0x48);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x0F, 0x38);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x10, 0x2B);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xFF, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x36, 0x02);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x3A, 0x70);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE3, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x40);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x03);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x24, 0x12);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x25, 0x1E);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x26, 0x28);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x27, 0x52);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x28, 0x57);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x29, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x2A, 0xDF);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x38, 0x9C);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x39, 0xA7);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x53);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0x3C);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0xFE);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x5C, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x91, 0x77);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x92, 0x77);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA0, 0x55);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA1, 0x50);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA4, 0x9C);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA7, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA8, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA9, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAA, 0xFC);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAB, 0x28);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAC, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAD, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAE, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xAF, 0x03);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB0, 0x08);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x26);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB2, 0x28);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB3, 0x28);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x33);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x08);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x26);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x08);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x26);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x0E);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD1, 0x0E);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x29);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD4, 0x2B);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB2, 0x0C);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD2, 0x0A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB3, 0x28);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD3, 0x28);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x11);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD6, 0x0D);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x32);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD7, 0x30);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC1, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE1, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x0A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD8, 0x0A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB9, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD9, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBD, 0x13);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDD, 0x13);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBC, 0x11);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDC, 0x11);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBB, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDB, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBA, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDA, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBE, 0x18);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDE, 0x18);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBF, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xDF, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC0, 0x17);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE0, 0x17);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x3B);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD5, 0x3C);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB0, 0x0B);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD0, 0x0C);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x03);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x2A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x2A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0x2A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x2A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x61);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0xC7);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x82);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x83);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x30, 0x2A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x31, 0x2A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x32, 0x2A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x33, 0x2A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x34, 0x61);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x35, 0xC5);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x37, 0x23);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x40, 0x82);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x41, 0x83);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x42, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x43, 0x81);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x44, 0x11);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x45, 0xF2);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x46, 0xF1);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x47, 0x11);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x48, 0xF4);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x49, 0xF3);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x51, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x52, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x53, 0x03);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x54, 0x11);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x55, 0xF6);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x56, 0xF5);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x57, 0x11);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x58, 0xF8);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0xF7);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7E, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7F, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xE0, 0x5A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB1, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB4, 0x0E);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB5, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB6, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB7, 0x07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB8, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xB9, 0x05);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xBA, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xC7, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCA, 0x0E);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCB, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCC, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCD, 0x07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCE, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xCF, 0x05);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xD0, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x81, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x84, 0x0E);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x85, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x86, 0x07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x87, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x88, 0x05);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x89, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x8A, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x97, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9A, 0x0E);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9B, 0x0F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9C, 0x07);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9D, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9E, 0x05);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x9F, 0x06);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xA0, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x01, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x02, 0xDA);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0xBA);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0xA8);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x9A);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x06, 0x70);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x07, 0xFF);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x08, 0x91);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x09, 0x90);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0A, 0xFF);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0B, 0x8F);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0C, 0x60);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0D, 0x58);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0E, 0x48);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x0F, 0x38);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x10, 0x2B);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x30);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x52);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xFF, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x36, 0x02);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x3A, 0x70);
|
||||
|
||||
dev_dbg(ctx->dev, "Panel init sequence done\n");
|
||||
|
||||
|
||||
@@ -100,106 +100,87 @@ static void nt35950_reset(struct nt35950 *nt)
|
||||
|
||||
/*
|
||||
* nt35950_set_cmd2_page - Select manufacturer control (CMD2) page
|
||||
* @dsi_ctx: context for mipi_dsi functions
|
||||
* @nt: Main driver structure
|
||||
* @page: Page number (0-7)
|
||||
*
|
||||
* Return: Number of transferred bytes or negative number on error
|
||||
*/
|
||||
static int nt35950_set_cmd2_page(struct nt35950 *nt, u8 page)
|
||||
static void nt35950_set_cmd2_page(struct mipi_dsi_multi_context *dsi_ctx,
|
||||
struct nt35950 *nt, u8 page)
|
||||
{
|
||||
const u8 mauc_cmd2_page[] = { MCS_CMD_MAUCCTR, 0x55, 0xaa, 0x52,
|
||||
0x08, page };
|
||||
int ret;
|
||||
|
||||
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], mauc_cmd2_page,
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, mauc_cmd2_page,
|
||||
ARRAY_SIZE(mauc_cmd2_page));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
nt->last_page = page;
|
||||
return 0;
|
||||
if (!dsi_ctx->accum_err)
|
||||
nt->last_page = page;
|
||||
}
|
||||
|
||||
/*
|
||||
* nt35950_set_data_compression - Set data compression mode
|
||||
* @dsi_ctx: context for mipi_dsi functions
|
||||
* @nt: Main driver structure
|
||||
* @comp_mode: Compression mode
|
||||
*
|
||||
* Return: Number of transferred bytes or negative number on error
|
||||
*/
|
||||
static int nt35950_set_data_compression(struct nt35950 *nt, u8 comp_mode)
|
||||
static void nt35950_set_data_compression(struct mipi_dsi_multi_context *dsi_ctx,
|
||||
struct nt35950 *nt, u8 comp_mode)
|
||||
{
|
||||
u8 cmd_data_compression[] = { MCS_PARAM_DATA_COMPRESSION, comp_mode };
|
||||
u8 cmd_vesa_dsc_on[] = { MCS_PARAM_VESA_DSC_ON, !!comp_mode };
|
||||
u8 cmd_vesa_dsc_setting[] = { MCS_PARAM_VESA_DSC_SETTING, 0x03 };
|
||||
u8 last_page = nt->last_page;
|
||||
int ret;
|
||||
|
||||
/* Set CMD2 Page 0 if we're not there yet */
|
||||
if (last_page != 0) {
|
||||
ret = nt35950_set_cmd2_page(nt, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (last_page != 0)
|
||||
nt35950_set_cmd2_page(dsi_ctx, nt, 0);
|
||||
|
||||
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_data_compression,
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_data_compression,
|
||||
ARRAY_SIZE(cmd_data_compression));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_on,
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_vesa_dsc_on,
|
||||
ARRAY_SIZE(cmd_vesa_dsc_on));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Set the vesa dsc setting on Page 4 */
|
||||
ret = nt35950_set_cmd2_page(nt, 4);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
nt35950_set_cmd2_page(dsi_ctx, nt, 4);
|
||||
|
||||
/* Display Stream Compression setting, always 0x03 */
|
||||
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_vesa_dsc_setting,
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_vesa_dsc_setting,
|
||||
ARRAY_SIZE(cmd_vesa_dsc_setting));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Get back to the previously set page */
|
||||
return nt35950_set_cmd2_page(nt, last_page);
|
||||
nt35950_set_cmd2_page(dsi_ctx, nt, last_page);
|
||||
}
|
||||
|
||||
/*
|
||||
* nt35950_set_scaler - Enable/disable resolution upscaling
|
||||
* @nt: Main driver structure
|
||||
* @dsi_ctx: context for mipi_dsi functions
|
||||
* @scale_up: Scale up function control
|
||||
*
|
||||
* Return: Number of transferred bytes or negative number on error
|
||||
*/
|
||||
static int nt35950_set_scaler(struct nt35950 *nt, u8 scale_up)
|
||||
static void nt35950_set_scaler(struct mipi_dsi_multi_context *dsi_ctx,
|
||||
u8 scale_up)
|
||||
{
|
||||
u8 cmd_scaler[] = { MCS_PARAM_SCALER_FUNCTION, scale_up };
|
||||
|
||||
return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler,
|
||||
ARRAY_SIZE(cmd_scaler));
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_scaler,
|
||||
ARRAY_SIZE(cmd_scaler));
|
||||
}
|
||||
|
||||
/*
|
||||
* nt35950_set_scale_mode - Resolution upscaling mode
|
||||
* @nt: Main driver structure
|
||||
* @dsi_ctx: context for mipi_dsi functions
|
||||
* @mode: Scaler mode (MCS_DATA_COMPRESSION_*)
|
||||
*
|
||||
* Return: Number of transferred bytes or negative number on error
|
||||
*/
|
||||
static int nt35950_set_scale_mode(struct nt35950 *nt, u8 mode)
|
||||
static void nt35950_set_scale_mode(struct mipi_dsi_multi_context *dsi_ctx,
|
||||
u8 mode)
|
||||
{
|
||||
u8 cmd_scaler[] = { MCS_PARAM_SCALEUP_MODE, mode };
|
||||
|
||||
return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_scaler,
|
||||
ARRAY_SIZE(cmd_scaler));
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_scaler,
|
||||
ARRAY_SIZE(cmd_scaler));
|
||||
}
|
||||
|
||||
/*
|
||||
* nt35950_inject_black_image - Display a completely black image
|
||||
* @nt: Main driver structure
|
||||
* @dsi_ctx: context for mipi_dsi functions
|
||||
*
|
||||
* After IC setup, the attached panel may show random data
|
||||
* due to driveric behavior changes (resolution, compression,
|
||||
@@ -208,43 +189,34 @@ static int nt35950_set_scale_mode(struct nt35950 *nt, u8 mode)
|
||||
* the display.
|
||||
* It makes sense to push a black image before sending the sleep-out
|
||||
* and display-on commands.
|
||||
*
|
||||
* Return: Number of transferred bytes or negative number on error
|
||||
*/
|
||||
static int nt35950_inject_black_image(struct nt35950 *nt)
|
||||
static void nt35950_inject_black_image(struct mipi_dsi_multi_context *dsi_ctx)
|
||||
{
|
||||
const u8 cmd0_black_img[] = { 0x6f, 0x01 };
|
||||
const u8 cmd1_black_img[] = { 0xf3, 0x10 };
|
||||
u8 cmd_test[] = { 0xff, 0xaa, 0x55, 0xa5, 0x80 };
|
||||
int ret;
|
||||
|
||||
/* Enable test command */
|
||||
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_test, ARRAY_SIZE(cmd_test));
|
||||
|
||||
/* Send a black image */
|
||||
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd0_black_img,
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd0_black_img,
|
||||
ARRAY_SIZE(cmd0_black_img));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd1_black_img,
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd1_black_img,
|
||||
ARRAY_SIZE(cmd1_black_img));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Disable test command */
|
||||
cmd_test[ARRAY_SIZE(cmd_test) - 1] = 0x00;
|
||||
return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_test, ARRAY_SIZE(cmd_test));
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_test, ARRAY_SIZE(cmd_test));
|
||||
}
|
||||
|
||||
/*
|
||||
* nt35950_set_dispout - Set Display Output register parameters
|
||||
* @nt: Main driver structure
|
||||
*
|
||||
* Return: Number of transferred bytes or negative number on error
|
||||
* @dsi_ctx: context for mipi_dsi functions
|
||||
*/
|
||||
static int nt35950_set_dispout(struct nt35950 *nt)
|
||||
static void nt35950_set_dispout(struct mipi_dsi_multi_context *dsi_ctx,
|
||||
struct nt35950 *nt)
|
||||
{
|
||||
u8 cmd_dispout[] = { MCS_PARAM_DISP_OUTPUT_CTRL, 0x00 };
|
||||
const struct nt35950_panel_mode *mode_data = nt->desc->mode_data;
|
||||
@@ -254,8 +226,8 @@ static int nt35950_set_dispout(struct nt35950 *nt)
|
||||
if (mode_data[nt->cur_mode].enable_sram)
|
||||
cmd_dispout[1] |= MCS_DISP_OUT_SRAM_EN;
|
||||
|
||||
return mipi_dsi_dcs_write_buffer(nt->dsi[0], cmd_dispout,
|
||||
ARRAY_SIZE(cmd_dispout));
|
||||
mipi_dsi_dcs_write_buffer_multi(dsi_ctx, cmd_dispout,
|
||||
ARRAY_SIZE(cmd_dispout));
|
||||
}
|
||||
|
||||
static int nt35950_get_current_mode(struct nt35950 *nt)
|
||||
@@ -284,78 +256,47 @@ static int nt35950_on(struct nt35950 *nt)
|
||||
{
|
||||
const struct nt35950_panel_mode *mode_data = nt->desc->mode_data;
|
||||
struct mipi_dsi_device *dsi = nt->dsi[0];
|
||||
struct device *dev = &dsi->dev;
|
||||
int ret;
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
|
||||
nt->cur_mode = nt35950_get_current_mode(nt);
|
||||
nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
ret = nt35950_set_cmd2_page(nt, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
nt35950_set_cmd2_page(&dsi_ctx, nt, 0);
|
||||
nt35950_set_data_compression(&dsi_ctx, nt, mode_data[nt->cur_mode].compression);
|
||||
nt35950_set_scale_mode(&dsi_ctx, mode_data[nt->cur_mode].scaler_mode);
|
||||
nt35950_set_scaler(&dsi_ctx, mode_data[nt->cur_mode].scaler_on);
|
||||
nt35950_set_dispout(&dsi_ctx, nt);
|
||||
|
||||
ret = nt35950_set_data_compression(nt, mode_data[nt->cur_mode].compression);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = nt35950_set_scale_mode(nt, mode_data[nt->cur_mode].scaler_mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = nt35950_set_scaler(nt, mode_data[nt->cur_mode].scaler_on);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = nt35950_set_dispout(nt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set tear on: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mipi_dsi_dcs_set_tear_scanline(dsi, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set tear scanline: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
mipi_dsi_dcs_set_tear_scanline_multi(&dsi_ctx, 0);
|
||||
|
||||
/* CMD2 Page 1 */
|
||||
ret = nt35950_set_cmd2_page(nt, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
nt35950_set_cmd2_page(&dsi_ctx, nt, 1);
|
||||
|
||||
/* Unknown command */
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x88, 0x88);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x88, 0x88);
|
||||
|
||||
/* CMD2 Page 7 */
|
||||
ret = nt35950_set_cmd2_page(nt, 7);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
nt35950_set_cmd2_page(&dsi_ctx, nt, 7);
|
||||
|
||||
/* Enable SubPixel Rendering */
|
||||
mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_EN, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MCS_PARAM_SPR_EN, 0x01);
|
||||
|
||||
/* SPR Mode: YYG Rainbow-RGB */
|
||||
mipi_dsi_dcs_write_seq(dsi, MCS_PARAM_SPR_MODE, MCS_SPR_MODE_YYG_RAINBOW_RGB);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MCS_PARAM_SPR_MODE,
|
||||
MCS_SPR_MODE_YYG_RAINBOW_RGB);
|
||||
|
||||
/* CMD3 */
|
||||
ret = nt35950_inject_black_image(nt);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
nt35950_inject_black_image(&dsi_ctx);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||
|
||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
msleep(120);
|
||||
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_on(dsi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
msleep(120);
|
||||
if (dsi_ctx.accum_err)
|
||||
return dsi_ctx.accum_err;
|
||||
|
||||
nt->dsi[0]->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||
nt->dsi[1]->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||
@@ -363,30 +304,19 @@ static int nt35950_on(struct nt35950 *nt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nt35950_off(struct nt35950 *nt)
|
||||
static void nt35950_off(struct nt35950 *nt)
|
||||
{
|
||||
struct device *dev = &nt->dsi[0]->dev;
|
||||
int ret;
|
||||
struct mipi_dsi_device *dsi = nt->dsi[0];
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_off(nt->dsi[0]);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set display off: %d\n", ret);
|
||||
goto set_lpm;
|
||||
}
|
||||
usleep_range(10000, 11000);
|
||||
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
|
||||
mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000);
|
||||
|
||||
ret = mipi_dsi_dcs_enter_sleep_mode(nt->dsi[0]);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
|
||||
goto set_lpm;
|
||||
}
|
||||
msleep(150);
|
||||
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 150);
|
||||
|
||||
set_lpm:
|
||||
nt->dsi[0]->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
nt->dsi[1]->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nt35950_sharp_init_vregs(struct nt35950 *nt, struct device *dev)
|
||||
@@ -427,7 +357,6 @@ static int nt35950_sharp_init_vregs(struct nt35950 *nt, struct device *dev)
|
||||
static int nt35950_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct nt35950 *nt = to_nt35950(panel);
|
||||
struct device *dev = &nt->dsi[0]->dev;
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(nt->vregs[0].consumer);
|
||||
@@ -452,10 +381,6 @@ static int nt35950_prepare(struct drm_panel *panel)
|
||||
nt35950_reset(nt);
|
||||
|
||||
ret = nt35950_on(nt);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to initialize panel: %d\n", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
if (ret < 0) {
|
||||
@@ -469,12 +394,8 @@ end:
|
||||
static int nt35950_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct nt35950 *nt = to_nt35950(panel);
|
||||
struct device *dev = &nt->dsi[0]->dev;
|
||||
int ret;
|
||||
|
||||
ret = nt35950_off(nt);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to deinitialize panel: %d\n", ret);
|
||||
nt35950_off(nt);
|
||||
|
||||
gpiod_set_value_cansleep(nt->reset_gpio, 0);
|
||||
regulator_bulk_disable(ARRAY_SIZE(nt->vregs), nt->vregs);
|
||||
|
||||
@@ -19,7 +19,13 @@ struct visionox_vtdr6130 {
|
||||
struct drm_panel panel;
|
||||
struct mipi_dsi_device *dsi;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct regulator_bulk_data supplies[3];
|
||||
struct regulator_bulk_data *supplies;
|
||||
};
|
||||
|
||||
static const struct regulator_bulk_data visionox_vtdr6130_supplies[] = {
|
||||
{ .supply = "vddio" },
|
||||
{ .supply = "vci" },
|
||||
{ .supply = "vdd" },
|
||||
};
|
||||
|
||||
static inline struct visionox_vtdr6130 *to_visionox_vtdr6130(struct drm_panel *panel)
|
||||
@@ -40,123 +46,106 @@ static void visionox_vtdr6130_reset(struct visionox_vtdr6130 *ctx)
|
||||
static int visionox_vtdr6130_on(struct visionox_vtdr6130 *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
struct device *dev = &dsi->dev;
|
||||
int ret;
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
|
||||
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
|
||||
|
||||
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
if (ret)
|
||||
return ret;
|
||||
mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
|
||||
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
|
||||
mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x59, 0x09);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x6c, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x6d, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x6f, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x70,
|
||||
0x12, 0x00, 0x00, 0xab, 0x30, 0x80, 0x09, 0x60, 0x04,
|
||||
0x38, 0x00, 0x28, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00,
|
||||
0x02, 0x0e, 0x00, 0x20, 0x03, 0xdd, 0x00, 0x07, 0x00,
|
||||
0x0c, 0x02, 0x77, 0x02, 0x8b, 0x18, 0x00, 0x10, 0xf0,
|
||||
0x07, 0x10, 0x20, 0x00, 0x06, 0x0f, 0x0f, 0x33, 0x0e,
|
||||
0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70, 0x77,
|
||||
0x79, 0x7b, 0x7d, 0x7e, 0x02, 0x02, 0x22, 0x00, 0x2a,
|
||||
0x40, 0x2a, 0xbe, 0x3a, 0xfc, 0x3a, 0xfa, 0x3a, 0xf8,
|
||||
0x3b, 0x38, 0x3b, 0x78, 0x3b, 0xb6, 0x4b, 0xb6, 0x4b,
|
||||
0xf4, 0x4b, 0xf4, 0x6c, 0x34, 0x84, 0x74, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x10);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb1,
|
||||
0x01, 0x38, 0x00, 0x14, 0x00, 0x1c, 0x00, 0x01, 0x66,
|
||||
0x00, 0x14, 0x00, 0x14, 0x00, 0x01, 0x66, 0x00, 0x14,
|
||||
0x05, 0xcc, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x13);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xce,
|
||||
0x09, 0x11, 0x09, 0x11, 0x08, 0xc1, 0x07, 0xfa, 0x05,
|
||||
0xa4, 0x00, 0x3c, 0x00, 0x34, 0x00, 0x24, 0x00, 0x0c,
|
||||
0x00, 0x0c, 0x04, 0x00, 0x35);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x14);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x03, 0x33);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb4,
|
||||
0x00, 0x33, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,
|
||||
0x3e, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb5,
|
||||
0x00, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x06, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xb9, 0x00, 0x00, 0x08, 0x09, 0x09, 0x09);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xbc,
|
||||
0x10, 0x00, 0x00, 0x06, 0x11, 0x09, 0x3b, 0x09, 0x47,
|
||||
0x09, 0x47, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xbe,
|
||||
0x10, 0x10, 0x00, 0x08, 0x22, 0x09, 0x19, 0x09, 0x25,
|
||||
0x09, 0x25, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x80);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x14);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xfa, 0x08, 0x08, 0x08);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x81);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x05);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf3, 0x0f);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xaa, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x82);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf9, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x51, 0x83);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x04);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf8, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0x65, 0x01);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xf4, 0x9a);
|
||||
mipi_dsi_dcs_write_seq(dsi, 0xff, 0x5a, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx,
|
||||
MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx,
|
||||
MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0x00,
|
||||
0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x59, 0x09);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6c, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6d, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x6f, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x12, 0x00, 0x00, 0xab,
|
||||
0x30, 0x80, 0x09, 0x60, 0x04, 0x38, 0x00,
|
||||
0x28, 0x02, 0x1c, 0x02, 0x1c, 0x02, 0x00,
|
||||
0x02, 0x0e, 0x00, 0x20, 0x03, 0xdd, 0x00,
|
||||
0x07, 0x00, 0x0c, 0x02, 0x77, 0x02, 0x8b,
|
||||
0x18, 0x00, 0x10, 0xf0, 0x07, 0x10, 0x20,
|
||||
0x00, 0x06, 0x0f, 0x0f, 0x33, 0x0e, 0x1c,
|
||||
0x2a, 0x38, 0x46, 0x54, 0x62, 0x69, 0x70,
|
||||
0x77, 0x79, 0x7b, 0x7d, 0x7e, 0x02, 0x02,
|
||||
0x22, 0x00, 0x2a, 0x40, 0x2a, 0xbe, 0x3a,
|
||||
0xfc, 0x3a, 0xfa, 0x3a, 0xf8, 0x3b, 0x38,
|
||||
0x3b, 0x78, 0x3b, 0xb6, 0x4b, 0xb6, 0x4b,
|
||||
0xf4, 0x4b, 0xf4, 0x6c, 0x34, 0x84, 0x74,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x10);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x01, 0x38, 0x00, 0x14,
|
||||
0x00, 0x1c, 0x00, 0x01, 0x66, 0x00, 0x14,
|
||||
0x00, 0x14, 0x00, 0x01, 0x66, 0x00, 0x14,
|
||||
0x05, 0xcc, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x13);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xce, 0x09, 0x11, 0x09, 0x11,
|
||||
0x08, 0xc1, 0x07, 0xfa, 0x05, 0xa4, 0x00,
|
||||
0x3c, 0x00, 0x34, 0x00, 0x24, 0x00, 0x0c,
|
||||
0x00, 0x0c, 0x04, 0x00, 0x35);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x14);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x03, 0x33);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x00, 0x33, 0x00, 0x00,
|
||||
0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00,
|
||||
0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb5, 0x00, 0x09, 0x09, 0x09,
|
||||
0x09, 0x09, 0x09, 0x06, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x00, 0x00, 0x08, 0x09,
|
||||
0x09, 0x09);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbc, 0x10, 0x00, 0x00, 0x06,
|
||||
0x11, 0x09, 0x3b, 0x09, 0x47, 0x09, 0x47,
|
||||
0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbe, 0x10, 0x10, 0x00, 0x08,
|
||||
0x22, 0x09, 0x19, 0x09, 0x25, 0x09, 0x25,
|
||||
0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x80);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x14);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfa, 0x08, 0x08, 0x08);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x81);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x05);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x0f);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xaa, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x82);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf9, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x51, 0x83);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x04);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf8, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x00);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x65, 0x01);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf4, 0x9a);
|
||||
mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xff, 0x5a, 0x00);
|
||||
|
||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(120);
|
||||
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_on(dsi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set display on: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(20);
|
||||
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
|
||||
return 0;
|
||||
return dsi_ctx.accum_err;
|
||||
}
|
||||
|
||||
static int visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx)
|
||||
static void visionox_vtdr6130_off(struct visionox_vtdr6130 *ctx)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
struct device *dev = &dsi->dev;
|
||||
int ret;
|
||||
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
|
||||
|
||||
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_off(dsi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set display off: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(20);
|
||||
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 20);
|
||||
|
||||
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
msleep(120);
|
||||
|
||||
return 0;
|
||||
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
|
||||
mipi_dsi_msleep(&dsi_ctx, 120);
|
||||
}
|
||||
|
||||
static int visionox_vtdr6130_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
|
||||
struct device *dev = &ctx->dsi->dev;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies),
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(visionox_vtdr6130_supplies),
|
||||
ctx->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -165,9 +154,9 @@ static int visionox_vtdr6130_prepare(struct drm_panel *panel)
|
||||
|
||||
ret = visionox_vtdr6130_on(ctx);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to initialize panel: %d\n", ret);
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
|
||||
regulator_bulk_disable(ARRAY_SIZE(visionox_vtdr6130_supplies),
|
||||
ctx->supplies);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -177,16 +166,13 @@ static int visionox_vtdr6130_prepare(struct drm_panel *panel)
|
||||
static int visionox_vtdr6130_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct visionox_vtdr6130 *ctx = to_visionox_vtdr6130(panel);
|
||||
struct device *dev = &ctx->dsi->dev;
|
||||
int ret;
|
||||
|
||||
ret = visionox_vtdr6130_off(ctx);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
|
||||
visionox_vtdr6130_off(ctx);
|
||||
|
||||
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
|
||||
regulator_bulk_disable(ARRAY_SIZE(visionox_vtdr6130_supplies),
|
||||
ctx->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -266,12 +252,10 @@ static int visionox_vtdr6130_probe(struct mipi_dsi_device *dsi)
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->supplies[0].supply = "vddio";
|
||||
ctx->supplies[1].supply = "vci";
|
||||
ctx->supplies[2].supply = "vdd";
|
||||
|
||||
ret = devm_regulator_bulk_get(&dsi->dev, ARRAY_SIZE(ctx->supplies),
|
||||
ctx->supplies);
|
||||
ret = devm_regulator_bulk_get_const(&dsi->dev,
|
||||
ARRAY_SIZE(visionox_vtdr6130_supplies),
|
||||
visionox_vtdr6130_supplies,
|
||||
&ctx->supplies);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -60,14 +60,6 @@ config DRM_RCAR_MIPI_DSI
|
||||
select DRM_MIPI_DSI
|
||||
select RESET_CONTROLLER
|
||||
|
||||
config DRM_RZG2L_MIPI_DSI
|
||||
tristate "RZ/G2L MIPI DSI Encoder Support"
|
||||
depends on DRM && DRM_BRIDGE && OF
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
select DRM_MIPI_DSI
|
||||
help
|
||||
Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.
|
||||
|
||||
config DRM_RCAR_VSP
|
||||
bool "R-Car DU VSP Compositor Support" if ARM
|
||||
default y if ARM64
|
||||
|
||||
@@ -14,5 +14,3 @@ obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o
|
||||
obj-$(CONFIG_DRM_RCAR_DW_HDMI) += rcar_dw_hdmi.o
|
||||
obj-$(CONFIG_DRM_RCAR_LVDS) += rcar_lvds.o
|
||||
obj-$(CONFIG_DRM_RCAR_MIPI_DSI) += rcar_mipi_dsi.o
|
||||
|
||||
obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o
|
||||
|
||||
@@ -10,3 +10,11 @@ config DRM_RZG2L_DU
|
||||
help
|
||||
Choose this option if you have an RZ/G2L alike chipset.
|
||||
If M is selected the module will be called rzg2l-du-drm.
|
||||
|
||||
config DRM_RZG2L_MIPI_DSI
|
||||
tristate "RZ/G2L MIPI DSI Encoder Support"
|
||||
depends on DRM && DRM_BRIDGE && OF
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
select DRM_MIPI_DSI
|
||||
help
|
||||
Enable support for the RZ/G2L Display Unit embedded MIPI DSI encoders.
|
||||
|
||||
@@ -6,3 +6,5 @@ rzg2l-du-drm-y := rzg2l_du_crtc.o \
|
||||
|
||||
rzg2l-du-drm-$(CONFIG_VIDEO_RENESAS_VSP1) += rzg2l_du_vsp.o
|
||||
obj-$(CONFIG_DRM_RZG2L_DU) += rzg2l-du-drm.o
|
||||
|
||||
obj-$(CONFIG_DRM_RZG2L_MIPI_DSI) += rzg2l_mipi_dsi.o
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "rzg2l_du_vsp.h"
|
||||
|
||||
#define DU_MCR0 0x00
|
||||
#define DU_MCR0_DPI_OE BIT(0)
|
||||
#define DU_MCR0_DI_EN BIT(8)
|
||||
|
||||
#define DU_DITR0 0x10
|
||||
@@ -216,9 +217,14 @@ static void rzg2l_du_crtc_put(struct rzg2l_du_crtc *rcrtc)
|
||||
|
||||
static void rzg2l_du_start_stop(struct rzg2l_du_crtc *rcrtc, bool start)
|
||||
{
|
||||
struct rzg2l_du_crtc_state *rstate = to_rzg2l_crtc_state(rcrtc->crtc.state);
|
||||
struct rzg2l_du_device *rcdu = rcrtc->dev;
|
||||
u32 val = DU_MCR0_DI_EN;
|
||||
|
||||
writel(start ? DU_MCR0_DI_EN : 0, rcdu->mmio + DU_MCR0);
|
||||
if (rstate->outputs & BIT(RZG2L_DU_OUTPUT_DPAD0))
|
||||
val |= DU_MCR0_DPI_OE;
|
||||
|
||||
writel(start ? val : 0, rcdu->mmio + DU_MCR0);
|
||||
}
|
||||
|
||||
static void rzg2l_du_crtc_start(struct rzg2l_du_crtc *rcrtc)
|
||||
|
||||
@@ -25,6 +25,16 @@
|
||||
* Device Information
|
||||
*/
|
||||
|
||||
static const struct rzg2l_du_device_info rzg2l_du_r9a07g043u_info = {
|
||||
.channels_mask = BIT(0),
|
||||
.routes = {
|
||||
[RZG2L_DU_OUTPUT_DPAD0] = {
|
||||
.possible_outputs = BIT(0),
|
||||
.port = 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = {
|
||||
.channels_mask = BIT(0),
|
||||
.routes = {
|
||||
@@ -40,6 +50,7 @@ static const struct rzg2l_du_device_info rzg2l_du_r9a07g044_info = {
|
||||
};
|
||||
|
||||
static const struct of_device_id rzg2l_du_of_table[] = {
|
||||
{ .compatible = "renesas,r9a07g043u-du", .data = &rzg2l_du_r9a07g043u_info },
|
||||
{ .compatible = "renesas,r9a07g044-du", .data = &rzg2l_du_r9a07g044_info },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
@@ -183,7 +183,8 @@ static int rzg2l_du_encoders_init(struct rzg2l_du_device *rcdu)
|
||||
|
||||
/* Find the output route corresponding to the port number. */
|
||||
for (i = 0; i < RZG2L_DU_OUTPUT_MAX; ++i) {
|
||||
if (rcdu->info->routes[i].port == ep.port) {
|
||||
if (rcdu->info->routes[i].possible_outputs &&
|
||||
rcdu->info->routes[i].port == ep.port) {
|
||||
output = i;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -974,28 +974,32 @@ static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
|
||||
|
||||
static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
const struct drm_display_info *info = &connector->display_info;
|
||||
struct sti_hdmi_connector *hdmi_connector
|
||||
= to_sti_hdmi_connector(connector);
|
||||
struct sti_hdmi *hdmi = hdmi_connector->hdmi;
|
||||
struct edid *edid;
|
||||
const struct drm_edid *drm_edid;
|
||||
int count;
|
||||
|
||||
DRM_DEBUG_DRIVER("\n");
|
||||
|
||||
edid = drm_get_edid(connector, hdmi->ddc_adapt);
|
||||
if (!edid)
|
||||
drm_edid = drm_edid_read(connector);
|
||||
|
||||
drm_edid_connector_update(connector, drm_edid);
|
||||
|
||||
cec_notifier_set_phys_addr(hdmi->notifier,
|
||||
connector->display_info.source_physical_address);
|
||||
|
||||
if (!drm_edid)
|
||||
goto fail;
|
||||
|
||||
cec_notifier_set_phys_addr_from_edid(hdmi->notifier, edid);
|
||||
|
||||
count = drm_add_edid_modes(connector, edid);
|
||||
drm_connector_update_edid_property(connector, edid);
|
||||
count = drm_edid_connector_add_modes(connector);
|
||||
|
||||
DRM_DEBUG_KMS("%s : %dx%d cm\n",
|
||||
(connector->display_info.is_hdmi ? "hdmi monitor" : "dvi monitor"),
|
||||
edid->width_cm, edid->height_cm);
|
||||
info->is_hdmi ? "hdmi monitor" : "dvi monitor",
|
||||
info->width_mm / 10, info->height_mm / 10);
|
||||
|
||||
kfree(edid);
|
||||
drm_edid_free(drm_edid);
|
||||
return count;
|
||||
|
||||
fail:
|
||||
|
||||
@@ -133,7 +133,7 @@ struct tegra_output {
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
struct i2c_adapter *ddc;
|
||||
const struct edid *edid;
|
||||
const struct drm_edid *drm_edid;
|
||||
struct cec_notifier *cec;
|
||||
unsigned int hpd_irq;
|
||||
struct gpio_desc *hpd_gpio;
|
||||
|
||||
@@ -46,6 +46,7 @@ struct gr3d {
|
||||
unsigned int nclocks;
|
||||
struct reset_control_bulk_data resets[RST_GR3D_MAX];
|
||||
unsigned int nresets;
|
||||
struct dev_pm_domain_list *pd_list;
|
||||
|
||||
DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS);
|
||||
};
|
||||
@@ -369,18 +370,12 @@ static int gr3d_power_up_legacy_domain(struct device *dev, const char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gr3d_del_link(void *link)
|
||||
{
|
||||
device_link_del(link);
|
||||
}
|
||||
|
||||
static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
|
||||
{
|
||||
static const char * const opp_genpd_names[] = { "3d0", "3d1", NULL };
|
||||
const u32 link_flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME;
|
||||
struct device **opp_virt_devs, *pd_dev;
|
||||
struct device_link *link;
|
||||
unsigned int i;
|
||||
struct dev_pm_domain_attach_data pd_data = {
|
||||
.pd_names = (const char *[]) { "3d0", "3d1" },
|
||||
.num_pd_names = 2,
|
||||
};
|
||||
int err;
|
||||
|
||||
err = of_count_phandle_with_args(dev->of_node, "power-domains",
|
||||
@@ -414,29 +409,10 @@ static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
|
||||
if (dev->pm_domain)
|
||||
return 0;
|
||||
|
||||
err = devm_pm_opp_attach_genpd(dev, opp_genpd_names, &opp_virt_devs);
|
||||
if (err)
|
||||
err = dev_pm_domain_attach_list(dev, &pd_data, &gr3d->pd_list);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 0; opp_genpd_names[i]; i++) {
|
||||
pd_dev = opp_virt_devs[i];
|
||||
if (!pd_dev) {
|
||||
dev_err(dev, "failed to get %s power domain\n",
|
||||
opp_genpd_names[i]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
link = device_link_add(dev, pd_dev, link_flags);
|
||||
if (!link) {
|
||||
dev_err(dev, "failed to link to %s\n", dev_name(pd_dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = devm_add_action_or_reset(dev, gr3d_del_link, link);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -527,13 +503,13 @@ static int gr3d_probe(struct platform_device *pdev)
|
||||
|
||||
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
|
||||
if (err)
|
||||
return err;
|
||||
goto err;
|
||||
|
||||
err = host1x_client_register(&gr3d->client.base);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to register host1x client: %d\n",
|
||||
err);
|
||||
return err;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* initialize address register map */
|
||||
@@ -541,6 +517,9 @@ static int gr3d_probe(struct platform_device *pdev)
|
||||
set_bit(gr3d_addr_regs[i], gr3d->addr_regs);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev_pm_domain_detach_list(gr3d->pd_list);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void gr3d_remove(struct platform_device *pdev)
|
||||
@@ -549,6 +528,7 @@ static void gr3d_remove(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
host1x_client_unregister(&gr3d->client.base);
|
||||
dev_pm_domain_detach_list(gr3d->pd_list);
|
||||
}
|
||||
|
||||
static int __maybe_unused gr3d_runtime_suspend(struct device *dev)
|
||||
|
||||
@@ -521,12 +521,11 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
|
||||
|
||||
static inline u32 compute_phase_incr(fixed20_12 in, unsigned int out)
|
||||
{
|
||||
u64 tmp, tmp1, tmp2;
|
||||
u64 tmp, tmp1;
|
||||
|
||||
tmp = (u64)dfixed_trunc(in);
|
||||
tmp2 = (u64)out;
|
||||
tmp1 = (tmp << NFB) + (tmp2 >> 1);
|
||||
do_div(tmp1, tmp2);
|
||||
tmp1 = (tmp << NFB) + ((u64)out >> 1);
|
||||
do_div(tmp1, out);
|
||||
|
||||
return lower_32_bits(tmp1);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
int tegra_output_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct tegra_output *output = connector_to_output(connector);
|
||||
struct edid *edid = NULL;
|
||||
const struct drm_edid *drm_edid;
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
@@ -34,18 +34,17 @@ int tegra_output_connector_get_modes(struct drm_connector *connector)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (output->edid)
|
||||
edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL);
|
||||
if (output->drm_edid)
|
||||
drm_edid = drm_edid_dup(output->drm_edid);
|
||||
else if (output->ddc)
|
||||
edid = drm_get_edid(connector, output->ddc);
|
||||
drm_edid = drm_edid_read_ddc(connector, output->ddc);
|
||||
|
||||
cec_notifier_set_phys_addr_from_edid(output->cec, edid);
|
||||
drm_connector_update_edid_property(connector, edid);
|
||||
drm_edid_connector_update(connector, drm_edid);
|
||||
cec_notifier_set_phys_addr(output->cec,
|
||||
connector->display_info.source_physical_address);
|
||||
|
||||
if (edid) {
|
||||
err = drm_add_edid_modes(connector, edid);
|
||||
kfree(edid);
|
||||
}
|
||||
err = drm_edid_connector_add_modes(connector);
|
||||
drm_edid_free(drm_edid);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -98,6 +97,7 @@ static irqreturn_t hpd_irq(int irq, void *data)
|
||||
int tegra_output_probe(struct tegra_output *output)
|
||||
{
|
||||
struct device_node *ddc, *panel;
|
||||
const void *edid;
|
||||
unsigned long flags;
|
||||
int err, size;
|
||||
|
||||
@@ -124,8 +124,6 @@ int tegra_output_probe(struct tegra_output *output)
|
||||
return PTR_ERR(output->panel);
|
||||
}
|
||||
|
||||
output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
|
||||
|
||||
ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
|
||||
if (ddc) {
|
||||
output->ddc = of_get_i2c_adapter_by_node(ddc);
|
||||
@@ -137,6 +135,9 @@ int tegra_output_probe(struct tegra_output *output)
|
||||
}
|
||||
}
|
||||
|
||||
edid = of_get_property(output->of_node, "nvidia,edid", &size);
|
||||
output->drm_edid = drm_edid_alloc(edid, size);
|
||||
|
||||
output->hpd_gpio = devm_fwnode_gpiod_get(output->dev,
|
||||
of_fwnode_handle(output->of_node),
|
||||
"nvidia,hpd",
|
||||
@@ -187,6 +188,8 @@ put_i2c:
|
||||
if (output->ddc)
|
||||
i2c_put_adapter(output->ddc);
|
||||
|
||||
drm_edid_free(output->drm_edid);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -197,6 +200,8 @@ void tegra_output_remove(struct tegra_output *output)
|
||||
|
||||
if (output->ddc)
|
||||
i2c_put_adapter(output->ddc);
|
||||
|
||||
drm_edid_free(output->drm_edid);
|
||||
}
|
||||
|
||||
int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
|
||||
|
||||
@@ -464,7 +464,7 @@ static int gm12u320_set_ecomode(struct gm12u320_device *gm12u320)
|
||||
* Note this assumes this driver is only ever used with the Acer C120, if we
|
||||
* add support for other devices the vendor and model should be parameterized.
|
||||
*/
|
||||
static struct edid gm12u320_edid = {
|
||||
static const struct edid gm12u320_edid = {
|
||||
.header = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 },
|
||||
.mfg_id = { 0x04, 0x72 }, /* "ACR" */
|
||||
.prod_code = { 0x20, 0xc1 }, /* C120h */
|
||||
@@ -523,8 +523,15 @@ static struct edid gm12u320_edid = {
|
||||
|
||||
static int gm12u320_conn_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_update_edid_property(connector, &gm12u320_edid);
|
||||
return drm_add_edid_modes(connector, &gm12u320_edid);
|
||||
const struct drm_edid *drm_edid;
|
||||
int count;
|
||||
|
||||
drm_edid = drm_edid_alloc(&gm12u320_edid, sizeof(gm12u320_edid));
|
||||
drm_edid_connector_update(connector, drm_edid);
|
||||
count = drm_edid_connector_add_modes(connector);
|
||||
drm_edid_free(drm_edid);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct drm_connector_helper_funcs gm12u320_conn_helper_funcs = {
|
||||
|
||||
@@ -28,7 +28,6 @@ $(obj)/generated/%_wa_oob.c $(obj)/generated/%_wa_oob.h: $(obj)/xe_gen_wa_oob \
|
||||
xe-y += xe_bb.o \
|
||||
xe_bo.o \
|
||||
xe_bo_evict.o \
|
||||
xe_debugfs.o \
|
||||
xe_devcoredump.o \
|
||||
xe_device.o \
|
||||
xe_device_sysfs.o \
|
||||
@@ -46,7 +45,6 @@ xe-y += xe_bb.o \
|
||||
xe_gt.o \
|
||||
xe_gt_ccs_mode.o \
|
||||
xe_gt_clock.o \
|
||||
xe_gt_debugfs.o \
|
||||
xe_gt_freq.o \
|
||||
xe_gt_idle.o \
|
||||
xe_gt_mcr.o \
|
||||
@@ -59,7 +57,6 @@ xe-y += xe_bb.o \
|
||||
xe_guc_ads.o \
|
||||
xe_guc_ct.o \
|
||||
xe_guc_db_mgr.o \
|
||||
xe_guc_debugfs.o \
|
||||
xe_guc_hwconfig.o \
|
||||
xe_guc_id_mgr.o \
|
||||
xe_guc_klv_helpers.o \
|
||||
@@ -69,9 +66,9 @@ xe-y += xe_bb.o \
|
||||
xe_heci_gsc.o \
|
||||
xe_hw_engine.o \
|
||||
xe_hw_engine_class_sysfs.o \
|
||||
xe_hw_engine_group.o \
|
||||
xe_hw_fence.o \
|
||||
xe_huc.o \
|
||||
xe_huc_debugfs.o \
|
||||
xe_irq.o \
|
||||
xe_lrc.o \
|
||||
xe_migrate.o \
|
||||
@@ -107,7 +104,6 @@ xe-y += xe_bb.o \
|
||||
xe_ttm_vram_mgr.o \
|
||||
xe_tuning.o \
|
||||
xe_uc.o \
|
||||
xe_uc_debugfs.o \
|
||||
xe_uc_fw.o \
|
||||
xe_vm.o \
|
||||
xe_vram.o \
|
||||
@@ -124,7 +120,6 @@ xe-$(CONFIG_HWMON) += xe_hwmon.o
|
||||
# graphics virtualization (SR-IOV) support
|
||||
xe-y += \
|
||||
xe_gt_sriov_vf.o \
|
||||
xe_gt_sriov_vf_debugfs.o \
|
||||
xe_guc_relay.o \
|
||||
xe_memirq.o \
|
||||
xe_sriov.o
|
||||
@@ -133,7 +128,6 @@ xe-$(CONFIG_PCI_IOV) += \
|
||||
xe_gt_sriov_pf.o \
|
||||
xe_gt_sriov_pf_config.o \
|
||||
xe_gt_sriov_pf_control.o \
|
||||
xe_gt_sriov_pf_debugfs.o \
|
||||
xe_gt_sriov_pf_monitor.o \
|
||||
xe_gt_sriov_pf_policy.o \
|
||||
xe_gt_sriov_pf_service.o \
|
||||
@@ -281,6 +275,16 @@ ifeq ($(CONFIG_DRM_FBDEV_EMULATION),y)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_FS),y)
|
||||
xe-y += xe_debugfs.o \
|
||||
xe_gt_debugfs.o \
|
||||
xe_gt_sriov_vf_debugfs.o \
|
||||
xe_gt_stats.o \
|
||||
xe_guc_debugfs.o \
|
||||
xe_huc_debugfs.o \
|
||||
xe_uc_debugfs.o
|
||||
|
||||
xe-$(CONFIG_PCI_IOV) += xe_gt_sriov_pf_debugfs.o
|
||||
|
||||
xe-$(CONFIG_DRM_XE_DISPLAY) += \
|
||||
i915-display/intel_display_debugfs.o \
|
||||
i915-display/intel_display_debugfs_params.o \
|
||||
|
||||
@@ -351,6 +351,7 @@ enum xe_guc_klv_ids {
|
||||
GUC_WORKAROUND_KLV_ID_GAM_PFQ_SHADOW_TAIL_POLLING = 0x9005,
|
||||
GUC_WORKAROUND_KLV_ID_DISABLE_MTP_DURING_ASYNC_COMPUTE = 0x9007,
|
||||
GUC_WA_KLV_NP_RD_WRITE_TO_CLEAR_RCSM_AT_CGP_LATE_RESTORE = 0x9008,
|
||||
GUC_WORKAROUND_KLV_ID_BACK_TO_BACK_RCS_ENGINE_RESET = 0x9009,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
#define I915_VMA_H
|
||||
|
||||
#include <uapi/drm/i915_drm.h>
|
||||
#include <drm/drm_mm.h>
|
||||
|
||||
#include "xe_ggtt_types.h"
|
||||
|
||||
/* We don't want these from i915_drm.h in case of Xe */
|
||||
#undef I915_TILING_X
|
||||
@@ -19,7 +20,7 @@ struct xe_bo;
|
||||
|
||||
struct i915_vma {
|
||||
struct xe_bo *bo, *dpt;
|
||||
struct drm_mm_node node;
|
||||
struct xe_ggtt_node *node;
|
||||
};
|
||||
|
||||
#define i915_ggtt_clear_scanout(bo) do { } while (0)
|
||||
@@ -28,7 +29,7 @@ struct i915_vma {
|
||||
|
||||
static inline u32 i915_ggtt_offset(const struct i915_vma *vma)
|
||||
{
|
||||
return vma->node.start;
|
||||
return vma->node->base.start;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -46,7 +46,7 @@ static bool has_display(struct xe_device *xe)
|
||||
*/
|
||||
bool xe_display_driver_probe_defer(struct pci_dev *pdev)
|
||||
{
|
||||
if (!xe_modparam.enable_display)
|
||||
if (!xe_modparam.probe_display)
|
||||
return 0;
|
||||
|
||||
return intel_display_driver_probe_defer(pdev);
|
||||
@@ -62,7 +62,7 @@ bool xe_display_driver_probe_defer(struct pci_dev *pdev)
|
||||
*/
|
||||
void xe_display_driver_set_hooks(struct drm_driver *driver)
|
||||
{
|
||||
if (!xe_modparam.enable_display)
|
||||
if (!xe_modparam.probe_display)
|
||||
return;
|
||||
|
||||
driver->driver_features |= DRIVER_MODESET | DRIVER_ATOMIC;
|
||||
@@ -104,7 +104,7 @@ static void xe_display_fini_nommio(struct drm_device *dev, void *dummy)
|
||||
{
|
||||
struct xe_device *xe = to_xe_device(dev);
|
||||
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_power_domains_cleanup(xe);
|
||||
@@ -112,7 +112,7 @@ static void xe_display_fini_nommio(struct drm_device *dev, void *dummy)
|
||||
|
||||
int xe_display_init_nommio(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return 0;
|
||||
|
||||
/* Fake uncore lock */
|
||||
@@ -129,7 +129,7 @@ static void xe_display_fini_noirq(void *arg)
|
||||
struct xe_device *xe = arg;
|
||||
struct intel_display *display = &xe->display;
|
||||
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_display_driver_remove_noirq(xe);
|
||||
@@ -141,7 +141,7 @@ int xe_display_init_noirq(struct xe_device *xe)
|
||||
struct intel_display *display = &xe->display;
|
||||
int err;
|
||||
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return 0;
|
||||
|
||||
intel_display_driver_early_probe(xe);
|
||||
@@ -172,7 +172,7 @@ static void xe_display_fini_noaccel(void *arg)
|
||||
{
|
||||
struct xe_device *xe = arg;
|
||||
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_display_driver_remove_nogem(xe);
|
||||
@@ -182,7 +182,7 @@ int xe_display_init_noaccel(struct xe_device *xe)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return 0;
|
||||
|
||||
err = intel_display_driver_probe_nogem(xe);
|
||||
@@ -194,7 +194,7 @@ int xe_display_init_noaccel(struct xe_device *xe)
|
||||
|
||||
int xe_display_init(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return 0;
|
||||
|
||||
return intel_display_driver_probe(xe);
|
||||
@@ -202,7 +202,7 @@ int xe_display_init(struct xe_device *xe)
|
||||
|
||||
void xe_display_fini(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_hpd_poll_fini(xe);
|
||||
@@ -213,7 +213,7 @@ void xe_display_fini(struct xe_device *xe)
|
||||
|
||||
void xe_display_register(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_display_driver_register(xe);
|
||||
@@ -223,7 +223,7 @@ void xe_display_register(struct xe_device *xe)
|
||||
|
||||
void xe_display_unregister(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_unregister_dsm_handler();
|
||||
@@ -233,7 +233,7 @@ void xe_display_unregister(struct xe_device *xe)
|
||||
|
||||
void xe_display_driver_remove(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_display_driver_remove(xe);
|
||||
@@ -243,7 +243,7 @@ void xe_display_driver_remove(struct xe_device *xe)
|
||||
|
||||
void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
if (master_ctl & DISPLAY_IRQ)
|
||||
@@ -254,7 +254,7 @@ void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir)
|
||||
{
|
||||
struct intel_display *display = &xe->display;
|
||||
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
if (gu_misc_iir & GU_MISC_GSE)
|
||||
@@ -263,7 +263,7 @@ void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir)
|
||||
|
||||
void xe_display_irq_reset(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
gen11_display_irq_reset(xe);
|
||||
@@ -271,7 +271,7 @@ void xe_display_irq_reset(struct xe_device *xe)
|
||||
|
||||
void xe_display_irq_postinstall(struct xe_device *xe, struct xe_gt *gt)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
if (gt->info.id == XE_GT0)
|
||||
@@ -308,11 +308,23 @@ static void xe_display_flush_cleanup_work(struct xe_device *xe)
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: System and runtime suspend/resume sequences will be sanitized as a follow-up. */
|
||||
void xe_display_pm_runtime_suspend(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
if (xe->d3cold.allowed)
|
||||
xe_display_pm_suspend(xe, true);
|
||||
|
||||
intel_hpd_poll_enable(xe);
|
||||
}
|
||||
|
||||
void xe_display_pm_suspend(struct xe_device *xe, bool runtime)
|
||||
{
|
||||
struct intel_display *display = &xe->display;
|
||||
bool s2idle = suspend_to_idle();
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -320,11 +332,14 @@ void xe_display_pm_suspend(struct xe_device *xe, bool runtime)
|
||||
* properly.
|
||||
*/
|
||||
intel_power_domains_disable(xe);
|
||||
if (has_display(xe))
|
||||
intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_SUSPENDED, true);
|
||||
if (!runtime && has_display(xe)) {
|
||||
drm_kms_helper_poll_disable(&xe->drm);
|
||||
|
||||
if (!runtime)
|
||||
intel_display_driver_disable_user_access(xe);
|
||||
intel_display_driver_suspend(xe);
|
||||
}
|
||||
|
||||
xe_display_flush_cleanup_work(xe);
|
||||
|
||||
xe_display_flush_cleanup_work(xe);
|
||||
|
||||
@@ -332,19 +347,20 @@ void xe_display_pm_suspend(struct xe_device *xe, bool runtime)
|
||||
|
||||
intel_hpd_cancel_work(xe);
|
||||
|
||||
if (!runtime && has_display(xe))
|
||||
intel_display_driver_suspend_access(xe);
|
||||
|
||||
intel_encoder_suspend_all(&xe->display);
|
||||
|
||||
intel_opregion_suspend(display, s2idle ? PCI_D1 : PCI_D3cold);
|
||||
|
||||
intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_SUSPENDED, true);
|
||||
|
||||
intel_dmc_suspend(xe);
|
||||
}
|
||||
|
||||
void xe_display_pm_suspend_late(struct xe_device *xe)
|
||||
{
|
||||
bool s2idle = suspend_to_idle();
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_power_domains_suspend(xe, s2idle);
|
||||
@@ -352,9 +368,20 @@ void xe_display_pm_suspend_late(struct xe_device *xe)
|
||||
intel_display_power_suspend_late(xe);
|
||||
}
|
||||
|
||||
void xe_display_pm_runtime_resume(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_hpd_poll_disable(xe);
|
||||
|
||||
if (xe->d3cold.allowed)
|
||||
xe_display_pm_resume(xe, true);
|
||||
}
|
||||
|
||||
void xe_display_pm_resume_early(struct xe_device *xe)
|
||||
{
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_display_power_resume_early(xe);
|
||||
@@ -366,7 +393,7 @@ void xe_display_pm_resume(struct xe_device *xe, bool runtime)
|
||||
{
|
||||
struct intel_display *display = &xe->display;
|
||||
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
return;
|
||||
|
||||
intel_dmc_resume(xe);
|
||||
@@ -377,14 +404,17 @@ void xe_display_pm_resume(struct xe_device *xe, bool runtime)
|
||||
intel_display_driver_init_hw(xe);
|
||||
intel_hpd_init(xe);
|
||||
|
||||
if (!runtime && has_display(xe))
|
||||
intel_display_driver_resume_access(xe);
|
||||
|
||||
/* MST sideband requires HPD interrupts enabled */
|
||||
intel_dp_mst_resume(xe);
|
||||
if (!runtime)
|
||||
if (!runtime && has_display(xe)) {
|
||||
intel_display_driver_resume(xe);
|
||||
|
||||
intel_hpd_poll_disable(xe);
|
||||
if (has_display(xe))
|
||||
drm_kms_helper_poll_enable(&xe->drm);
|
||||
intel_display_driver_enable_user_access(xe);
|
||||
intel_hpd_poll_disable(xe);
|
||||
}
|
||||
|
||||
intel_opregion_resume(display);
|
||||
|
||||
@@ -404,7 +434,7 @@ int xe_display_probe(struct xe_device *xe)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!xe->info.enable_display)
|
||||
if (!xe->info.probe_display)
|
||||
goto no_display;
|
||||
|
||||
intel_display_device_probe(xe);
|
||||
@@ -417,7 +447,7 @@ int xe_display_probe(struct xe_device *xe)
|
||||
return 0;
|
||||
|
||||
no_display:
|
||||
xe->info.enable_display = false;
|
||||
xe->info.probe_display = false;
|
||||
unset_display_features(xe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ void xe_display_pm_suspend(struct xe_device *xe, bool runtime);
|
||||
void xe_display_pm_suspend_late(struct xe_device *xe);
|
||||
void xe_display_pm_resume_early(struct xe_device *xe);
|
||||
void xe_display_pm_resume(struct xe_device *xe, bool runtime);
|
||||
void xe_display_pm_runtime_suspend(struct xe_device *xe);
|
||||
void xe_display_pm_runtime_resume(struct xe_device *xe);
|
||||
|
||||
#else
|
||||
|
||||
@@ -67,6 +69,8 @@ static inline void xe_display_pm_suspend(struct xe_device *xe, bool runtime) {}
|
||||
static inline void xe_display_pm_suspend_late(struct xe_device *xe) {}
|
||||
static inline void xe_display_pm_resume_early(struct xe_device *xe) {}
|
||||
static inline void xe_display_pm_resume(struct xe_device *xe, bool runtime) {}
|
||||
static inline void xe_display_pm_runtime_suspend(struct xe_device *xe) {}
|
||||
static inline void xe_display_pm_runtime_resume(struct xe_device *xe) {}
|
||||
|
||||
#endif /* CONFIG_DRM_XE_DISPLAY */
|
||||
#endif /* _XE_DISPLAY_H_ */
|
||||
|
||||
@@ -204,21 +204,28 @@ static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb,
|
||||
if (xe_bo_is_vram(bo) && ggtt->flags & XE_GGTT_FLAGS_64K)
|
||||
align = max_t(u32, align, SZ_64K);
|
||||
|
||||
if (bo->ggtt_node.size && view->type == I915_GTT_VIEW_NORMAL) {
|
||||
if (bo->ggtt_node && view->type == I915_GTT_VIEW_NORMAL) {
|
||||
vma->node = bo->ggtt_node;
|
||||
} else if (view->type == I915_GTT_VIEW_NORMAL) {
|
||||
u32 x, size = bo->ttm.base.size;
|
||||
|
||||
ret = xe_ggtt_insert_special_node_locked(ggtt, &vma->node, size,
|
||||
align, 0);
|
||||
if (ret)
|
||||
vma->node = xe_ggtt_node_init(ggtt);
|
||||
if (IS_ERR(vma->node)) {
|
||||
ret = PTR_ERR(vma->node);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = xe_ggtt_node_insert_locked(vma->node, size, align, 0);
|
||||
if (ret) {
|
||||
xe_ggtt_node_fini(vma->node);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
for (x = 0; x < size; x += XE_PAGE_SIZE) {
|
||||
u64 pte = ggtt->pt_ops->pte_encode_bo(bo, x,
|
||||
xe->pat.idx[XE_CACHE_NONE]);
|
||||
|
||||
ggtt->pt_ops->ggtt_set_pte(ggtt, vma->node.start + x, pte);
|
||||
ggtt->pt_ops->ggtt_set_pte(ggtt, vma->node->base.start + x, pte);
|
||||
}
|
||||
} else {
|
||||
u32 i, ggtt_ofs;
|
||||
@@ -227,12 +234,19 @@ static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb,
|
||||
/* display seems to use tiles instead of bytes here, so convert it back.. */
|
||||
u32 size = intel_rotation_info_size(rot_info) * XE_PAGE_SIZE;
|
||||
|
||||
ret = xe_ggtt_insert_special_node_locked(ggtt, &vma->node, size,
|
||||
align, 0);
|
||||
if (ret)
|
||||
vma->node = xe_ggtt_node_init(ggtt);
|
||||
if (IS_ERR(vma->node)) {
|
||||
ret = PTR_ERR(vma->node);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ggtt_ofs = vma->node.start;
|
||||
ret = xe_ggtt_node_insert_locked(vma->node, size, align, 0);
|
||||
if (ret) {
|
||||
xe_ggtt_node_fini(vma->node);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ggtt_ofs = vma->node->base.start;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rot_info->plane); i++)
|
||||
write_ggtt_rotated(bo, ggtt, &ggtt_ofs,
|
||||
@@ -320,14 +334,11 @@ err:
|
||||
|
||||
static void __xe_unpin_fb_vma(struct i915_vma *vma)
|
||||
{
|
||||
struct xe_device *xe = to_xe_device(vma->bo->ttm.base.dev);
|
||||
struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt;
|
||||
|
||||
if (vma->dpt)
|
||||
xe_bo_unpin_map_no_vm(vma->dpt);
|
||||
else if (!drm_mm_node_allocated(&vma->bo->ggtt_node) ||
|
||||
vma->bo->ggtt_node.start != vma->node.start)
|
||||
xe_ggtt_remove_node(ggtt, &vma->node, false);
|
||||
else if (!xe_ggtt_node_allocated(vma->bo->ggtt_node) ||
|
||||
vma->bo->ggtt_node->base.start != vma->node->base.start)
|
||||
xe_ggtt_node_remove(vma->node, false);
|
||||
|
||||
ttm_bo_reserve(&vma->bo->ttm, false, false, NULL);
|
||||
ttm_bo_unpin(&vma->bo->ttm);
|
||||
@@ -377,8 +388,8 @@ void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
|
||||
}
|
||||
|
||||
/*
|
||||
* For Xe introduce dummy intel_dpt_create which just return NULL and
|
||||
* intel_dpt_destroy which does nothing.
|
||||
* For Xe introduce dummy intel_dpt_create which just return NULL,
|
||||
* intel_dpt_destroy which does nothing, and fake intel_dpt_ofsset returning 0;
|
||||
*/
|
||||
struct i915_address_space *intel_dpt_create(struct intel_framebuffer *fb)
|
||||
{
|
||||
@@ -389,3 +400,8 @@ void intel_dpt_destroy(struct i915_address_space *vm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u64 intel_dpt_offset(struct i915_vma *dpt_vma)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
#define CSFE_CHICKEN1(base) XE_REG((base) + 0xd4, XE_REG_OPTION_MASKED)
|
||||
#define GHWSP_CSB_REPORT_DIS REG_BIT(15)
|
||||
#define PPHWSP_CSB_AND_TIMESTAMP_REPORT_DIS REG_BIT(14)
|
||||
#define CS_PRIORITY_MEM_READ REG_BIT(7)
|
||||
|
||||
#define FF_SLICE_CS_CHICKEN1(base) XE_REG((base) + 0xe0, XE_REG_OPTION_MASKED)
|
||||
#define FFSC_PERCTX_PREEMPT_CTRL REG_BIT(14)
|
||||
|
||||
@@ -80,7 +80,10 @@
|
||||
#define LE_CACHEABILITY_MASK REG_GENMASK(1, 0)
|
||||
#define LE_CACHEABILITY(value) REG_FIELD_PREP(LE_CACHEABILITY_MASK, value)
|
||||
|
||||
#define XE2_GAMREQSTRM_CTRL XE_REG(0x4194)
|
||||
#define STATELESS_COMPRESSION_CTRL XE_REG_MCR(0x4148)
|
||||
#define UNIFIED_COMPRESSION_FORMAT REG_GENMASK(3, 0)
|
||||
|
||||
#define XE2_GAMREQSTRM_CTRL XE_REG_MCR(0x4194)
|
||||
#define CG_DIS_CNTLBUS REG_BIT(6)
|
||||
|
||||
#define CCS_AUX_INV XE_REG(0x4208)
|
||||
@@ -193,6 +196,7 @@
|
||||
#define GSCPSMI_BASE XE_REG(0x880c)
|
||||
|
||||
#define CCCHKNREG1 XE_REG_MCR(0x8828)
|
||||
#define L3CMPCTRL REG_BIT(23)
|
||||
#define ENCOMPPERFFIX REG_BIT(18)
|
||||
|
||||
/* Fuse readout registers for GT */
|
||||
@@ -367,6 +371,9 @@
|
||||
#define XEHP_L3NODEARBCFG XE_REG_MCR(0xb0b4)
|
||||
#define XEHP_LNESPARE REG_BIT(19)
|
||||
|
||||
#define L3SQCREG2 XE_REG_MCR(0xb104)
|
||||
#define COMPMEMRD256BOVRFETCHEN REG_BIT(20)
|
||||
|
||||
#define L3SQCREG3 XE_REG_MCR(0xb108)
|
||||
#define COMPPWOVERFETCHEN REG_BIT(28)
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
|
||||
|
||||
/* Optionally clear bo *and* CCS data in VRAM. */
|
||||
if (clear) {
|
||||
fence = xe_migrate_clear(tile->migrate, bo, bo->ttm.resource);
|
||||
fence = xe_migrate_clear(tile->migrate, bo, bo->ttm.resource,
|
||||
XE_MIGRATE_CLEAR_FLAG_FULL);
|
||||
if (IS_ERR(fence)) {
|
||||
KUNIT_FAIL(test, "Failed to submit bo clear.\n");
|
||||
return PTR_ERR(fence);
|
||||
@@ -124,7 +125,7 @@ static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,
|
||||
kunit_info(test, "Testing system memory\n");
|
||||
|
||||
bo = xe_bo_create_user(xe, NULL, NULL, SZ_1M, DRM_XE_GEM_CPU_CACHING_WC,
|
||||
ttm_bo_type_device, bo_flags);
|
||||
bo_flags);
|
||||
if (IS_ERR(bo)) {
|
||||
KUNIT_FAIL(test, "Failed to create bo.\n");
|
||||
return;
|
||||
@@ -205,7 +206,6 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
|
||||
xe_vm_lock(vm, false);
|
||||
bo = xe_bo_create_user(xe, NULL, vm, 0x10000,
|
||||
DRM_XE_GEM_CPU_CACHING_WC,
|
||||
ttm_bo_type_device,
|
||||
bo_flags);
|
||||
xe_vm_unlock(vm);
|
||||
if (IS_ERR(bo)) {
|
||||
@@ -215,7 +215,7 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc
|
||||
|
||||
external = xe_bo_create_user(xe, NULL, NULL, 0x10000,
|
||||
DRM_XE_GEM_CPU_CACHING_WC,
|
||||
ttm_bo_type_device, bo_flags);
|
||||
bo_flags);
|
||||
if (IS_ERR(external)) {
|
||||
KUNIT_FAIL(test, "external bo create err=%pe\n", external);
|
||||
goto cleanup_bo;
|
||||
|
||||
@@ -126,7 +126,7 @@ static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
|
||||
|
||||
kunit_info(test, "running %s\n", __func__);
|
||||
bo = xe_bo_create_user(xe, NULL, NULL, size, DRM_XE_GEM_CPU_CACHING_WC,
|
||||
ttm_bo_type_device, params->mem_mask);
|
||||
params->mem_mask);
|
||||
if (IS_ERR(bo)) {
|
||||
KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
|
||||
PTR_ERR(bo));
|
||||
|
||||
@@ -105,7 +105,8 @@ static void test_copy(struct xe_migrate *m, struct xe_bo *bo,
|
||||
}
|
||||
|
||||
xe_map_memset(xe, &remote->vmap, 0, 0xd0, remote->size);
|
||||
fence = xe_migrate_clear(m, remote, remote->ttm.resource);
|
||||
fence = xe_migrate_clear(m, remote, remote->ttm.resource,
|
||||
XE_MIGRATE_CLEAR_FLAG_FULL);
|
||||
if (!sanity_fence_failed(xe, fence, big ? "Clearing remote big bo" :
|
||||
"Clearing remote small bo", test)) {
|
||||
retval = xe_map_rd(xe, &remote->vmap, 0, u64);
|
||||
@@ -279,7 +280,8 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
|
||||
kunit_info(test, "Clearing small buffer object\n");
|
||||
xe_map_memset(xe, &tiny->vmap, 0, 0x22, tiny->size);
|
||||
expected = 0;
|
||||
fence = xe_migrate_clear(m, tiny, tiny->ttm.resource);
|
||||
fence = xe_migrate_clear(m, tiny, tiny->ttm.resource,
|
||||
XE_MIGRATE_CLEAR_FLAG_FULL);
|
||||
if (sanity_fence_failed(xe, fence, "Clearing small bo", test))
|
||||
goto out;
|
||||
|
||||
@@ -300,7 +302,8 @@ static void xe_migrate_sanity_test(struct xe_migrate *m, struct kunit *test)
|
||||
kunit_info(test, "Clearing big buffer object\n");
|
||||
xe_map_memset(xe, &big->vmap, 0, 0x11, big->size);
|
||||
expected = 0;
|
||||
fence = xe_migrate_clear(m, big, big->ttm.resource);
|
||||
fence = xe_migrate_clear(m, big, big->ttm.resource,
|
||||
XE_MIGRATE_CLEAR_FLAG_FULL);
|
||||
if (sanity_fence_failed(xe, fence, "Clearing big bo", test))
|
||||
goto out;
|
||||
|
||||
@@ -603,7 +606,8 @@ static void test_clear(struct xe_device *xe, struct xe_tile *tile,
|
||||
|
||||
kunit_info(test, "Clear vram buffer object\n");
|
||||
expected = 0x0000000000000000;
|
||||
fence = xe_migrate_clear(tile->migrate, vram_bo, vram_bo->ttm.resource);
|
||||
fence = xe_migrate_clear(tile->migrate, vram_bo, vram_bo->ttm.resource,
|
||||
XE_MIGRATE_CLEAR_FLAG_FULL);
|
||||
if (sanity_fence_failed(xe, fence, "Clear vram_bo", test))
|
||||
return;
|
||||
dma_fence_put(fence);
|
||||
@@ -637,7 +641,7 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
|
||||
long ret;
|
||||
|
||||
sys_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
|
||||
DRM_XE_GEM_CPU_CACHING_WC, ttm_bo_type_device,
|
||||
DRM_XE_GEM_CPU_CACHING_WC,
|
||||
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS);
|
||||
|
||||
if (IS_ERR(sys_bo)) {
|
||||
@@ -660,8 +664,9 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
|
||||
}
|
||||
xe_bo_unlock(sys_bo);
|
||||
|
||||
ccs_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M, DRM_XE_GEM_CPU_CACHING_WC,
|
||||
ttm_bo_type_device, bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS);
|
||||
ccs_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
|
||||
DRM_XE_GEM_CPU_CACHING_WC,
|
||||
bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS);
|
||||
|
||||
if (IS_ERR(ccs_bo)) {
|
||||
KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
|
||||
@@ -683,8 +688,9 @@ static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *til
|
||||
}
|
||||
xe_bo_unlock(ccs_bo);
|
||||
|
||||
vram_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M, DRM_XE_GEM_CPU_CACHING_WC,
|
||||
ttm_bo_type_device, bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS);
|
||||
vram_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M,
|
||||
DRM_XE_GEM_CPU_CACHING_WC,
|
||||
bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS);
|
||||
if (IS_ERR(vram_bo)) {
|
||||
KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
|
||||
PTR_ERR(vram_bo));
|
||||
|
||||
@@ -12,58 +12,6 @@
|
||||
#include <kunit/test-bug.h>
|
||||
#include <kunit/visibility.h>
|
||||
|
||||
struct kunit_test_data {
|
||||
int ndevs;
|
||||
xe_device_fn xe_fn;
|
||||
};
|
||||
|
||||
static int dev_to_xe_device_fn(struct device *dev, void *__data)
|
||||
|
||||
{
|
||||
struct drm_device *drm = dev_get_drvdata(dev);
|
||||
struct kunit_test_data *data = __data;
|
||||
int ret = 0;
|
||||
int idx;
|
||||
|
||||
data->ndevs++;
|
||||
|
||||
if (drm_dev_enter(drm, &idx))
|
||||
ret = data->xe_fn(to_xe_device(dev_get_drvdata(dev)));
|
||||
drm_dev_exit(idx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_call_for_each_device - Iterate over all devices this driver binds to
|
||||
* @xe_fn: Function to call for each device.
|
||||
*
|
||||
* This function iterated over all devices this driver binds to, and calls
|
||||
* @xe_fn: for each one of them. If the called function returns anything else
|
||||
* than 0, iteration is stopped and the return value is returned by this
|
||||
* function. Across each function call, drm_dev_enter() / drm_dev_exit() is
|
||||
* called for the corresponding drm device.
|
||||
*
|
||||
* Return: Number of devices iterated or
|
||||
* the error code of a call to @xe_fn returning an error code.
|
||||
*/
|
||||
int xe_call_for_each_device(xe_device_fn xe_fn)
|
||||
{
|
||||
int ret;
|
||||
struct kunit_test_data data = {
|
||||
.xe_fn = xe_fn,
|
||||
.ndevs = 0,
|
||||
};
|
||||
|
||||
ret = driver_for_each_device(&xe_pci_driver.driver, NULL,
|
||||
&data, dev_to_xe_device_fn);
|
||||
|
||||
if (!data.ndevs)
|
||||
kunit_skip(current->kunit_test, "test runs only on hardware\n");
|
||||
|
||||
return ret ?: data.ndevs;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_call_for_each_graphics_ip - Iterate over all recognized graphics IPs
|
||||
* @xe_fn: Function to call for each device.
|
||||
|
||||
@@ -19,7 +19,6 @@ typedef int (*xe_device_fn)(struct xe_device *);
|
||||
typedef void (*xe_graphics_fn)(const struct xe_graphics_desc *);
|
||||
typedef void (*xe_media_fn)(const struct xe_media_desc *);
|
||||
|
||||
int xe_call_for_each_device(xe_device_fn xe_fn);
|
||||
void xe_call_for_each_graphics_ip(xe_graphics_fn xe_fn);
|
||||
void xe_call_for_each_media_ip(xe_media_fn xe_fn);
|
||||
|
||||
|
||||
@@ -793,8 +793,16 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (move_lacks_source)
|
||||
fence = xe_migrate_clear(migrate, bo, new_mem);
|
||||
if (move_lacks_source) {
|
||||
u32 flags = 0;
|
||||
|
||||
if (mem_type_is_vram(new_mem->mem_type))
|
||||
flags |= XE_MIGRATE_CLEAR_FLAG_FULL;
|
||||
else if (handle_system_ccs)
|
||||
flags |= XE_MIGRATE_CLEAR_FLAG_CCS_DATA;
|
||||
|
||||
fence = xe_migrate_clear(migrate, bo, new_mem, flags);
|
||||
}
|
||||
else
|
||||
fence = xe_migrate_copy(migrate, bo, bo, old_mem,
|
||||
new_mem, handle_system_ccs);
|
||||
@@ -1090,7 +1098,7 @@ static void xe_ttm_bo_destroy(struct ttm_buffer_object *ttm_bo)
|
||||
|
||||
xe_assert(xe, list_empty(&ttm_bo->base.gpuva.list));
|
||||
|
||||
if (bo->ggtt_node.size)
|
||||
if (bo->ggtt_node && bo->ggtt_node->base.size)
|
||||
xe_ggtt_remove_bo(bo->tile->mem.ggtt, bo);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
@@ -1491,11 +1499,10 @@ struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
|
||||
struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
|
||||
struct xe_vm *vm, size_t size,
|
||||
u16 cpu_caching,
|
||||
enum ttm_bo_type type,
|
||||
u32 flags)
|
||||
{
|
||||
struct xe_bo *bo = __xe_bo_create_locked(xe, tile, vm, size, 0, ~0ULL,
|
||||
cpu_caching, type,
|
||||
cpu_caching, ttm_bo_type_device,
|
||||
flags | XE_BO_FLAG_USER);
|
||||
if (!IS_ERR(bo))
|
||||
xe_bo_unlock_vm_held(bo);
|
||||
@@ -2026,7 +2033,7 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
}
|
||||
|
||||
bo = xe_bo_create_user(xe, NULL, vm, args->size, args->cpu_caching,
|
||||
ttm_bo_type_device, bo_flags);
|
||||
bo_flags);
|
||||
|
||||
if (vm)
|
||||
xe_vm_unlock(vm);
|
||||
@@ -2332,7 +2339,6 @@ int xe_bo_dumb_create(struct drm_file *file_priv,
|
||||
|
||||
bo = xe_bo_create_user(xe, NULL, NULL, args->size,
|
||||
DRM_XE_GEM_CPU_CACHING_WC,
|
||||
ttm_bo_type_device,
|
||||
XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) |
|
||||
XE_BO_FLAG_SCANOUT |
|
||||
XE_BO_FLAG_NEEDS_CPU_ACCESS);
|
||||
|
||||
@@ -87,7 +87,6 @@ struct xe_bo *xe_bo_create(struct xe_device *xe, struct xe_tile *tile,
|
||||
struct xe_bo *xe_bo_create_user(struct xe_device *xe, struct xe_tile *tile,
|
||||
struct xe_vm *vm, size_t size,
|
||||
u16 cpu_caching,
|
||||
enum ttm_bo_type type,
|
||||
u32 flags);
|
||||
struct xe_bo *xe_bo_create_pin_map(struct xe_device *xe, struct xe_tile *tile,
|
||||
struct xe_vm *vm, size_t size,
|
||||
@@ -195,9 +194,12 @@ xe_bo_main_addr(struct xe_bo *bo, size_t page_size)
|
||||
static inline u32
|
||||
xe_bo_ggtt_addr(struct xe_bo *bo)
|
||||
{
|
||||
XE_WARN_ON(bo->ggtt_node.size > bo->size);
|
||||
XE_WARN_ON(bo->ggtt_node.start + bo->ggtt_node.size > (1ull << 32));
|
||||
return bo->ggtt_node.start;
|
||||
if (XE_WARN_ON(!bo->ggtt_node))
|
||||
return 0;
|
||||
|
||||
XE_WARN_ON(bo->ggtt_node->base.size > bo->size);
|
||||
XE_WARN_ON(bo->ggtt_node->base.start + bo->ggtt_node->base.size > (1ull << 32));
|
||||
return bo->ggtt_node->base.start;
|
||||
}
|
||||
|
||||
int xe_bo_vmap(struct xe_bo *bo);
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
|
||||
#include <linux/iosys-map.h>
|
||||
|
||||
#include <drm/drm_mm.h>
|
||||
#include <drm/ttm/ttm_bo.h>
|
||||
#include <drm/ttm/ttm_device.h>
|
||||
#include <drm/ttm/ttm_execbuf_util.h>
|
||||
#include <drm/ttm/ttm_placement.h>
|
||||
|
||||
#include "xe_ggtt_types.h"
|
||||
|
||||
struct xe_device;
|
||||
struct xe_vm;
|
||||
|
||||
@@ -39,7 +40,7 @@ struct xe_bo {
|
||||
/** @placement: current placement for this BO */
|
||||
struct ttm_placement placement;
|
||||
/** @ggtt_node: GGTT node if this BO is mapped in the GGTT */
|
||||
struct drm_mm_node ggtt_node;
|
||||
struct xe_ggtt_node *ggtt_node;
|
||||
/** @vmap: iosys map of this buffer */
|
||||
struct iosys_map vmap;
|
||||
/** @ttm_kmap: TTM bo kmap object for internal use only. Keep off. */
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
struct xe_device;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void xe_debugfs_register(struct xe_device *xe);
|
||||
#else
|
||||
static inline void xe_debugfs_register(struct xe_device *xe) { }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -66,22 +66,9 @@ static struct xe_guc *exec_queue_to_guc(struct xe_exec_queue *q)
|
||||
return &q->gt->uc.guc;
|
||||
}
|
||||
|
||||
static void xe_devcoredump_deferred_snap_work(struct work_struct *work)
|
||||
static ssize_t __xe_devcoredump_read(char *buffer, size_t count,
|
||||
struct xe_devcoredump *coredump)
|
||||
{
|
||||
struct xe_devcoredump_snapshot *ss = container_of(work, typeof(*ss), work);
|
||||
|
||||
/* keep going if fw fails as we still want to save the memory and SW data */
|
||||
if (xe_force_wake_get(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL))
|
||||
xe_gt_info(ss->gt, "failed to get forcewake for coredump capture\n");
|
||||
xe_vm_snapshot_capture_delayed(ss->vm);
|
||||
xe_guc_exec_queue_snapshot_capture_delayed(ss->ge);
|
||||
xe_force_wake_put(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL);
|
||||
}
|
||||
|
||||
static ssize_t xe_devcoredump_read(char *buffer, loff_t offset,
|
||||
size_t count, void *data, size_t datalen)
|
||||
{
|
||||
struct xe_devcoredump *coredump = data;
|
||||
struct xe_device *xe;
|
||||
struct xe_devcoredump_snapshot *ss;
|
||||
struct drm_printer p;
|
||||
@@ -89,18 +76,11 @@ static ssize_t xe_devcoredump_read(char *buffer, loff_t offset,
|
||||
struct timespec64 ts;
|
||||
int i;
|
||||
|
||||
if (!coredump)
|
||||
return -ENODEV;
|
||||
|
||||
xe = coredump_to_xe(coredump);
|
||||
ss = &coredump->snapshot;
|
||||
|
||||
/* Ensure delayed work is captured before continuing */
|
||||
flush_work(&ss->work);
|
||||
|
||||
iter.data = buffer;
|
||||
iter.offset = 0;
|
||||
iter.start = offset;
|
||||
iter.start = 0;
|
||||
iter.remain = count;
|
||||
|
||||
p = drm_coredump_printer(&iter);
|
||||
@@ -134,10 +114,83 @@ static ssize_t xe_devcoredump_read(char *buffer, loff_t offset,
|
||||
return count - iter.remain;
|
||||
}
|
||||
|
||||
static void xe_devcoredump_snapshot_free(struct xe_devcoredump_snapshot *ss)
|
||||
{
|
||||
int i;
|
||||
|
||||
xe_guc_ct_snapshot_free(ss->ct);
|
||||
ss->ct = NULL;
|
||||
|
||||
xe_guc_exec_queue_snapshot_free(ss->ge);
|
||||
ss->ge = NULL;
|
||||
|
||||
xe_sched_job_snapshot_free(ss->job);
|
||||
ss->job = NULL;
|
||||
|
||||
for (i = 0; i < XE_NUM_HW_ENGINES; i++)
|
||||
if (ss->hwe[i]) {
|
||||
xe_hw_engine_snapshot_free(ss->hwe[i]);
|
||||
ss->hwe[i] = NULL;
|
||||
}
|
||||
|
||||
xe_vm_snapshot_free(ss->vm);
|
||||
ss->vm = NULL;
|
||||
}
|
||||
|
||||
static void xe_devcoredump_deferred_snap_work(struct work_struct *work)
|
||||
{
|
||||
struct xe_devcoredump_snapshot *ss = container_of(work, typeof(*ss), work);
|
||||
struct xe_devcoredump *coredump = container_of(ss, typeof(*coredump), snapshot);
|
||||
|
||||
/* keep going if fw fails as we still want to save the memory and SW data */
|
||||
if (xe_force_wake_get(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL))
|
||||
xe_gt_info(ss->gt, "failed to get forcewake for coredump capture\n");
|
||||
xe_vm_snapshot_capture_delayed(ss->vm);
|
||||
xe_guc_exec_queue_snapshot_capture_delayed(ss->ge);
|
||||
xe_force_wake_put(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL);
|
||||
|
||||
/* Calculate devcoredump size */
|
||||
ss->read.size = __xe_devcoredump_read(NULL, INT_MAX, coredump);
|
||||
|
||||
ss->read.buffer = kvmalloc(ss->read.size, GFP_USER);
|
||||
if (!ss->read.buffer)
|
||||
return;
|
||||
|
||||
__xe_devcoredump_read(ss->read.buffer, ss->read.size, coredump);
|
||||
xe_devcoredump_snapshot_free(ss);
|
||||
}
|
||||
|
||||
static ssize_t xe_devcoredump_read(char *buffer, loff_t offset,
|
||||
size_t count, void *data, size_t datalen)
|
||||
{
|
||||
struct xe_devcoredump *coredump = data;
|
||||
struct xe_devcoredump_snapshot *ss;
|
||||
ssize_t byte_copied;
|
||||
|
||||
if (!coredump)
|
||||
return -ENODEV;
|
||||
|
||||
ss = &coredump->snapshot;
|
||||
|
||||
/* Ensure delayed work is captured before continuing */
|
||||
flush_work(&ss->work);
|
||||
|
||||
if (!ss->read.buffer)
|
||||
return -ENODEV;
|
||||
|
||||
if (offset >= ss->read.size)
|
||||
return 0;
|
||||
|
||||
byte_copied = count < ss->read.size - offset ? count :
|
||||
ss->read.size - offset;
|
||||
memcpy(buffer, ss->read.buffer + offset, byte_copied);
|
||||
|
||||
return byte_copied;
|
||||
}
|
||||
|
||||
static void xe_devcoredump_free(void *data)
|
||||
{
|
||||
struct xe_devcoredump *coredump = data;
|
||||
int i;
|
||||
|
||||
/* Our device is gone. Nothing to do... */
|
||||
if (!data || !coredump_to_xe(coredump))
|
||||
@@ -145,13 +198,8 @@ static void xe_devcoredump_free(void *data)
|
||||
|
||||
cancel_work_sync(&coredump->snapshot.work);
|
||||
|
||||
xe_guc_ct_snapshot_free(coredump->snapshot.ct);
|
||||
xe_guc_exec_queue_snapshot_free(coredump->snapshot.ge);
|
||||
xe_sched_job_snapshot_free(coredump->snapshot.job);
|
||||
for (i = 0; i < XE_NUM_HW_ENGINES; i++)
|
||||
if (coredump->snapshot.hwe[i])
|
||||
xe_hw_engine_snapshot_free(coredump->snapshot.hwe[i]);
|
||||
xe_vm_snapshot_free(coredump->snapshot.vm);
|
||||
xe_devcoredump_snapshot_free(&coredump->snapshot);
|
||||
kvfree(coredump->snapshot.read.buffer);
|
||||
|
||||
/* To prevent stale data on next snapshot, clear everything */
|
||||
memset(&coredump->snapshot, 0, sizeof(coredump->snapshot));
|
||||
@@ -260,4 +308,5 @@ int xe_devcoredump_init(struct xe_device *xe)
|
||||
{
|
||||
return devm_add_action_or_reset(xe->drm.dev, xe_driver_devcoredump_fini, &xe->drm);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -46,6 +46,14 @@ struct xe_devcoredump_snapshot {
|
||||
struct xe_sched_job_snapshot *job;
|
||||
/** @vm: Snapshot of VM state */
|
||||
struct xe_vm_snapshot *vm;
|
||||
|
||||
/** @read: devcoredump in human readable format */
|
||||
struct {
|
||||
/** @read.size: size of devcoredump in human readable format */
|
||||
ssize_t size;
|
||||
/** @read.buffer: buffer of devcoredump in human readable format */
|
||||
char *buffer;
|
||||
} read;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "xe_gt_printk.h"
|
||||
#include "xe_gt_sriov_vf.h"
|
||||
#include "xe_guc.h"
|
||||
#include "xe_hw_engine_group.h"
|
||||
#include "xe_hwmon.h"
|
||||
#include "xe_irq.h"
|
||||
#include "xe_memirq.h"
|
||||
@@ -165,6 +166,8 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
|
||||
* vm->lock taken during xe_exec_queue_kill().
|
||||
*/
|
||||
xa_for_each(&xef->exec_queue.xa, idx, q) {
|
||||
if (q->vm && q->hwe->hw_engine_group)
|
||||
xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q);
|
||||
xe_exec_queue_kill(q);
|
||||
xe_exec_queue_put(q);
|
||||
}
|
||||
@@ -543,7 +546,7 @@ static void update_device_info(struct xe_device *xe)
|
||||
{
|
||||
/* disable features that are not available/applicable to VFs */
|
||||
if (IS_SRIOV_VF(xe)) {
|
||||
xe->info.enable_display = 0;
|
||||
xe->info.probe_display = 0;
|
||||
xe->info.has_heci_gscfi = 0;
|
||||
xe->info.skip_guc_pc = 1;
|
||||
xe->info.skip_pcode = 1;
|
||||
|
||||
@@ -15,6 +15,11 @@ static inline struct xe_device *to_xe_device(const struct drm_device *dev)
|
||||
return container_of(dev, struct xe_device, drm);
|
||||
}
|
||||
|
||||
static inline struct xe_device *kdev_to_xe_device(struct device *kdev)
|
||||
{
|
||||
return dev_get_drvdata(kdev);
|
||||
}
|
||||
|
||||
static inline struct xe_device *pdev_to_xe_device(struct pci_dev *pdev)
|
||||
{
|
||||
return pci_get_drvdata(pdev);
|
||||
@@ -134,16 +139,6 @@ static inline struct xe_force_wake *gt_to_fw(struct xe_gt *gt)
|
||||
|
||||
void xe_device_assert_mem_access(struct xe_device *xe);
|
||||
|
||||
static inline bool xe_device_in_fault_mode(struct xe_device *xe)
|
||||
{
|
||||
return xe->usm.num_vm_in_fault_mode != 0;
|
||||
}
|
||||
|
||||
static inline bool xe_device_in_non_fault_mode(struct xe_device *xe)
|
||||
{
|
||||
return xe->usm.num_vm_in_non_fault_mode != 0;
|
||||
}
|
||||
|
||||
static inline bool xe_device_has_flat_ccs(struct xe_device *xe)
|
||||
{
|
||||
return xe->info.has_flat_ccs;
|
||||
|
||||
@@ -204,7 +204,7 @@ struct xe_tile {
|
||||
struct xe_memirq memirq;
|
||||
|
||||
/** @sriov.vf.ggtt_balloon: GGTT regions excluded from use. */
|
||||
struct drm_mm_node ggtt_balloon[2];
|
||||
struct xe_ggtt_node *ggtt_balloon[2];
|
||||
} vf;
|
||||
} sriov;
|
||||
|
||||
@@ -282,8 +282,15 @@ struct xe_device {
|
||||
u8 has_sriov:1;
|
||||
/** @info.has_usm: Device has unified shared memory support */
|
||||
u8 has_usm:1;
|
||||
/** @info.enable_display: display enabled */
|
||||
u8 enable_display:1;
|
||||
/**
|
||||
* @info.probe_display: Probe display hardware. If set to
|
||||
* false, the driver will behave as if there is no display
|
||||
* hardware present and will not try to read/write to it in any
|
||||
* way. The display hardware, if it exists, will not be
|
||||
* exposed to userspace and will be left untouched in whatever
|
||||
* state the firmware or bootloader left it in.
|
||||
*/
|
||||
u8 probe_display:1;
|
||||
/** @info.skip_mtcfg: skip Multi-Tile configuration from MTCFG register */
|
||||
u8 skip_mtcfg:1;
|
||||
/** @info.skip_pcode: skip access to PCODE uC */
|
||||
@@ -355,10 +362,6 @@ struct xe_device {
|
||||
struct xarray asid_to_vm;
|
||||
/** @usm.next_asid: next ASID, used to cyclical alloc asids */
|
||||
u32 next_asid;
|
||||
/** @usm.num_vm_in_fault_mode: number of VM in fault mode */
|
||||
u32 num_vm_in_fault_mode;
|
||||
/** @usm.num_vm_in_non_fault_mode: number of VM in non-fault mode */
|
||||
u32 num_vm_in_non_fault_mode;
|
||||
/** @usm.lock: protects UM state */
|
||||
struct mutex lock;
|
||||
} usm;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "xe_bo.h"
|
||||
#include "xe_device.h"
|
||||
#include "xe_exec_queue.h"
|
||||
#include "xe_hw_engine_group.h"
|
||||
#include "xe_macros.h"
|
||||
#include "xe_ring_ops_types.h"
|
||||
#include "xe_sched_job.h"
|
||||
@@ -124,6 +125,8 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
bool write_locked, skip_retry = false;
|
||||
ktime_t end = 0;
|
||||
int err = 0;
|
||||
struct xe_hw_engine_group *group;
|
||||
enum xe_hw_engine_group_execution_mode mode, previous_mode;
|
||||
|
||||
if (XE_IOCTL_DBG(xe, args->extensions) ||
|
||||
XE_IOCTL_DBG(xe, args->pad[0] || args->pad[1] || args->pad[2]) ||
|
||||
@@ -182,6 +185,15 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
|
||||
}
|
||||
}
|
||||
|
||||
group = q->hwe->hw_engine_group;
|
||||
mode = xe_hw_engine_group_find_exec_mode(q);
|
||||
|
||||
if (mode == EXEC_MODE_DMA_FENCE) {
|
||||
err = xe_hw_engine_group_get_mode(group, mode, &previous_mode);
|
||||
if (err)
|
||||
goto err_syncs;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (!xe_vm_in_lr_mode(vm) && xe_vm_userptr_check_repin(vm)) {
|
||||
err = down_write_killable(&vm->lock);
|
||||
@@ -199,7 +211,7 @@ retry:
|
||||
downgrade_write(&vm->lock);
|
||||
write_locked = false;
|
||||
if (err)
|
||||
goto err_unlock_list;
|
||||
goto err_hw_exec_mode;
|
||||
}
|
||||
|
||||
if (!args->num_batch_buffer) {
|
||||
@@ -312,6 +324,9 @@ retry:
|
||||
spin_unlock(&xe->ttm.lru_lock);
|
||||
}
|
||||
|
||||
if (mode == EXEC_MODE_LR)
|
||||
xe_hw_engine_group_resume_faulting_lr_jobs(group);
|
||||
|
||||
err_repin:
|
||||
if (!xe_vm_in_lr_mode(vm))
|
||||
up_read(&vm->userptr.notifier_lock);
|
||||
@@ -324,6 +339,9 @@ err_unlock_list:
|
||||
up_read(&vm->lock);
|
||||
if (err == -EAGAIN && !skip_retry)
|
||||
goto retry;
|
||||
err_hw_exec_mode:
|
||||
if (mode == EXEC_MODE_DMA_FENCE)
|
||||
xe_hw_engine_group_put(group);
|
||||
err_syncs:
|
||||
while (num_syncs--)
|
||||
xe_sync_entry_cleanup(&syncs[num_syncs]);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "xe_device.h"
|
||||
#include "xe_gt.h"
|
||||
#include "xe_hw_engine_class_sysfs.h"
|
||||
#include "xe_hw_engine_group.h"
|
||||
#include "xe_hw_fence.h"
|
||||
#include "xe_lrc.h"
|
||||
#include "xe_macros.h"
|
||||
@@ -73,6 +74,7 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe,
|
||||
q->ops = gt->exec_queue_ops;
|
||||
INIT_LIST_HEAD(&q->lr.link);
|
||||
INIT_LIST_HEAD(&q->multi_gt_link);
|
||||
INIT_LIST_HEAD(&q->hw_engine_group_link);
|
||||
|
||||
q->sched_props.timeslice_us = hwe->eclass->sched_props.timeslice_us;
|
||||
q->sched_props.preempt_timeout_us =
|
||||
@@ -166,7 +168,8 @@ err_post_alloc:
|
||||
|
||||
struct xe_exec_queue *xe_exec_queue_create_class(struct xe_device *xe, struct xe_gt *gt,
|
||||
struct xe_vm *vm,
|
||||
enum xe_engine_class class, u32 flags)
|
||||
enum xe_engine_class class,
|
||||
u32 flags, u64 extensions)
|
||||
{
|
||||
struct xe_hw_engine *hwe, *hwe0 = NULL;
|
||||
enum xe_hw_engine_id id;
|
||||
@@ -186,7 +189,54 @@ struct xe_exec_queue *xe_exec_queue_create_class(struct xe_device *xe, struct xe
|
||||
if (!logical_mask)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
return xe_exec_queue_create(xe, vm, logical_mask, 1, hwe0, flags, 0);
|
||||
return xe_exec_queue_create(xe, vm, logical_mask, 1, hwe0, flags, extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_exec_queue_create_bind() - Create bind exec queue.
|
||||
* @xe: Xe device.
|
||||
* @tile: tile which bind exec queue belongs to.
|
||||
* @flags: exec queue creation flags
|
||||
* @extensions: exec queue creation extensions
|
||||
*
|
||||
* Normalize bind exec queue creation. Bind exec queue is tied to migration VM
|
||||
* for access to physical memory required for page table programming. On a
|
||||
* faulting devices the reserved copy engine instance must be used to avoid
|
||||
* deadlocking (user binds cannot get stuck behind faults as kernel binds which
|
||||
* resolve faults depend on user binds). On non-faulting devices any copy engine
|
||||
* can be used.
|
||||
*
|
||||
* Returns exec queue on success, ERR_PTR on failure
|
||||
*/
|
||||
struct xe_exec_queue *xe_exec_queue_create_bind(struct xe_device *xe,
|
||||
struct xe_tile *tile,
|
||||
u32 flags, u64 extensions)
|
||||
{
|
||||
struct xe_gt *gt = tile->primary_gt;
|
||||
struct xe_exec_queue *q;
|
||||
struct xe_vm *migrate_vm;
|
||||
|
||||
migrate_vm = xe_migrate_get_vm(tile->migrate);
|
||||
if (xe->info.has_usm) {
|
||||
struct xe_hw_engine *hwe = xe_gt_hw_engine(gt,
|
||||
XE_ENGINE_CLASS_COPY,
|
||||
gt->usm.reserved_bcs_instance,
|
||||
false);
|
||||
|
||||
if (!hwe)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
q = xe_exec_queue_create(xe, migrate_vm,
|
||||
BIT(hwe->logical_instance), 1, hwe,
|
||||
flags, extensions);
|
||||
} else {
|
||||
q = xe_exec_queue_create_class(xe, gt, migrate_vm,
|
||||
XE_ENGINE_CLASS_COPY, flags,
|
||||
extensions);
|
||||
}
|
||||
xe_vm_put(migrate_vm);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void xe_exec_queue_destroy(struct kref *ref)
|
||||
@@ -418,63 +468,6 @@ static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const enum xe_engine_class user_to_xe_engine_class[] = {
|
||||
[DRM_XE_ENGINE_CLASS_RENDER] = XE_ENGINE_CLASS_RENDER,
|
||||
[DRM_XE_ENGINE_CLASS_COPY] = XE_ENGINE_CLASS_COPY,
|
||||
[DRM_XE_ENGINE_CLASS_VIDEO_DECODE] = XE_ENGINE_CLASS_VIDEO_DECODE,
|
||||
[DRM_XE_ENGINE_CLASS_VIDEO_ENHANCE] = XE_ENGINE_CLASS_VIDEO_ENHANCE,
|
||||
[DRM_XE_ENGINE_CLASS_COMPUTE] = XE_ENGINE_CLASS_COMPUTE,
|
||||
};
|
||||
|
||||
static struct xe_hw_engine *
|
||||
find_hw_engine(struct xe_device *xe,
|
||||
struct drm_xe_engine_class_instance eci)
|
||||
{
|
||||
u32 idx;
|
||||
|
||||
if (eci.engine_class >= ARRAY_SIZE(user_to_xe_engine_class))
|
||||
return NULL;
|
||||
|
||||
if (eci.gt_id >= xe->info.gt_count)
|
||||
return NULL;
|
||||
|
||||
idx = array_index_nospec(eci.engine_class,
|
||||
ARRAY_SIZE(user_to_xe_engine_class));
|
||||
|
||||
return xe_gt_hw_engine(xe_device_get_gt(xe, eci.gt_id),
|
||||
user_to_xe_engine_class[idx],
|
||||
eci.engine_instance, true);
|
||||
}
|
||||
|
||||
static u32 bind_exec_queue_logical_mask(struct xe_device *xe, struct xe_gt *gt,
|
||||
struct drm_xe_engine_class_instance *eci,
|
||||
u16 width, u16 num_placements)
|
||||
{
|
||||
struct xe_hw_engine *hwe;
|
||||
enum xe_hw_engine_id id;
|
||||
u32 logical_mask = 0;
|
||||
|
||||
if (XE_IOCTL_DBG(xe, width != 1))
|
||||
return 0;
|
||||
if (XE_IOCTL_DBG(xe, num_placements != 1))
|
||||
return 0;
|
||||
if (XE_IOCTL_DBG(xe, eci[0].engine_instance != 0))
|
||||
return 0;
|
||||
|
||||
eci[0].engine_class = DRM_XE_ENGINE_CLASS_COPY;
|
||||
|
||||
for_each_hw_engine(hwe, gt, id) {
|
||||
if (xe_hw_engine_is_reserved(hwe))
|
||||
continue;
|
||||
|
||||
if (hwe->class ==
|
||||
user_to_xe_engine_class[DRM_XE_ENGINE_CLASS_COPY])
|
||||
logical_mask |= BIT(hwe->logical_instance);
|
||||
}
|
||||
|
||||
return logical_mask;
|
||||
}
|
||||
|
||||
static u32 calc_validate_logical_mask(struct xe_device *xe, struct xe_gt *gt,
|
||||
struct drm_xe_engine_class_instance *eci,
|
||||
u16 width, u16 num_placements)
|
||||
@@ -497,7 +490,7 @@ static u32 calc_validate_logical_mask(struct xe_device *xe, struct xe_gt *gt,
|
||||
|
||||
n = j * width + i;
|
||||
|
||||
hwe = find_hw_engine(xe, eci[n]);
|
||||
hwe = xe_hw_engine_lookup(xe, eci[n]);
|
||||
if (XE_IOCTL_DBG(xe, !hwe))
|
||||
return 0;
|
||||
|
||||
@@ -536,8 +529,9 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_xe_engine_class_instance __user *user_eci =
|
||||
u64_to_user_ptr(args->instances);
|
||||
struct xe_hw_engine *hwe;
|
||||
struct xe_vm *vm, *migrate_vm;
|
||||
struct xe_vm *vm;
|
||||
struct xe_gt *gt;
|
||||
struct xe_tile *tile;
|
||||
struct xe_exec_queue *q = NULL;
|
||||
u32 logical_mask;
|
||||
u32 id;
|
||||
@@ -562,37 +556,20 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
|
||||
return -EINVAL;
|
||||
|
||||
if (eci[0].engine_class == DRM_XE_ENGINE_CLASS_VM_BIND) {
|
||||
for_each_gt(gt, xe, id) {
|
||||
if (XE_IOCTL_DBG(xe, args->width != 1) ||
|
||||
XE_IOCTL_DBG(xe, args->num_placements != 1) ||
|
||||
XE_IOCTL_DBG(xe, eci[0].engine_instance != 0))
|
||||
return -EINVAL;
|
||||
|
||||
for_each_tile(tile, xe, id) {
|
||||
struct xe_exec_queue *new;
|
||||
u32 flags;
|
||||
u32 flags = EXEC_QUEUE_FLAG_VM;
|
||||
|
||||
if (xe_gt_is_media_type(gt))
|
||||
continue;
|
||||
if (id)
|
||||
flags |= EXEC_QUEUE_FLAG_BIND_ENGINE_CHILD;
|
||||
|
||||
eci[0].gt_id = gt->info.id;
|
||||
logical_mask = bind_exec_queue_logical_mask(xe, gt, eci,
|
||||
args->width,
|
||||
args->num_placements);
|
||||
if (XE_IOCTL_DBG(xe, !logical_mask))
|
||||
return -EINVAL;
|
||||
|
||||
hwe = find_hw_engine(xe, eci[0]);
|
||||
if (XE_IOCTL_DBG(xe, !hwe))
|
||||
return -EINVAL;
|
||||
|
||||
/* The migration vm doesn't hold rpm ref */
|
||||
xe_pm_runtime_get_noresume(xe);
|
||||
|
||||
flags = EXEC_QUEUE_FLAG_VM | (id ? EXEC_QUEUE_FLAG_BIND_ENGINE_CHILD : 0);
|
||||
|
||||
migrate_vm = xe_migrate_get_vm(gt_to_tile(gt)->migrate);
|
||||
new = xe_exec_queue_create(xe, migrate_vm, logical_mask,
|
||||
args->width, hwe, flags,
|
||||
args->extensions);
|
||||
|
||||
xe_pm_runtime_put(xe); /* now held by engine */
|
||||
|
||||
xe_vm_put(migrate_vm);
|
||||
new = xe_exec_queue_create_bind(xe, tile, flags,
|
||||
args->extensions);
|
||||
if (IS_ERR(new)) {
|
||||
err = PTR_ERR(new);
|
||||
if (q)
|
||||
@@ -613,7 +590,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
|
||||
if (XE_IOCTL_DBG(xe, !logical_mask))
|
||||
return -EINVAL;
|
||||
|
||||
hwe = find_hw_engine(xe, eci[0]);
|
||||
hwe = xe_hw_engine_lookup(xe, eci[0]);
|
||||
if (XE_IOCTL_DBG(xe, !hwe))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -648,6 +625,12 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,
|
||||
if (XE_IOCTL_DBG(xe, err))
|
||||
goto put_exec_queue;
|
||||
}
|
||||
|
||||
if (q->vm && q->hwe->hw_engine_group) {
|
||||
err = xe_hw_engine_group_add_exec_queue(q->hwe->hw_engine_group, q);
|
||||
if (err)
|
||||
goto put_exec_queue;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&xef->exec_queue.lock);
|
||||
@@ -798,6 +781,15 @@ void xe_exec_queue_update_run_ticks(struct xe_exec_queue *q)
|
||||
xef->run_ticks[q->class] += (new_ts - old_ts) * q->width;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_exec_queue_kill - permanently stop all execution from an exec queue
|
||||
* @q: The exec queue
|
||||
*
|
||||
* This function permanently stops all activity on an exec queue. If the queue
|
||||
* is actively executing on the HW, it will be kicked off the engine; any
|
||||
* pending jobs are discarded and all future submissions are rejected.
|
||||
* This function is safe to call multiple times.
|
||||
*/
|
||||
void xe_exec_queue_kill(struct xe_exec_queue *q)
|
||||
{
|
||||
struct xe_exec_queue *eq = q, *next;
|
||||
@@ -830,6 +822,9 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data,
|
||||
if (XE_IOCTL_DBG(xe, !q))
|
||||
return -ENOENT;
|
||||
|
||||
if (q->vm && q->hwe->hw_engine_group)
|
||||
xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q);
|
||||
|
||||
xe_exec_queue_kill(q);
|
||||
|
||||
trace_xe_exec_queue_close(q);
|
||||
@@ -841,10 +836,12 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data,
|
||||
static void xe_exec_queue_last_fence_lockdep_assert(struct xe_exec_queue *q,
|
||||
struct xe_vm *vm)
|
||||
{
|
||||
if (q->flags & EXEC_QUEUE_FLAG_VM)
|
||||
if (q->flags & EXEC_QUEUE_FLAG_VM) {
|
||||
lockdep_assert_held(&vm->lock);
|
||||
else
|
||||
} else {
|
||||
xe_vm_assert_held(vm);
|
||||
lockdep_assert_held(&q->hwe->hw_engine_group->mode_sem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -856,10 +853,7 @@ void xe_exec_queue_last_fence_put(struct xe_exec_queue *q, struct xe_vm *vm)
|
||||
{
|
||||
xe_exec_queue_last_fence_lockdep_assert(q, vm);
|
||||
|
||||
if (q->last_fence) {
|
||||
dma_fence_put(q->last_fence);
|
||||
q->last_fence = NULL;
|
||||
}
|
||||
xe_exec_queue_last_fence_put_unlocked(q);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -901,6 +895,33 @@ struct dma_fence *xe_exec_queue_last_fence_get(struct xe_exec_queue *q,
|
||||
return fence;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_exec_queue_last_fence_get_for_resume() - Get last fence
|
||||
* @q: The exec queue
|
||||
* @vm: The VM the engine does a bind or exec for
|
||||
*
|
||||
* Get last fence, takes a ref. Only safe to be called in the context of
|
||||
* resuming the hw engine group's long-running exec queue, when the group
|
||||
* semaphore is held.
|
||||
*
|
||||
* Returns: last fence if not signaled, dma fence stub if signaled
|
||||
*/
|
||||
struct dma_fence *xe_exec_queue_last_fence_get_for_resume(struct xe_exec_queue *q,
|
||||
struct xe_vm *vm)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
|
||||
lockdep_assert_held_write(&q->hwe->hw_engine_group->mode_sem);
|
||||
|
||||
if (q->last_fence &&
|
||||
test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &q->last_fence->flags))
|
||||
xe_exec_queue_last_fence_put_unlocked(q);
|
||||
|
||||
fence = q->last_fence ? q->last_fence : dma_fence_get_stub();
|
||||
dma_fence_get(fence);
|
||||
return fence;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_exec_queue_last_fence_set() - Set last fence
|
||||
* @q: The exec queue
|
||||
|
||||
@@ -20,7 +20,11 @@ struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *v
|
||||
u64 extensions);
|
||||
struct xe_exec_queue *xe_exec_queue_create_class(struct xe_device *xe, struct xe_gt *gt,
|
||||
struct xe_vm *vm,
|
||||
enum xe_engine_class class, u32 flags);
|
||||
enum xe_engine_class class,
|
||||
u32 flags, u64 extensions);
|
||||
struct xe_exec_queue *xe_exec_queue_create_bind(struct xe_device *xe,
|
||||
struct xe_tile *tile,
|
||||
u32 flags, u64 extensions);
|
||||
|
||||
void xe_exec_queue_fini(struct xe_exec_queue *q);
|
||||
void xe_exec_queue_destroy(struct kref *ref);
|
||||
@@ -73,6 +77,8 @@ void xe_exec_queue_last_fence_put(struct xe_exec_queue *e, struct xe_vm *vm);
|
||||
void xe_exec_queue_last_fence_put_unlocked(struct xe_exec_queue *e);
|
||||
struct dma_fence *xe_exec_queue_last_fence_get(struct xe_exec_queue *e,
|
||||
struct xe_vm *vm);
|
||||
struct dma_fence *xe_exec_queue_last_fence_get_for_resume(struct xe_exec_queue *e,
|
||||
struct xe_vm *vm);
|
||||
void xe_exec_queue_last_fence_set(struct xe_exec_queue *e, struct xe_vm *vm,
|
||||
struct dma_fence *fence);
|
||||
int xe_exec_queue_last_fence_test_dep(struct xe_exec_queue *q,
|
||||
|
||||
@@ -140,6 +140,8 @@ struct xe_exec_queue {
|
||||
* Protected by @vm's resv. Unused if @vm == NULL.
|
||||
*/
|
||||
u64 tlb_flush_seqno;
|
||||
/** @hw_engine_group_link: link into exec queues in the same hw engine group */
|
||||
struct list_head hw_engine_group_link;
|
||||
/** @lrc: logical ring context for this exec queue */
|
||||
struct xe_lrc *lrc[];
|
||||
};
|
||||
|
||||
@@ -30,6 +30,39 @@
|
||||
#include "xe_wa.h"
|
||||
#include "xe_wopcm.h"
|
||||
|
||||
/**
|
||||
* DOC: Global Graphics Translation Table (GGTT)
|
||||
*
|
||||
* Xe GGTT implements the support for a Global Virtual Address space that is used
|
||||
* for resources that are accessible to privileged (i.e. kernel-mode) processes,
|
||||
* and not tied to a specific user-level process. For example, the Graphics
|
||||
* micro-Controller (GuC) and Display Engine (if present) utilize this Global
|
||||
* address space.
|
||||
*
|
||||
* The Global GTT (GGTT) translates from the Global virtual address to a physical
|
||||
* address that can be accessed by HW. The GGTT is a flat, single-level table.
|
||||
*
|
||||
* Xe implements a simplified version of the GGTT specifically managing only a
|
||||
* certain range of it that goes from the Write Once Protected Content Memory (WOPCM)
|
||||
* Layout to a predefined GUC_GGTT_TOP. This approach avoids complications related to
|
||||
* the GuC (Graphics Microcontroller) hardware limitations. The GuC address space
|
||||
* is limited on both ends of the GGTT, because the GuC shim HW redirects
|
||||
* accesses to those addresses to other HW areas instead of going through the
|
||||
* GGTT. On the bottom end, the GuC can't access offsets below the WOPCM size,
|
||||
* while on the top side the limit is fixed at GUC_GGTT_TOP. To keep things
|
||||
* simple, instead of checking each object to see if they are accessed by GuC or
|
||||
* not, we just exclude those areas from the allocator. Additionally, to simplify
|
||||
* the driver load, we use the maximum WOPCM size in this logic instead of the
|
||||
* programmed one, so we don't need to wait until the actual size to be
|
||||
* programmed is determined (which requires FW fetch) before initializing the
|
||||
* GGTT. These simplifications might waste space in the GGTT (about 20-25 MBs
|
||||
* depending on the platform) but we can live with this. Another benefit of this
|
||||
* is the GuC bootrom can't access anything below the WOPCM max size so anything
|
||||
* the bootrom needs to access (e.g. a RSA key) needs to be placed in the GGTT
|
||||
* above the WOPCM max size. Starting the GGTT allocations above the WOPCM max
|
||||
* give us the correct placement for free.
|
||||
*/
|
||||
|
||||
static u64 xelp_ggtt_pte_encode_bo(struct xe_bo *bo, u64 bo_offset,
|
||||
u16 pat_index)
|
||||
{
|
||||
@@ -128,11 +161,12 @@ static void ggtt_fini_early(struct drm_device *drm, void *arg)
|
||||
{
|
||||
struct xe_ggtt *ggtt = arg;
|
||||
|
||||
destroy_workqueue(ggtt->wq);
|
||||
mutex_destroy(&ggtt->lock);
|
||||
drm_mm_takedown(&ggtt->mm);
|
||||
}
|
||||
|
||||
static void ggtt_fini(struct drm_device *drm, void *arg)
|
||||
static void ggtt_fini(void *arg)
|
||||
{
|
||||
struct xe_ggtt *ggtt = arg;
|
||||
|
||||
@@ -164,12 +198,16 @@ static const struct xe_ggtt_pt_ops xelpg_pt_wa_ops = {
|
||||
.ggtt_set_pte = xe_ggtt_set_pte_and_flush,
|
||||
};
|
||||
|
||||
/*
|
||||
* Early GGTT initialization, which allows to create new mappings usable by the
|
||||
* GuC.
|
||||
* Mappings are not usable by the HW engines, as it doesn't have scratch /
|
||||
/**
|
||||
* xe_ggtt_init_early - Early GGTT initialization
|
||||
* @ggtt: the &xe_ggtt to be initialized
|
||||
*
|
||||
* It allows to create new mappings usable by the GuC.
|
||||
* Mappings are not usable by the HW engines, as it doesn't have scratch nor
|
||||
* initial clear done to it yet. That will happen in the regular, non-early
|
||||
* GGTT init.
|
||||
* GGTT initialization.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_ggtt_init_early(struct xe_ggtt *ggtt)
|
||||
{
|
||||
@@ -194,29 +232,6 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
|
||||
if (IS_DGFX(xe) && xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K)
|
||||
ggtt->flags |= XE_GGTT_FLAGS_64K;
|
||||
|
||||
/*
|
||||
* 8B per entry, each points to a 4KB page.
|
||||
*
|
||||
* The GuC address space is limited on both ends of the GGTT, because
|
||||
* the GuC shim HW redirects accesses to those addresses to other HW
|
||||
* areas instead of going through the GGTT. On the bottom end, the GuC
|
||||
* can't access offsets below the WOPCM size, while on the top side the
|
||||
* limit is fixed at GUC_GGTT_TOP. To keep things simple, instead of
|
||||
* checking each object to see if they are accessed by GuC or not, we
|
||||
* just exclude those areas from the allocator. Additionally, to
|
||||
* simplify the driver load, we use the maximum WOPCM size in this logic
|
||||
* instead of the programmed one, so we don't need to wait until the
|
||||
* actual size to be programmed is determined (which requires FW fetch)
|
||||
* before initializing the GGTT. These simplifications might waste space
|
||||
* in the GGTT (about 20-25 MBs depending on the platform) but we can
|
||||
* live with this.
|
||||
*
|
||||
* Another benifit of this is the GuC bootrom can't access anything
|
||||
* below the WOPCM max size so anything the bootom needs to access (e.g.
|
||||
* a RSA key) needs to be placed in the GGTT above the WOPCM max size.
|
||||
* Starting the GGTT allocations above the WOPCM max give us the correct
|
||||
* placement for free.
|
||||
*/
|
||||
if (ggtt->size > GUC_GGTT_TOP)
|
||||
ggtt->size = GUC_GGTT_TOP;
|
||||
|
||||
@@ -228,6 +243,8 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
|
||||
else
|
||||
ggtt->pt_ops = &xelp_pt_ops;
|
||||
|
||||
ggtt->wq = alloc_workqueue("xe-ggtt-wq", 0, 0);
|
||||
|
||||
drm_mm_init(&ggtt->mm, xe_wopcm_size(xe),
|
||||
ggtt->size - xe_wopcm_size(xe));
|
||||
mutex_init(&ggtt->lock);
|
||||
@@ -262,6 +279,77 @@ static void xe_ggtt_initial_clear(struct xe_ggtt *ggtt)
|
||||
mutex_unlock(&ggtt->lock);
|
||||
}
|
||||
|
||||
static void ggtt_node_remove(struct xe_ggtt_node *node)
|
||||
{
|
||||
struct xe_ggtt *ggtt = node->ggtt;
|
||||
struct xe_device *xe = tile_to_xe(ggtt->tile);
|
||||
bool bound;
|
||||
int idx;
|
||||
|
||||
bound = drm_dev_enter(&xe->drm, &idx);
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
if (bound)
|
||||
xe_ggtt_clear(ggtt, node->base.start, node->base.size);
|
||||
drm_mm_remove_node(&node->base);
|
||||
node->base.size = 0;
|
||||
mutex_unlock(&ggtt->lock);
|
||||
|
||||
if (!bound)
|
||||
goto free_node;
|
||||
|
||||
if (node->invalidate_on_remove)
|
||||
xe_ggtt_invalidate(ggtt);
|
||||
|
||||
drm_dev_exit(idx);
|
||||
|
||||
free_node:
|
||||
xe_ggtt_node_fini(node);
|
||||
}
|
||||
|
||||
static void ggtt_node_remove_work_func(struct work_struct *work)
|
||||
{
|
||||
struct xe_ggtt_node *node = container_of(work, typeof(*node),
|
||||
delayed_removal_work);
|
||||
struct xe_device *xe = tile_to_xe(node->ggtt->tile);
|
||||
|
||||
xe_pm_runtime_get(xe);
|
||||
ggtt_node_remove(node);
|
||||
xe_pm_runtime_put(xe);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_node_remove - Remove a &xe_ggtt_node from the GGTT
|
||||
* @node: the &xe_ggtt_node to be removed
|
||||
* @invalidate: if node needs invalidation upon removal
|
||||
*/
|
||||
void xe_ggtt_node_remove(struct xe_ggtt_node *node, bool invalidate)
|
||||
{
|
||||
struct xe_ggtt *ggtt;
|
||||
struct xe_device *xe;
|
||||
|
||||
if (!node || !node->ggtt)
|
||||
return;
|
||||
|
||||
ggtt = node->ggtt;
|
||||
xe = tile_to_xe(ggtt->tile);
|
||||
|
||||
node->invalidate_on_remove = invalidate;
|
||||
|
||||
if (xe_pm_runtime_get_if_active(xe)) {
|
||||
ggtt_node_remove(node);
|
||||
xe_pm_runtime_put(xe);
|
||||
} else {
|
||||
queue_work(ggtt->wq, &node->delayed_removal_work);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_init - Regular non-early GGTT initialization
|
||||
* @ggtt: the &xe_ggtt to be initialized
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_ggtt_init(struct xe_ggtt *ggtt)
|
||||
{
|
||||
struct xe_device *xe = tile_to_xe(ggtt->tile);
|
||||
@@ -289,7 +377,7 @@ int xe_ggtt_init(struct xe_ggtt *ggtt)
|
||||
|
||||
xe_ggtt_initial_clear(ggtt);
|
||||
|
||||
return drmm_add_action_or_reset(&xe->drm, ggtt_fini, ggtt);
|
||||
return devm_add_action_or_reset(xe->drm.dev, ggtt_fini, ggtt);
|
||||
err:
|
||||
ggtt->scratch = NULL;
|
||||
return err;
|
||||
@@ -314,26 +402,6 @@ static void xe_ggtt_invalidate(struct xe_ggtt *ggtt)
|
||||
ggtt_invalidate_gt_tlb(ggtt->tile->media_gt);
|
||||
}
|
||||
|
||||
void xe_ggtt_printk(struct xe_ggtt *ggtt, const char *prefix)
|
||||
{
|
||||
u16 pat_index = tile_to_xe(ggtt->tile)->pat.idx[XE_CACHE_WB];
|
||||
u64 addr, scratch_pte;
|
||||
|
||||
scratch_pte = ggtt->pt_ops->pte_encode_bo(ggtt->scratch, 0, pat_index);
|
||||
|
||||
printk("%sGlobal GTT:", prefix);
|
||||
for (addr = 0; addr < ggtt->size; addr += XE_PAGE_SIZE) {
|
||||
unsigned int i = addr / XE_PAGE_SIZE;
|
||||
|
||||
xe_tile_assert(ggtt->tile, addr <= U32_MAX);
|
||||
if (ggtt->gsm[i] == scratch_pte)
|
||||
continue;
|
||||
|
||||
printk("%s ggtt[0x%08x] = 0x%016llx",
|
||||
prefix, (u32)addr, ggtt->gsm[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void xe_ggtt_dump_node(struct xe_ggtt *ggtt,
|
||||
const struct drm_mm_node *node, const char *description)
|
||||
{
|
||||
@@ -347,88 +415,180 @@ static void xe_ggtt_dump_node(struct xe_ggtt *ggtt,
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_balloon - prevent allocation of specified GGTT addresses
|
||||
* @ggtt: the &xe_ggtt where we want to make reservation
|
||||
* xe_ggtt_node_insert_balloon - prevent allocation of specified GGTT addresses
|
||||
* @node: the &xe_ggtt_node to hold reserved GGTT node
|
||||
* @start: the starting GGTT address of the reserved region
|
||||
* @end: then end GGTT address of the reserved region
|
||||
* @node: the &drm_mm_node to hold reserved GGTT node
|
||||
*
|
||||
* Use xe_ggtt_deballoon() to release a reserved GGTT node.
|
||||
* Use xe_ggtt_node_remove_balloon() to release a reserved GGTT node.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_ggtt_balloon(struct xe_ggtt *ggtt, u64 start, u64 end, struct drm_mm_node *node)
|
||||
int xe_ggtt_node_insert_balloon(struct xe_ggtt_node *node, u64 start, u64 end)
|
||||
{
|
||||
struct xe_ggtt *ggtt = node->ggtt;
|
||||
int err;
|
||||
|
||||
xe_tile_assert(ggtt->tile, start < end);
|
||||
xe_tile_assert(ggtt->tile, IS_ALIGNED(start, XE_PAGE_SIZE));
|
||||
xe_tile_assert(ggtt->tile, IS_ALIGNED(end, XE_PAGE_SIZE));
|
||||
xe_tile_assert(ggtt->tile, !drm_mm_node_allocated(node));
|
||||
xe_tile_assert(ggtt->tile, !drm_mm_node_allocated(&node->base));
|
||||
|
||||
node->color = 0;
|
||||
node->start = start;
|
||||
node->size = end - start;
|
||||
node->base.color = 0;
|
||||
node->base.start = start;
|
||||
node->base.size = end - start;
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
err = drm_mm_reserve_node(&ggtt->mm, node);
|
||||
err = drm_mm_reserve_node(&ggtt->mm, &node->base);
|
||||
mutex_unlock(&ggtt->lock);
|
||||
|
||||
if (xe_gt_WARN(ggtt->tile->primary_gt, err,
|
||||
"Failed to balloon GGTT %#llx-%#llx (%pe)\n",
|
||||
node->start, node->start + node->size, ERR_PTR(err)))
|
||||
node->base.start, node->base.start + node->base.size, ERR_PTR(err)))
|
||||
return err;
|
||||
|
||||
xe_ggtt_dump_node(ggtt, node, "balloon");
|
||||
xe_ggtt_dump_node(ggtt, &node->base, "balloon");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_deballoon - release a reserved GGTT region
|
||||
* @ggtt: the &xe_ggtt where reserved node belongs
|
||||
* @node: the &drm_mm_node with reserved GGTT region
|
||||
* xe_ggtt_node_remove_balloon - release a reserved GGTT region
|
||||
* @node: the &xe_ggtt_node with reserved GGTT region
|
||||
*
|
||||
* See xe_ggtt_balloon() for details.
|
||||
* See xe_ggtt_node_insert_balloon() for details.
|
||||
*/
|
||||
void xe_ggtt_deballoon(struct xe_ggtt *ggtt, struct drm_mm_node *node)
|
||||
void xe_ggtt_node_remove_balloon(struct xe_ggtt_node *node)
|
||||
{
|
||||
if (!drm_mm_node_allocated(node))
|
||||
if (!node || !node->ggtt)
|
||||
return;
|
||||
|
||||
xe_ggtt_dump_node(ggtt, node, "deballoon");
|
||||
if (!drm_mm_node_allocated(&node->base))
|
||||
goto free_node;
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
drm_mm_remove_node(node);
|
||||
mutex_unlock(&ggtt->lock);
|
||||
xe_ggtt_dump_node(node->ggtt, &node->base, "remove-balloon");
|
||||
|
||||
mutex_lock(&node->ggtt->lock);
|
||||
drm_mm_remove_node(&node->base);
|
||||
mutex_unlock(&node->ggtt->lock);
|
||||
|
||||
free_node:
|
||||
xe_ggtt_node_fini(node);
|
||||
}
|
||||
|
||||
int xe_ggtt_insert_special_node_locked(struct xe_ggtt *ggtt, struct drm_mm_node *node,
|
||||
u32 size, u32 align, u32 mm_flags)
|
||||
/**
|
||||
* xe_ggtt_node_insert_locked - Locked version to insert a &xe_ggtt_node into the GGTT
|
||||
* @node: the &xe_ggtt_node to be inserted
|
||||
* @size: size of the node
|
||||
* @align: alignment constrain of the node
|
||||
* @mm_flags: flags to control the node behavior
|
||||
*
|
||||
* It cannot be called without first having called xe_ggtt_init() once.
|
||||
* To be used in cases where ggtt->lock is already taken.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node,
|
||||
u32 size, u32 align, u32 mm_flags)
|
||||
{
|
||||
return drm_mm_insert_node_generic(&ggtt->mm, node, size, align, 0,
|
||||
return drm_mm_insert_node_generic(&node->ggtt->mm, &node->base, size, align, 0,
|
||||
mm_flags);
|
||||
}
|
||||
|
||||
int xe_ggtt_insert_special_node(struct xe_ggtt *ggtt, struct drm_mm_node *node,
|
||||
u32 size, u32 align)
|
||||
/**
|
||||
* xe_ggtt_node_insert - Insert a &xe_ggtt_node into the GGTT
|
||||
* @node: the &xe_ggtt_node to be inserted
|
||||
* @size: size of the node
|
||||
* @align: alignment constrain of the node
|
||||
*
|
||||
* It cannot be called without first having called xe_ggtt_init() once.
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
ret = xe_ggtt_insert_special_node_locked(ggtt, node, size,
|
||||
align, DRM_MM_INSERT_HIGH);
|
||||
mutex_unlock(&ggtt->lock);
|
||||
if (!node || !node->ggtt)
|
||||
return -ENOENT;
|
||||
|
||||
mutex_lock(&node->ggtt->lock);
|
||||
ret = xe_ggtt_node_insert_locked(node, size, align,
|
||||
DRM_MM_INSERT_HIGH);
|
||||
mutex_unlock(&node->ggtt->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_node_init - Initialize %xe_ggtt_node struct
|
||||
* @ggtt: the &xe_ggtt where the new node will later be inserted/reserved.
|
||||
*
|
||||
* This function will allocated the struct %xe_ggtt_node and return it's pointer.
|
||||
* This struct will then be freed after the node removal upon xe_ggtt_node_remove()
|
||||
* or xe_ggtt_node_remove_balloon().
|
||||
* Having %xe_ggtt_node struct allocated doesn't mean that the node is already allocated
|
||||
* in GGTT. Only the xe_ggtt_node_insert(), xe_ggtt_node_insert_locked(),
|
||||
* xe_ggtt_node_insert_balloon() will ensure the node is inserted or reserved in GGTT.
|
||||
*
|
||||
* Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise.
|
||||
**/
|
||||
struct xe_ggtt_node *xe_ggtt_node_init(struct xe_ggtt *ggtt)
|
||||
{
|
||||
struct xe_ggtt_node *node = kzalloc(sizeof(*node), GFP_NOFS);
|
||||
|
||||
if (!node)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
INIT_WORK(&node->delayed_removal_work, ggtt_node_remove_work_func);
|
||||
node->ggtt = ggtt;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_node_fini - Forcebly finalize %xe_ggtt_node struct
|
||||
* @node: the &xe_ggtt_node to be freed
|
||||
*
|
||||
* If anything went wrong with either xe_ggtt_node_insert(), xe_ggtt_node_insert_locked(),
|
||||
* or xe_ggtt_node_insert_balloon(); and this @node is not going to be reused, then,
|
||||
* this function needs to be called to free the %xe_ggtt_node struct
|
||||
**/
|
||||
void xe_ggtt_node_fini(struct xe_ggtt_node *node)
|
||||
{
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_node_allocated - Check if node is allocated in GGTT
|
||||
* @node: the &xe_ggtt_node to be inspected
|
||||
*
|
||||
* Return: True if allocated, False otherwise.
|
||||
*/
|
||||
bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node)
|
||||
{
|
||||
if (!node || !node->ggtt)
|
||||
return false;
|
||||
|
||||
return drm_mm_node_allocated(&node->base);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_map_bo - Map the BO into GGTT
|
||||
* @ggtt: the &xe_ggtt where node will be mapped
|
||||
* @bo: the &xe_bo to be mapped
|
||||
*/
|
||||
void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_bo *bo)
|
||||
{
|
||||
u16 cache_mode = bo->flags & XE_BO_FLAG_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB;
|
||||
u16 pat_index = tile_to_xe(ggtt->tile)->pat.idx[cache_mode];
|
||||
u64 start = bo->ggtt_node.start;
|
||||
u64 start;
|
||||
u64 offset, pte;
|
||||
|
||||
if (XE_WARN_ON(!bo->ggtt_node))
|
||||
return;
|
||||
|
||||
start = bo->ggtt_node->base.start;
|
||||
|
||||
for (offset = 0; offset < bo->size; offset += XE_PAGE_SIZE) {
|
||||
pte = ggtt->pt_ops->pte_encode_bo(bo, offset, pat_index);
|
||||
ggtt->pt_ops->ggtt_set_pte(ggtt, start + offset, pte);
|
||||
@@ -444,9 +604,9 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
|
||||
if (xe_bo_is_vram(bo) && ggtt->flags & XE_GGTT_FLAGS_64K)
|
||||
alignment = SZ_64K;
|
||||
|
||||
if (XE_WARN_ON(bo->ggtt_node.size)) {
|
||||
if (XE_WARN_ON(bo->ggtt_node)) {
|
||||
/* Someone's already inserted this BO in the GGTT */
|
||||
xe_tile_assert(ggtt->tile, bo->ggtt_node.size == bo->size);
|
||||
xe_tile_assert(ggtt->tile, bo->ggtt_node->base.size == bo->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -455,71 +615,110 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
|
||||
return err;
|
||||
|
||||
xe_pm_runtime_get_noresume(tile_to_xe(ggtt->tile));
|
||||
|
||||
bo->ggtt_node = xe_ggtt_node_init(ggtt);
|
||||
if (IS_ERR(bo->ggtt_node)) {
|
||||
err = PTR_ERR(bo->ggtt_node);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
err = drm_mm_insert_node_in_range(&ggtt->mm, &bo->ggtt_node, bo->size,
|
||||
err = drm_mm_insert_node_in_range(&ggtt->mm, &bo->ggtt_node->base, bo->size,
|
||||
alignment, 0, start, end, 0);
|
||||
if (!err)
|
||||
if (err)
|
||||
xe_ggtt_node_fini(bo->ggtt_node);
|
||||
else
|
||||
xe_ggtt_map_bo(ggtt, bo);
|
||||
mutex_unlock(&ggtt->lock);
|
||||
|
||||
if (!err && bo->flags & XE_BO_FLAG_GGTT_INVALIDATE)
|
||||
xe_ggtt_invalidate(ggtt);
|
||||
|
||||
out:
|
||||
xe_pm_runtime_put(tile_to_xe(ggtt->tile));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_insert_bo_at - Insert BO at a specific GGTT space
|
||||
* @ggtt: the &xe_ggtt where bo will be inserted
|
||||
* @bo: the &xe_bo to be inserted
|
||||
* @start: address where it will be inserted
|
||||
* @end: end of the range where it will be inserted
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
|
||||
u64 start, u64 end)
|
||||
{
|
||||
return __xe_ggtt_insert_bo_at(ggtt, bo, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_insert_bo - Insert BO into GGTT
|
||||
* @ggtt: the &xe_ggtt where bo will be inserted
|
||||
* @bo: the &xe_bo to be inserted
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo)
|
||||
{
|
||||
return __xe_ggtt_insert_bo_at(ggtt, bo, 0, U64_MAX);
|
||||
}
|
||||
|
||||
void xe_ggtt_remove_node(struct xe_ggtt *ggtt, struct drm_mm_node *node,
|
||||
bool invalidate)
|
||||
{
|
||||
struct xe_device *xe = tile_to_xe(ggtt->tile);
|
||||
bool bound;
|
||||
int idx;
|
||||
|
||||
bound = drm_dev_enter(&xe->drm, &idx);
|
||||
if (bound)
|
||||
xe_pm_runtime_get_noresume(xe);
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
if (bound)
|
||||
xe_ggtt_clear(ggtt, node->start, node->size);
|
||||
drm_mm_remove_node(node);
|
||||
node->size = 0;
|
||||
mutex_unlock(&ggtt->lock);
|
||||
|
||||
if (!bound)
|
||||
return;
|
||||
|
||||
if (invalidate)
|
||||
xe_ggtt_invalidate(ggtt);
|
||||
|
||||
xe_pm_runtime_put(xe);
|
||||
drm_dev_exit(idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_remove_bo - Remove a BO from the GGTT
|
||||
* @ggtt: the &xe_ggtt where node will be removed
|
||||
* @bo: the &xe_bo to be removed
|
||||
*/
|
||||
void xe_ggtt_remove_bo(struct xe_ggtt *ggtt, struct xe_bo *bo)
|
||||
{
|
||||
if (XE_WARN_ON(!bo->ggtt_node.size))
|
||||
if (XE_WARN_ON(!bo->ggtt_node))
|
||||
return;
|
||||
|
||||
/* This BO is not currently in the GGTT */
|
||||
xe_tile_assert(ggtt->tile, bo->ggtt_node.size == bo->size);
|
||||
xe_tile_assert(ggtt->tile, bo->ggtt_node->base.size == bo->size);
|
||||
|
||||
xe_ggtt_remove_node(ggtt, &bo->ggtt_node,
|
||||
xe_ggtt_node_remove(bo->ggtt_node,
|
||||
bo->flags & XE_BO_FLAG_GGTT_INVALIDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_largest_hole - Largest GGTT hole
|
||||
* @ggtt: the &xe_ggtt that will be inspected
|
||||
* @alignment: minimum alignment
|
||||
* @spare: If not NULL: in: desired memory size to be spared / out: Adjusted possible spare
|
||||
*
|
||||
* Return: size of the largest continuous GGTT region
|
||||
*/
|
||||
u64 xe_ggtt_largest_hole(struct xe_ggtt *ggtt, u64 alignment, u64 *spare)
|
||||
{
|
||||
const struct drm_mm *mm = &ggtt->mm;
|
||||
const struct drm_mm_node *entry;
|
||||
u64 hole_min_start = xe_wopcm_size(tile_to_xe(ggtt->tile));
|
||||
u64 hole_start, hole_end, hole_size;
|
||||
u64 max_hole = 0;
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
|
||||
drm_mm_for_each_hole(entry, mm, hole_start, hole_end) {
|
||||
hole_start = max(hole_start, hole_min_start);
|
||||
hole_start = ALIGN(hole_start, alignment);
|
||||
hole_end = ALIGN_DOWN(hole_end, alignment);
|
||||
if (hole_start >= hole_end)
|
||||
continue;
|
||||
hole_size = hole_end - hole_start;
|
||||
if (spare)
|
||||
*spare -= min3(*spare, hole_size, max_hole);
|
||||
max_hole = max(max_hole, hole_size);
|
||||
}
|
||||
|
||||
mutex_unlock(&ggtt->lock);
|
||||
|
||||
return max_hole;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
static u64 xe_encode_vfid_pte(u16 vfid)
|
||||
{
|
||||
@@ -548,22 +747,28 @@ static void xe_ggtt_assign_locked(struct xe_ggtt *ggtt, const struct drm_mm_node
|
||||
|
||||
/**
|
||||
* xe_ggtt_assign - assign a GGTT region to the VF
|
||||
* @ggtt: the &xe_ggtt where the node belongs
|
||||
* @node: the &drm_mm_node to update
|
||||
* @node: the &xe_ggtt_node to update
|
||||
* @vfid: the VF identifier
|
||||
*
|
||||
* This function is used by the PF driver to assign a GGTT region to the VF.
|
||||
* In addition to PTE's VFID bits 11:2 also PRESENT bit 0 is set as on some
|
||||
* platforms VFs can't modify that either.
|
||||
*/
|
||||
void xe_ggtt_assign(struct xe_ggtt *ggtt, const struct drm_mm_node *node, u16 vfid)
|
||||
void xe_ggtt_assign(const struct xe_ggtt_node *node, u16 vfid)
|
||||
{
|
||||
mutex_lock(&ggtt->lock);
|
||||
xe_ggtt_assign_locked(ggtt, node, vfid);
|
||||
mutex_unlock(&ggtt->lock);
|
||||
mutex_lock(&node->ggtt->lock);
|
||||
xe_ggtt_assign_locked(node->ggtt, &node->base, vfid);
|
||||
mutex_unlock(&node->ggtt->lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* xe_ggtt_dump - Dump GGTT for debug
|
||||
* @ggtt: the &xe_ggtt to be dumped
|
||||
* @p: the &drm_mm_printer helper handle to be used to dump the information
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int xe_ggtt_dump(struct xe_ggtt *ggtt, struct drm_printer *p)
|
||||
{
|
||||
int err;
|
||||
@@ -576,3 +781,43 @@ int xe_ggtt_dump(struct xe_ggtt *ggtt, struct drm_printer *p)
|
||||
mutex_unlock(&ggtt->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* xe_ggtt_print_holes - Print holes
|
||||
* @ggtt: the &xe_ggtt to be inspected
|
||||
* @alignment: min alignment
|
||||
* @p: the &drm_printer
|
||||
*
|
||||
* Print GGTT ranges that are available and return total size available.
|
||||
*
|
||||
* Return: Total available size.
|
||||
*/
|
||||
u64 xe_ggtt_print_holes(struct xe_ggtt *ggtt, u64 alignment, struct drm_printer *p)
|
||||
{
|
||||
const struct drm_mm *mm = &ggtt->mm;
|
||||
const struct drm_mm_node *entry;
|
||||
u64 hole_min_start = xe_wopcm_size(tile_to_xe(ggtt->tile));
|
||||
u64 hole_start, hole_end, hole_size;
|
||||
u64 total = 0;
|
||||
char buf[10];
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
|
||||
drm_mm_for_each_hole(entry, mm, hole_start, hole_end) {
|
||||
hole_start = max(hole_start, hole_min_start);
|
||||
hole_start = ALIGN(hole_start, alignment);
|
||||
hole_end = ALIGN_DOWN(hole_end, alignment);
|
||||
if (hole_start >= hole_end)
|
||||
continue;
|
||||
hole_size = hole_end - hole_start;
|
||||
total += hole_size;
|
||||
|
||||
string_get_size(hole_size, 1, STRING_UNITS_2, buf, sizeof(buf));
|
||||
drm_printf(p, "range:\t%#llx-%#llx\t(%s)\n",
|
||||
hole_start, hole_end - 1, buf);
|
||||
}
|
||||
|
||||
mutex_unlock(&ggtt->lock);
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -12,28 +12,30 @@ struct drm_printer;
|
||||
|
||||
int xe_ggtt_init_early(struct xe_ggtt *ggtt);
|
||||
int xe_ggtt_init(struct xe_ggtt *ggtt);
|
||||
void xe_ggtt_printk(struct xe_ggtt *ggtt, const char *prefix);
|
||||
|
||||
int xe_ggtt_balloon(struct xe_ggtt *ggtt, u64 start, u64 size, struct drm_mm_node *node);
|
||||
void xe_ggtt_deballoon(struct xe_ggtt *ggtt, struct drm_mm_node *node);
|
||||
struct xe_ggtt_node *xe_ggtt_node_init(struct xe_ggtt *ggtt);
|
||||
void xe_ggtt_node_fini(struct xe_ggtt_node *node);
|
||||
int xe_ggtt_node_insert_balloon(struct xe_ggtt_node *node,
|
||||
u64 start, u64 size);
|
||||
void xe_ggtt_node_remove_balloon(struct xe_ggtt_node *node);
|
||||
|
||||
int xe_ggtt_insert_special_node(struct xe_ggtt *ggtt, struct drm_mm_node *node,
|
||||
u32 size, u32 align);
|
||||
int xe_ggtt_insert_special_node_locked(struct xe_ggtt *ggtt,
|
||||
struct drm_mm_node *node,
|
||||
u32 size, u32 align, u32 mm_flags);
|
||||
void xe_ggtt_remove_node(struct xe_ggtt *ggtt, struct drm_mm_node *node,
|
||||
bool invalidate);
|
||||
int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align);
|
||||
int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node,
|
||||
u32 size, u32 align, u32 mm_flags);
|
||||
void xe_ggtt_node_remove(struct xe_ggtt_node *node, bool invalidate);
|
||||
bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node);
|
||||
void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
|
||||
int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
|
||||
int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
|
||||
u64 start, u64 end);
|
||||
void xe_ggtt_remove_bo(struct xe_ggtt *ggtt, struct xe_bo *bo);
|
||||
u64 xe_ggtt_largest_hole(struct xe_ggtt *ggtt, u64 alignment, u64 *spare);
|
||||
|
||||
int xe_ggtt_dump(struct xe_ggtt *ggtt, struct drm_printer *p);
|
||||
u64 xe_ggtt_print_holes(struct xe_ggtt *ggtt, u64 alignment, struct drm_printer *p);
|
||||
|
||||
#ifdef CONFIG_PCI_IOV
|
||||
void xe_ggtt_assign(struct xe_ggtt *ggtt, const struct drm_mm_node *node, u16 vfid);
|
||||
void xe_ggtt_assign(const struct xe_ggtt_node *node, u16 vfid);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,30 +13,70 @@
|
||||
struct xe_bo;
|
||||
struct xe_gt;
|
||||
|
||||
/**
|
||||
* struct xe_ggtt - Main GGTT struct
|
||||
*
|
||||
* In general, each tile can contains its own Global Graphics Translation Table
|
||||
* (GGTT) instance.
|
||||
*/
|
||||
struct xe_ggtt {
|
||||
/** @tile: Back pointer to tile where this GGTT belongs */
|
||||
struct xe_tile *tile;
|
||||
|
||||
/** @size: Total size of this GGTT */
|
||||
u64 size;
|
||||
|
||||
#define XE_GGTT_FLAGS_64K BIT(0)
|
||||
/**
|
||||
* @flags: Flags for this GGTT
|
||||
* Acceptable flags:
|
||||
* - %XE_GGTT_FLAGS_64K - if PTE size is 64K. Otherwise, regular is 4K.
|
||||
*/
|
||||
unsigned int flags;
|
||||
|
||||
/** @scratch: Internal object allocation used as a scratch page */
|
||||
struct xe_bo *scratch;
|
||||
|
||||
/** @lock: Mutex lock to protect GGTT data */
|
||||
struct mutex lock;
|
||||
|
||||
/**
|
||||
* @gsm: The iomem pointer to the actual location of the translation
|
||||
* table located in the GSM for easy PTE manipulation
|
||||
*/
|
||||
u64 __iomem *gsm;
|
||||
|
||||
/** @pt_ops: Page Table operations per platform */
|
||||
const struct xe_ggtt_pt_ops *pt_ops;
|
||||
|
||||
/** @mm: The memory manager used to manage individual GGTT allocations */
|
||||
struct drm_mm mm;
|
||||
|
||||
/** @access_count: counts GGTT writes */
|
||||
unsigned int access_count;
|
||||
/** @wq: Dedicated unordered work queue to process node removals */
|
||||
struct workqueue_struct *wq;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xe_ggtt_node - A node in GGTT.
|
||||
*
|
||||
* This struct needs to be initialized (only-once) with xe_ggtt_node_init() before any node
|
||||
* insertion, reservation, or 'ballooning'.
|
||||
* It will, then, be finalized by either xe_ggtt_node_remove() or xe_ggtt_node_deballoon().
|
||||
*/
|
||||
struct xe_ggtt_node {
|
||||
/** @ggtt: Back pointer to xe_ggtt where this region will be inserted at */
|
||||
struct xe_ggtt *ggtt;
|
||||
/** @base: A drm_mm_node */
|
||||
struct drm_mm_node base;
|
||||
/** @delayed_removal_work: The work struct for the delayed removal */
|
||||
struct work_struct delayed_removal_work;
|
||||
/** @invalidate_on_remove: If it needs invalidation upon removal */
|
||||
bool invalidate_on_remove;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xe_ggtt_pt_ops - GGTT Page table operations
|
||||
* Which can vary from platform to platform.
|
||||
*/
|
||||
struct xe_ggtt_pt_ops {
|
||||
/** @pte_encode_bo: Encode PTE address for a given BO */
|
||||
u64 (*pte_encode_bo)(struct xe_bo *bo, u64 bo_offset, u16 pat_index);
|
||||
/** @ggtt_set_pte: Directly write into GGTT's PTE */
|
||||
void (*ggtt_set_pte)(struct xe_ggtt *ggtt, u64 addr, u64 pte);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ static void xe_sched_process_msg_queue_if_ready(struct xe_gpu_scheduler *sched)
|
||||
{
|
||||
struct xe_sched_msg *msg;
|
||||
|
||||
spin_lock(&sched->base.job_list_lock);
|
||||
xe_sched_msg_lock(sched);
|
||||
msg = list_first_entry_or_null(&sched->msgs, struct xe_sched_msg, link);
|
||||
if (msg)
|
||||
xe_sched_process_msg_queue(sched);
|
||||
spin_unlock(&sched->base.job_list_lock);
|
||||
xe_sched_msg_unlock(sched);
|
||||
}
|
||||
|
||||
static struct xe_sched_msg *
|
||||
@@ -27,12 +27,12 @@ xe_sched_get_msg(struct xe_gpu_scheduler *sched)
|
||||
{
|
||||
struct xe_sched_msg *msg;
|
||||
|
||||
spin_lock(&sched->base.job_list_lock);
|
||||
xe_sched_msg_lock(sched);
|
||||
msg = list_first_entry_or_null(&sched->msgs,
|
||||
struct xe_sched_msg, link);
|
||||
if (msg)
|
||||
list_del(&msg->link);
|
||||
spin_unlock(&sched->base.job_list_lock);
|
||||
list_del_init(&msg->link);
|
||||
xe_sched_msg_unlock(sched);
|
||||
|
||||
return msg;
|
||||
}
|
||||
@@ -93,9 +93,16 @@ void xe_sched_submission_stop(struct xe_gpu_scheduler *sched)
|
||||
void xe_sched_add_msg(struct xe_gpu_scheduler *sched,
|
||||
struct xe_sched_msg *msg)
|
||||
{
|
||||
spin_lock(&sched->base.job_list_lock);
|
||||
list_add_tail(&msg->link, &sched->msgs);
|
||||
spin_unlock(&sched->base.job_list_lock);
|
||||
xe_sched_msg_lock(sched);
|
||||
xe_sched_add_msg_locked(sched, msg);
|
||||
xe_sched_msg_unlock(sched);
|
||||
}
|
||||
|
||||
void xe_sched_add_msg_locked(struct xe_gpu_scheduler *sched,
|
||||
struct xe_sched_msg *msg)
|
||||
{
|
||||
lockdep_assert_held(&sched->base.job_list_lock);
|
||||
|
||||
list_add_tail(&msg->link, &sched->msgs);
|
||||
xe_sched_process_msg_queue(sched);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,18 @@ void xe_sched_submission_stop(struct xe_gpu_scheduler *sched);
|
||||
|
||||
void xe_sched_add_msg(struct xe_gpu_scheduler *sched,
|
||||
struct xe_sched_msg *msg);
|
||||
void xe_sched_add_msg_locked(struct xe_gpu_scheduler *sched,
|
||||
struct xe_sched_msg *msg);
|
||||
|
||||
static inline void xe_sched_msg_lock(struct xe_gpu_scheduler *sched)
|
||||
{
|
||||
spin_lock(&sched->base.job_list_lock);
|
||||
}
|
||||
|
||||
static inline void xe_sched_msg_unlock(struct xe_gpu_scheduler *sched)
|
||||
{
|
||||
spin_unlock(&sched->base.job_list_lock);
|
||||
}
|
||||
|
||||
static inline void xe_sched_stop(struct xe_gpu_scheduler *sched)
|
||||
{
|
||||
|
||||
@@ -450,11 +450,6 @@ static void free_resources(void *arg)
|
||||
xe_exec_queue_put(gsc->q);
|
||||
gsc->q = NULL;
|
||||
}
|
||||
|
||||
if (gsc->private) {
|
||||
xe_bo_unpin_map_no_vm(gsc->private);
|
||||
gsc->private = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int xe_gsc_init_post_hwconfig(struct xe_gsc *gsc)
|
||||
@@ -474,10 +469,9 @@ int xe_gsc_init_post_hwconfig(struct xe_gsc *gsc)
|
||||
if (!hwe)
|
||||
return -ENODEV;
|
||||
|
||||
bo = xe_bo_create_pin_map(xe, tile, NULL, SZ_4M,
|
||||
ttm_bo_type_kernel,
|
||||
XE_BO_FLAG_STOLEN |
|
||||
XE_BO_FLAG_GGTT);
|
||||
bo = xe_managed_bo_create_pin_map(xe, tile, SZ_4M,
|
||||
XE_BO_FLAG_STOLEN |
|
||||
XE_BO_FLAG_GGTT);
|
||||
if (IS_ERR(bo))
|
||||
return PTR_ERR(bo);
|
||||
|
||||
|
||||
@@ -62,11 +62,6 @@ gsc_to_gt(struct xe_gsc *gsc)
|
||||
return container_of(gsc, struct xe_gt, uc.gsc);
|
||||
}
|
||||
|
||||
static inline struct xe_device *kdev_to_xe(struct device *kdev)
|
||||
{
|
||||
return dev_get_drvdata(kdev);
|
||||
}
|
||||
|
||||
bool xe_gsc_proxy_init_done(struct xe_gsc *gsc)
|
||||
{
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
@@ -345,7 +340,7 @@ void xe_gsc_proxy_irq_handler(struct xe_gsc *gsc, u32 iir)
|
||||
static int xe_gsc_proxy_component_bind(struct device *xe_kdev,
|
||||
struct device *mei_kdev, void *data)
|
||||
{
|
||||
struct xe_device *xe = kdev_to_xe(xe_kdev);
|
||||
struct xe_device *xe = kdev_to_xe_device(xe_kdev);
|
||||
struct xe_gt *gt = xe->tiles[0].media_gt;
|
||||
struct xe_gsc *gsc = >->uc.gsc;
|
||||
|
||||
@@ -360,7 +355,7 @@ static int xe_gsc_proxy_component_bind(struct device *xe_kdev,
|
||||
static void xe_gsc_proxy_component_unbind(struct device *xe_kdev,
|
||||
struct device *mei_kdev, void *data)
|
||||
{
|
||||
struct xe_device *xe = kdev_to_xe(xe_kdev);
|
||||
struct xe_device *xe = kdev_to_xe_device(xe_kdev);
|
||||
struct xe_gt *gt = xe->tiles[0].media_gt;
|
||||
struct xe_gsc *gsc = >->uc.gsc;
|
||||
|
||||
@@ -376,27 +371,6 @@ static const struct component_ops xe_gsc_proxy_component_ops = {
|
||||
.unbind = xe_gsc_proxy_component_unbind,
|
||||
};
|
||||
|
||||
static void proxy_channel_free(struct drm_device *drm, void *arg)
|
||||
{
|
||||
struct xe_gsc *gsc = arg;
|
||||
|
||||
if (!gsc->proxy.bo)
|
||||
return;
|
||||
|
||||
if (gsc->proxy.to_csme) {
|
||||
kfree(gsc->proxy.to_csme);
|
||||
gsc->proxy.to_csme = NULL;
|
||||
gsc->proxy.from_csme = NULL;
|
||||
}
|
||||
|
||||
if (gsc->proxy.bo) {
|
||||
iosys_map_clear(&gsc->proxy.to_gsc);
|
||||
iosys_map_clear(&gsc->proxy.from_gsc);
|
||||
xe_bo_unpin_map_no_vm(gsc->proxy.bo);
|
||||
gsc->proxy.bo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int proxy_channel_alloc(struct xe_gsc *gsc)
|
||||
{
|
||||
struct xe_gt *gt = gsc_to_gt(gsc);
|
||||
@@ -405,18 +379,15 @@ static int proxy_channel_alloc(struct xe_gsc *gsc)
|
||||
struct xe_bo *bo;
|
||||
void *csme;
|
||||
|
||||
csme = kzalloc(GSC_PROXY_CHANNEL_SIZE, GFP_KERNEL);
|
||||
csme = drmm_kzalloc(&xe->drm, GSC_PROXY_CHANNEL_SIZE, GFP_KERNEL);
|
||||
if (!csme)
|
||||
return -ENOMEM;
|
||||
|
||||
bo = xe_bo_create_pin_map(xe, tile, NULL, GSC_PROXY_CHANNEL_SIZE,
|
||||
ttm_bo_type_kernel,
|
||||
XE_BO_FLAG_SYSTEM |
|
||||
XE_BO_FLAG_GGTT);
|
||||
if (IS_ERR(bo)) {
|
||||
kfree(csme);
|
||||
bo = xe_managed_bo_create_pin_map(xe, tile, GSC_PROXY_CHANNEL_SIZE,
|
||||
XE_BO_FLAG_SYSTEM |
|
||||
XE_BO_FLAG_GGTT);
|
||||
if (IS_ERR(bo))
|
||||
return PTR_ERR(bo);
|
||||
}
|
||||
|
||||
gsc->proxy.bo = bo;
|
||||
gsc->proxy.to_gsc = IOSYS_MAP_INIT_OFFSET(&bo->vmap, 0);
|
||||
@@ -424,7 +395,7 @@ static int proxy_channel_alloc(struct xe_gsc *gsc)
|
||||
gsc->proxy.to_csme = csme;
|
||||
gsc->proxy.from_csme = csme + GSC_PROXY_BUFFER_SIZE;
|
||||
|
||||
return drmm_add_action_or_reset(&xe->drm, proxy_channel_free, gsc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -112,9 +112,9 @@ static void xe_gt_enable_host_l2_vram(struct xe_gt *gt)
|
||||
|
||||
if (!xe_gt_is_media_type(gt)) {
|
||||
xe_mmio_write32(gt, SCRATCH1LPFC, EN_L3_RW_CCS_CACHE_FLUSH);
|
||||
reg = xe_mmio_read32(gt, XE2_GAMREQSTRM_CTRL);
|
||||
reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMREQSTRM_CTRL);
|
||||
reg |= CG_DIS_CNTLBUS;
|
||||
xe_mmio_write32(gt, XE2_GAMREQSTRM_CTRL, reg);
|
||||
xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg);
|
||||
}
|
||||
|
||||
xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0x3);
|
||||
@@ -136,9 +136,9 @@ static void xe_gt_disable_host_l2_vram(struct xe_gt *gt)
|
||||
if (WARN_ON(err))
|
||||
return;
|
||||
|
||||
reg = xe_mmio_read32(gt, XE2_GAMREQSTRM_CTRL);
|
||||
reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMREQSTRM_CTRL);
|
||||
reg &= ~CG_DIS_CNTLBUS;
|
||||
xe_mmio_write32(gt, XE2_GAMREQSTRM_CTRL, reg);
|
||||
xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg);
|
||||
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
}
|
||||
@@ -559,7 +559,6 @@ int xe_gt_init_hwconfig(struct xe_gt *gt)
|
||||
|
||||
xe_gt_mcr_init_early(gt);
|
||||
xe_pat_init(gt);
|
||||
xe_gt_enable_host_l2_vram(gt);
|
||||
|
||||
err = xe_uc_init(>->uc);
|
||||
if (err)
|
||||
@@ -571,6 +570,7 @@ int xe_gt_init_hwconfig(struct xe_gt *gt)
|
||||
|
||||
xe_gt_topology_init(gt);
|
||||
xe_gt_mcr_init(gt);
|
||||
xe_gt_enable_host_l2_vram(gt);
|
||||
|
||||
out_fw:
|
||||
xe_force_wake_put(gt_to_fw(gt), XE_FW_GT);
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
#include "xe_gt_mcr.h"
|
||||
#include "xe_gt_sriov_pf_debugfs.h"
|
||||
#include "xe_gt_sriov_vf_debugfs.h"
|
||||
#include "xe_gt_stats.h"
|
||||
#include "xe_gt_topology.h"
|
||||
#include "xe_guc_hwconfig.h"
|
||||
#include "xe_hw_engine.h"
|
||||
#include "xe_lrc.h"
|
||||
#include "xe_macros.h"
|
||||
@@ -269,6 +271,15 @@ static int vecs_default_lrc(struct xe_gt *gt, struct drm_printer *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hwconfig(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
xe_pm_runtime_get(gt_to_xe(gt));
|
||||
xe_guc_hwconfig_dump(>->uc.guc, p);
|
||||
xe_pm_runtime_put(gt_to_xe(gt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_info_list debugfs_list[] = {
|
||||
{"hw_engines", .show = xe_gt_debugfs_simple_show, .data = hw_engines},
|
||||
{"force_reset", .show = xe_gt_debugfs_simple_show, .data = force_reset},
|
||||
@@ -286,6 +297,8 @@ static const struct drm_info_list debugfs_list[] = {
|
||||
{"default_lrc_bcs", .show = xe_gt_debugfs_simple_show, .data = bcs_default_lrc},
|
||||
{"default_lrc_vcs", .show = xe_gt_debugfs_simple_show, .data = vcs_default_lrc},
|
||||
{"default_lrc_vecs", .show = xe_gt_debugfs_simple_show, .data = vecs_default_lrc},
|
||||
{"stats", .show = xe_gt_debugfs_simple_show, .data = xe_gt_stats_print_info},
|
||||
{"hwconfig", .show = xe_gt_debugfs_simple_show, .data = hwconfig},
|
||||
};
|
||||
|
||||
void xe_gt_debugfs_register(struct xe_gt *gt)
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
#include "regs/xe_gt_regs.h"
|
||||
#include "xe_assert.h"
|
||||
#include "xe_gt.h"
|
||||
#include "xe_gt_printk.h"
|
||||
#include "xe_gt_topology.h"
|
||||
#include "xe_gt_types.h"
|
||||
#include "xe_guc_hwconfig.h"
|
||||
#include "xe_mmio.h"
|
||||
#include "xe_sriov.h"
|
||||
|
||||
@@ -297,6 +299,36 @@ static void init_steering_mslice(struct xe_gt *gt)
|
||||
|
||||
static unsigned int dss_per_group(struct xe_gt *gt)
|
||||
{
|
||||
struct xe_guc *guc = >->uc.guc;
|
||||
u32 max_slices = 0, max_subslices = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Try to query the GuC's hwconfig table for the maximum number of
|
||||
* slices and subslices. These don't reflect the platform's actual
|
||||
* slice/DSS counts, just the physical layout by which we should
|
||||
* determine the steering targets. On older platforms with older GuC
|
||||
* firmware releases it's possible that these attributes may not be
|
||||
* included in the table, so we can always fall back to the old
|
||||
* hardcoded layouts.
|
||||
*/
|
||||
#define HWCONFIG_ATTR_MAX_SLICES 1
|
||||
#define HWCONFIG_ATTR_MAX_SUBSLICES 70
|
||||
|
||||
ret = xe_guc_hwconfig_lookup_u32(guc, HWCONFIG_ATTR_MAX_SLICES,
|
||||
&max_slices);
|
||||
if (ret < 0 || max_slices == 0)
|
||||
goto fallback;
|
||||
|
||||
ret = xe_guc_hwconfig_lookup_u32(guc, HWCONFIG_ATTR_MAX_SUBSLICES,
|
||||
&max_subslices);
|
||||
if (ret < 0 || max_subslices == 0)
|
||||
goto fallback;
|
||||
|
||||
return DIV_ROUND_UP(max_subslices, max_slices);
|
||||
|
||||
fallback:
|
||||
xe_gt_dbg(gt, "GuC hwconfig cannot provide dss/slice; using typical fallback values\n");
|
||||
if (gt_to_xe(gt)->info.platform == XE_PVC)
|
||||
return 8;
|
||||
else if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 1250)
|
||||
@@ -314,16 +346,16 @@ static unsigned int dss_per_group(struct xe_gt *gt)
|
||||
*/
|
||||
void xe_gt_mcr_get_dss_steering(struct xe_gt *gt, unsigned int dss, u16 *group, u16 *instance)
|
||||
{
|
||||
int dss_per_grp = dss_per_group(gt);
|
||||
|
||||
xe_gt_assert(gt, dss < XE_MAX_DSS_FUSE_BITS);
|
||||
|
||||
*group = dss / dss_per_grp;
|
||||
*instance = dss % dss_per_grp;
|
||||
*group = dss / gt->steering_dss_per_grp;
|
||||
*instance = dss % gt->steering_dss_per_grp;
|
||||
}
|
||||
|
||||
static void init_steering_dss(struct xe_gt *gt)
|
||||
{
|
||||
gt->steering_dss_per_grp = dss_per_group(gt);
|
||||
|
||||
xe_gt_mcr_get_dss_steering(gt,
|
||||
min(xe_dss_mask_group_ffs(gt->fuse_topo.g_dss_mask, 0, 0),
|
||||
xe_dss_mask_group_ffs(gt->fuse_topo.c_dss_mask, 0, 0)),
|
||||
|
||||
@@ -287,7 +287,7 @@ static bool get_pagefault(struct pf_queue *pf_queue, struct pagefault *pf)
|
||||
PFD_VIRTUAL_ADDR_LO_SHIFT;
|
||||
|
||||
pf_queue->tail = (pf_queue->tail + PF_MSG_LEN_DW) %
|
||||
PF_QUEUE_NUM_DW;
|
||||
pf_queue->num_dw;
|
||||
ret = true;
|
||||
}
|
||||
spin_unlock_irq(&pf_queue->lock);
|
||||
@@ -299,7 +299,8 @@ static bool pf_queue_full(struct pf_queue *pf_queue)
|
||||
{
|
||||
lockdep_assert_held(&pf_queue->lock);
|
||||
|
||||
return CIRC_SPACE(pf_queue->head, pf_queue->tail, PF_QUEUE_NUM_DW) <=
|
||||
return CIRC_SPACE(pf_queue->head, pf_queue->tail,
|
||||
pf_queue->num_dw) <=
|
||||
PF_MSG_LEN_DW;
|
||||
}
|
||||
|
||||
@@ -312,22 +313,23 @@ int xe_guc_pagefault_handler(struct xe_guc *guc, u32 *msg, u32 len)
|
||||
u32 asid;
|
||||
bool full;
|
||||
|
||||
/*
|
||||
* The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0
|
||||
*/
|
||||
BUILD_BUG_ON(PF_QUEUE_NUM_DW % PF_MSG_LEN_DW);
|
||||
|
||||
if (unlikely(len != PF_MSG_LEN_DW))
|
||||
return -EPROTO;
|
||||
|
||||
asid = FIELD_GET(PFD_ASID, msg[1]);
|
||||
pf_queue = gt->usm.pf_queue + (asid % NUM_PF_QUEUE);
|
||||
|
||||
/*
|
||||
* The below logic doesn't work unless PF_QUEUE_NUM_DW % PF_MSG_LEN_DW == 0
|
||||
*/
|
||||
xe_gt_assert(gt, !(pf_queue->num_dw % PF_MSG_LEN_DW));
|
||||
|
||||
spin_lock_irqsave(&pf_queue->lock, flags);
|
||||
full = pf_queue_full(pf_queue);
|
||||
if (!full) {
|
||||
memcpy(pf_queue->data + pf_queue->head, msg, len * sizeof(u32));
|
||||
pf_queue->head = (pf_queue->head + len) % PF_QUEUE_NUM_DW;
|
||||
pf_queue->head = (pf_queue->head + len) %
|
||||
pf_queue->num_dw;
|
||||
queue_work(gt->usm.pf_wq, &pf_queue->worker);
|
||||
} else {
|
||||
drm_warn(&xe->drm, "PF Queue full, shouldn't be possible");
|
||||
@@ -386,26 +388,57 @@ static void pagefault_fini(void *arg)
|
||||
{
|
||||
struct xe_gt *gt = arg;
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
int i;
|
||||
|
||||
if (!xe->info.has_usm)
|
||||
return;
|
||||
|
||||
destroy_workqueue(gt->usm.acc_wq);
|
||||
destroy_workqueue(gt->usm.pf_wq);
|
||||
|
||||
for (i = 0; i < NUM_PF_QUEUE; ++i)
|
||||
kfree(gt->usm.pf_queue[i].data);
|
||||
}
|
||||
|
||||
static int xe_alloc_pf_queue(struct xe_gt *gt, struct pf_queue *pf_queue)
|
||||
{
|
||||
xe_dss_mask_t all_dss;
|
||||
int num_dss, num_eus;
|
||||
|
||||
bitmap_or(all_dss, gt->fuse_topo.g_dss_mask, gt->fuse_topo.c_dss_mask,
|
||||
XE_MAX_DSS_FUSE_BITS);
|
||||
|
||||
num_dss = bitmap_weight(all_dss, XE_MAX_DSS_FUSE_BITS);
|
||||
num_eus = bitmap_weight(gt->fuse_topo.eu_mask_per_dss,
|
||||
XE_MAX_EU_FUSE_BITS) * num_dss;
|
||||
|
||||
/* user can issue separate page faults per EU and per CS */
|
||||
pf_queue->num_dw =
|
||||
(num_eus + XE_NUM_HW_ENGINES) * PF_MSG_LEN_DW;
|
||||
|
||||
pf_queue->gt = gt;
|
||||
pf_queue->data = kcalloc(pf_queue->num_dw, sizeof(u32), GFP_KERNEL);
|
||||
if (!pf_queue->data)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&pf_queue->lock);
|
||||
INIT_WORK(&pf_queue->worker, pf_queue_work_func);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xe_gt_pagefault_init(struct xe_gt *gt)
|
||||
{
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!xe->info.has_usm)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < NUM_PF_QUEUE; ++i) {
|
||||
gt->usm.pf_queue[i].gt = gt;
|
||||
spin_lock_init(>->usm.pf_queue[i].lock);
|
||||
INIT_WORK(>->usm.pf_queue[i].worker, pf_queue_work_func);
|
||||
ret = xe_alloc_pf_queue(gt, >->usm.pf_queue[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
for (i = 0; i < NUM_ACC_QUEUE; ++i) {
|
||||
gt->usm.acc_queue[i].gt = gt;
|
||||
|
||||
@@ -232,14 +232,14 @@ static u32 encode_config_ggtt(u32 *cfg, const struct xe_gt_sriov_config *config)
|
||||
{
|
||||
u32 n = 0;
|
||||
|
||||
if (drm_mm_node_allocated(&config->ggtt_region)) {
|
||||
if (xe_ggtt_node_allocated(config->ggtt_region)) {
|
||||
cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_GGTT_START);
|
||||
cfg[n++] = lower_32_bits(config->ggtt_region.start);
|
||||
cfg[n++] = upper_32_bits(config->ggtt_region.start);
|
||||
cfg[n++] = lower_32_bits(config->ggtt_region->base.start);
|
||||
cfg[n++] = upper_32_bits(config->ggtt_region->base.start);
|
||||
|
||||
cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_GGTT_SIZE);
|
||||
cfg[n++] = lower_32_bits(config->ggtt_region.size);
|
||||
cfg[n++] = upper_32_bits(config->ggtt_region.size);
|
||||
cfg[n++] = lower_32_bits(config->ggtt_region->base.size);
|
||||
cfg[n++] = upper_32_bits(config->ggtt_region->base.size);
|
||||
}
|
||||
|
||||
return n;
|
||||
@@ -369,29 +369,28 @@ static int pf_distribute_config_ggtt(struct xe_tile *tile, unsigned int vfid, u6
|
||||
return err ?: err2;
|
||||
}
|
||||
|
||||
static void pf_release_ggtt(struct xe_tile *tile, struct drm_mm_node *node)
|
||||
static void pf_release_ggtt(struct xe_tile *tile, struct xe_ggtt_node *node)
|
||||
{
|
||||
struct xe_ggtt *ggtt = tile->mem.ggtt;
|
||||
|
||||
if (drm_mm_node_allocated(node)) {
|
||||
if (xe_ggtt_node_allocated(node)) {
|
||||
/*
|
||||
* explicit GGTT PTE assignment to the PF using xe_ggtt_assign()
|
||||
* is redundant, as PTE will be implicitly re-assigned to PF by
|
||||
* the xe_ggtt_clear() called by below xe_ggtt_remove_node().
|
||||
*/
|
||||
xe_ggtt_remove_node(ggtt, node, false);
|
||||
xe_ggtt_node_remove(node, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void pf_release_vf_config_ggtt(struct xe_gt *gt, struct xe_gt_sriov_config *config)
|
||||
{
|
||||
pf_release_ggtt(gt_to_tile(gt), &config->ggtt_region);
|
||||
pf_release_ggtt(gt_to_tile(gt), config->ggtt_region);
|
||||
config->ggtt_region = NULL;
|
||||
}
|
||||
|
||||
static int pf_provision_vf_ggtt(struct xe_gt *gt, unsigned int vfid, u64 size)
|
||||
{
|
||||
struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid);
|
||||
struct drm_mm_node *node = &config->ggtt_region;
|
||||
struct xe_ggtt_node *node = config->ggtt_region;
|
||||
struct xe_tile *tile = gt_to_tile(gt);
|
||||
struct xe_ggtt *ggtt = tile->mem.ggtt;
|
||||
u64 alignment = pf_get_ggtt_alignment(gt);
|
||||
@@ -403,40 +402,48 @@ static int pf_provision_vf_ggtt(struct xe_gt *gt, unsigned int vfid, u64 size)
|
||||
|
||||
size = round_up(size, alignment);
|
||||
|
||||
if (drm_mm_node_allocated(node)) {
|
||||
if (xe_ggtt_node_allocated(node)) {
|
||||
err = pf_distribute_config_ggtt(tile, vfid, 0, 0);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
|
||||
pf_release_ggtt(tile, node);
|
||||
}
|
||||
xe_gt_assert(gt, !drm_mm_node_allocated(node));
|
||||
xe_gt_assert(gt, !xe_ggtt_node_allocated(node));
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
err = xe_ggtt_insert_special_node(ggtt, node, size, alignment);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
node = xe_ggtt_node_init(ggtt);
|
||||
if (IS_ERR(node))
|
||||
return PTR_ERR(node);
|
||||
|
||||
xe_ggtt_assign(ggtt, node, vfid);
|
||||
err = xe_ggtt_node_insert(node, size, alignment);
|
||||
if (unlikely(err))
|
||||
goto err;
|
||||
|
||||
xe_ggtt_assign(node, vfid);
|
||||
xe_gt_sriov_dbg_verbose(gt, "VF%u assigned GGTT %llx-%llx\n",
|
||||
vfid, node->start, node->start + node->size - 1);
|
||||
vfid, node->base.start, node->base.start + node->base.size - 1);
|
||||
|
||||
err = pf_distribute_config_ggtt(gt->tile, vfid, node->start, node->size);
|
||||
err = pf_distribute_config_ggtt(gt->tile, vfid, node->base.start, node->base.size);
|
||||
if (unlikely(err))
|
||||
return err;
|
||||
goto err;
|
||||
|
||||
config->ggtt_region = node;
|
||||
return 0;
|
||||
err:
|
||||
xe_ggtt_node_fini(node);
|
||||
return err;
|
||||
}
|
||||
|
||||
static u64 pf_get_vf_config_ggtt(struct xe_gt *gt, unsigned int vfid)
|
||||
{
|
||||
struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid);
|
||||
struct drm_mm_node *node = &config->ggtt_region;
|
||||
struct xe_ggtt_node *node = config->ggtt_region;
|
||||
|
||||
xe_gt_assert(gt, !xe_gt_is_media_type(gt));
|
||||
return drm_mm_node_allocated(node) ? node->size : 0;
|
||||
return xe_ggtt_node_allocated(node) ? node->base.size : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -587,30 +594,11 @@ int xe_gt_sriov_pf_config_bulk_set_ggtt(struct xe_gt *gt, unsigned int vfid,
|
||||
static u64 pf_get_max_ggtt(struct xe_gt *gt)
|
||||
{
|
||||
struct xe_ggtt *ggtt = gt_to_tile(gt)->mem.ggtt;
|
||||
const struct drm_mm *mm = &ggtt->mm;
|
||||
const struct drm_mm_node *entry;
|
||||
u64 alignment = pf_get_ggtt_alignment(gt);
|
||||
u64 spare = pf_get_spare_ggtt(gt);
|
||||
u64 hole_min_start = xe_wopcm_size(gt_to_xe(gt));
|
||||
u64 hole_start, hole_end, hole_size;
|
||||
u64 max_hole = 0;
|
||||
u64 max_hole;
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
|
||||
drm_mm_for_each_hole(entry, mm, hole_start, hole_end) {
|
||||
hole_start = max(hole_start, hole_min_start);
|
||||
hole_start = ALIGN(hole_start, alignment);
|
||||
hole_end = ALIGN_DOWN(hole_end, alignment);
|
||||
if (hole_start >= hole_end)
|
||||
continue;
|
||||
hole_size = hole_end - hole_start;
|
||||
xe_gt_sriov_dbg_verbose(gt, "HOLE start %llx size %lluK\n",
|
||||
hole_start, hole_size / SZ_1K);
|
||||
spare -= min3(spare, hole_size, max_hole);
|
||||
max_hole = max(max_hole, hole_size);
|
||||
}
|
||||
|
||||
mutex_unlock(&ggtt->lock);
|
||||
max_hole = xe_ggtt_largest_hole(ggtt, alignment, &spare);
|
||||
|
||||
xe_gt_sriov_dbg_verbose(gt, "HOLE max %lluK reserved %lluK\n",
|
||||
max_hole / SZ_1K, spare / SZ_1K);
|
||||
@@ -2025,13 +2013,15 @@ int xe_gt_sriov_pf_config_print_ggtt(struct xe_gt *gt, struct drm_printer *p)
|
||||
|
||||
for (n = 1; n <= total_vfs; n++) {
|
||||
config = >->sriov.pf.vfs[n].config;
|
||||
if (!drm_mm_node_allocated(&config->ggtt_region))
|
||||
if (!xe_ggtt_node_allocated(config->ggtt_region))
|
||||
continue;
|
||||
|
||||
string_get_size(config->ggtt_region.size, 1, STRING_UNITS_2, buf, sizeof(buf));
|
||||
string_get_size(config->ggtt_region->base.size, 1, STRING_UNITS_2,
|
||||
buf, sizeof(buf));
|
||||
drm_printf(p, "VF%u:\t%#0llx-%#llx\t(%s)\n",
|
||||
n, config->ggtt_region.start,
|
||||
config->ggtt_region.start + config->ggtt_region.size - 1, buf);
|
||||
n, config->ggtt_region->base.start,
|
||||
config->ggtt_region->base.start + config->ggtt_region->base.size - 1,
|
||||
buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2119,12 +2109,8 @@ int xe_gt_sriov_pf_config_print_dbs(struct xe_gt *gt, struct drm_printer *p)
|
||||
int xe_gt_sriov_pf_config_print_available_ggtt(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
struct xe_ggtt *ggtt = gt_to_tile(gt)->mem.ggtt;
|
||||
const struct drm_mm *mm = &ggtt->mm;
|
||||
const struct drm_mm_node *entry;
|
||||
u64 alignment = pf_get_ggtt_alignment(gt);
|
||||
u64 hole_min_start = xe_wopcm_size(gt_to_xe(gt));
|
||||
u64 hole_start, hole_end, hole_size;
|
||||
u64 spare, avail, total = 0;
|
||||
u64 spare, avail, total;
|
||||
char buf[10];
|
||||
|
||||
xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
|
||||
@@ -2132,24 +2118,8 @@ int xe_gt_sriov_pf_config_print_available_ggtt(struct xe_gt *gt, struct drm_prin
|
||||
mutex_lock(xe_gt_sriov_pf_master_mutex(gt));
|
||||
|
||||
spare = pf_get_spare_ggtt(gt);
|
||||
total = xe_ggtt_print_holes(ggtt, alignment, p);
|
||||
|
||||
mutex_lock(&ggtt->lock);
|
||||
|
||||
drm_mm_for_each_hole(entry, mm, hole_start, hole_end) {
|
||||
hole_start = max(hole_start, hole_min_start);
|
||||
hole_start = ALIGN(hole_start, alignment);
|
||||
hole_end = ALIGN_DOWN(hole_end, alignment);
|
||||
if (hole_start >= hole_end)
|
||||
continue;
|
||||
hole_size = hole_end - hole_start;
|
||||
total += hole_size;
|
||||
|
||||
string_get_size(hole_size, 1, STRING_UNITS_2, buf, sizeof(buf));
|
||||
drm_printf(p, "range:\t%#llx-%#llx\t(%s)\n",
|
||||
hole_start, hole_end - 1, buf);
|
||||
}
|
||||
|
||||
mutex_unlock(&ggtt->lock);
|
||||
mutex_unlock(xe_gt_sriov_pf_master_mutex(gt));
|
||||
|
||||
string_get_size(total, 1, STRING_UNITS_2, buf, sizeof(buf));
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#ifndef _XE_GT_SRIOV_PF_CONFIG_TYPES_H_
|
||||
#define _XE_GT_SRIOV_PF_CONFIG_TYPES_H_
|
||||
|
||||
#include <drm/drm_mm.h>
|
||||
|
||||
#include "xe_ggtt_types.h"
|
||||
#include "xe_guc_klv_thresholds_set_types.h"
|
||||
|
||||
struct xe_bo;
|
||||
@@ -19,7 +18,7 @@ struct xe_bo;
|
||||
*/
|
||||
struct xe_gt_sriov_config {
|
||||
/** @ggtt_region: GGTT region assigned to the VF. */
|
||||
struct drm_mm_node ggtt_region;
|
||||
struct xe_ggtt_node *ggtt_region;
|
||||
/** @lmem_obj: LMEM allocation for use by the VF. */
|
||||
struct xe_bo *lmem_obj;
|
||||
/** @num_ctxs: number of GuC contexts IDs. */
|
||||
|
||||
@@ -495,6 +495,25 @@ u64 xe_gt_sriov_vf_lmem(struct xe_gt *gt)
|
||||
return gt->sriov.vf.self_config.lmem_size;
|
||||
}
|
||||
|
||||
static struct xe_ggtt_node *
|
||||
vf_balloon_ggtt_node(struct xe_ggtt *ggtt, u64 start, u64 end)
|
||||
{
|
||||
struct xe_ggtt_node *node;
|
||||
int err;
|
||||
|
||||
node = xe_ggtt_node_init(ggtt);
|
||||
if (IS_ERR(node))
|
||||
return node;
|
||||
|
||||
err = xe_ggtt_node_insert_balloon(node, start, end);
|
||||
if (err) {
|
||||
xe_ggtt_node_fini(node);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static int vf_balloon_ggtt(struct xe_gt *gt)
|
||||
{
|
||||
struct xe_gt_sriov_vf_selfconfig *config = >->sriov.vf.self_config;
|
||||
@@ -502,7 +521,6 @@ static int vf_balloon_ggtt(struct xe_gt *gt)
|
||||
struct xe_ggtt *ggtt = tile->mem.ggtt;
|
||||
struct xe_device *xe = gt_to_xe(gt);
|
||||
u64 start, end;
|
||||
int err;
|
||||
|
||||
xe_gt_assert(gt, IS_SRIOV_VF(xe));
|
||||
xe_gt_assert(gt, !xe_gt_is_media_type(gt));
|
||||
@@ -528,35 +546,31 @@ static int vf_balloon_ggtt(struct xe_gt *gt)
|
||||
start = xe_wopcm_size(xe);
|
||||
end = config->ggtt_base;
|
||||
if (end != start) {
|
||||
err = xe_ggtt_balloon(ggtt, start, end, &tile->sriov.vf.ggtt_balloon[0]);
|
||||
if (err)
|
||||
goto failed;
|
||||
tile->sriov.vf.ggtt_balloon[0] = vf_balloon_ggtt_node(ggtt, start, end);
|
||||
if (IS_ERR(tile->sriov.vf.ggtt_balloon[0]))
|
||||
return PTR_ERR(tile->sriov.vf.ggtt_balloon[0]);
|
||||
}
|
||||
|
||||
start = config->ggtt_base + config->ggtt_size;
|
||||
end = GUC_GGTT_TOP;
|
||||
if (end != start) {
|
||||
err = xe_ggtt_balloon(ggtt, start, end, &tile->sriov.vf.ggtt_balloon[1]);
|
||||
if (err)
|
||||
goto deballoon;
|
||||
tile->sriov.vf.ggtt_balloon[1] = vf_balloon_ggtt_node(ggtt, start, end);
|
||||
if (IS_ERR(tile->sriov.vf.ggtt_balloon[1])) {
|
||||
xe_ggtt_node_remove_balloon(tile->sriov.vf.ggtt_balloon[0]);
|
||||
return PTR_ERR(tile->sriov.vf.ggtt_balloon[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
deballoon:
|
||||
xe_ggtt_deballoon(ggtt, &tile->sriov.vf.ggtt_balloon[0]);
|
||||
failed:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void deballoon_ggtt(struct drm_device *drm, void *arg)
|
||||
{
|
||||
struct xe_tile *tile = arg;
|
||||
struct xe_ggtt *ggtt = tile->mem.ggtt;
|
||||
|
||||
xe_tile_assert(tile, IS_SRIOV_VF(tile_to_xe(tile)));
|
||||
xe_ggtt_deballoon(ggtt, &tile->sriov.vf.ggtt_balloon[1]);
|
||||
xe_ggtt_deballoon(ggtt, &tile->sriov.vf.ggtt_balloon[0]);
|
||||
xe_ggtt_node_remove_balloon(tile->sriov.vf.ggtt_balloon[1]);
|
||||
xe_ggtt_node_remove_balloon(tile->sriov.vf.ggtt_balloon[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
49
drivers/gpu/drm/xe/xe_gt_stats.c
Normal file
49
drivers/gpu/drm/xe/xe_gt_stats.c
Normal file
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright © 2024 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include <drm/drm_print.h>
|
||||
|
||||
#include "xe_gt.h"
|
||||
#include "xe_gt_stats.h"
|
||||
|
||||
/**
|
||||
* xe_gt_stats_incr - Increments the specified stats counter
|
||||
* @gt: graphics tile
|
||||
* @id: xe_gt_stats_id type id that needs to be incremented
|
||||
* @incr: value to be incremented with
|
||||
*
|
||||
* Increments the specified stats counter.
|
||||
*/
|
||||
void xe_gt_stats_incr(struct xe_gt *gt, const enum xe_gt_stats_id id, int incr)
|
||||
{
|
||||
if (id >= __XE_GT_STATS_NUM_IDS)
|
||||
return;
|
||||
|
||||
atomic_add(incr, >->stats.counters[id]);
|
||||
}
|
||||
|
||||
static const char *const stat_description[__XE_GT_STATS_NUM_IDS] = {
|
||||
"tlb_inval_count",
|
||||
};
|
||||
|
||||
/**
|
||||
* xe_gt_stats_print_info - Print the GT stats
|
||||
* @gt: graphics tile
|
||||
* @p: drm_printer where it will be printed out.
|
||||
*
|
||||
* This prints out all the available GT stats.
|
||||
*/
|
||||
int xe_gt_stats_print_info(struct xe_gt *gt, struct drm_printer *p)
|
||||
{
|
||||
enum xe_gt_stats_id id;
|
||||
|
||||
for (id = 0; id < __XE_GT_STATS_NUM_IDS; ++id)
|
||||
drm_printf(p, "%s: %d\n", stat_description[id],
|
||||
atomic_read(>->stats.counters[id]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
drivers/gpu/drm/xe/xe_gt_stats.h
Normal file
29
drivers/gpu/drm/xe/xe_gt_stats.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright © 2024 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef _XE_GT_STATS_H_
|
||||
#define _XE_GT_STATS_H_
|
||||
|
||||
struct xe_gt;
|
||||
struct drm_printer;
|
||||
|
||||
enum xe_gt_stats_id {
|
||||
XE_GT_STATS_ID_TLB_INVAL,
|
||||
/* must be the last entry */
|
||||
__XE_GT_STATS_NUM_IDS,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
int xe_gt_stats_print_info(struct xe_gt *gt, struct drm_printer *p);
|
||||
void xe_gt_stats_incr(struct xe_gt *gt, const enum xe_gt_stats_id id, int incr);
|
||||
#else
|
||||
static inline void
|
||||
xe_gt_stats_incr(struct xe_gt *gt, const enum xe_gt_stats_id id,
|
||||
int incr)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "xe_gt_printk.h"
|
||||
#include "xe_guc.h"
|
||||
#include "xe_guc_ct.h"
|
||||
#include "xe_gt_stats.h"
|
||||
#include "xe_mmio.h"
|
||||
#include "xe_pm.h"
|
||||
#include "xe_sriov.h"
|
||||
@@ -213,6 +214,7 @@ static int send_tlb_invalidation(struct xe_guc *guc,
|
||||
gt->tlb_invalidation.seqno = 1;
|
||||
}
|
||||
mutex_unlock(&guc->ct.lock);
|
||||
xe_gt_stats_incr(gt, XE_GT_STATS_ID_TLB_INVAL, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "xe_gt_idle_types.h"
|
||||
#include "xe_gt_sriov_pf_types.h"
|
||||
#include "xe_gt_sriov_vf_types.h"
|
||||
#include "xe_gt_stats.h"
|
||||
#include "xe_hw_engine_types.h"
|
||||
#include "xe_hw_fence_types.h"
|
||||
#include "xe_oa.h"
|
||||
@@ -133,6 +134,14 @@ struct xe_gt {
|
||||
u8 has_indirect_ring_state:1;
|
||||
} info;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
||||
/** @stats: GT stats */
|
||||
struct {
|
||||
/** @stats.counters: counters for various GT stats */
|
||||
atomic_t counters[__XE_GT_STATS_NUM_IDS];
|
||||
} stats;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @mmio: mmio info for GT. All GTs within a tile share the same
|
||||
* register space, but have their own copy of GSI registers at a
|
||||
@@ -238,9 +247,14 @@ struct xe_gt {
|
||||
struct pf_queue {
|
||||
/** @usm.pf_queue.gt: back pointer to GT */
|
||||
struct xe_gt *gt;
|
||||
#define PF_QUEUE_NUM_DW 128
|
||||
/** @usm.pf_queue.data: data in the page fault queue */
|
||||
u32 data[PF_QUEUE_NUM_DW];
|
||||
u32 *data;
|
||||
/**
|
||||
* @usm.pf_queue.num_dw: number of DWORDS in the page
|
||||
* fault queue. Dynamically calculated based on the number
|
||||
* of compute resources available.
|
||||
*/
|
||||
u32 num_dw;
|
||||
/**
|
||||
* @usm.pf_queue.tail: tail pointer in DWs for page fault queue,
|
||||
* moved by worker which processes faults (consumer).
|
||||
@@ -367,6 +381,12 @@ struct xe_gt {
|
||||
u16 instance_target;
|
||||
} steering[NUM_STEERING_TYPES];
|
||||
|
||||
/**
|
||||
* @steering_dss_per_grp: number of DSS per steering group (gslice,
|
||||
* cslice, etc.).
|
||||
*/
|
||||
unsigned int steering_dss_per_grp;
|
||||
|
||||
/**
|
||||
* @mcr_lock: protects the MCR_SELECTOR register for the duration
|
||||
* of a steered operation
|
||||
|
||||
@@ -350,6 +350,8 @@ int xe_guc_init(struct xe_guc *guc)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
xe_uc_fw_change_status(&guc->fw, XE_UC_FIRMWARE_LOADABLE);
|
||||
|
||||
ret = devm_add_action_or_reset(xe->drm.dev, guc_fini_hw, guc);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -358,8 +360,6 @@ int xe_guc_init(struct xe_guc *guc)
|
||||
|
||||
xe_guc_comm_init_early(guc);
|
||||
|
||||
xe_uc_fw_change_status(&guc->fw, XE_UC_FIRMWARE_LOADABLE);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
#include "xe_hw_engine_types.h"
|
||||
#include "xe_macros.h"
|
||||
|
||||
/*
|
||||
* GuC version number components are defined to be only 8-bit size,
|
||||
* so converting to a 32bit 8.8.8 integer allows simple (and safe)
|
||||
* numerical comparisons.
|
||||
*/
|
||||
#define MAKE_GUC_VER(maj, min, pat) (((maj) << 16) | ((min) << 8) | (pat))
|
||||
#define MAKE_GUC_VER_STRUCT(ver) MAKE_GUC_VER((ver).major, (ver).minor, (ver).patch)
|
||||
#define GUC_SUBMIT_VER(guc) MAKE_VER_STRUCT((guc)->fw.versions.found[XE_UC_FW_VER_COMPATIBILITY])
|
||||
#define GUC_FIRMWARE_VER(guc) MAKE_VER_STRUCT((guc)->fw.versions.found[XE_UC_FW_VER_RELEASE])
|
||||
|
||||
struct drm_printer;
|
||||
|
||||
void xe_guc_comm_init_early(struct xe_guc *guc);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "xe_map.h"
|
||||
#include "xe_mmio.h"
|
||||
#include "xe_platform_types.h"
|
||||
#include "xe_uc_fw.h"
|
||||
#include "xe_wa.h"
|
||||
|
||||
/* Slack of a few additional entries per engine */
|
||||
@@ -367,6 +368,11 @@ static void guc_waklv_init(struct xe_guc_ads *ads)
|
||||
0xC40,
|
||||
&offset, &remain);
|
||||
|
||||
if (XE_WA(gt, 14022293748) || XE_WA(gt, 22019794406))
|
||||
guc_waklv_enable_simple(ads,
|
||||
GUC_WORKAROUND_KLV_ID_BACK_TO_BACK_RCS_ENGINE_RESET,
|
||||
&offset, &remain);
|
||||
|
||||
size = guc_ads_waklv_size(ads) - remain;
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user