Commit 74919e27 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-misc-next-2026-03-20' of...

Merge tag 'drm-misc-next-2026-03-20' of https://gitlab.freedesktop.org/drm/misc/kernel

 into drm-next

drm-misc-next for v7.1:

UAPI Changes:

math:
- provide __KERNEL_DIV_ROUND_CLOSEST() in UAPI

mode:
- provide DRM_ARGB_GET*() macros for reading color components

Cross-subsystem Changes:

math:
- implement DIV_ROUND_CLOSEST() with __KERNEL_DIV_ROUND_CLOSEST()

Core Changes:

atomic:
- fix handling of colorop state in atomic updates
- provide CRTC background color

ttm:
- improve tests and doumentation

Driver Changes:

amdxdna:
- allow forcing DMA through IOMMU IOVA
- improve debugging

bridge:
- Support Lontium LT8713SX DP MST bridge plus DT bindings

imx:
- support planes behind the primary plane
- fix bus-format selection

ivpu:
- perform engine reset on TDR error

panel:
- novatek-nt36672a: Use mipi_dsi_*_multi() functions
- panel-edp: Support BOE NV153WUM-N42, CMN N153JCA-ELK, CSW MNF307QS3-2

renesas:
- rz-du: clean up

rockchip:
- support CRTC background color

sun4i:
- fix leak in init code
- clean up

tildc
- clean up

v3d:
- improve handling of struct v3d_stats
- improve error handling
- clean up

vkms:
- support CRTC background color

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

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patch.msgid.link/20260320082604.GA17867@linux.fritz.box
parents b3970e97 ade00a6c
Loading
Loading
Loading
Loading
+113 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/bridge/lontium,lt8713sx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Lontium LT8713SX Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0/DP++ bridge-hub

maintainers:
  - Vishnu Saini <vishnu.saini@oss.qualcomm.com>

description:
  The Lontium LT8713SX is a Type-C/DP1.4 to Type-C/DP1.4/HDMI2.0 converter
  that integrates one DP input and up to three configurable output interfaces
  (DP1.4 / HDMI2.0 / DP++), with SST/MST functionality and audio support.

properties:
  compatible:
    enum:
      - lontium,lt8713sx

  reg:
    maxItems: 1

  vcc-supply:
    description: Regulator for 3.3V vcc.

  vdd-supply:
    description: Regulator for 1.1V vdd.

  reset-gpios:
    description: GPIO connected to active low RESET pin.

  ports:
    $ref: /schemas/graph.yaml#/properties/ports

    properties:
      port@0:
        $ref: /schemas/graph.yaml#/properties/port
        description:
          DP port for DP input from soc to bridge chip

      port@1:
        $ref: /schemas/graph.yaml#/properties/port
        description:
          DP port for DP output from bridge

      port@2:
        $ref: /schemas/graph.yaml#/properties/port
        description:
          Additional DP port for DP output from bridge

      port@3:
        $ref: /schemas/graph.yaml#/properties/port
        description:
          Additional DP port for DP output from bridge

    required:
      - port@0

required:
  - compatible
  - reg
  - ports

additionalProperties: false

examples:
  - |
    #include <dt-bindings/gpio/gpio.h>

    i2c {
        #address-cells = <1>;
        #size-cells = <0>;
        bridge@4f {
            compatible = "lontium,lt8713sx";
            reg = <0x4f>;
            reset-gpios = <&tlmm 6 GPIO_ACTIVE_LOW>;

            ports {
                #address-cells = <1>;
                #size-cells = <0>;

                port@0 {
                    reg = <0>;
                    lt8713sx_dp_in: endpoint {
                        remote-endpoint = <&mdss_dp0_out>;
                    };
                };

                port@1 {
                    reg = <1>;
                    lt8713sx_dp0_out: endpoint {
                        remote-endpoint = <&dp0_connector_in>;
                    };
                };

                port@2 {
                    reg = <2>;
                    lt8713sx_dp1_out: endpoint {
                        remote-endpoint = <&dp1_connector_in>;
                    };
                };

                port@3 {
                    reg = <3>;
                    lt8713sx_dp2_out: endpoint {
                        remote-endpoint = <&dp2_connector_in>;
                    };
                };
            };
        };
    };
