summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dmub
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2025-03-24 17:57:13 +1000
committerDave Airlie <airlied@redhat.com>2025-03-24 17:57:18 +1000
commita82866fbecca6961c00edb2035ad66478571012c (patch)
tree3629257979b058778933272ee77597946772216e /drivers/gpu/drm/amd/display/dmub
parentf72e21eaaefe54e3f2eadaa63f55f9f3ba01a786 (diff)
parent7547510d4a915f4f6d9b1262182d8db6763508f4 (diff)
Merge tag 'amd-drm-next-6.15-2025-03-21' of https://gitlab.freedesktop.org/agd5f/linux into drm-next
amd-drm-next-6.15-2025-03-21: amdgpu: - Refine nomodeset handling - RAS fixes - DCN 3.x fixes - DMUB fixes - eDP fixes - SMU 14.0.2 fixes - SMU 13.0.6 fixes - SMU 13.0.12 fixes - SDMA engine reset fixes - Enforce Isolation fixes - Runtime workload profile ref count fixes - Documentation fixes - SR-IOV fixes - MES fixes - GC 11.5 cleaner shader support - SDMA VM invalidation fixes - IP discovery improvements for GC based chips amdkfd: - Dequeue wait count fixes - Precise memops fixes radeon: - Code cleanup Signed-off-by: Dave Airlie <airlied@redhat.com> From: Alex Deucher <alexander.deucher@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20250321210909.2809595-1-alexander.deucher@amd.com
Diffstat (limited to 'drivers/gpu/drm/amd/display/dmub')
-rw-r--r--drivers/gpu/drm/amd/display/dmub/dmub_srv.h132
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c121
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h4
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c299
4 files changed, 177 insertions, 379 deletions
diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
index 203e3a440845..4e0efff92dca 100644
--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
@@ -51,8 +51,8 @@
* for the cache windows.
*
* The call to dmub_srv_hw_init() programs the DMCUB registers to prepare
- * for command submission. Commands can be queued via dmub_srv_fb_cmd_queue()
- * and executed via dmub_srv_fb_cmd_execute().
+ * for command submission. Commands can be queued via dmub_srv_cmd_queue()
+ * and executed via dmub_srv_cmd_execute().
*
* If the queue is full the dmub_srv_wait_for_idle() call can be used to
* wait until the queue has been cleared.
@@ -170,13 +170,6 @@ enum dmub_srv_power_state_type {
DMUB_POWER_STATE_D3 = 8
};
-/* enum dmub_inbox_cmd_interface type - defines default interface for host->dmub commands */
-enum dmub_inbox_cmd_interface_type {
- DMUB_CMD_INTERFACE_DEFAULT = 0,
- DMUB_CMD_INTERFACE_FB = 1,
- DMUB_CMD_INTERFACE_REG = 2,
-};
-
/**
* struct dmub_region - dmub hw memory region
* @base: base address for region, must be 256 byte aligned
@@ -356,21 +349,6 @@ struct dmub_diagnostic_data {
uint8_t is_cw6_enabled : 1;
};
-struct dmub_srv_inbox {
- /* generic status */
- uint64_t num_submitted;
- uint64_t num_reported;
- union {
- /* frame buffer mailbox status */
- struct dmub_rb rb;
- /* register mailbox status */
- struct {
- bool is_pending;
- bool is_multi_pending;
- };
- };
-};
-
/**
* struct dmub_srv_base_funcs - Driver specific base callbacks
*/
@@ -484,21 +462,18 @@ struct dmub_srv_hw_funcs {
void (*init_reg_offsets)(struct dmub_srv *dmub, struct dc_context *ctx);
void (*subvp_save_surf_addr)(struct dmub_srv *dmub, const struct dc_plane_address *addr, uint8_t subvp_index);
-
void (*send_reg_inbox0_cmd_msg)(struct dmub_srv *dmub,
union dmub_rb_cmd *cmd);
uint32_t (*read_reg_inbox0_rsp_int_status)(struct dmub_srv *dmub);
void (*read_reg_inbox0_cmd_rsp)(struct dmub_srv *dmub,
union dmub_rb_cmd *cmd);
void (*write_reg_inbox0_rsp_int_ack)(struct dmub_srv *dmub);
- void (*clear_reg_inbox0_rsp_int_ack)(struct dmub_srv *dmub);
- void (*enable_reg_inbox0_rsp_int)(struct dmub_srv *dmub, bool enable);
-
uint32_t (*read_reg_outbox0_rdy_int_status)(struct dmub_srv *dmub);
void (*write_reg_outbox0_rdy_int_ack)(struct dmub_srv *dmub);
void (*read_reg_outbox0_msg)(struct dmub_srv *dmub, uint32_t *msg);
void (*write_reg_outbox0_rsp)(struct dmub_srv *dmub, uint32_t *rsp);
uint32_t (*read_reg_outbox0_rsp_int_status)(struct dmub_srv *dmub);
+ void (*enable_reg_inbox0_rsp_int)(struct dmub_srv *dmub, bool enable);
void (*enable_reg_outbox0_rdy_int)(struct dmub_srv *dmub, bool enable);
};
@@ -518,7 +493,6 @@ struct dmub_srv_create_params {
enum dmub_asic asic;
uint32_t fw_version;
bool is_virtual;
- enum dmub_inbox_cmd_interface_type inbox_type;
};
/**
@@ -547,9 +521,8 @@ struct dmub_srv {
const struct dmub_srv_dcn401_regs *regs_dcn401;
struct dmub_srv_base_funcs funcs;
struct dmub_srv_hw_funcs hw_funcs;
- struct dmub_srv_inbox inbox1;
+ struct dmub_rb inbox1_rb;
uint32_t inbox1_last_wptr;
- struct dmub_srv_inbox reg_inbox0;
/**
* outbox1_rb is accessed without locks (dal & dc)
* and to be used only in dmub_srv_stat_get_notification()
@@ -569,7 +542,6 @@ struct dmub_srv {
struct dmub_fw_meta_info meta_info;
struct dmub_feature_caps feature_caps;
struct dmub_visual_confirm_color visual_confirm_color;
- enum dmub_inbox_cmd_interface_type inbox_type;
enum dmub_srv_power_state_type power_state;
struct dmub_diagnostic_data debug;
@@ -727,7 +699,19 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub);
/**
- * dmub_srv_fb_cmd_queue() - queues a command to the DMUB
+ * dmub_srv_sync_inbox1() - sync sw state with hw state
+ * @dmub: the dmub service
+ *
+ * Sync sw state with hw state when resume from S0i3
+ *
+ * Return:
+ * DMUB_STATUS_OK - success
+ * DMUB_STATUS_INVALID - unspecified error
+ */
+enum dmub_status dmub_srv_sync_inbox1(struct dmub_srv *dmub);
+
+/**
+ * dmub_srv_cmd_queue() - queues a command to the DMUB
* @dmub: the dmub service
* @cmd: the command to queue
*
@@ -739,11 +723,11 @@ enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub);
* DMUB_STATUS_QUEUE_FULL - no remaining room in queue
* DMUB_STATUS_INVALID - unspecified error
*/
-enum dmub_status dmub_srv_fb_cmd_queue(struct dmub_srv *dmub,
+enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub,
const union dmub_rb_cmd *cmd);
/**
- * dmub_srv_fb_cmd_execute() - Executes a queued sequence to the dmub
+ * dmub_srv_cmd_execute() - Executes a queued sequence to the dmub
* @dmub: the dmub service
*
* Begins execution of queued commands on the dmub.
@@ -752,7 +736,7 @@ enum dmub_status dmub_srv_fb_cmd_queue(struct dmub_srv *dmub,
* DMUB_STATUS_OK - success
* DMUB_STATUS_INVALID - unspecified error
*/
-enum dmub_status dmub_srv_fb_cmd_execute(struct dmub_srv *dmub);
+enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub);
/**
* dmub_srv_wait_for_hw_pwr_up() - Waits for firmware hardware power up is completed
@@ -811,23 +795,6 @@ enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub,
uint32_t timeout_us);
/**
- * dmub_srv_wait_for_pending() - Re-entrant wait for messages currently pending
- * @dmub: the dmub service
- * @timeout_us: the maximum number of microseconds to wait
- *
- * Waits until the commands queued prior to this call are complete.
- * If interfaces remain busy due to additional work being submitted
- * concurrently, this function will not continue to wait.
- *
- * Return:
- * DMUB_STATUS_OK - success
- * DMUB_STATUS_TIMEOUT - wait for buffer to flush timed out
- * DMUB_STATUS_INVALID - unspecified error
- */
-enum dmub_status dmub_srv_wait_for_pending(struct dmub_srv *dmub,
- uint32_t timeout_us);
-
-/**
* dmub_srv_wait_for_idle() - Waits for the DMUB to be idle
* @dmub: the dmub service
* @timeout_us: the maximum number of microseconds to wait
@@ -925,6 +892,9 @@ enum dmub_status dmub_srv_get_fw_boot_status(struct dmub_srv *dmub,
enum dmub_status dmub_srv_get_fw_boot_option(struct dmub_srv *dmub,
union dmub_fw_boot_options *option);
+enum dmub_status dmub_srv_cmd_with_reply_data(struct dmub_srv *dmub,
+ union dmub_rb_cmd *cmd);
+
enum dmub_status dmub_srv_set_skip_panel_power_sequence(struct dmub_srv *dmub,
bool skip);
@@ -989,51 +959,35 @@ enum dmub_status dmub_srv_clear_inbox0_ack(struct dmub_srv *dmub);
void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_address *addr, uint8_t subvp_index);
/**
- * dmub_srv_set_power_state() - Track DC power state in dmub_srv
+ * dmub_srv_send_reg_inbox0_cmd() - send a dmub command and wait for the command
+ * being processed by DMUB.
* @dmub: The dmub service
- * @power_state: DC power state setting
- *
- * Store DC power state in dmub_srv. If dmub_srv is in D3, then don't send messages to DMUB
+ * @cmd: The dmub command being sent. If with_replay is true, the function will
+ * update cmd with replied data.
+ * @with_reply: true if DMUB reply needs to be copied back to cmd. false if the
+ * cmd doesn't need to be replied.
+ * @timeout_us: timeout in microseconds.
*
* Return:
- * void
+ * DMUB_STATUS_OK - success
+ * DMUB_STATUS_TIMEOUT - DMUB fails to process the command within the timeout
+ * interval.
*/
-void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state);
+enum dmub_status dmub_srv_send_reg_inbox0_cmd(
+ struct dmub_srv *dmub,
+ union dmub_rb_cmd *cmd,
+ bool with_reply, uint32_t timeout_us);
/**
- * dmub_srv_reg_cmd_execute() - Executes provided command to the dmub
- * @dmub: the dmub service
- * @cmd: the command packet to be executed
- *
- * Executes a single command for the dmub.
- *
- * Return:
- * DMUB_STATUS_OK - success
- * DMUB_STATUS_INVALID - unspecified error
- */
-enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_cmd *cmd);
-
-
-/**
- * dmub_srv_cmd_get_response() - Copies return data for command into buffer
- * @dmub: the dmub service
- * @cmd_rsp: response buffer
- *
- * Copies return data for command into buffer
- */
-void dmub_srv_cmd_get_response(struct dmub_srv *dmub,
- union dmub_rb_cmd *cmd_rsp);
-
-/**
- * dmub_srv_sync_inboxes() - Sync inbox state
- * @dmub: the dmub service
+ * dmub_srv_set_power_state() - Track DC power state in dmub_srv
+ * @dmub: The dmub service
+ * @power_state: DC power state setting
*
- * Sync inbox state
+ * Store DC power state in dmub_srv. If dmub_srv is in D3, then don't send messages to DMUB
*
* Return:
- * DMUB_STATUS_OK - success
- * DMUB_STATUS_INVALID - unspecified error
+ * void
*/
-enum dmub_status dmub_srv_sync_inboxes(struct dmub_srv *dmub);
+void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state);
#endif /* _DMUB_SRV_H_ */
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c
index 731ca9b6a6cf..e67f7c4784eb 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c
@@ -517,69 +517,28 @@ void dmub_dcn401_send_reg_inbox0_cmd_msg(struct dmub_srv *dmub,
union dmub_rb_cmd *cmd)
{
uint32_t *dwords = (uint32_t *)cmd;
- int32_t payload_size_bytes = cmd->cmd_common.header.payload_bytes;
- uint32_t msg_index;
- static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch");
-
- /* read remaining data based on payload size */
- for (msg_index = 0; msg_index < 15; msg_index++) {
- if (payload_size_bytes <= msg_index * 4) {
- break;
- }
- switch (msg_index) {
- case 0:
- REG_WRITE(DMCUB_REG_INBOX0_MSG0, dwords[msg_index + 1]);
- break;
- case 1:
- REG_WRITE(DMCUB_REG_INBOX0_MSG1, dwords[msg_index + 1]);
- break;
- case 2:
- REG_WRITE(DMCUB_REG_INBOX0_MSG2, dwords[msg_index + 1]);
- break;
- case 3:
- REG_WRITE(DMCUB_REG_INBOX0_MSG3, dwords[msg_index + 1]);
- break;
- case 4:
- REG_WRITE(DMCUB_REG_INBOX0_MSG4, dwords[msg_index + 1]);
- break;
- case 5:
- REG_WRITE(DMCUB_REG_INBOX0_MSG5, dwords[msg_index + 1]);
- break;
- case 6:
- REG_WRITE(DMCUB_REG_INBOX0_MSG6, dwords[msg_index + 1]);
- break;
- case 7:
- REG_WRITE(DMCUB_REG_INBOX0_MSG7, dwords[msg_index + 1]);
- break;
- case 8:
- REG_WRITE(DMCUB_REG_INBOX0_MSG8, dwords[msg_index + 1]);
- break;
- case 9:
- REG_WRITE(DMCUB_REG_INBOX0_MSG9, dwords[msg_index + 1]);
- break;
- case 10:
- REG_WRITE(DMCUB_REG_INBOX0_MSG10, dwords[msg_index + 1]);
- break;
- case 11:
- REG_WRITE(DMCUB_REG_INBOX0_MSG11, dwords[msg_index + 1]);
- break;
- case 12:
- REG_WRITE(DMCUB_REG_INBOX0_MSG12, dwords[msg_index + 1]);
- break;
- case 13:
- REG_WRITE(DMCUB_REG_INBOX0_MSG13, dwords[msg_index + 1]);
- break;
- case 14:
- REG_WRITE(DMCUB_REG_INBOX0_MSG14, dwords[msg_index + 1]);
- break;
- }
- }
+ static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch");
+ REG_WRITE(DMCUB_REG_INBOX0_MSG0, dwords[0]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG1, dwords[1]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG2, dwords[2]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG3, dwords[3]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG4, dwords[4]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG5, dwords[5]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG6, dwords[6]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG7, dwords[7]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG8, dwords[8]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG9, dwords[9]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG10, dwords[10]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG11, dwords[11]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG12, dwords[12]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG13, dwords[13]);
+ REG_WRITE(DMCUB_REG_INBOX0_MSG14, dwords[14]);
/* writing to INBOX RDY register will trigger DMUB REG INBOX0 RDY
* interrupt.
*/
- REG_WRITE(DMCUB_REG_INBOX0_RDY, dwords[0]);
+ REG_WRITE(DMCUB_REG_INBOX0_RDY, dwords[15]);
}
uint32_t dmub_dcn401_read_reg_inbox0_rsp_int_status(struct dmub_srv *dmub)
@@ -597,39 +556,30 @@ void dmub_dcn401_read_reg_inbox0_cmd_rsp(struct dmub_srv *dmub,
static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch");
- dwords[0] = REG_READ(DMCUB_REG_INBOX0_RSP);
- dwords[1] = REG_READ(DMCUB_REG_INBOX0_MSG0);
- dwords[2] = REG_READ(DMCUB_REG_INBOX0_MSG1);
- dwords[3] = REG_READ(DMCUB_REG_INBOX0_MSG2);
- dwords[4] = REG_READ(DMCUB_REG_INBOX0_MSG3);
- dwords[5] = REG_READ(DMCUB_REG_INBOX0_MSG4);
- dwords[6] = REG_READ(DMCUB_REG_INBOX0_MSG5);
- dwords[7] = REG_READ(DMCUB_REG_INBOX0_MSG6);
- dwords[8] = REG_READ(DMCUB_REG_INBOX0_MSG7);
- dwords[9] = REG_READ(DMCUB_REG_INBOX0_MSG8);
- dwords[10] = REG_READ(DMCUB_REG_INBOX0_MSG9);
- dwords[11] = REG_READ(DMCUB_REG_INBOX0_MSG10);
- dwords[12] = REG_READ(DMCUB_REG_INBOX0_MSG11);
- dwords[13] = REG_READ(DMCUB_REG_INBOX0_MSG12);
- dwords[14] = REG_READ(DMCUB_REG_INBOX0_MSG13);
- dwords[15] = REG_READ(DMCUB_REG_INBOX0_MSG14);
+ dwords[0] = REG_READ(DMCUB_REG_INBOX0_MSG0);
+ dwords[1] = REG_READ(DMCUB_REG_INBOX0_MSG1);
+ dwords[2] = REG_READ(DMCUB_REG_INBOX0_MSG2);
+ dwords[3] = REG_READ(DMCUB_REG_INBOX0_MSG3);
+ dwords[4] = REG_READ(DMCUB_REG_INBOX0_MSG4);
+ dwords[5] = REG_READ(DMCUB_REG_INBOX0_MSG5);
+ dwords[6] = REG_READ(DMCUB_REG_INBOX0_MSG6);
+ dwords[7] = REG_READ(DMCUB_REG_INBOX0_MSG7);
+ dwords[8] = REG_READ(DMCUB_REG_INBOX0_MSG8);
+ dwords[9] = REG_READ(DMCUB_REG_INBOX0_MSG9);
+ dwords[10] = REG_READ(DMCUB_REG_INBOX0_MSG10);
+ dwords[11] = REG_READ(DMCUB_REG_INBOX0_MSG11);
+ dwords[12] = REG_READ(DMCUB_REG_INBOX0_MSG12);
+ dwords[13] = REG_READ(DMCUB_REG_INBOX0_MSG13);
+ dwords[14] = REG_READ(DMCUB_REG_INBOX0_MSG14);
+ dwords[15] = REG_READ(DMCUB_REG_INBOX0_RSP);
}
void dmub_dcn401_write_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub)
{
REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK, 1);
-}
-
-void dmub_dcn401_clear_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub)
-{
REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK, 0);
}
-void dmub_dcn401_enable_reg_inbox0_rsp_int(struct dmub_srv *dmub, bool enable)
-{
- REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_EN, enable ? 1:0);
-}
-
void dmub_dcn401_write_reg_outbox0_rdy_int_ack(struct dmub_srv *dmub)
{
REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK, 1);
@@ -654,6 +604,11 @@ uint32_t dmub_dcn401_read_reg_outbox0_rsp_int_status(struct dmub_srv *dmub)
return status;
}
+void dmub_dcn401_enable_reg_inbox0_rsp_int(struct dmub_srv *dmub, bool enable)
+{
+ REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_EN, enable ? 1:0);
+}
+
void dmub_dcn401_enable_reg_outbox0_rdy_int(struct dmub_srv *dmub, bool enable)
{
REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN, enable ? 1:0);
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h
index 88c3a44d67d9..c35be52676f6 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h
@@ -277,13 +277,11 @@ uint32_t dmub_dcn401_read_reg_inbox0_rsp_int_status(struct dmub_srv *dmub);
void dmub_dcn401_read_reg_inbox0_cmd_rsp(struct dmub_srv *dmub,
union dmub_rb_cmd *cmd);
void dmub_dcn401_write_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub);
-void dmub_dcn401_clear_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub);
-void dmub_dcn401_enable_reg_inbox0_rsp_int(struct dmub_srv *dmub, bool enable);
-
void dmub_dcn401_write_reg_outbox0_rdy_int_ack(struct dmub_srv *dmub);
void dmub_dcn401_read_reg_outbox0_msg(struct dmub_srv *dmub, uint32_t *msg);
void dmub_dcn401_write_reg_outbox0_rsp(struct dmub_srv *dmub, uint32_t *msg);
uint32_t dmub_dcn401_read_reg_outbox0_rsp_int_status(struct dmub_srv *dmub);
+void dmub_dcn401_enable_reg_inbox0_rsp_int(struct dmub_srv *dmub, bool enable);
void dmub_dcn401_enable_reg_outbox0_rdy_int(struct dmub_srv *dmub, bool enable);
uint32_t dmub_dcn401_read_reg_outbox0_rdy_int_status(struct dmub_srv *dmub);
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
index 713576a1f6fa..ae8133816b43 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
@@ -157,9 +157,6 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
{
struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs;
- /* default to specifying now inbox type */
- enum dmub_inbox_cmd_interface_type default_inbox_type = DMUB_CMD_INTERFACE_DEFAULT;
-
switch (asic) {
case DMUB_ASIC_DCN20:
case DMUB_ASIC_DCN21:
@@ -398,15 +395,10 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
funcs->get_current_time = dmub_dcn401_get_current_time;
funcs->get_diagnostic_data = dmub_dcn401_get_diagnostic_data;
-
funcs->send_reg_inbox0_cmd_msg = dmub_dcn401_send_reg_inbox0_cmd_msg;
funcs->read_reg_inbox0_rsp_int_status = dmub_dcn401_read_reg_inbox0_rsp_int_status;
funcs->read_reg_inbox0_cmd_rsp = dmub_dcn401_read_reg_inbox0_cmd_rsp;
funcs->write_reg_inbox0_rsp_int_ack = dmub_dcn401_write_reg_inbox0_rsp_int_ack;
- funcs->clear_reg_inbox0_rsp_int_ack = dmub_dcn401_clear_reg_inbox0_rsp_int_ack;
- funcs->enable_reg_inbox0_rsp_int = dmub_dcn401_enable_reg_inbox0_rsp_int;
- default_inbox_type = DMUB_CMD_INTERFACE_FB; // still default to FB for now
-
funcs->write_reg_outbox0_rdy_int_ack = dmub_dcn401_write_reg_outbox0_rdy_int_ack;
funcs->read_reg_outbox0_msg = dmub_dcn401_read_reg_outbox0_msg;
funcs->write_reg_outbox0_rsp = dmub_dcn401_write_reg_outbox0_rsp;
@@ -419,20 +411,6 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
return false;
}
- /* set default inbox type if not overriden */
- if (dmub->inbox_type == DMUB_CMD_INTERFACE_DEFAULT) {
- if (default_inbox_type != DMUB_CMD_INTERFACE_DEFAULT) {
- /* use default inbox type as specified by DCN rev */
- dmub->inbox_type = default_inbox_type;
- } else if (funcs->send_reg_inbox0_cmd_msg) {
- /* prefer reg as default inbox type if present */
- dmub->inbox_type = DMUB_CMD_INTERFACE_REG;
- } else {
- /* use fb as fallback */
- dmub->inbox_type = DMUB_CMD_INTERFACE_FB;
- }
- }
-
return true;
}
@@ -448,7 +426,6 @@ enum dmub_status dmub_srv_create(struct dmub_srv *dmub,
dmub->asic = params->asic;
dmub->fw_version = params->fw_version;
dmub->is_virtual = params->is_virtual;
- dmub->inbox_type = params->inbox_type;
/* Setup asic dependent hardware funcs. */
if (!dmub_srv_hw_setup(dmub, params->asic)) {
@@ -718,7 +695,7 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
inbox1.base = cw4.region.base;
inbox1.top = cw4.region.base + DMUB_RB_SIZE;
outbox1.base = inbox1.top;
- outbox1.top = inbox1.top + DMUB_RB_SIZE;
+ outbox1.top = cw4.region.top;
cw5.offset.quad_part = tracebuff_fb->gpu_addr;
cw5.region.base = DMUB_CW5_BASE;
@@ -731,7 +708,7 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
cw6.region.base = DMUB_CW6_BASE;
cw6.region.top = cw6.region.base + fw_state_fb->size;
- dmub->fw_state = fw_state_fb->cpu_addr;
+ dmub->fw_state = (void *)((uintptr_t)(fw_state_fb->cpu_addr) + DMUB_DEBUG_FW_STATE_OFFSET);
region6.offset.quad_part = shared_state_fb->gpu_addr;
region6.region.base = DMUB_CW6_BASE;
@@ -760,7 +737,7 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
rb_params.ctx = dmub;
rb_params.base_address = mail_fb->cpu_addr;
rb_params.capacity = DMUB_RB_SIZE;
- dmub_rb_init(&dmub->inbox1.rb, &rb_params);
+ dmub_rb_init(&dmub->inbox1_rb, &rb_params);
// Initialize outbox1 ring buffer
rb_params.ctx = dmub;
@@ -791,6 +768,27 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub,
return DMUB_STATUS_OK;
}
+enum dmub_status dmub_srv_sync_inbox1(struct dmub_srv *dmub)
+{
+ if (!dmub->sw_init)
+ return DMUB_STATUS_INVALID;
+
+ if (dmub->hw_funcs.get_inbox1_rptr && dmub->hw_funcs.get_inbox1_wptr) {
+ uint32_t rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
+ uint32_t wptr = dmub->hw_funcs.get_inbox1_wptr(dmub);
+
+ if (rptr > dmub->inbox1_rb.capacity || wptr > dmub->inbox1_rb.capacity) {
+ return DMUB_STATUS_HW_FAILURE;
+ } else {
+ dmub->inbox1_rb.rptr = rptr;
+ dmub->inbox1_rb.wrpt = wptr;
+ dmub->inbox1_last_wptr = dmub->inbox1_rb.wrpt;
+ }
+ }
+
+ return DMUB_STATUS_OK;
+}
+
enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
{
if (!dmub->sw_init)
@@ -801,13 +799,8 @@ enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
/* mailboxes have been reset in hw, so reset the sw state as well */
dmub->inbox1_last_wptr = 0;
- dmub->inbox1.rb.wrpt = 0;
- dmub->inbox1.rb.rptr = 0;
- dmub->inbox1.num_reported = 0;
- dmub->inbox1.num_submitted = 0;
- dmub->reg_inbox0.num_reported = 0;
- dmub->reg_inbox0.num_submitted = 0;
- dmub->reg_inbox0.is_pending = 0;
+ dmub->inbox1_rb.wrpt = 0;
+ dmub->inbox1_rb.rptr = 0;
dmub->outbox0_rb.wrpt = 0;
dmub->outbox0_rb.rptr = 0;
dmub->outbox1_rb.wrpt = 0;
@@ -818,7 +811,7 @@ enum dmub_status dmub_srv_hw_reset(struct dmub_srv *dmub)
return DMUB_STATUS_OK;
}
-enum dmub_status dmub_srv_fb_cmd_queue(struct dmub_srv *dmub,
+enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub,
const union dmub_rb_cmd *cmd)
{
if (!dmub->hw_init)
@@ -827,20 +820,18 @@ enum dmub_status dmub_srv_fb_cmd_queue(struct dmub_srv *dmub,
if (dmub->power_state != DMUB_POWER_STATE_D0)
return DMUB_STATUS_POWER_STATE_D3;
- if (dmub->inbox1.rb.rptr > dmub->inbox1.rb.capacity ||
- dmub->inbox1.rb.wrpt > dmub->inbox1.rb.capacity) {
+ if (dmub->inbox1_rb.rptr > dmub->inbox1_rb.capacity ||
+ dmub->inbox1_rb.wrpt > dmub->inbox1_rb.capacity) {
return DMUB_STATUS_HW_FAILURE;
}
- if (dmub_rb_push_front(&dmub->inbox1.rb, cmd)) {
- dmub->inbox1.num_submitted++;
+ if (dmub_rb_push_front(&dmub->inbox1_rb, cmd))
return DMUB_STATUS_OK;
- }
return DMUB_STATUS_QUEUE_FULL;
}
-enum dmub_status dmub_srv_fb_cmd_execute(struct dmub_srv *dmub)
+enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub)
{
struct dmub_rb flush_rb;
@@ -855,13 +846,13 @@ enum dmub_status dmub_srv_fb_cmd_execute(struct dmub_srv *dmub)
* been flushed to framebuffer memory. Otherwise DMCUB might
* read back stale, fully invalid or partially invalid data.
*/
- flush_rb = dmub->inbox1.rb;
+ flush_rb = dmub->inbox1_rb;
flush_rb.rptr = dmub->inbox1_last_wptr;
dmub_rb_flush_pending(&flush_rb);
- dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1.rb.wrpt);
+ dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt);
- dmub->inbox1_last_wptr = dmub->inbox1.rb.wrpt;
+ dmub->inbox1_last_wptr = dmub->inbox1_rb.wrpt;
return DMUB_STATUS_OK;
}
@@ -919,97 +910,26 @@ enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub,
return DMUB_STATUS_TIMEOUT;
}
-static void dmub_srv_update_reg_inbox0_status(struct dmub_srv *dmub)
-{
- if (dmub->reg_inbox0.is_pending) {
- dmub->reg_inbox0.is_pending = dmub->hw_funcs.read_reg_inbox0_rsp_int_status &&
- !dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub);
-
- if (!dmub->reg_inbox0.is_pending) {
- /* ack the rsp interrupt */
- if (dmub->hw_funcs.write_reg_inbox0_rsp_int_ack)
- dmub->hw_funcs.write_reg_inbox0_rsp_int_ack(dmub);
-
- /* only update the reported count if commands aren't being batched */
- if (!dmub->reg_inbox0.is_pending && !dmub->reg_inbox0.is_multi_pending) {
- dmub->reg_inbox0.num_reported = dmub->reg_inbox0.num_submitted;
- }
- }
- }
-}
-
-enum dmub_status dmub_srv_wait_for_pending(struct dmub_srv *dmub,
- uint32_t timeout_us)
-{
- uint32_t i;
- const uint32_t polling_interval_us = 1;
- struct dmub_srv_inbox scratch_reg_inbox0 = dmub->reg_inbox0;
- struct dmub_srv_inbox scratch_inbox1 = dmub->inbox1;
- const volatile struct dmub_srv_inbox *reg_inbox0 = &dmub->reg_inbox0;
- const volatile struct dmub_srv_inbox *inbox1 = &dmub->inbox1;
-
- if (!dmub->hw_init ||
- !dmub->hw_funcs.get_inbox1_wptr)
- return DMUB_STATUS_INVALID;
-
- /* take a snapshot of the required mailbox state */
- scratch_inbox1.rb.wrpt = dmub->hw_funcs.get_inbox1_wptr(dmub);
-
- for (i = 0; i <= timeout_us; i += polling_interval_us) {
- scratch_inbox1.rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
-
- scratch_reg_inbox0.is_pending = scratch_reg_inbox0.is_pending &&
- dmub->hw_funcs.read_reg_inbox0_rsp_int_status &&
- !dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub);
-
- if (scratch_inbox1.rb.rptr > dmub->inbox1.rb.capacity)
- return DMUB_STATUS_HW_FAILURE;
-
- /* check current HW state first, but use command submission vs reported as a fallback */
- if ((dmub_rb_empty(&scratch_inbox1.rb) ||
- inbox1->num_reported >= scratch_inbox1.num_submitted) &&
- (!scratch_reg_inbox0.is_pending ||
- reg_inbox0->num_reported >= scratch_reg_inbox0.num_submitted))
- return DMUB_STATUS_OK;
-
- udelay(polling_interval_us);
- }
-
- return DMUB_STATUS_TIMEOUT;
-}
-
enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub,
uint32_t timeout_us)
{
uint32_t i, rptr;
- const uint32_t polling_interval_us = 1;
if (!dmub->hw_init)
return DMUB_STATUS_INVALID;
- for (i = 0; i < timeout_us; i += polling_interval_us) {
- /* update inbox1 state */
+ for (i = 0; i <= timeout_us; ++i) {
rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
- if (rptr > dmub->inbox1.rb.capacity)
+ if (rptr > dmub->inbox1_rb.capacity)
return DMUB_STATUS_HW_FAILURE;
- if (dmub->inbox1.rb.rptr > rptr) {
- /* rb wrapped */
- dmub->inbox1.num_reported += (rptr + dmub->inbox1.rb.capacity - dmub->inbox1.rb.rptr) / DMUB_RB_CMD_SIZE;
- } else {
- dmub->inbox1.num_reported += (rptr - dmub->inbox1.rb.rptr) / DMUB_RB_CMD_SIZE;
- }
- dmub->inbox1.rb.rptr = rptr;
-
- /* update reg_inbox0 */
- dmub_srv_update_reg_inbox0_status(dmub);
+ dmub->inbox1_rb.rptr = rptr;
- /* check for idle */
- if (dmub_rb_empty(&dmub->inbox1.rb) && !dmub->reg_inbox0.is_pending)
+ if (dmub_rb_empty(&dmub->inbox1_rb))
return DMUB_STATUS_OK;
- udelay(polling_interval_us);
+ udelay(1);
}
return DMUB_STATUS_TIMEOUT;
@@ -1120,6 +1040,35 @@ enum dmub_status dmub_srv_set_skip_panel_power_sequence(struct dmub_srv *dmub,
return DMUB_STATUS_OK;
}
+enum dmub_status dmub_srv_cmd_with_reply_data(struct dmub_srv *dmub,
+ union dmub_rb_cmd *cmd)
+{
+ enum dmub_status status = DMUB_STATUS_OK;
+
+ // Queue command
+ status = dmub_srv_cmd_queue(dmub, cmd);
+
+ if (status != DMUB_STATUS_OK)
+ return status;
+
+ // Execute command
+ status = dmub_srv_cmd_execute(dmub);
+
+ if (status != DMUB_STATUS_OK)
+ return status;
+
+ // Wait for DMUB to process command
+ status = dmub_srv_wait_for_idle(dmub, 100000);
+
+ if (status != DMUB_STATUS_OK)
+ return status;
+
+ // Copy data back from ring buffer into command
+ dmub_rb_get_return_data(&dmub->inbox1_rb, cmd);
+
+ return status;
+}
+
static inline bool dmub_rb_out_trace_buffer_front(struct dmub_rb *rb,
void *entry)
{
@@ -1211,105 +1160,47 @@ void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_
}
}
-void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state)
-{
- if (!dmub || !dmub->hw_init)
- return;
-
- dmub->power_state = dmub_srv_power_state;
-}
-enum dmub_status dmub_srv_reg_cmd_execute(struct dmub_srv *dmub, union dmub_rb_cmd *cmd)
+enum dmub_status dmub_srv_send_reg_inbox0_cmd(
+ struct dmub_srv *dmub,
+ union dmub_rb_cmd *cmd,
+ bool with_reply, uint32_t timeout_us)
{
- uint32_t num_pending = 0;
-
- if (!dmub->hw_init)
- return DMUB_STATUS_INVALID;
-
- if (dmub->power_state != DMUB_POWER_STATE_D0)
- return DMUB_STATUS_POWER_STATE_D3;
-
- if (!dmub->hw_funcs.send_reg_inbox0_cmd_msg ||
- !dmub->hw_funcs.clear_reg_inbox0_rsp_int_ack)
- return DMUB_STATUS_INVALID;
-
- if (dmub->reg_inbox0.num_submitted >= dmub->reg_inbox0.num_reported)
- num_pending = dmub->reg_inbox0.num_submitted - dmub->reg_inbox0.num_reported;
- else
- /* num_submitted wrapped */
- num_pending = DMUB_REG_INBOX0_RB_MAX_ENTRY -
- (dmub->reg_inbox0.num_reported - dmub->reg_inbox0.num_submitted);
-
- if (num_pending >= DMUB_REG_INBOX0_RB_MAX_ENTRY)
- return DMUB_STATUS_QUEUE_FULL;
+ uint32_t rsp_ready = 0;
+ uint32_t i;
- /* clear last rsp ack and send message */
- dmub->hw_funcs.clear_reg_inbox0_rsp_int_ack(dmub);
dmub->hw_funcs.send_reg_inbox0_cmd_msg(dmub, cmd);
- dmub->reg_inbox0.num_submitted++;
- dmub->reg_inbox0.is_pending = true;
- dmub->reg_inbox0.is_multi_pending = cmd->cmd_common.header.multi_cmd_pending;
-
- return DMUB_STATUS_OK;
-}
-
-void dmub_srv_cmd_get_response(struct dmub_srv *dmub,
- union dmub_rb_cmd *cmd_rsp)
-{
- if (dmub) {
- if (dmub->inbox_type == DMUB_CMD_INTERFACE_REG &&
- dmub->hw_funcs.read_reg_inbox0_cmd_rsp) {
- dmub->hw_funcs.read_reg_inbox0_cmd_rsp(dmub, cmd_rsp);
- } else {
- dmub_rb_get_return_data(&dmub->inbox1.rb, cmd_rsp);
- }
+ for (i = 0; i < timeout_us; i++) {
+ rsp_ready = dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub);
+ if (rsp_ready)
+ break;
+ udelay(1);
}
-}
-
-static enum dmub_status dmub_srv_sync_reg_inbox0(struct dmub_srv *dmub)
-{
- if (!dmub || !dmub->sw_init)
- return DMUB_STATUS_INVALID;
-
- dmub->reg_inbox0.is_pending = 0;
- dmub->reg_inbox0.is_multi_pending = 0;
-
- return DMUB_STATUS_OK;
-}
+ if (rsp_ready == 0)
+ return DMUB_STATUS_TIMEOUT;
-static enum dmub_status dmub_srv_sync_inbox1(struct dmub_srv *dmub)
-{
- if (!dmub->sw_init)
- return DMUB_STATUS_INVALID;
+ if (with_reply)
+ dmub->hw_funcs.read_reg_inbox0_cmd_rsp(dmub, cmd);
- if (dmub->hw_funcs.get_inbox1_rptr && dmub->hw_funcs.get_inbox1_wptr) {
- uint32_t rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
- uint32_t wptr = dmub->hw_funcs.get_inbox1_wptr(dmub);
+ dmub->hw_funcs.write_reg_inbox0_rsp_int_ack(dmub);
- if (rptr > dmub->inbox1.rb.capacity || wptr > dmub->inbox1.rb.capacity) {
- return DMUB_STATUS_HW_FAILURE;
- } else {
- dmub->inbox1.rb.rptr = rptr;
- dmub->inbox1.rb.wrpt = wptr;
- dmub->inbox1_last_wptr = dmub->inbox1.rb.wrpt;
- }
+ /* wait for rsp int status is cleared to initial state before exit */
+ for (; i <= timeout_us; i++) {
+ rsp_ready = dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub);
+ if (rsp_ready == 0)
+ break;
+ udelay(1);
}
+ ASSERT(rsp_ready == 0);
return DMUB_STATUS_OK;
}
-enum dmub_status dmub_srv_sync_inboxes(struct dmub_srv *dmub)
+void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state)
{
- enum dmub_status status;
-
- status = dmub_srv_sync_reg_inbox0(dmub);
- if (status != DMUB_STATUS_OK)
- return status;
-
- status = dmub_srv_sync_inbox1(dmub);
- if (status != DMUB_STATUS_OK)
- return status;
+ if (!dmub || !dmub->hw_init)
+ return;
- return DMUB_STATUS_OK;
+ dmub->power_state = dmub_srv_power_state;
}