+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ amdxdna-y := \
	aie2_solver.o \
	amdxdna_ctx.o \
	amdxdna_gem.o \
	amdxdna_iommu.o \
	amdxdna_mailbox.o \
	amdxdna_mailbox_helper.o \
	amdxdna_pci_drv.o \
+81 −10
Original line number Diff line number Diff line
@@ -29,6 +29,16 @@ MODULE_PARM_DESC(force_cmdlist, "Force use command list (Default true)");

#define HWCTX_MAX_TIMEOUT	60000 /* milliseconds */

struct aie2_ctx_health {
	struct amdxdna_ctx_health header;
	u32 txn_op_idx;
	u32 ctx_pc;
	u32 fatal_error_type;
	u32 fatal_error_exception_type;
	u32 fatal_error_exception_pc;
	u32 fatal_error_app_module;
};

static void aie2_job_release(struct kref *ref)
{
	struct amdxdna_sched_job *job;
@@ -39,6 +49,7 @@ static void aie2_job_release(struct kref *ref)
	wake_up(&job->hwctx->priv->job_free_wq);
	if (job->out_fence)
		dma_fence_put(job->out_fence);
	kfree(job->aie2_job_health);
	kfree(job);
}

@@ -68,7 +79,8 @@ static int aie2_hwctx_restart(struct amdxdna_dev *xdna, struct amdxdna_hwctx *hw
	}

	ret = aie2_map_host_buf(xdna->dev_handle, hwctx->fw_ctx_id,
				heap->mem.userptr, heap->mem.size);
				amdxdna_obj_dma_addr(hwctx->client, heap),
				heap->mem.size);
	if (ret) {
		XDNA_ERR(xdna, "Map host buf failed, ret %d", ret);
		goto out;
@@ -175,6 +187,50 @@ aie2_sched_notify(struct amdxdna_sched_job *job)
	aie2_job_put(job);
}

static void aie2_set_cmd_timeout(struct amdxdna_sched_job *job)
{
	struct aie2_ctx_health *aie2_health __free(kfree) = NULL;
	struct amdxdna_dev *xdna = job->hwctx->client->xdna;
	struct amdxdna_gem_obj *cmd_abo = job->cmd_bo;
	struct app_health_report *report = job->aie2_job_health;
	u32 fail_cmd_idx = 0;

	if (!report)
		goto set_timeout;

	XDNA_ERR(xdna, "Firmware timeout state capture:");
	XDNA_ERR(xdna, "\tVersion: %d.%d", report->major, report->minor);
	XDNA_ERR(xdna, "\tReport size: 0x%x", report->size);
	XDNA_ERR(xdna, "\tContext ID: %d", report->context_id);
	XDNA_ERR(xdna, "\tDPU PC: 0x%x", report->dpu_pc);
	XDNA_ERR(xdna, "\tTXN OP ID: 0x%x", report->txn_op_id);
	XDNA_ERR(xdna, "\tContext PC: 0x%x", report->ctx_pc);
	XDNA_ERR(xdna, "\tFatal error type: 0x%x", report->fatal_info.fatal_type);
	XDNA_ERR(xdna, "\tFatal error exception type: 0x%x", report->fatal_info.exception_type);
	XDNA_ERR(xdna, "\tFatal error exception PC: 0x%x", report->fatal_info.exception_pc);
	XDNA_ERR(xdna, "\tFatal error app module: 0x%x", report->fatal_info.app_module);
	XDNA_ERR(xdna, "\tFatal error task ID: %d", report->fatal_info.task_index);
	XDNA_ERR(xdna, "\tTimed out sub command ID: %d", report->run_list_id);

	fail_cmd_idx = report->run_list_id;
	aie2_health = kzalloc_obj(*aie2_health);
	if (!aie2_health)
		goto set_timeout;

	aie2_health->header.version = AMDXDNA_CMD_CTX_HEALTH_V1;
	aie2_health->header.npu_gen = AMDXDNA_CMD_CTX_HEALTH_AIE2;
	aie2_health->txn_op_idx = report->txn_op_id;
	aie2_health->ctx_pc = report->ctx_pc;
	aie2_health->fatal_error_type = report->fatal_info.fatal_type;
	aie2_health->fatal_error_exception_type = report->fatal_info.exception_type;
	aie2_health->fatal_error_exception_pc = report->fatal_info.exception_pc;
	aie2_health->fatal_error_app_module = report->fatal_info.app_module;

set_timeout:
	amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_TIMEOUT,
			      aie2_health, sizeof(*aie2_health));
}

static int
aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
{
@@ -186,13 +242,13 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
	cmd_abo = job->cmd_bo;

	if (unlikely(job->job_timeout)) {
		amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_TIMEOUT);
		aie2_set_cmd_timeout(job);
		ret = -EINVAL;
		goto out;
	}

	if (unlikely(!data) || unlikely(size != sizeof(u32))) {
		amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ABORT);
		amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ABORT, NULL, 0);
		ret = -EINVAL;
		goto out;
	}
@@ -202,7 +258,7 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
	if (status == AIE2_STATUS_SUCCESS)
		amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_COMPLETED);
	else
		amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ERROR);
		amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ERROR, NULL, 0);

out:
	aie2_sched_notify(job);
@@ -236,21 +292,21 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
	struct amdxdna_sched_job *job = handle;
	struct amdxdna_gem_obj *cmd_abo;
	struct amdxdna_dev *xdna;
	u32 fail_cmd_idx = 0;
	u32 fail_cmd_status;
	u32 fail_cmd_idx;
	u32 cmd_status;
	int ret = 0;

	cmd_abo = job->cmd_bo;

	if (unlikely(job->job_timeout)) {
		amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_TIMEOUT);
		aie2_set_cmd_timeout(job);
		ret = -EINVAL;
		goto out;
	}

	if (unlikely(!data) || unlikely(size != sizeof(u32) * 3)) {
		amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ABORT);
		amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ABORT, NULL, 0);
		ret = -EINVAL;
		goto out;
	}
@@ -270,10 +326,10 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
		 fail_cmd_idx, fail_cmd_status);

	if (fail_cmd_status == AIE2_STATUS_SUCCESS) {
		amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_ABORT);
		amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_ABORT, NULL, 0);
		ret = -EINVAL;
	} else {
		amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_ERROR);
		amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_ERROR, NULL, 0);
	}

out:
@@ -362,12 +418,26 @@ aie2_sched_job_timedout(struct drm_sched_job *sched_job)
{
	struct amdxdna_sched_job *job = drm_job_to_xdna_job(sched_job);
	struct amdxdna_hwctx *hwctx = job->hwctx;
	struct app_health_report *report;
	struct amdxdna_dev *xdna;
	int ret;

	xdna = hwctx->client->xdna;
	trace_xdna_job(sched_job, hwctx->name, "job timedout", job->seq);
	job->job_timeout = true;

	mutex_lock(&xdna->dev_lock);
	report = kzalloc_obj(*report);
	if (!report)
		goto reset_hwctx;

	ret = aie2_query_app_health(xdna->dev_handle, hwctx->fw_ctx_id, report);
	if (ret)
		kfree(report);
	else
		job->aie2_job_health = report;

reset_hwctx:
	aie2_hwctx_stop(xdna, hwctx, sched_job);

	aie2_hwctx_restart(xdna, hwctx);
@@ -637,7 +707,8 @@ int aie2_hwctx_init(struct amdxdna_hwctx *hwctx)
	}

	ret = aie2_map_host_buf(xdna->dev_handle, hwctx->fw_ctx_id,
				heap->mem.userptr, heap->mem.size);
				amdxdna_obj_dma_addr(hwctx->client, heap),
				heap->mem.size);
	if (ret) {
		XDNA_ERR(xdna, "Map host buffer failed, ret %d", ret);
		goto release_resource;
+2 −3
Original line number Diff line number Diff line
@@ -355,9 +355,8 @@ int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev)
		return -ENOMEM;

	events->buf = aie2_alloc_msg_buffer(ndev, &total_size, &events->addr);

	if (!events->buf) {
		ret = -ENOMEM;
	if (IS_ERR(events->buf)) {
		ret = PTR_ERR(events->buf);
		goto free_events;
	}
	events->size = total_size;
+93 −12
Original line number Diff line number Diff line
@@ -61,13 +61,29 @@ void *aie2_alloc_msg_buffer(struct amdxdna_dev_hdl *ndev, u32 *size,
	*size = max(*size, SZ_8K);
	order = get_order(*size);
	if (order > MAX_PAGE_ORDER)
		return NULL;
		return ERR_PTR(-EINVAL);
	*size = PAGE_SIZE << order;

	if (amdxdna_iova_on(xdna))
		return amdxdna_iommu_alloc(xdna, *size, dma_addr);

	return dma_alloc_noncoherent(xdna->ddev.dev, *size, dma_addr,
				      DMA_FROM_DEVICE, GFP_KERNEL);
}

void aie2_free_msg_buffer(struct amdxdna_dev_hdl *ndev, size_t size,
			  void *cpu_addr, dma_addr_t dma_addr)
{
	struct amdxdna_dev *xdna = ndev->xdna;

	if (amdxdna_iova_on(xdna)) {
		amdxdna_iommu_free(xdna, size, cpu_addr, dma_addr);
		return;
	}

	dma_free_noncoherent(xdna->ddev.dev, size, cpu_addr, dma_addr, DMA_FROM_DEVICE);
}

int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev)
{
	DECLARE_AIE2_MSG(suspend, MSG_OP_SUSPEND);
@@ -256,7 +272,7 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
	req.num_col = hwctx->num_col;
	req.num_unused_col = hwctx->num_unused_col;
	req.num_cq_pairs_requested = 1;
	req.pasid = hwctx->client->pasid;
	req.pasid = amdxdna_pasid_on(hwctx->client) ? hwctx->client->pasid : 0;
	req.context_priority = aie2_get_context_priority(ndev, hwctx);

	ret = aie2_send_mgmt_msg_wait(ndev, &msg);
@@ -380,8 +396,8 @@ int aie2_query_status(struct amdxdna_dev_hdl *ndev, char __user *buf,
	int ret;

	buff_addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr);
	if (!buff_addr)
		return -ENOMEM;
	if (IS_ERR(buff_addr))
		return PTR_ERR(buff_addr);

	/* Go through each hardware context and mark the AIE columns that are active */
	list_for_each_entry(client, &xdna->client_list, node)
@@ -436,8 +452,8 @@ int aie2_query_telemetry(struct amdxdna_dev_hdl *ndev,
		return -EINVAL;

	addr = aie2_alloc_msg_buffer(ndev, &buf_sz, &dma_addr);
	if (!addr)
		return -ENOMEM;
	if (IS_ERR(addr))
		return PTR_ERR(addr);

	req.buf_addr = dma_addr;
	req.buf_size = buf_sz;
@@ -986,7 +1002,7 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,
	struct amdxdna_cmd_chain *payload;
	struct xdna_mailbox_msg msg;
	union exec_chain_req req;
	u32 payload_len;
	u32 payload_len, ccnt;
	u32 offset = 0;
	size_t size;
	int ret;
@@ -995,12 +1011,24 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,

	op = amdxdna_cmd_get_op(cmd_abo);
	payload = amdxdna_cmd_get_payload(cmd_abo, &payload_len);
	if (op != ERT_CMD_CHAIN || !payload ||
	    payload_len < struct_size(payload, data, payload->command_count))
	if (op != ERT_CMD_CHAIN) {
		XDNA_DBG(xdna, "Invalid op code %d", op);
		return -EINVAL;
	}

	if (!payload) {
		XDNA_DBG(xdna, "Failed to get command payload");
		return -EINVAL;
	}

	ccnt = payload->command_count;
	if (payload_len < struct_size(payload, data, ccnt)) {
		XDNA_DBG(xdna, "Invalid command count %d", ccnt);
		return -EINVAL;
	}

	op = ERT_INVALID_CMD;
	for (i = 0; i < payload->command_count; i++) {
	for (i = 0; i < ccnt; i++) {
		u32 boh = (u32)(payload->data[i]);
		struct amdxdna_gem_obj *abo;

@@ -1019,19 +1047,26 @@ int aie2_cmdlist_multi_execbuf(struct amdxdna_hwctx *hwctx,

		offset += size;
	}

	XDNA_DBG(xdna, "Total %d commands:", ccnt);
	print_hex_dump_debug("cmdbufs: ", DUMP_PREFIX_OFFSET, 16, 4,
			     cmdbuf_abo->mem.kva, offset, false);

	msg.opcode = EXEC_MSG_OPS(xdna)->get_chain_msg_op(op);
	if (msg.opcode == MSG_OP_MAX_OPCODE)
		return -EOPNOTSUPP;

	/* The offset is the accumulated total size of the cmd buffer */
	EXEC_MSG_OPS(xdna)->init_chain_req(&req, cmdbuf_abo->mem.dev_addr,
					   offset, payload->command_count);
					   offset, ccnt);
	drm_clflush_virt_range(cmdbuf_abo->mem.kva, offset);

	msg.handle = job;
	msg.notify_cb = notify_cb;
	msg.send_data = (u8 *)&req;
	msg.send_size = sizeof(req);
	print_hex_dump_debug("cmdlist msg: ", DUMP_PREFIX_OFFSET, 16, 4,
			     &req, msg.send_size, false);
	ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
	if (ret) {
		XDNA_ERR(xdna, "Send message failed");
@@ -1060,6 +1095,9 @@ int aie2_cmdlist_single_execbuf(struct amdxdna_hwctx *hwctx,
	if (ret)
		return ret;

	print_hex_dump_debug("cmdbuf: ", DUMP_PREFIX_OFFSET, 16, 4,
			     cmdbuf_abo->mem.kva, size, false);

	msg.opcode = EXEC_MSG_OPS(xdna)->get_chain_msg_op(op);
	if (msg.opcode == MSG_OP_MAX_OPCODE)
		return -EOPNOTSUPP;
@@ -1072,6 +1110,8 @@ int aie2_cmdlist_single_execbuf(struct amdxdna_hwctx *hwctx,
	msg.notify_cb = notify_cb;
	msg.send_data = (u8 *)&req;
	msg.send_size = sizeof(req);
	print_hex_dump_debug("cmdlist msg: ", DUMP_PREFIX_OFFSET, 16, 4,
			     &req, msg.send_size, false);
	ret = xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
	if (ret) {
		XDNA_ERR(hwctx->client->xdna, "Send message failed");
@@ -1145,3 +1185,44 @@ int aie2_config_debug_bo(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *

	return xdna_mailbox_send_msg(chann, &msg, TX_TIMEOUT);
}

int aie2_query_app_health(struct amdxdna_dev_hdl *ndev, u32 context_id,
			  struct app_health_report *report)
{
	DECLARE_AIE2_MSG(get_app_health, MSG_OP_GET_APP_HEALTH);
	struct amdxdna_dev *xdna = ndev->xdna;
	struct app_health_report *buf;
	dma_addr_t dma_addr;
	u32 buf_size;
	int ret;

	if (!AIE2_FEATURE_ON(ndev, AIE2_APP_HEALTH)) {
		XDNA_DBG(xdna, "App health feature not supported");
		return -EOPNOTSUPP;
	}

	buf_size = sizeof(*report);
	buf = aie2_alloc_msg_buffer(ndev, &buf_size, &dma_addr);
	if (IS_ERR(buf)) {
		XDNA_ERR(xdna, "Failed to allocate buffer for app health");
		return PTR_ERR(buf);
	}

	req.buf_addr = dma_addr;
	req.context_id = context_id;
	req.buf_size = buf_size;

	drm_clflush_virt_range(buf, sizeof(*report));
	ret = aie2_send_mgmt_msg_wait(ndev, &msg);
	if (ret) {
		XDNA_ERR(xdna, "Get app health failed, ret %d status 0x%x", ret, resp.status);
		goto free_buf;
	}

	/* Copy the report to caller's buffer */
	memcpy(report, buf, sizeof(*report));

free_buf:
	aie2_free_msg_buffer(ndev, buf_size, buf, dma_addr);
	return ret;
}
Loading