drm/amd/display: Add new sources for DCN6

Add DCN6 code to DC, DML2, and DMUB

Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Roman Li <Roman.Li@amd.com>
Reviewed-by: Ivan Lipski <ivan.lipski@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Aurabindo Pillai
2026-07-22 14:45:53 -04:00
committed by Alex Deucher
parent fe219bd7d9
commit 7f7d7ea1fa
107 changed files with 48882 additions and 1 deletions

View File

@@ -0,0 +1,389 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2026 Advanced Micro Devices, Inc.
#ifndef DALSMC_H
#define DALSMC_H
/**
* @file dalsmc.h
*
* @brief VBIOS and DAL to PMFW Interface
*
* Clients: VBIOS and DAL
* Protocols: dalsmc
*
* @date 2016 - 2026
*/
/**
* @mainpage PMFW-DAL Message Interface
*
* The protocol uses six registers:
*
* - MSG_REG write the message ID (DALSMC_MSG_*) to trigger the transaction
* - ARG_REG_0 input argument Reg0; also carries response data on completion
* - ARG_REG_1 input argument Reg1
* - ARG_REG_2 input argument Reg2
* - ARG_REG_3 input argument Reg3
* - RESP_REG poll until non-zero; value is a DALSMC_Result_* response code
*
* Programming sequence:
* 1. Clear RESP_REG to 0
* 2. Write input arguments to ARG_REG_0..3
* 3. Write message ID to MSG_REG (triggers PMFW interrupt)
* 4. Poll RESP_REG until non-zero value is the result code
* 5. Read response data from ARG_REG_0 (message-specific)
*
* For payloads too large for the four argument registers, the protocol supports
* DRAM table transfers where DAL allocates a DRAM buffer and exchanges bulk data
* with PMFW through system memory.
*
* This documentation contains the subsections:\n\n
* @ref ResponseCodes\n
* @ref Messages\n
* @ref DramTables\n
*/
#define DALSMC_VERSION 0x1
/** @defgroup ResponseCodes PMFW Response Codes
* @{
*/
// SMU Response Codes:
#define DALSMC_Result_OK 0x01
#define DALSMC_Result_Failed 0xFF
#define DALSMC_Result_UnknownCmd 0xFE
#define DALSMC_Result_CmdRejectedPrereq 0xFD
#define DALSMC_Result_CmdRejectedBusy 0xFC
/** @} */
/** @defgroup Messages Message definitions
* @{
*/
/** Generic register overlay — four 32-bit C2PMSG argument registers. */
typedef struct {
uint32_t Reg0;
uint32_t Reg1;
uint32_t Reg2;
uint32_t Reg3;
} DALSMC_args_t;
/**
* DALSMC_MSG_TestMessage - Test interface connectivity.
*
* Echos back the argument value incremented by 1. Use to verify the mailbox
* is functional before sending real messages.
*
* Request: TestValue arbitrary test integer
* Response: Reg0 TestValue + 1
*/
#define DALSMC_MSG_TestMessage 0x01
typedef union {
struct {
uint32_t TestValue;
uint32_t Reserved[3];
};
DALSMC_args_t Args;
} DALSMC_TestMessage_arg_t;
/**
* DALSMC_MSG_GetMsgHeaderVersion - Query the DALSMC header version running on PMFW.
*
* DAL uses the returned version to determine which messages are supported in
* environments that require backwards compatibility.
*
* Request: (none)
* Response: Reg0 DALSMC_VERSION value compiled into PMFW
*/
#define DALSMC_MSG_GetMsgHeaderVersion 0x02
/**
* DALSMC_MSG_TransferTableSmu2Dram - Transfer a PMFW table into DRAM.
* DALSMC_MSG_TransferTableDram2Smu - Transfer a DRAM buffer into PMFW.
*
* Both directions use the same argument layout. The DRAM address must be set
* beforehand (AddrLow / AddrHigh are the GPU MC address bits [31:0] / [63:32]).
*
* Smu2Dram supported tables: TABLE_DAL_INIT (DPM clocks + UTM QoS + memory config)
* Dram2Smu supported tables: TABLE_SOC_UTM (debug override of UTM QoS parameters)
*
* Request: TableId table identifier (TABLE_* defines below)
* AddrLow GPU MC address bits [31:0] of destination/source buffer
* AddrHigh GPU MC address bits [63:32] of destination/source buffer
* Response: (none beyond result code)
*/
#define DALSMC_MSG_TransferTableSmu2Dram 0x03
#define DALSMC_MSG_TransferTableDram2Smu 0x04
typedef union {
struct {
uint32_t TableId;
uint32_t AddrLow;
uint32_t AddrHigh;
uint32_t Reserved;
};
DALSMC_args_t Args;
} DALSMC_TransferTable_arg_t;
/**
* DALSMC_MSG_SetHardMinByFreq - Set a lower bound frequency constraint on a PPCLK.
*
* Response does not indicate that the effective clock has already been raised to
* meet the minimum requirement; poll DALSMC_MSG_ReturnHardMinStatus for the status
* of the request.
*
* Supported clocks: SOCCLK, DISPCLK, DPPCLK, DCFCLK, DTBCLK.
*
* Request: FreqKhz[23:0] target minimum frequency in kHz (0 to ~16.7 GHz)
* Ppclk[31:24] PPCLK_e clock identifier
* Response: (none beyond result code)
*/
#define DALSMC_MSG_SetHardMinByFreq 0x05
typedef union {
struct {
uint32_t FreqKhz : 24;
uint32_t Ppclk : 8;
uint32_t Reserved[3];
};
DALSMC_args_t Args;
} DALSMC_SetHardMinByFreq_arg_t;
/**
* DALSMC_MSG_SetMinDeepSleepDcfclk - Set the minimum DCFCLK frequency in deep sleep.
*
* Request: MinDcfclkMhz minimum DCFCLK frequency in MHz during deep sleep
* Response: (none beyond result code)
*/
#define DALSMC_MSG_SetMinDeepSleepDcfclk 0x06
typedef union {
struct {
uint32_t MinDcfclkMhz;
uint32_t Reserved[3];
};
DALSMC_args_t Args;
} DALSMC_SetMinDeepSleepDcfclk_arg_t;
/**
* DALSMC_MSG_BacoAudioD3PME - Wake the audio block from D3/BACO.
*
* Triggers PMFW to bring the AZ (audio) block out of its D3 power state.
* No arguments or response data; result code indicates success.
*/
#define DALSMC_MSG_BacoAudioD3PME 0x07
/**
* DALSMC_MSG_ReturnHardMinStatus - Query outstanding hard-min request status.
*
* Returns a bitmask reporting which PPCLK hard-min requests have been satisfied
* by the arbiter. Each bit position corresponds to the matching PPCLK_e value.
* A set bit means the arbiter has reached or exceeded the requested minimum.
*
* Request: (none)
* Response: Reg0 bitmask of satisfied PPCLKs (bit N set PPCLK_e N is satisfied)
*/
#define DALSMC_MSG_ReturnHardMinStatus 0x08
/**
* DALSMC_MSG_IndicatePstateStatus - Indicate to PMFW various DMU behaviors required
* to support UCLK P-state, for example whether or not DMU needs to modulate refresh
* rate to perform UCLK switches.
*
* Request: WaitResp[0] DAL requires a synchronous response before proceeding
* DrrEnable[1] DRR (dynamic refresh rate modulation) is active
* AltCh[2] alternate-channel mode is active
* AllowUclk[16] DCN can tolerate UCLK P-state switches
* AllowFclk[17] DCN can tolerate FCLK P-state switches
* Response: (none beyond result code)
*/
#define DALSMC_MSG_IndicatePstateStatus 0x09
typedef union {
struct {
uint32_t WaitResp : 1;
uint32_t DrrEnable : 1;
uint32_t AltCh : 1;
uint32_t Reserved : 13;
uint32_t AllowUclk : 1;
uint32_t AllowFclk : 1;
uint32_t Reserved1 : 14;
uint32_t Reserved2[3];
};
DALSMC_args_t Args;
} DALSMC_IndicatePstateStatus_arg_t;
/**
* DALSMC_MSG_UpdateUTMQoSRequest - Update the active UTM QoS bandwidth/latency request.
*
* Passes the current display bandwidth and latency requirements to PMFW so it
* can select the appropriate SoC operating point (UCLK/FCLK level) from the
* UTM table. Called whenever the display configuration changes.
*
* The QoS requirement must take effect before PMFW sends its response.
*
* Request: LatencySopIndex index into the UTM SOP table that satisfies latency
* NominalBandwidthKBps required nominal (average) bandwidth in KB/s
* UrgentBandwidthKBps required urgent bandwidth in KB/s
* LsdmaBandwidthKBps required LSDMA bandwidth in KB/s
* Response: (none beyond result code)
*/
#define DALSMC_MSG_UpdateUTMQoSRequest 0x0A
typedef union {
struct {
uint32_t LatencySopIndex;
uint32_t NominalBandwidthKBps;
uint32_t UrgentBandwidthKBps;
uint32_t LsdmaBandwidthKBps;
};
DALSMC_args_t Args;
} DALSMC_UpdateUTMQoSRequest_arg_t;
/**
* DALSMC_MSG_SetDisplayIdleOptimizations - Notify PMFW of DCN idle-state conditions.
*
* Indicates which display-side power optimizations are currently safe to apply.
* PMFW uses these flags to gate deeper SoC power states such as S0i2.
*
* Request: DfRequestDisabled[0] DF (data fabric) requests from DCN are disabled
* PhyRefClkOff[1] PHY reference clock has been gated off
* S0i2Rdy[2] DCN is ready for the system to enter S0i2
* Response: (none beyond result code)
*/
#define DALSMC_MSG_SetDisplayIdleOptimizations 0x0B
typedef union {
struct {
uint32_t DfRequestDisabled : 1;
uint32_t PhyRefClkOff : 1;
uint32_t S0i2Rdy : 1;
uint32_t Reserved : 29;
uint32_t Reserved1[3];
};
DALSMC_args_t Args;
} DALSMC_SetDisplayIdleOptimizations_arg_t;
/**
* DALSMC_MSG_SetStutterEfficiency - Report DCN stutter efficiency to PMFW.
*
* Informs PMFW of the current stutter utilisation for base and low-power stutter
* modes so PMFW can adjust memory power policy accordingly.
*
* Base mode lower enter+exit latency (PHY LP1, no UCIE LP).
* Low-power mode higher enter+exit latency (PHY LP2, UCIE LP1).
*
* Request: BaseEfficiencyPct[7:0] stutter efficiency % in base mode
* LowPowerEfficiencyPct[15:8] stutter efficiency % in low-power mode
* Response: (none beyond result code)
*/
#define DALSMC_MSG_SetStutterEfficiency 0x0C
typedef union {
struct {
uint32_t BaseEfficiencyPct : 8;
uint32_t LowPowerEfficiencyPct : 8;
uint32_t Reserved : 16;
uint32_t Reserved1[3];
};
DALSMC_args_t Args;
} DALSMC_SetStutterEfficiency_arg_t;
#define DALSMC_Message_Count 0x0D ///< Total number of messages
/** @} */
/** @defgroup DramTables DRAM Tables
* @brief Bulk data structures exchanged between DAL and PMFW via system DRAM.
*
* Used when the payload exceeds the four 32-bit C2PMSG argument registers
* (DALSMC_args_t). DAL allocates a DRAM buffer, passes its address through
* DALSMC_TransferTable_arg_t, and issues either a
* DALSMC_MSG_TransferTableSmu2Dram or DALSMC_MSG_TransferTableDram2Smu message.
* @{
*/
typedef struct {
uint32_t LoadLevelCount : 4;
uint32_t SopCount : 4;
uint32_t Reserved : 24;
} SocUtmTableHeader_t;
typedef struct {
uint32_t UrgentRampPs;
uint32_t TripPs;
uint32_t MetaTripToMemPs;
uint32_t MaxReqLatencyUrgPs;
uint32_t AvgReqLatencyUrgPs;
uint32_t MaxReqLatencyNonUrgPs;
uint32_t AvgReqLatencyNonUrgPs;
uint32_t DfResponseTimePs;
uint32_t UrgentBandwidthKBps;
uint32_t NominalBandwidthKBps;
uint32_t LsdmaBandwidthKBps;
uint32_t Reserved[1];
} SocUtmSopEntry_t;
typedef struct {
uint32_t SmuVersion;
uint32_t SmuDriverIfVersion;
uint32_t Reserved[2];
} DalInitHeader_t;
#define NUM_CLOCK_LEVELS 8
typedef struct {
uint32_t Clocks[NUM_CLOCK_LEVELS];
uint32_t DcMaxClock;
uint32_t NumClocks;
uint32_t Reserved[2];
} DpmClock_t;
typedef struct {
uint32_t NumUmcChannels;
uint32_t Reserved[3];
} MemoryConfig_t;
/**
* TABLE_SOC_UTM - SoC UTM QoS table.
*
* Provides per-load-level bandwidth and latency bounds used by the display
* engine to meet memory access requirements.
*
* Normal path: embedded in DalInitTable_t, fetched once via
* DALSMC_MSG_TransferTableSmu2Dram(TABLE_DAL_INIT).
*
* Override path (debug only): TABLE_SOC_UTM via
* DALSMC_MSG_TransferTableDram2Smu to override custom QoS parameters into PMFW.
*/
#define TABLE_SOC_UTM 0xC
/* TODO: rename back to MAX_UTM_SOP_COUNT once utm_qos_model_types.h conflict is resolved */
#define DALSMC_MAX_UTM_SOP_COUNT 16
#define MAX_UTM_LOAD_LEVEL_COUNT 16
#define UTM_LOAD_LEVEL_INDEX_IDLE 0
#define UTM_LOAD_LEVEL_INDEX_ACTIVE_ALTERNATE_PSTATE 1
#define UTM_LOAD_LEVEL_INDEX_ACTIVE 2
#define UTM_SOP_ENTRIES_OFFSET(LoadLevel, SopIndex) \
(sizeof(SocUtmTableHeader_t) \
+ ((LoadLevel) * DALSMC_MAX_UTM_SOP_COUNT \
+ (SopIndex)) * sizeof(SocUtmSopEntry_t))
typedef struct {
SocUtmTableHeader_t Header;
SocUtmSopEntry_t Sops[MAX_UTM_LOAD_LEVEL_COUNT][DALSMC_MAX_UTM_SOP_COUNT];
} SocUtmTable_t;
/**
* TABLE_DAL_INIT - Full TABLE_DAL_INIT payload transferred from SMU to DRAM.
*/
#define TABLE_DAL_INIT 0xD
#define MAX_PPCLK_COUNT 12
#define DPM_CLOCK_OFFSET(Ppclk) \
(sizeof(DalInitHeader_t) + (Ppclk) * sizeof(DpmClock_t))
#define UTM_TABLE_OFFSET \
(sizeof(DalInitHeader_t) + MAX_PPCLK_COUNT * sizeof(DpmClock_t))
#define MEMORY_CONFIG_OFFSET \
(sizeof(DalInitHeader_t) + MAX_PPCLK_COUNT * sizeof(DpmClock_t) \
+ sizeof(SocUtmTable_t))
typedef struct {
DalInitHeader_t Header;
DpmClock_t PPClocks[MAX_PPCLK_COUNT];
SocUtmTable_t UtmTable;
MemoryConfig_t MemoryConfig;
} DalInitTable_t;
/** @} */
#endif /* DALSMC_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,150 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DCN60_CLK_MGR_H_
#define __DCN60_CLK_MGR_H_
#ifdef CONFIG_DRM_AMD_DC_FP
#include "bounding_boxes/utm_qos_model_types.h"
#include "bounding_boxes/utm_qos_model_dchub_v3.h"
#endif
union dcn60_clk_mgr_block_sequence_params {
struct {
/* inputs */
uint32_t ppclk;
uint16_t freq_mhz;
/* outputs */
int *response;
} update_hardmin_params;
struct {
/* inputs */
uint32_t ppclk;
int freq_khz;
/* outputs */
int *response;
} update_hardmin_optimized_params;
struct {
/* inputs */
uint16_t freq_mhz;
} update_deep_sleep_dcfclk_params;
struct {
/* inputs */
bool allow_fclk;
bool allow_uclk;
bool wait_resp;
bool drr_enable;
bool alt_ch_enable;
} indicate_pstate_status_params;
struct {
/* inputs */
struct dc_state *context;
int *ref_dppclk_khz;
bool safe_to_lower;
} update_dppclk_dto_params;
struct {
/* inputs */
struct dc_state *context;
int *ref_dtbclk_khz;
} update_dtbclk_dto_params;
struct {
/* inputs */
struct dc_state *context;
} update_dentist_params;
struct {
/* inputs */
struct dmcu *dmcu;
unsigned int wait;
} update_psr_wait_loop_params;
struct {
/* inputs */
uint8_t base_efficiency;
uint8_t low_power_efficiency;
} update_stutter_efficiency_params;
struct {
unsigned int utm_urgent_bandwidth_lb_KBps;
unsigned int utm_nominal_bandwidth_lb_KBps;
unsigned int utm_lsdma_bandwidth_lb_KBps;
unsigned int utm_latency_ub_index;
} update_utm_qos_request_params;
};
enum dcn60_clk_mgr_block_sequence_func {
CLK_MGR60_READ_CLOCKS_FROM_DENTIST,
CLK_MGR60_UPDATE_HARDMIN_PPCLK,
CLK_MGR60_UPDATE_HARDMIN_PPCLK_OPTIMIZED,
CLK_MGR60_UPDATE_DEEP_SLEEP_DCFCLK,
CLK_MGR60_INDICATE_PSTATE_STATUS,
CLK_MGR60_UPDATE_DPPCLK_DTO,
CLK_MGR60_UPDATE_DTBCLK_DTO,
CLK_MGR60_UPDATE_DENTIST,
CLK_MGR60_UPDATE_PSR_WAIT_LOOP,
CLK_MGR60_UPDATE_STUTTER_EFFICIENCY,
CLK_MGR60_UPDATE_UTM_QOS_REQUEST
};
struct dcn60_clk_mgr_block_sequence {
union dcn60_clk_mgr_block_sequence_params params;
enum dcn60_clk_mgr_block_sequence_func func;
};
struct dcn60_update_action {
/** clk_mgr state needs updating */
bool update;
/** SMU message required */
bool send_message;
};
struct dcn60_enablement_action {
/** feature transitioning to enabled */
bool enable;
/** feature transitioning to disabled */
bool disable;
/** SMU message required for this transition */
bool send_message;
};
/**
* struct dcn60_bandwidth_clocks_update_action - captures what clock and
* p-state changes are needed for a bandwidth update, separating the action
* logic from block sequence construction and state mutation.
*/
struct dcn60_bandwidth_clocks_update_action {
struct dcn60_update_action dcfclk;
struct dcn60_update_action deep_sleep_dcfclk;
struct dcn60_update_action socclk;
struct dcn60_update_action stutter;
struct dcn60_update_action utm_qos;
struct dcn60_enablement_action uclk_pstate;
struct dcn60_enablement_action fclk_pstate;
struct dcn60_enablement_action fams;
struct dcn60_enablement_action alt_ch;
};
struct dcn60_clk_mgr {
struct clk_mgr_internal base;
struct dcn60_clk_mgr_block_sequence block_sequence[DCN401_CLK_MGR_MAX_SEQUENCE_SIZE];
#ifdef CONFIG_DRM_AMD_DC_FP
struct utm_qos_model utm_qos_model;
struct utm_qos_model_dchub_v3 dchub_v3;
#endif
unsigned int num_block_sequence_steps;
};
void dcn60_init_clocks(struct clk_mgr *clk_mgr_base);
struct block_sequence_state;
void dcn60_build_clock_update_for_bls(
struct clk_mgr *clk_mgr_base,
struct dc_state *context,
bool safe_to_lower,
struct block_sequence_state *seq_state);
struct clk_mgr_internal *dcn60_clk_mgr_construct(struct dc_context *ctx,
struct dccg *dccg);
void dcn60_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr);
#endif /* __DCN60_CLK_MGR_H_ */

View File

@@ -0,0 +1,369 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dcn60_clk_mgr_smu_msg.h"
#include "clk_mgr_internal.h"
#include "reg_helper.h"
#include "dalsmc.h"
#include "dcn401/dcn401_smu14_driver_if.h"
/* MMIO = MP1_BASE__INST0_SEG1 (0x16200 from at2_offset.h)
* + regMP1_SMN_C2PMSG_N (sequential from 0xA2)
* MSG=C2PMSG_98, RESP=C2PMSG_99, ARG0..3=C2PMSG_100..103
*/
#ifndef mmDAL_MSG_REG
#define mmDAL_MSG_REG 0x162A2
#endif
#ifndef mmDAL_RESP_REG
#define mmDAL_RESP_REG 0x162A3
#endif
#ifndef mmDAL_ARG_REG
#define mmDAL_ARG_REG 0x162A4
#endif
#ifndef mmDAL_ARG_REG_0
#define mmDAL_ARG_REG_0 0x162A4
#endif
#ifndef mmDAL_ARG_REG_1
#define mmDAL_ARG_REG_1 0x162A5
#endif
#ifndef mmDAL_ARG_REG_2
#define mmDAL_ARG_REG_2 0x162A6
#endif
#ifndef mmDAL_ARG_REG_3
#define mmDAL_ARG_REG_3 0x162A7
#endif
#define REG(reg_name) \
mm ## reg_name
#include "logger_types.h"
#define smu_print(str, ...) {DC_LOG_SMU(str, ##__VA_ARGS__); }
/**
* dcn60_smu_wait_for_response - Poll DAL_RESP_REG until non-zero.
* @clk_mgr: clock manager instance
* @delay_us: microseconds to wait between each poll iteration
* @max_retries: maximum number of poll iterations before giving up
* @total_delay_us: if non-NULL, accumulates the total poll delay
*
* Cannot use REG_WAIT because the condition is "not equal to zero"
* and the translation in msg_if.h is incompatible with REG_WAIT.
*
* Return: RESP_REG value (non-zero on success, 0 on timeout)
*/
static uint32_t dcn60_smu_wait_for_response(struct clk_mgr_internal *clk_mgr,
unsigned int delay_us, unsigned int max_retries,
unsigned int *total_delay_us)
{
uint32_t reg = 0;
if (total_delay_us)
*total_delay_us = 0;
do {
reg = REG_READ(DAL_RESP_REG);
if (reg)
break;
if (delay_us >= 1000)
msleep(delay_us/1000);
else if (delay_us > 0)
udelay(delay_us);
if (total_delay_us)
*total_delay_us += delay_us;
} while (max_retries--);
return reg;
}
/**
* dcn60_smu_send_msg_with_args - Send a DALSMC message with four argument registers.
* @clk_mgr: clock manager instance
* @msg_id: DALSMC_MSG_* message identifier
* @args: four-register argument payload
* @param_out: if non-NULL, receives ARG_REG_0 on success
* @total_delay_us: if non-NULL, accumulates the total poll delay
*/
static bool dcn60_smu_send_msg_with_args(struct clk_mgr_internal *clk_mgr,
uint32_t msg_id, DALSMC_args_t args, uint32_t *param_out,
unsigned int *total_delay_us)
{
unsigned int delay1_us = 0, delay2_us = 0;
if (total_delay_us)
*total_delay_us = 0;
/* Wait for response register to be ready */
dcn60_smu_wait_for_response(clk_mgr, 10, 200000,
total_delay_us ? &delay1_us : NULL);
smu_print("SMU msg 0x%x enter: arg0=0x%08x arg1=0x%08x arg2=0x%08x arg3=0x%08x\n",
msg_id, args.Reg0, args.Reg1, args.Reg2, args.Reg3);
TRACE_SMU_MSG_ENTER(msg_id, args.Reg0, clk_mgr->base.ctx);
/* Clear response register */
REG_WRITE(DAL_RESP_REG, 0);
/* Write all four argument registers */
REG_WRITE(DAL_ARG_REG_0, args.Reg0);
REG_WRITE(DAL_ARG_REG_1, args.Reg1);
REG_WRITE(DAL_ARG_REG_2, args.Reg2);
REG_WRITE(DAL_ARG_REG_3, args.Reg3);
/* Trigger the message transaction by writing the message ID */
REG_WRITE(DAL_MSG_REG, msg_id);
/* Wait for response */
if (dcn60_smu_wait_for_response(clk_mgr, 10, 200000,
total_delay_us ? &delay2_us : NULL) == DALSMC_Result_OK) {
if (param_out)
*param_out = REG_READ(DAL_ARG_REG_0);
if (total_delay_us)
*total_delay_us = delay1_us + delay2_us;
smu_print("SMU msg 0x%x exit: ok resp=0x%08x\n",
msg_id, param_out ? *param_out : 0);
TRACE_SMU_MSG_EXIT(true, param_out ? *param_out : 0, clk_mgr->base.ctx);
return true;
}
if (total_delay_us)
*total_delay_us = delay1_us + 2000000;
smu_print("SMU msg 0x%x exit: failed\n", msg_id);
TRACE_SMU_MSG_EXIT(false, 0, clk_mgr->base.ctx);
return false;
}
static unsigned int dcn60_smu_get_hard_min_status(struct clk_mgr_internal *clk_mgr,
bool *no_timeout, unsigned int *total_delay_us)
{
DALSMC_args_t args = {};
uint32_t response = 0;
*no_timeout = dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_ReturnHardMinStatus, args, &response,
total_delay_us);
smu_print("SMU Get hard min status: no_timeout %d delay %d us clk bits %x\n",
*no_timeout, *total_delay_us, response);
return response;
}
static bool dcn60_smu_wait_hard_min_status(struct clk_mgr_internal *clk_mgr, uint32_t ppclk)
{
const unsigned int max_delay_us = 1000000;
unsigned int hardmin_status_mask = (1 << ppclk);
unsigned int total_delay_us = 0;
bool hardmin_done = false;
while (!hardmin_done && total_delay_us < max_delay_us) {
unsigned int hardmin_status;
unsigned int read_total_delay_us;
bool no_timeout;
if (!hardmin_done && total_delay_us > 0) {
/* hardmin not yet fulfilled, wait 500us and retry*/
udelay(500);
total_delay_us += 500;
smu_print("SMU Wait hard min status for %d us\n", total_delay_us);
}
hardmin_status = dcn60_smu_get_hard_min_status(clk_mgr, &no_timeout, &read_total_delay_us);
total_delay_us += read_total_delay_us;
hardmin_done = hardmin_status & hardmin_status_mask;
}
return hardmin_done;
}
/* TODO: update callers to pass kHz directly for finer granularity
* now that the DALSMC interface supports 24-bit kHz encoding.
*/
unsigned int dcn60_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz)
{
DALSMC_SetHardMinByFreq_arg_t arg = {};
uint32_t response = 0;
bool hard_min_done = false;
smu_print("SMU Set hard min by freq: clk = %d, freq_mhz = %d MHz\n", clk, freq_mhz);
/* New interface encodes frequency in kHz (24-bit) and PPCLK in bits [31:24] */
arg.FreqKhz = (uint32_t)freq_mhz * 1000;
arg.Ppclk = clk;
dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_SetHardMinByFreq, arg.Args, &response, NULL);
/* wait until hardmin acknowledged */
hard_min_done = dcn60_smu_wait_hard_min_status(clk_mgr, clk);
smu_print("SMU Frequency set = %d KHz hard_min_done %d\n", response, hard_min_done);
return response;
}
void dcn60_smu_set_stutter_efficiency(struct clk_mgr_internal *clk_mgr, uint8_t base_efficiency, uint8_t low_power_efficiency)
{
DALSMC_SetStutterEfficiency_arg_t arg = {};
smu_print("SMU Set stutter efficiencies: base(LP1) = %d percent, low power(LP2) = %d percent\n",
base_efficiency, low_power_efficiency);
arg.BaseEfficiencyPct = base_efficiency;
arg.LowPowerEfficiencyPct = low_power_efficiency;
dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_SetStutterEfficiency, arg.Args, NULL, NULL);
}
void dcn60_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, uint32_t freq_mhz)
{
DALSMC_SetMinDeepSleepDcfclk_arg_t arg = {};
smu_print("SMU Set min deep sleep dcfclk: freq_mhz = %d MHz\n", freq_mhz);
arg.MinDcfclkMhz = freq_mhz;
dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_SetMinDeepSleepDcfclk, arg.Args, NULL, NULL);
}
void dcn60_smu_set_pme_workaround(struct clk_mgr_internal *clk_mgr)
{
DALSMC_args_t args = {};
smu_print("SMU Set PME workaround (BacoAudioD3PME)\n");
dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_BacoAudioD3PME, args, NULL, NULL);
}
void dcn60_smu_indicate_pstate_status(struct clk_mgr_internal *clk_mgr,
bool allow_fclk, bool allow_uclk,
bool wait_resp, bool drr_enable, bool alt_ch_enable)
{
DALSMC_IndicatePstateStatus_arg_t arg = {};
smu_print("SMU Indicate pstate status: allow_fclk=%d allow_uclk=%d wait_resp=%d drr_enable=%d alt_ch_enable=%d\n",
allow_fclk, allow_uclk, wait_resp, drr_enable, alt_ch_enable);
arg.AllowFclk = allow_fclk ? 1 : 0;
arg.AllowUclk = allow_uclk ? 1 : 0;
arg.WaitResp = wait_resp ? 1 : 0;
arg.DrrEnable = drr_enable ? 1 : 0;
arg.AltCh = alt_ch_enable ? 1 : 0;
dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_IndicatePstateStatus, arg.Args, NULL, NULL);
}
static bool dcn60_smu_transfer_table_smu_2_dram(struct clk_mgr_internal *clk_mgr,
uint32_t table_id, long long dram_addr)
{
DALSMC_TransferTable_arg_t arg = {};
smu_print("SMU TransferTableSmu2Dram: table_id=0x%x addr=0x%08x_%08x\n",
table_id,
(uint32_t)(dram_addr >> 32),
(uint32_t)(dram_addr & 0xFFFFFFFF));
arg.TableId = table_id;
arg.AddrLow = (uint32_t)(dram_addr & 0xFFFFFFFF);
arg.AddrHigh = (uint32_t)(dram_addr >> 32);
return dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_TransferTableSmu2Dram, arg.Args, NULL, NULL);
}
static bool dcn60_smu_transfer_table_dram_2_smu(struct clk_mgr_internal *clk_mgr,
uint32_t table_id, long long dram_addr)
{
DALSMC_TransferTable_arg_t arg = {};
smu_print("SMU TransferTableDram2Smu: table_id=0x%x addr=0x%08x_%08x\n",
table_id,
(uint32_t)(dram_addr >> 32),
(uint32_t)(dram_addr & 0xFFFFFFFF));
arg.TableId = table_id;
arg.AddrLow = (uint32_t)(dram_addr & 0xFFFFFFFF);
arg.AddrHigh = (uint32_t)(dram_addr >> 32);
return dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_TransferTableDram2Smu, arg.Args, NULL, NULL);
}
bool dcn60_smu_set_soc_utm_table(struct clk_mgr_internal *clk_mgr,
long long dram_addr)
{
return dcn60_smu_transfer_table_dram_2_smu(clk_mgr,
TABLE_SOC_UTM, dram_addr);
}
bool dcn60_smu_get_dal_init_table(struct clk_mgr_internal *clk_mgr,
const DalInitTable_t **init_table)
{
if (!dcn60_smu_transfer_table_smu_2_dram(clk_mgr,
TABLE_DAL_INIT, clk_mgr->dal_init_table_addr))
return false;
*init_table = (const DalInitTable_t *)clk_mgr->dal_init_table;
return true;
}
bool dcn60_smu_update_utm_qos_request(struct clk_mgr_internal *clk_mgr,
uint32_t latency_sop_index,
uint32_t nominal_bandwidth_KBps,
uint32_t urgent_bandwidth_KBps,
uint32_t lsdma_bandwidth_KBps)
{
DALSMC_UpdateUTMQoSRequest_arg_t arg = {};
smu_print("SMU UpdateUTMQoSRequest: sop_idx=%d nominal=%d urgent=%d lsdma=%d KBps\n",
latency_sop_index, nominal_bandwidth_KBps,
urgent_bandwidth_KBps, lsdma_bandwidth_KBps);
arg.LatencySopIndex = latency_sop_index;
arg.NominalBandwidthKBps = nominal_bandwidth_KBps;
arg.UrgentBandwidthKBps = urgent_bandwidth_KBps;
arg.LsdmaBandwidthKBps = lsdma_bandwidth_KBps;
return dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_UpdateUTMQoSRequest, arg.Args, NULL, NULL);
}
bool dcn60_smu_get_msg_header_version(struct clk_mgr_internal *clk_mgr,
uint32_t *version)
{
DALSMC_args_t args = {};
return dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_GetMsgHeaderVersion, args, version, NULL);
}
void dcn60_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, bool is_idle)
{
DALSMC_SetDisplayIdleOptimizations_arg_t arg = {};
arg.DfRequestDisabled = is_idle ? 1 : 0;
arg.PhyRefClkOff = is_idle ? 1 : 0;
arg.S0i2Rdy = is_idle ? 1 : 0;
smu_print("SMU SetDisplayIdleOptimizations: DfRequestDisabled=%d PhyRefClkOff=%d S0i2Rdy=%d\n",
arg.DfRequestDisabled, arg.PhyRefClkOff, arg.S0i2Rdy);
dcn60_smu_send_msg_with_args(clk_mgr,
DALSMC_MSG_SetDisplayIdleOptimizations, arg.Args, NULL, NULL);
}

View File

@@ -0,0 +1,35 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DCN60_CLK_MGR_SMU_MSG_H_
#define __DCN60_CLK_MGR_SMU_MSG_H_
#include "os_types.h"
#include "core_types.h"
#include "dalsmc.h"
struct clk_mgr_internal;
unsigned int dcn60_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz);
void dcn60_smu_set_stutter_efficiency(struct clk_mgr_internal *clk_mgr,
uint8_t base_efficiency, uint8_t low_power_efficiency);
void dcn60_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, uint32_t freq_mhz);
void dcn60_smu_set_pme_workaround(struct clk_mgr_internal *clk_mgr);
void dcn60_smu_indicate_pstate_status(struct clk_mgr_internal *clk_mgr,
bool allow_fclk, bool allow_uclk,
bool wait_resp, bool drr_enable, bool alt_ch_enable);
bool dcn60_smu_update_utm_qos_request(struct clk_mgr_internal *clk_mgr,
uint32_t latency_sop_index,
uint32_t nominal_bandwidth_KBps,
uint32_t urgent_bandwidth_KBps,
uint32_t lsdma_bandwidth_KBps);
bool dcn60_smu_set_soc_utm_table(struct clk_mgr_internal *clk_mgr,
long long dram_addr);
bool dcn60_smu_get_dal_init_table(struct clk_mgr_internal *clk_mgr,
const DalInitTable_t **init_table);
bool dcn60_smu_get_msg_header_version(struct clk_mgr_internal *clk_mgr,
uint32_t *version);
void dcn60_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, bool is_idle);
#endif /* __DCN60_CLK_MGR_SMU_MSG_H_ */

View File

@@ -0,0 +1,187 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "reg_helper.h"
#include "core_types.h"
#include "dcn42/dcn42_dccg.h"
#include "dcn60_dccg.h"
#define TO_DCN_DCCG(dccg)\
container_of(dccg, struct dcn_dccg, base)
#define REG(reg) \
(dccg_dcn->regs->reg)
#undef FN
#define FN(reg_name, field_name) \
dccg_dcn->dccg_shift->field_name, dccg_dcn->dccg_mask->field_name
#define CTX \
dccg_dcn->base.ctx
#define DC_LOGGER \
dccg->ctx->logger
static void dccg60_set_pixel_rate_div(
struct dccg *dccg,
uint32_t otg_inst,
enum pixel_rate_div tmds_div,
enum pixel_rate_div unused)
{
(void)unused;
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
uint32_t cur_tmds_div = PIXEL_RATE_DIV_NA;
uint32_t dp_dto_int;
uint32_t reg_val;
// only 2 is valid on dcn401
if (tmds_div != PIXEL_RATE_DIV_BY_2 && tmds_div != PIXEL_RATE_DIV_BY_4) {
return;
}
dccg401_get_pixel_rate_div(dccg, otg_inst, &cur_tmds_div, &dp_dto_int);
if (tmds_div == cur_tmds_div)
return;
// encode enum to register value
reg_val = tmds_div == PIXEL_RATE_DIV_BY_4 ? 1 : 0;
switch (otg_inst) {
case 0:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG0_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 1:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG1_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 2:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG2_TMDS_PIXEL_RATE_DIV, reg_val);
break;
case 3:
REG_UPDATE(OTG_PIXEL_RATE_DIV,
OTG3_TMDS_PIXEL_RATE_DIV, reg_val);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static void dccg60_set_dto_dscclk(struct dccg *dccg, uint32_t inst,
uint32_t num_slices_h)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
switch (inst) {
case 0:
REG_UPDATE_2(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, 1,
DSCCLK0_DTO_MODULO, 1);
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK0_EN, 1);
/*
* Source for dscclk should be set when dto tuned clock is used.
* For 1 slice config, set src to dprefclk.
* For 2 or more slice config, set src to dispclk.
*/
if (num_slices_h == 1)
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, 1);
else
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, 0);
break;
case 1:
REG_UPDATE_2(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, 1,
DSCCLK1_DTO_MODULO, 1);
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK1_EN, 1);
if (num_slices_h == 1)
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, 1);
else
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, 0);
break;
case 2:
REG_UPDATE_2(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, 1,
DSCCLK2_DTO_MODULO, 1);
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK2_EN, 1);
if (num_slices_h == 1)
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, 1);
else
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, 0);
break;
case 3:
REG_UPDATE_2(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, 1,
DSCCLK3_DTO_MODULO, 1);
REG_UPDATE(DSCCLK_DTO_CTRL, DSCCLK3_EN, 1);
if (num_slices_h == 1)
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, 1);
else
REG_UPDATE(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, 0);
break;
default:
BREAK_TO_DEBUGGER();
return;
}
}
static const struct dccg_funcs dccg60_funcs = {
.enable_hdmicharclk = dccg401_enable_hdmicharclk,
.disable_hdmicharclk = dccg401_disable_hdmicharclk,
.set_hdmistreamclk = dccg401_set_hdmistreamclk,
.update_dpp_dto = dccg401_update_dpp_dto,
.get_dccg_ref_freq = dccg401_get_dccg_ref_freq,
.dccg_init = dccg401_init,
.set_dpstreamclk = dccg401_set_dpstreamclk,
.enable_symclk32_se = dccg31_enable_symclk32_se,
.disable_symclk32_se = dccg31_disable_symclk32_se,
.enable_symclk32_le = dccg401_enable_symclk32_le,
.disable_symclk32_le = dccg401_disable_symclk32_le,
.set_physymclk = dccg401_set_physymclk,
.set_dtbclk_dto = NULL,
.set_dto_dscclk = dccg60_set_dto_dscclk,
.set_ref_dscclk = dccg401_set_ref_dscclk,
.set_valid_pixel_rate = NULL,
.set_fifo_errdet_ovr_en = dccg2_set_fifo_errdet_ovr_en,
.set_audio_dtbclk_dto = NULL,
.otg_add_pixel = dccg42_otg_add_pixel,
.otg_drop_pixel = dccg42_otg_drop_pixel,
.set_pixel_rate_div = dccg60_set_pixel_rate_div,
.get_pixel_rate_div = dccg401_get_pixel_rate_div,
.set_dp_dto = dccg401_set_dp_dto,
.enable_symclk_se = dccg401_enable_symclk_se,
.disable_symclk_se = dccg401_disable_symclk_se,
.set_dtbclk_p_src = dccg401_set_dtbclk_p_src,
.dccg_read_reg_state = dccg31_read_reg_state,
.allow_clock_gating = dccg2_allow_clock_gating
};
struct dccg *dccg60_create(
struct dc_context *ctx,
const struct dccg_registers *regs,
const struct dccg_shift *dccg_shift,
const struct dccg_mask *dccg_mask)
{
struct dcn_dccg *dccg_dcn = kzalloc(sizeof(*dccg_dcn), GFP_KERNEL);
struct dccg *base;
if (dccg_dcn == NULL) {
BREAK_TO_DEBUGGER();
return NULL;
}
base = &dccg_dcn->base;
base->ctx = ctx;
base->funcs = &dccg60_funcs;
dccg_dcn->regs = regs;
dccg_dcn->dccg_shift = dccg_shift;
dccg_dcn->dccg_mask = dccg_mask;
return &dccg_dcn->base;
}

View File

@@ -0,0 +1,182 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DCN60_DCCG_H__
#define __DCN60_DCCG_H__
#include "dcn401/dcn401_dccg.h"
#define DCCG_MASK_SH_LIST_DCN60(mask_sh) \
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 0, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 1, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 2, mask_sh),\
DCCG_SFI(DPPCLK_DTO_CTRL, DTO_DB_EN, DPPCLK, 3, mask_sh),\
DCCG_SF(DPPCLK_CTRL, DPPCLK0_EN, mask_sh),\
DCCG_SF(DPPCLK_CTRL, DPPCLK1_EN, mask_sh),\
DCCG_SF(DPPCLK_CTRL, DPPCLK2_EN, mask_sh),\
DCCG_SF(DPPCLK_CTRL, DPPCLK3_EN, mask_sh),\
DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\
DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\
DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_EN, mask_sh),\
DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_SRC_SEL, mask_sh),\
DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_EN, mask_sh),\
DCCG_SF(PHYASYMCLK_CLOCK_CNTL, PHYASYMCLK_SRC_SEL, mask_sh),\
DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_EN, mask_sh),\
DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_SRC_SEL, mask_sh),\
DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_EN, mask_sh),\
DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_SRC_SEL, mask_sh),\
DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_EN, mask_sh),\
DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_SRC_SEL, mask_sh),\
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK0_EN, mask_sh),\
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK1_EN, mask_sh),\
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK2_EN, mask_sh),\
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_EN, mask_sh),\
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK0_SRC_SEL, mask_sh),\
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK1_SRC_SEL, mask_sh),\
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK2_SRC_SEL, mask_sh),\
DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_SRC_SEL, mask_sh),\
DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_EN, mask_sh),\
DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE2_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_EN, mask_sh),\
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_EN, mask_sh),\
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE2_EN, mask_sh),\
DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_EN, mask_sh),\
DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE0_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE1_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE0_EN, mask_sh),\
DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE1_EN, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 0, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 1, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 2, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 3, mask_sh),\
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG0_ADD_PIXEL, mask_sh),\
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG1_ADD_PIXEL, mask_sh),\
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG2_ADD_PIXEL, mask_sh),\
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG3_ADD_PIXEL, mask_sh),\
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG0_DROP_PIXEL, mask_sh),\
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG1_DROP_PIXEL, mask_sh),\
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG2_DROP_PIXEL, mask_sh),\
DCCG_SF(OTG_ADD_DROP_PIXEL_CNTL, OTG3_DROP_PIXEL, mask_sh),\
DCCG_SF(OTG_PIXEL_RATE_DIV, OTG0_TMDS_PIXEL_RATE_DIV, mask_sh),\
DCCG_SF(OTG_PIXEL_RATE_DIV, DPDTO0_INT, mask_sh),\
DCCG_SF(OTG_PIXEL_RATE_DIV, OTG1_TMDS_PIXEL_RATE_DIV, mask_sh),\
DCCG_SF(OTG_PIXEL_RATE_DIV, DPDTO1_INT, mask_sh),\
DCCG_SF(OTG_PIXEL_RATE_DIV, OTG2_TMDS_PIXEL_RATE_DIV, mask_sh),\
DCCG_SF(OTG_PIXEL_RATE_DIV, DPDTO2_INT, mask_sh),\
DCCG_SF(OTG_PIXEL_RATE_DIV, OTG3_TMDS_PIXEL_RATE_DIV, mask_sh),\
DCCG_SF(OTG_PIXEL_RATE_DIV, DPDTO3_INT, mask_sh),\
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P0_SRC_SEL, mask_sh),\
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P0_EN, mask_sh),\
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P1_SRC_SEL, mask_sh),\
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P1_EN, mask_sh),\
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P2_SRC_SEL, mask_sh),\
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P2_EN, mask_sh),\
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P3_SRC_SEL, mask_sh),\
DCCG_SF(DTBCLK_P_CNTL, DTBCLK_P3_EN, mask_sh),\
DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO_SEL, mask_sh),\
DCCG_SF(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 0, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 1, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 2, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 3, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 0, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 1, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 2, mask_sh),\
DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 3, mask_sh),\
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_EN, mask_sh),\
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_EN, mask_sh),\
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_EN, mask_sh),\
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_EN, mask_sh),\
DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, mask_sh),\
DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_MODULO, mask_sh),\
DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, mask_sh),\
DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_MODULO, mask_sh),\
DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_PHASE, mask_sh),\
DCCG_SF(DSCCLK2_DTO_PARAM, DSCCLK2_DTO_MODULO, mask_sh),\
DCCG_SF(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, mask_sh),\
DCCG_SF(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_MODULO, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, HDMISTREAMCLK0_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE1_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE2_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE3_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE0_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE1_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE2_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE3_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE0_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE1_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE2_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE3_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, HDMICHARCLK0_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYA_REFCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYB_REFCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYC_REFCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYD_REFCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_FE_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_FE_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_FE_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_FE_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_CLOCK_ENABLE, mask_sh),\
DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_CLOCK_ENABLE, mask_sh),\
DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_CLOCK_ENABLE, mask_sh),\
DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_CLOCK_ENABLE, mask_sh),\
DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_EN, mask_sh),\
DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_EN, mask_sh),\
DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_EN, mask_sh),\
DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_EN, mask_sh),\
DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_SRC_SEL, mask_sh),\
DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_SRC_SEL, mask_sh),\
DCCG_SF(DSCCLK_SRC_SEL, DSCCLK0_SRC_SEL, mask_sh),\
DCCG_SF(DSCCLK_SRC_SEL, DSCCLK1_SRC_SEL, mask_sh),\
DCCG_SF(DSCCLK_SRC_SEL, DSCCLK2_SRC_SEL, mask_sh),\
DCCG_SF(DSCCLK_SRC_SEL, DSCCLK3_SRC_SEL, mask_sh),\
struct dccg *dccg60_create(
struct dc_context *ctx,
const struct dccg_registers *regs,
const struct dccg_shift *dccg_shift,
const struct dccg_mask *dccg_mask);
#endif //__DCN60_DCCG_H__

View File

@@ -0,0 +1,372 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "reg_helper.h"
#include "core_types.h"
#include "link_encoder.h"
#include "dcn31/dcn31_dio_link_encoder.h"
#include "dcn32/dcn32_dio_link_encoder.h"
#include "dcn401/dcn401_dio_link_encoder.h"
#include "dcn42/dcn42_dio_link_encoder.h"
#include "dcn60_dio_link_encoder.h"
#include "stream_encoder.h"
#include "dc_bios_types.h"
#include "gpio_service_interface.h"
#ifndef MIN
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#endif
#define CTX \
enc10->base.ctx
#define DC_LOGGER \
enc10->base.ctx->logger
#define REG(reg)\
(enc10->link_regs->reg)
#undef FN
#define FN(reg_name, field_name) \
enc10->link_shift->field_name, enc10->link_mask->field_name
#define AUX_REG(reg)\
(enc10->aux_regs->reg)
#define AUX_REG_READ(reg_name) \
dm_read_reg(CTX, AUX_REG(reg_name))
#define AUX_REG_WRITE(reg_name, val) \
dm_write_reg(CTX, AUX_REG(reg_name), val)
#define AUX_REG_UPDATE_N(reg_name, n, ...) \
generic_reg_update_ex(CTX, \
AUX_REG(reg_name), \
n, __VA_ARGS__)
#define AUX_REG_UPDATE_1(reg_name, field, val) \
AUX_REG_UPDATE_N(reg_name, 1, \
FN(reg_name, field), val)
#define HPD_REG(reg)\
(enc10->hpd_regs->reg)
#define HPD_REG_GET(reg_name, field, val) \
generic_reg_get(CTX, HPD_REG(reg_name), \
FN(reg_name, field), val)
#define HPD_REG_SET_N(reg_name, n, initial_val, ...) \
generic_reg_set_ex(CTX, \
HPD_REG(reg_name), \
initial_val, \
n, __VA_ARGS__)
#define HPD_REG_SET_2(reg, init_value, f1, v1, f2, v2) \
HPD_REG_SET_N(reg, 2, init_value, \
FN(reg, f1), v1,\
FN(reg, f2), v2)
#define HPD_REG_SET_1(reg, init_value, f1, v1) \
HPD_REG_SET_N(reg, 1, init_value, \
FN(reg, f1), v1)
#ifndef MIN
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#endif
// DP2/HDMI FRL PRESET_LEVEL EQ options for FFE byte
// Preset level 0-32 bits[0:4]
#define PRESET_LEVEL_BYTE__LEVEL__SHIFT 0x0u
#define PRESET_LEVEL_BYTE__LEVEL__MASK 0x1Fu
// Enable no preshoot bit[5]
#define PRESET_LEVEL_BYTE__NO_PRE__SHIFT 0x5u
#define PRESET_LEVEL_BYTE__NO_PRE__MASK 0x20u
// Enable no demphasis bit[6]
#define PRESET_LEVEL_BYTE__NO_DEMPH__SHIFT 0x6u
#define PRESET_LEVEL_BYTE__NO_DEMPH__MASK 0x40u
// Enable method 2 bit[7]
#define PRESET_LEVEL_BYTE__METHOD_2__SHIFT 0x7u
#define PRESET_LEVEL_BYTE__METHOD_2__MASK 0x80u
void enc60_hw_init(struct link_encoder *enc)
{
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
switch (enc10->base.connector.id) {
case CONNECTOR_ID_DISPLAY_PORT:
case CONNECTOR_ID_EDP:
AUX_REG_WRITE(AUX_DPHY_RX_CONTROL0, 0x103d1110);
AUX_REG_WRITE(AUX_DPHY_TX_CONTROL, 0x21c7a);
dcn10_aux_initialize(enc10);
break;
default:
break;
}
REG_UPDATE(TMDS_CTL_BITS, TMDS_CTL0, 1);
// Polarity update is handled by DMU init.
// AUX_PAD_MODE update done by DMU init
}
static enum bp_result link_transmitter_control(
struct dcn10_link_encoder *enc10,
struct bp_transmitter_control *cntl)
{
enum bp_result result;
struct dc_bios *bp = enc10->base.ctx->dc_bios;
result = bp->funcs->transmitter_control(bp, cntl);
return result;
}
//---------------------------------------------------
// Task: Program EQ setting
// Note:
// EQ setting can be dont during P2 state or P0 state
// If set in P0 state, The values are latched in a single
// cycle of txX_clk but will take maximum of 40 txX_clk symbols
// to be reflected on the output. During this period the
// analog serial lines might have a transitional behavior.
//---------------------------------------------------
void dpcs60_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings)
{
const uint8_t max_ffe_level = 0x7;
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
struct bp_transmitter_control cntl = { 0 };
if (enc10->base.ctx->dc->debug.ignore_ffe)
return;
if (FFE_Level <= max_ffe_level)
enc10->base.txffe_state = FFE_Level;
if (enc10->base.ctx->dc->debug.select_ffe)
enc10->base.txffe_state =
(uint8_t)enc10->base.ctx->dc->debug.select_ffe;
if (FFE_Level == 0xEE) {
enc10->base.txffe_state++;
if (enc10->base.txffe_state > max_ffe_level)
enc10->base.txffe_state = 0;
}
if (no_ffe) {
de_emphasis_only = true;
pre_shoot_only = true;
}
/* Pass on the input params to DMCUB for proper calc of eq settings */
cntl.lane_settings = ((de_emphasis_only ? 1u : 0u) << PRESET_LEVEL_BYTE__NO_PRE__SHIFT) |
((pre_shoot_only ? 1u : 0u) << PRESET_LEVEL_BYTE__NO_DEMPH__SHIFT) |
((enc10->base.txffe_state & PRESET_LEVEL_BYTE__LEVEL__MASK)
<< PRESET_LEVEL_BYTE__LEVEL__SHIFT);
cntl.lane_select = 0;
cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
cntl.transmitter = enc10->base.transmitter;
cntl.connector_obj_id = enc10->base.connector;
cntl.lanes_number = link_settings->frl_num_lanes;
cntl.hpd_sel = enc10->base.hpd_source;
/* Use below or dc_link_frl_bandwidth_kbps()? */
switch (link_settings->frl_link_rate) {
case HDMI_FRL_LINK_RATE_3GBPS:
cntl.pixel_clock = 166667 / 10;
break;
case HDMI_FRL_LINK_RATE_6GBPS:
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
cntl.pixel_clock = 333333 / 10;
break;
case HDMI_FRL_LINK_RATE_8GBPS:
cntl.pixel_clock = 444444 / 10;
break;
case HDMI_FRL_LINK_RATE_10GBPS:
cntl.pixel_clock = 555555 / 10;
break;
case HDMI_FRL_LINK_RATE_12GBPS:
cntl.pixel_clock = 666667 / 10;
break;
case HDMI_FRL_LINK_RATE_16GBPS:
cntl.pixel_clock = 888889 / 10;
break;
case HDMI_FRL_LINK_RATE_20GBPS:
default:
cntl.pixel_clock = 1111111 / 10;
break;
}
/* call VBIOS table to set eq settings - voltage swing and pre-emphasis */
link_transmitter_control(enc10, &cntl);
}
static const struct link_encoder_funcs dcn60_link_enc_funcs = {
.read_state = link_enc2_read_state,
.validate_output_with_stream =
dcn30_link_encoder_validate_output_with_stream,
.hw_init = enc60_hw_init,
.setup = dcn401_link_encoder_setup,
.enable_tmds_output = dcn10_link_encoder_enable_tmds_output,
.enable_dp_output = dcn401_link_encoder_enable_dp_output,
.enable_dp_mst_output = dcn10_link_encoder_enable_dp_mst_output,
.disable_output = dcn10_link_encoder_disable_output,
.dp_set_lane_settings = dcn10_link_encoder_dp_set_lane_settings,
.dp_set_phy_pattern = dcn10_link_encoder_dp_set_phy_pattern,
.update_mst_stream_allocation_table =
dcn10_link_encoder_update_mst_stream_allocation_table,
.psr_program_dp_dphy_fast_training =
dcn10_psr_program_dp_dphy_fast_training,
.psr_program_secondary_packet = dcn10_psr_program_secondary_packet,
.connect_dig_be_to_fe = dcn10_link_encoder_connect_dig_be_to_fe,
.enable_hpd = dcn10_link_encoder_enable_hpd,
.disable_hpd = dcn10_link_encoder_disable_hpd,
.is_dig_enabled = dcn401_is_dig_enabled,
.destroy = dcn10_link_encoder_destroy,
.fec_set_enable = enc2_fec_set_enable,
.fec_set_ready = enc2_fec_set_ready,
.fec_is_active = enc2_fec_is_active,
.get_dig_frontend = dcn10_get_dig_frontend,
.get_dig_mode = dcn401_get_dig_mode,
.is_in_alt_mode = dcn32_link_encoder_is_in_alt_mode,
.get_max_link_cap = dcn32_link_encoder_get_max_link_cap,
.dpcstx_set_order_invert_18_bit = NULL,
.set_phy_source = NULL,
.dpcs_initialize_phy = NULL,
.dpcs_configure_phypll = NULL,
.dpcs_configure_dpcs = NULL,
.dpcs_enable_dpcs = NULL,
.prog_eq_setting = dpcs60_program_eq_setting,
.get_txffe = dpcs401_get_txffe,
.set_txffe = dpcs401_set_txffe,
.set_dio_phy_mux = dcn31_link_encoder_set_dio_phy_mux,
.setup_ri_pj_check_in_sw_or_hw_mode = dcn401_setup_ri_pj_check_in_sw_or_hw_mode,
.get_hpd_state = dcn42_get_hpd_state,
.program_hpd_filter = dcn42_program_hpd_filter,
};
void dcn60_link_encoder_construct(
struct dcn20_link_encoder *enc20,
const struct encoder_init_data *init_data,
const struct encoder_feature_support *enc_features,
const struct dcn10_link_enc_registers *link_regs,
const struct dcn10_link_enc_aux_registers *aux_regs,
const struct dcn10_link_enc_hpd_registers *hpd_regs,
const struct dcn10_link_enc_shift *link_shift,
const struct dcn10_link_enc_mask *link_mask)
{
struct bp_connector_speed_cap_info bp_cap_info = {0};
const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs;
enum bp_result result = BP_RESULT_OK;
struct dcn10_link_encoder *enc10 = &enc20->enc10;
enc10->base.funcs = &dcn60_link_enc_funcs;
enc10->base.ctx = init_data->ctx;
enc10->base.id = init_data->encoder;
enc10->base.hpd_source = init_data->hpd_source;
enc10->base.hpd_active_high = init_data->hpd_active_high;
enc10->base.connector = init_data->connector;
enc10->base.preferred_engine = ENGINE_ID_UNKNOWN;
enc10->base.features = *enc_features;
if (enc10->base.connector.id == CONNECTOR_ID_USBC)
enc10->base.features.flags.bits.DP_IS_USB_C = 1;
enc10->base.transmitter = init_data->transmitter;
/* set the flag to indicate whether driver poll the I2C data pin
* while doing the DP sink detect
*/
/* if (dal_adapter_service_is_feature_supported(as,
FEATURE_DP_SINK_DETECT_POLL_DATA_PIN))
enc10->base.features.flags.bits.
DP_SINK_DETECT_POLL_DATA_PIN = true;*/
enc10->base.output_signals =
SIGNAL_TYPE_DVI_SINGLE_LINK |
SIGNAL_TYPE_DVI_DUAL_LINK |
SIGNAL_TYPE_LVDS |
SIGNAL_TYPE_DISPLAY_PORT |
SIGNAL_TYPE_DISPLAY_PORT_MST |
SIGNAL_TYPE_EDP |
SIGNAL_TYPE_HDMI_TYPE_A;
enc10->link_regs = link_regs;
enc10->aux_regs = aux_regs;
enc10->hpd_regs = hpd_regs;
enc10->link_shift = link_shift;
enc10->link_mask = link_mask;
switch (enc10->base.transmitter) {
case TRANSMITTER_UNIPHY_A:
enc10->base.preferred_engine = ENGINE_ID_DIGA;
break;
case TRANSMITTER_UNIPHY_B:
enc10->base.preferred_engine = ENGINE_ID_DIGB;
break;
case TRANSMITTER_UNIPHY_C:
enc10->base.preferred_engine = ENGINE_ID_DIGC;
break;
case TRANSMITTER_UNIPHY_D:
enc10->base.preferred_engine = ENGINE_ID_DIGD;
break;
case TRANSMITTER_UNIPHY_E:
enc10->base.preferred_engine = ENGINE_ID_DIGE;
break;
default:
ASSERT_CRITICAL(false);
enc10->base.preferred_engine = ENGINE_ID_UNKNOWN;
}
/* default to one to mirror Windows behavior */
enc10->base.features.flags.bits.HDMI_6GB_EN = 1;
if (bp_funcs->get_connector_speed_cap_info)
result = bp_funcs->get_connector_speed_cap_info(enc10->base.ctx->dc_bios,
enc10->base.connector, &bp_cap_info);
/* Override features with DCE-specific values */
if (result == BP_RESULT_OK) {
enc10->base.features.flags.bits.IS_HBR2_CAPABLE =
bp_cap_info.DP_HBR2_EN;
enc10->base.features.flags.bits.IS_HBR3_CAPABLE =
bp_cap_info.DP_HBR3_EN;
enc10->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
enc10->base.features.flags.bits.IS_DP2_CAPABLE = 1;
enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN;
enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN;
enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN;
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE =
bp_cap_info.FRL_8G_EN || bp_cap_info.FRL_10G_EN || bp_cap_info.FRL_12G_EN ||
bp_cap_info.FRL_16G_EN || bp_cap_info.FRL_20G_EN || bp_cap_info.FRL_24G_EN;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = bp_cap_info.FRL_8G_EN;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = bp_cap_info.FRL_10G_EN;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = bp_cap_info.FRL_12G_EN;
enc10->base.features.flags.bits.IS_FRL_16G_CAPABLE = bp_cap_info.FRL_16G_EN;
enc10->base.features.flags.bits.IS_FRL_20G_CAPABLE = bp_cap_info.FRL_20G_EN;
enc10->base.features.flags.bits.IS_FRL_24G_CAPABLE = bp_cap_info.FRL_24G_EN;
enc10->base.txffe_state = 0;
} else {
DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
__func__,
result);
}
if (enc10->base.ctx->dc->debug.hdmi20_disable) {
enc10->base.features.flags.bits.HDMI_6GB_EN = 0;
}
if (enc10->base.ctx->dc->config.force_hdmi21_frl_enc_enable) {
enc10->base.features.flags.bits.IS_HDMI_FRL_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_8G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_10G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_12G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_16G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_20G_CAPABLE = 1;
enc10->base.features.flags.bits.IS_FRL_24G_CAPABLE = 0;
}
}

View File

@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DC_LINK_ENCODER__DCN60_H__
#define __DC_LINK_ENCODER__DCN60_H__
#include "dcn30/dcn30_dio_link_encoder.h"
#define LINK_ENCODER_MASK_SH_LIST_DCN60(mask_sh) \
LE_SF(DIG0_HDCP_I2C_CONTROL_0, HDCP_I2C_DISABLE, mask_sh),\
LE_SF(DIG0_HDCP_I2C_CONTROL_0, HDCP_I2C_DDC_SELECT, mask_sh),\
LE_SF(DIG0_HDCP_INT_CONTROL, HDCP_I2C_XFER_REQ_MASK, mask_sh),\
LE_SF(HPD0_DC_HPD_INT_STATUS, DC_HPD_SENSE, mask_sh),\
LE_SF(HPD0_DC_HPD_TOGGLE_FILT_CNTL, DC_HPD_CONNECT_INT_DELAY, mask_sh),\
LE_SF(HPD0_DC_HPD_TOGGLE_FILT_CNTL, DC_HPD_DISCONNECT_INT_DELAY, mask_sh),\
LE_SF(DC_GPIO_DDC1_MASK, AUX_PAD1_MODE, mask_sh),\
SF(HPD_CTRL, HPD1_Y_POL_INVERT, mask_sh),\
SF(HPD_CTRL, HPD2_Y_POL_INVERT, mask_sh),\
SF(HPD_CTRL, HPD3_Y_POL_INVERT, mask_sh),\
SF(HPD_CTRL, HPD4_Y_POL_INVERT, mask_sh)
void dcn60_link_encoder_construct(
struct dcn20_link_encoder *enc20,
const struct encoder_init_data *init_data,
const struct encoder_feature_support *enc_features,
const struct dcn10_link_enc_registers *link_regs,
const struct dcn10_link_enc_aux_registers *aux_regs,
const struct dcn10_link_enc_hpd_registers *hpd_regs,
const struct dcn10_link_enc_shift *link_shift,
const struct dcn10_link_enc_mask *link_mask);
void dpcs60_program_eq_setting(
struct link_encoder *enc,
uint8_t FFE_Level,
bool de_emphasis_only,
bool pre_shoot_only,
bool no_ffe,
const struct dc_hdmi_frl_link_settings *link_settings);
void enc60_hw_init(struct link_encoder *enc);
#endif /* __DC_LINK_ENCODER__DCN60_H__ */

View File

@@ -0,0 +1,538 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dc_bios_types.h"
#include "dcn30/dcn30_dio_stream_encoder.h"
#include "dcn32/dcn32_dio_stream_encoder.h"
#include "dcn35/dcn35_dio_stream_encoder.h"
#include "dcn401/dcn401_dio_stream_encoder.h"
#include "dcn60_dio_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
#include "link_service.h"
#include "dpcd_defs.h"
#define DC_LOGGER \
enc1->base.ctx->logger
#define REG(reg)\
(enc1->regs->reg)
#undef FN
#define FN(reg_name, field_name) \
(uint8_t)enc1->se_shift->field_name, enc1->se_mask->field_name
#define VBI_LINE_0 0
#define HDMI_CLOCK_CHANNEL_RATE_MORE_340M 340000
#define CTX \
enc1->base.ctx
static void enc60_dp_set_odm_combine(
struct stream_encoder *enc,
bool odm_combine)
{
(void)enc;
(void)odm_combine;
}
/* setup stream encoder in hdmi mode */
static void enc60_stream_encoder_hdmi_set_stream_attribute(
struct stream_encoder *enc,
struct dc_crtc_timing *crtc_timing,
int actual_pix_clk_khz,
bool enable_audio)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
if (!enc->ctx->dc->debug.avoid_vbios_exec_table) {
struct bp_encoder_control cntl = {0};
cntl.action = ENCODER_CONTROL_SETUP;
cntl.engine_id = enc1->base.id;
cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
cntl.enable_dp_audio = enable_audio;
cntl.pixel_clock = actual_pix_clk_khz;
cntl.lanes_number = LANE_COUNT_FOUR;
if (enc1->base.bp->funcs->encoder_control(
enc1->base.bp, &cntl) != BP_RESULT_OK)
return;
} else {
//Set pattern for clock channel, default vlue 0x63 does not work
REG_UPDATE(DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, 0x1F);
//DIG_BE_TMDS_HDMI_MODE : TMDS-HDMI mode is already set in link_encoder_setup
//DIG_SOURCE_SELECT is already set in dig_connect_to_otg
/* DIG_START is removed from the register spec */
}
/* Configure pixel encoding */
enc401_stream_encoder_set_stream_attribute_helper(enc1, crtc_timing);
/* setup HDMI engine */
REG_UPDATE_4(HDMI_CONTROL,
HDMI_DEEP_COLOR_ENABLE, 0,
HDMI_DATA_SCRAMBLE_EN, 0,
HDMI_NO_EXTRA_NULL_PACKET_FILLED, 1,
HDMI_CLOCK_CHANNEL_RATE, 0);
/* Configure color depth */
switch (crtc_timing->display_color_depth) {
case COLOR_DEPTH_888:
REG_UPDATE(HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, 0);
break;
case COLOR_DEPTH_101010:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
case COLOR_DEPTH_121212:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
case COLOR_DEPTH_161616:
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DEEP_COLOR_DEPTH, 3,
HDMI_DEEP_COLOR_ENABLE, 1);
break;
default:
break;
}
if (actual_pix_clk_khz >= HDMI_CLOCK_CHANNEL_RATE_MORE_340M) {
/* enable HDMI data scrambler
* HDMI_CLOCK_CHANNEL_RATE_MORE_340M
* Clock channel frequency is 1/4 of character rate.
*/
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DATA_SCRAMBLE_EN, 1,
HDMI_CLOCK_CHANNEL_RATE, 1);
} else if (crtc_timing->flags.LTE_340MCSC_SCRAMBLE) {
/* TODO: New feature for DCE11, still need to implement */
/* enable HDMI data scrambler
* HDMI_CLOCK_CHANNEL_FREQ_EQUAL_TO_CHAR_RATE
* Clock channel frequency is the same
* as character rate
*/
REG_UPDATE_2(HDMI_CONTROL,
HDMI_DATA_SCRAMBLE_EN, 1,
HDMI_CLOCK_CHANNEL_RATE, 0);
}
/* Enable transmission of General Control packet on every frame */
REG_UPDATE_3(HDMI_VBI_PACKET_CONTROL,
HDMI_GC_CONT, 1,
HDMI_GC_SEND, 1,
HDMI_NULL_SEND, 1);
/* Disable Audio Content Protection packet transmission */
REG_UPDATE(HDMI_VBI_PACKET_CONTROL, HDMI_ACP_SEND, 0);
/* following belongs to audio */
/* Enable Audio InfoFrame packet transmission. */
REG_UPDATE(HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, 1);
/* update double-buffered AUDIO_INFO registers immediately */
// ASSERT(enc->afmt);
// enc->afmt->funcs->audio_info_immediate_update(enc->afmt);
/* Select line number on which to send Audio InfoFrame packets */
REG_UPDATE(HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_LINE,
VBI_LINE_0 + 2);
/* set HDMI GC AVMUTE */
REG_UPDATE(HDMI_GC, HDMI_GC_AVMUTE, 0);
}
static void enc60_stream_encoder_update_hdmi_info_packets(
struct stream_encoder *enc,
const struct encoder_info_frame *info_frame)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
/* for bring up, disable dp double TODO */
REG_UPDATE(HDMI_DB_CONTROL, HDMI_DB_DISABLE, 1);
REG_UPDATE(DIG_FE_AUDIO_CNTL, APG_CLOCK_ENABLE, 1);
/*Always add mandatory packets first followed by optional ones*/
enc3_update_hdmi_info_packet(enc1, 0, &info_frame->avi);
enc3_update_hdmi_info_packet(enc1, 5, &info_frame->hfvsif);
enc3_update_hdmi_info_packet(enc1, 2, &info_frame->gamut);
enc3_update_hdmi_info_packet(enc1, 1, &info_frame->vendor);
enc3_update_hdmi_info_packet(enc1, 3, &info_frame->spd);
enc3_update_hdmi_info_packet(enc1, 4, &info_frame->hdrsmd);
enc3_update_hdmi_info_packet(enc1, 6, &info_frame->vtem);
}
static void enc60_se_enable_audio_clock(
struct stream_encoder *enc,
bool enable)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
REG_UPDATE(DIG_FE_AUDIO_CNTL, APG_CLOCK_ENABLE, enable);
}
static void enc60_se_setup_hdmi_audio(
struct stream_encoder *enc,
const struct audio_crtc_info *crtc_info)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
struct audio_clock_info audio_clock_info = {0};
/* HDMI_AUDIO_PACKET_CONTROL */
REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
HDMI_AUDIO_DELAY_EN, 1);
/* HDMI_ACR_PACKET_CONTROL */
REG_UPDATE_2(HDMI_ACR_PACKET_CONTROL,
HDMI_ACR_AUTO_SEND, 1,
HDMI_ACR_SOURCE, 0);
/* Program audio clock sample/regeneration parameters */
get_audio_clock_info(crtc_info->color_depth,
crtc_info->requested_pixel_clock_100Hz,
crtc_info->calculated_pixel_clock_100Hz,
&audio_clock_info);
DC_LOG_HW_AUDIO(
"\n%s:Input::requested_pixel_clock_100Hz = %d" \
"calculated_pixel_clock_100Hz = %d \n", __func__, \
crtc_info->requested_pixel_clock_100Hz, \
crtc_info->calculated_pixel_clock_100Hz);
/* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
REG_UPDATE(HDMI_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
/* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
REG_UPDATE(HDMI_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
/* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
REG_UPDATE(HDMI_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
/* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
REG_UPDATE(HDMI_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
/* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
REG_UPDATE(HDMI_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
/* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
REG_UPDATE(HDMI_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
/* Video driver cannot know in advance which sample rate will
* be used by HD Audio driver
* HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
* programmed below in interruppt callback
*/
}
static void enc60_se_hdmi_audio_setup(
struct stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
enc60_se_enable_audio_clock(enc, true);
enc60_se_setup_hdmi_audio(enc, audio_crtc_info);
REG_UPDATE(DIG_FE_AUDIO_CNTL,
DIG_FE_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst);
ASSERT (enc->apg);
enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
}
static void enc60_se_hdmi_audio_disable(
struct stream_encoder *enc)
{
ASSERT (enc->apg);
if (enc->apg && enc->apg->funcs->disable_apg)
enc->apg->funcs->disable_apg(enc->apg);
enc60_se_enable_audio_clock(enc, false);
}
static void enc60_stream_encoder_stop_dp_info_packets(
struct stream_encoder *enc)
{
/* stop generic packets on DP */
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
uint32_t value = 0;
REG_SET_9(DP_SEC_CNTL, 0,
DP_SEC_GSP0_ENABLE, 0,
DP_SEC_GSP1_ENABLE, 0,
DP_SEC_GSP2_ENABLE, 0,
DP_SEC_GSP3_ENABLE, 0,
DP_SEC_GSP4_ENABLE, 0,
DP_SEC_GSP5_ENABLE, 0,
DP_SEC_GSP6_ENABLE, 0,
DP_SEC_GSP7_ENABLE, 0,
DP_SEC_STREAM_ENABLE, 0);
/* this register shared with audio info frame.
* therefore we need to keep master enabled
* if at least one of the fields is not 0 */
value = REG_READ(DP_SEC_CNTL);
if (value)
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
}
#define DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT 0x8000
#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC 1
static void enc60_se_setup_dp_audio(
struct stream_encoder *enc)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
/* --- DP Audio packet configurations --- */
/* ATP Configuration */
REG_SET(DP_SEC_AUD_N, 0,
DP_SEC_AUD_N, DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT);
/* Async/auto-calc timestamp mode */
REG_SET(DP_SEC_TIMESTAMP, 0, DP_SEC_TIMESTAMP_MODE,
DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC);
}
static void enc60_se_dp_audio_enable(
struct stream_encoder *enc)
{
enc60_se_enable_audio_clock(enc, true);
enc60_se_setup_dp_audio(enc);
enc1_se_enable_dp_audio(enc);
/* Enable APG block */
enc->apg->funcs->enable_apg(enc->apg);
}
static void enc60_se_disable_dp_audio(
struct stream_encoder *enc)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
uint32_t value = 0;
/* Disable Audio packets */
REG_UPDATE_5(DP_SEC_CNTL,
DP_SEC_ASP_ENABLE, 0,
DP_SEC_ATP_ENABLE, 0,
DP_SEC_AIP_ENABLE, 0,
DP_SEC_ACM_ENABLE, 0,
DP_SEC_STREAM_ENABLE, 0);
/* This register shared with encoder info frame. Therefore we need to
* keep master enabled if at least on of the fields is not 0
*/
value = REG_READ(DP_SEC_CNTL);
if (value != 0)
REG_UPDATE(DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, 1);
}
static void enc60_se_dp_audio_disable(
struct stream_encoder *enc)
{
enc60_se_disable_dp_audio(enc);
/* Disable APG block */
enc->apg->funcs->disable_apg(enc->apg);
enc60_se_enable_audio_clock(enc, false);
}
static void enc60_audio_mute_control(
struct stream_encoder *enc,
bool mute)
{
ASSERT (enc->apg);
if (mute)
enc->apg->funcs->disable_apg(enc->apg);
else
enc->apg->funcs->enable_apg(enc->apg);
}
static void enc60_se_dp_audio_setup(
struct stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
enc60_se_enable_audio_clock(enc, true);
/*ACR setup*/
REG_UPDATE(DIG_FE_AUDIO_CNTL,
DIG_FE_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst);
ASSERT(enc->apg);
enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
}
static void enc60_dp_set_dsc_pps_info_packet(struct stream_encoder *enc,
bool enable,
uint8_t *dsc_packed_pps,
bool immediate_update)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
if (enable) {
struct dc_info_packet pps_sdp;
int i;
/* Configure for PPS packet size (128 bytes) */
REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP11_PPS, 1);
/* Load PPS into infoframe (SDP) registers */
pps_sdp.valid = true;
pps_sdp.hb0 = 0;
pps_sdp.hb1 = DC_DP_INFOFRAME_TYPE_PPS;
pps_sdp.hb2 = 127;
pps_sdp.hb3 = 0;
for (i = 0; i < 4; i++) {
memcpy(pps_sdp.sb, &dsc_packed_pps[i * 32], 32);
enc1->base.vpg->funcs->update_generic_info_packet(
enc1->base.vpg,
11 + i,
&pps_sdp,
immediate_update);
}
/* SW should make sure VBID[6] update line number is bigger
* than PPS transmit line number
*/
REG_UPDATE(DP_GSP11_CNTL,
DP_SEC_GSP11_LINE_NUM, 2);
REG_UPDATE_2(DP_MSA_VBID_MISC,
DP_VBID6_LINE_REFERENCE, 0,
DP_VBID6_LINE_NUM, 3);
/* Send PPS data at the line number specified above.
* DP spec requires PPS to be sent only when it changes, however since
* decoder has to be able to handle its change on every frame, we're
* sending it always (i.e. on every frame) to reduce the chance it'd be
* missed by decoder. If it turns out required to send PPS only when it
* changes, we can use DP_SEC_GSP11_SEND register.
*/
REG_UPDATE(DP_GSP11_CNTL,
DP_SEC_GSP11_ENABLE, 1);
REG_UPDATE(DP_SEC_CNTL,
DP_SEC_STREAM_ENABLE, 1);
} else {
/* Disable Generic Stream Packet 11 (GSP) transmission */
REG_UPDATE(DP_GSP11_CNTL, DP_SEC_GSP11_ENABLE, 0);
REG_UPDATE(DP_SEC_CNTL2, DP_SEC_GSP11_PPS, 0);
}
}
static void enc60_reset_hdmi_stream_attribute(
struct stream_encoder *enc)
{
struct dcn10_stream_encoder *enc1 = DCN10STRENC_FROM_STRENC(enc);
REG_UPDATE_3(HDMI_CONTROL,
HDMI_DEEP_COLOR_ENABLE, 0,
HDMI_DATA_SCRAMBLE_EN, 0,
HDMI_CLOCK_CHANNEL_RATE, 0);
}
static const struct stream_encoder_funcs dcn60_str_enc_funcs = {
.dp_set_odm_combine =
enc60_dp_set_odm_combine,
.dp_set_stream_attribute =
enc401_stream_encoder_dp_set_stream_attribute,
.hdmi_set_stream_attribute =
enc60_stream_encoder_hdmi_set_stream_attribute,
.dvi_set_stream_attribute =
enc401_stream_encoder_dvi_set_stream_attribute,
.set_throttled_vcp_size =
enc1_stream_encoder_set_throttled_vcp_size,
.update_hdmi_info_packets =
enc60_stream_encoder_update_hdmi_info_packets,
.stop_hdmi_info_packets =
enc3_stream_encoder_stop_hdmi_info_packets,
.update_dp_info_packets_sdp_line_num =
enc3_stream_encoder_update_dp_info_packets_sdp_line_num,
.update_dp_info_packets =
enc3_stream_encoder_update_dp_info_packets,
.stop_dp_info_packets =
enc60_stream_encoder_stop_dp_info_packets,
.dp_blank =
enc1_stream_encoder_dp_blank,
.dp_unblank =
enc401_stream_encoder_dp_unblank,
.audio_mute_control = enc60_audio_mute_control,
.dp_audio_setup = enc60_se_dp_audio_setup,
.dp_audio_enable = enc60_se_dp_audio_enable,
.dp_audio_disable = enc60_se_dp_audio_disable,
.hdmi_audio_setup = enc60_se_hdmi_audio_setup,
.hdmi_audio_disable = enc60_se_hdmi_audio_disable,
.setup_stereo_sync = enc1_setup_stereo_sync,
.set_avmute = enc1_stream_encoder_set_avmute,
.dig_connect_to_otg = enc1_dig_connect_to_otg,
.dig_source_otg = enc1_dig_source_otg,
.dp_get_pixel_format = enc1_stream_encoder_dp_get_pixel_format,
.enc_read_state = enc401_read_state,
.dp_set_dsc_config = NULL,
.dp_set_dsc_pps_info_packet = enc60_dp_set_dsc_pps_info_packet,
.set_dynamic_metadata = enc401_set_dynamic_metadata,
.hdmi_reset_stream_attribute = enc60_reset_hdmi_stream_attribute,
.enable_stream = enc401_stream_encoder_enable,
.set_input_mode = enc401_set_dig_input_mode,
.enable_fifo = enc35_enable_fifo,
.disable_fifo = enc35_disable_fifo,
.map_stream_to_link = enc401_stream_encoder_map_to_link,
};
void dcn60_dio_stream_encoder_construct(
struct dcn10_stream_encoder *enc1,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct apg *apg,
const struct dcn10_stream_enc_registers *regs,
const struct dcn10_stream_encoder_shift *se_shift,
const struct dcn10_stream_encoder_mask *se_mask)
{
enc1->base.funcs = &dcn60_str_enc_funcs;
enc1->base.ctx = ctx;
enc1->base.id = eng_id;
enc1->base.bp = bp;
enc1->base.vpg = vpg;
enc1->base.apg = apg;
enc1->regs = regs;
enc1->se_shift = se_shift;
enc1->se_mask = se_mask;
enc1->base.stream_enc_inst = vpg->inst;
}

View File

@@ -0,0 +1,181 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DC_DIO_STREAM_ENCODER_DCN60_H__
#define __DC_DIO_STREAM_ENCODER_DCN60_H__
#include "dcn30/dcn30_vpg.h"
#include "dcn30/dcn30_afmt.h"
#include "dcn31/dcn31_apg.h"
#include "stream_encoder.h"
#include "dcn20/dcn20_stream_encoder.h"
#define SE_COMMON_MASK_SH_LIST_DCN60(mask_sh)\
SE_SF(DP0_DP_PIXEL_FORMAT, PIXEL_ENCODING_TYPE, mask_sh),\
SE_SF(DP0_DP_PIXEL_FORMAT, UNCOMPRESSED_PIXEL_FORMAT, mask_sh),\
SE_SF(DP0_DP_PIXEL_FORMAT, UNCOMPRESSED_COMPONENT_DEPTH, mask_sh),\
SE_SF(DP0_DP_PIXEL_FORMAT, COMPRESSED_PIXEL_FORMAT, mask_sh),\
SE_SF(DIG0_HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE, mask_sh),\
SE_SF(DIG0_HDMI_CONTROL, HDMI_DEEP_COLOR_DEPTH, mask_sh),\
SE_SF(DIG0_HDMI_CONTROL, HDMI_DATA_SCRAMBLE_EN, mask_sh),\
SE_SF(DIG0_HDMI_CONTROL, HDMI_NO_EXTRA_NULL_PACKET_FILLED, mask_sh),\
SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT, mask_sh),\
SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_GC_SEND, mask_sh),\
SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND, mask_sh),\
SE_SF(DIG0_HDMI_VBI_PACKET_CONTROL, HDMI_ACP_SEND, mask_sh),\
SE_SF(DIG0_HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_SEND, mask_sh),\
SE_SF(DIG0_HDMI_INFOFRAME_CONTROL0, HDMI_AUDIO_INFO_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GC, HDMI_GC_AVMUTE, mask_sh),\
SE_SF(DP0_DP_MSE_RATE_CNTL, DP_MSE_RATE_X, mask_sh),\
SE_SF(DP0_DP_MSE_RATE_CNTL, DP_MSE_RATE_Y, mask_sh),\
SE_SF(DP0_DP_MSE_RATE_UPDATE, DP_MSE_RATE_UPDATE_PENDING, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP0_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_STREAM_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP1_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP2_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP3_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL1, DP_SEC_GSP5_LINE_REFERENCE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND_PENDING, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL4, DP_SEC_GSP4_LINE_NUM, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL5, DP_SEC_GSP5_LINE_NUM, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP4_SEND_ANY_LINE, mask_sh),\
SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_DIS_DEFER, mask_sh),\
SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE, mask_sh),\
SE_SF(DP0_DP_VID_STREAM_CNTL, DP_VID_STREAM_STATUS, mask_sh),\
SE_SF(DP0_DP_STEER_FIFO, DP_STEER_FIFO_RESET, mask_sh),\
SE_SF(DP0_DP_STEER_FIFO, DP_STEER_FIFO_ENABLE, mask_sh),\
SE_SF(DP0_DP_VID_TIMING, DP_VID_M_N_GEN_EN, mask_sh),\
SE_SF(DP0_DP_VID_N, DP_VID_N, mask_sh),\
SE_SF(DP0_DP_VID_M, DP_VID_M, mask_sh),\
SE_SF(DIG0_HDMI_AUDIO_PACKET_CONTROL, HDMI_AUDIO_DELAY_EN, mask_sh),\
SE_SF(DIG0_HDMI_ACR_PACKET_CONTROL, HDMI_ACR_AUTO_SEND, mask_sh),\
SE_SF(DIG0_HDMI_ACR_PACKET_CONTROL, HDMI_ACR_SOURCE, mask_sh),\
SE_SF(DIG0_HDMI_ACR_32_0, HDMI_ACR_CTS_32, mask_sh),\
SE_SF(DIG0_HDMI_ACR_32_1, HDMI_ACR_N_32, mask_sh),\
SE_SF(DIG0_HDMI_ACR_44_0, HDMI_ACR_CTS_44, mask_sh),\
SE_SF(DIG0_HDMI_ACR_44_1, HDMI_ACR_N_44, mask_sh),\
SE_SF(DIG0_HDMI_ACR_48_0, HDMI_ACR_CTS_48, mask_sh),\
SE_SF(DIG0_HDMI_ACR_48_1, HDMI_ACR_N_48, mask_sh),\
SE_SF(DP0_DP_SEC_AUD_N, DP_SEC_AUD_N, mask_sh),\
SE_SF(DP0_DP_SEC_TIMESTAMP, DP_SEC_TIMESTAMP_MODE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ASP_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ATP_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_AIP_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ACM_ENABLE, mask_sh),\
SE_SF(DIG0_HDMI_CONTROL, HDMI_CLOCK_CHANNEL_RATE, mask_sh),\
SE_SF(DIG1_HDMI_CONTROL, TMDS_PIXEL_ENCODING, mask_sh),\
SE_SF(DIG1_HDMI_CONTROL, TMDS_COLOR_FORMAT, mask_sh),\
SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_SELECT, mask_sh),\
SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP4_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP5_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP6_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_GSP7_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP7_SEND, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL6, DP_SEC_GSP7_LINE_NUM, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL2, DP_SEC_GSP11_PPS, mask_sh),\
SE_SF(DP0_DP_GSP11_CNTL, DP_SEC_GSP11_ENABLE, mask_sh),\
SE_SF(DP0_DP_GSP11_CNTL, DP_SEC_GSP11_LINE_NUM, mask_sh),\
SE_SF(DP0_DP_DB_CNTL, DP_DB_DISABLE, mask_sh),\
SE_SF(DP0_DP_MSA_COLORIMETRY, DP_MSA_MISC0, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM1, DP_MSA_HTOTAL, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM1, DP_MSA_VTOTAL, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM2, DP_MSA_HSTART, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM2, DP_MSA_VSTART, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM3, DP_MSA_HSYNCWIDTH, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM3, DP_MSA_HSYNCPOLARITY, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM3, DP_MSA_VSYNCWIDTH, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM3, DP_MSA_VSYNCPOLARITY, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_HWIDTH, mask_sh),\
SE_SF(DP0_DP_MSA_TIMING_PARAM4, DP_MSA_VHEIGHT, mask_sh),\
SE_SF(DIG0_HDMI_DB_CONTROL, HDMI_DB_DISABLE, mask_sh),\
SE_SF(DP0_DP_VID_TIMING, DP_VID_N_INTERVAL, mask_sh),\
SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh), \
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC0_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC1_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC2_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC3_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC4_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC5_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC6_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL0, HDMI_GENERIC7_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC8_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC8_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC9_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC9_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC10_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC10_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC11_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC11_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC12_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC12_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC13_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC13_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC14_CONT, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL6, HDMI_GENERIC14_SEND, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL1, HDMI_GENERIC0_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL1, HDMI_GENERIC1_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL2, HDMI_GENERIC2_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL2, HDMI_GENERIC3_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL3, HDMI_GENERIC4_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL3, HDMI_GENERIC5_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL4, HDMI_GENERIC6_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL4, HDMI_GENERIC7_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL7, HDMI_GENERIC8_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL7, HDMI_GENERIC9_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL8, HDMI_GENERIC10_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL8, HDMI_GENERIC11_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL9, HDMI_GENERIC12_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL9, HDMI_GENERIC13_LINE, mask_sh),\
SE_SF(DIG0_HDMI_GENERIC_PACKET_CONTROL10, HDMI_GENERIC14_LINE, mask_sh),\
SE_SF(DP0_DP_MSA_VBID_MISC, DP_VBID6_LINE_REFERENCE, mask_sh),\
SE_SF(DP0_DP_MSA_VBID_MISC, DP_VBID6_LINE_NUM, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_ENGINE_EN, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_HUBP_REQUESTOR_ID, mask_sh),\
SE_SF(DME0_DME_CONTROL, METADATA_STREAM_TYPE, mask_sh),\
SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_LINE_REFERENCE, mask_sh),\
SE_SF(DP0_DP_SEC_METADATA_TRANSMISSION, DP_SEC_METADATA_PACKET_LINE, mask_sh),\
SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_ENABLE, mask_sh),\
SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE_REFERENCE, mask_sh),\
SE_SF(DIG0_HDMI_METADATA_PACKET_CONTROL, HDMI_METADATA_PACKET_LINE, mask_sh),\
SE_SF(DIG0_HDMI_CONTROL, DOLBY_VISION_EN, mask_sh),\
SE_SF(DIG0_DIG_FE_EN_CNTL, DIG_FE_ENABLE, mask_sh),\
SE_SF(DIG0_DIG_FE_CLK_CNTL, DIG_FE_MODE, mask_sh),\
SE_SF(DIG0_DIG_FE_CLK_CNTL, DIG_FE_CLK_EN, mask_sh),\
SE_SF(DIG0_DIG_FE_CLK_CNTL, DIG_FE_SOFT_RESET, mask_sh),\
SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\
SE_SF(DP0_DP_SEC_FRAMING4, DP_SST_SDP_SPLITTING, mask_sh),\
SE_SF(DIG0_DIG_CLOCK_PATTERN, DIG_CLOCK_PATTERN, mask_sh),\
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_OUTPUT_PIXEL_PER_CYCLE, mask_sh),\
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_READ_START_LEVEL, mask_sh),\
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_ENABLE, mask_sh),\
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_RESET, mask_sh),\
SE_SF(DIG0_DIG_FIFO_CTRL0, DIG_FIFO_RESET_DONE, mask_sh),\
SE_SF(DIG0_STREAM_MAPPER_CONTROL, DIG_STREAM_LINK_TARGET, mask_sh),\
SE_SF(DIG0_DIG_FE_AUDIO_CNTL, DIG_FE_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, mask_sh),\
SE_SF(DIG0_DIG_FE_AUDIO_CNTL, APG_CLOCK_ENABLE, mask_sh),
void dcn60_dio_stream_encoder_construct(
struct dcn10_stream_encoder *enc1,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct apg *apg,
const struct dcn10_stream_enc_registers *regs,
const struct dcn10_stream_encoder_shift *se_shift,
const struct dcn10_stream_encoder_mask *se_mask);
#endif /* __DC_DIO_STREAM_ENCODER_DCN60_H__ */

View File

@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DCN5_SOC_BB_H__
#define __DCN5_SOC_BB_H__
#include "dml2_external_lib_deps.h"
#include "utm_qos_model_dchub_v1.h"
#include "dml_top_soc_parameter_types.h"
static inline void dcn5_initialize_soc_bb(struct dml2_soc_bb *soc_bb)
{
memset(soc_bb, 0, sizeof(struct dml2_soc_bb));
}
static inline void dcn5_initialize_ip_caps(struct dml2_ip_capabilities *ip_caps)
{
memset(ip_caps, 0, sizeof(struct dml2_ip_capabilities));
}
static inline void dcn5_initialize_utm_qos_model(struct utm_qos_model *qos_model, struct utm_qos_model_dchub_v1 *dchub)
{
memset(qos_model, 0, sizeof(struct utm_qos_model));
memset(dchub, 0, sizeof(struct utm_qos_model_dchub_v1));
qos_model->dchub_v1 = dchub;
}
static inline void dcn5or_initialize_utm_qos_model(struct utm_qos_model *qos_model, struct utm_qos_model_dchub_v1 *dchub)
{
memset(qos_model, 0, sizeof(struct utm_qos_model));
memset(dchub, 0, sizeof(struct utm_qos_model_dchub_v1));
qos_model->dchub_v1 = dchub;
}
#endif /* __DCN5_SOC_BB_H__ */

View File

@@ -0,0 +1,229 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DCN6_SOC_BB_H__
#define __DCN6_SOC_BB_H__
#include "dml2_external_lib_deps.h"
#include "utm_qos_model_dchub_v2.h"
#include "utm_qos_model_dchub_v3.h"
#include "dml_top_soc_parameter_types.h"
static inline void dcn6_test_initialize_soc_bb(struct dml2_soc_bb *soc_bb)
{
memset(soc_bb, 0, sizeof(struct dml2_soc_bb));
}
static inline void dcn6b_test_initialize_soc_bb(struct dml2_soc_bb *soc_bb)
{
dcn6_test_initialize_soc_bb(soc_bb);
}
static inline void dcn6_test_initialize_ip_caps(struct dml2_ip_capabilities *ip_caps)
{
memset(ip_caps, 0, sizeof(struct dml2_ip_capabilities));
}
static inline void dcn6_initialize_utm_qos_model_with_fixed_allocation(struct utm_qos_model *qos_model, struct utm_qos_model_dchub_v2 *dchub)
{
memset(qos_model, 0, sizeof(struct utm_qos_model));
memset(dchub, 0, sizeof(struct utm_qos_model_dchub_v2));
qos_model->dchub_v2 = dchub;
}
static inline void dcn6_test_initialize_utm_qos_model(struct utm_qos_model *qos_model, struct utm_qos_model_dchub_v2 *dchub)
{
}
static inline void dcn6b_test_initialize_utm_qos_model(struct utm_qos_model *qos_model, struct utm_qos_model_dchub_v2 *dchub)
{
dcn6_initialize_utm_qos_model_with_fixed_allocation(qos_model, dchub);
}
static inline void dcn6_n_minus_1_initialize_utm_qos_model(
struct utm_qos_model *qos_model, struct utm_qos_model_dchub_v2 *dchub)
{
memset(qos_model, 0, sizeof(struct utm_qos_model));
memset(dchub, 0, sizeof(struct utm_qos_model_dchub_v2));
qos_model->dchub_v2 = dchub;
qos_model->sops[0].fclk_khz = 300000;
qos_model->sops[0].uclk_khz = 97000;
qos_model->sops[1].fclk_khz = 503684;
qos_model->sops[1].uclk_khz = 435000;
qos_model->sops[2].fclk_khz = 1007368;
qos_model->sops[2].uclk_khz = 521000;
qos_model->sops[3].fclk_khz = 1206526;
qos_model->sops[3].uclk_khz = 731000;
qos_model->sops[4].fclk_khz = 1250000;
qos_model->sops[4].uclk_khz = 822000;
qos_model->sops[5].fclk_khz = 1250000;
qos_model->sops[5].uclk_khz = 962000;
qos_model->sops[6].fclk_khz = 1250000;
qos_model->sops[6].uclk_khz = 1069000;
qos_model->sops[7].fclk_khz = 1250000;
qos_model->sops[7].uclk_khz = 1187000;
qos_model->socbb.fabric_datapath_to_dcn_data_return_bytes = 64;
qos_model->socbb.dram_channel_width_bytes = 2;
qos_model->socbb.dram_channel_count = 16;
qos_model->socbb.dram_transactions_per_clock = 16;
qos_model->socbb.fabric_derate_percent_nominal = 57;
qos_model->socbb.fabric_derate_percent_urgent = 75;
qos_model->socbb.dram_derate_percent_nominal = 17;
qos_model->socbb.dram_derate_percent_urgent = 22;
qos_model->sop_count = 8;
dchub->latencies[0].urgent_ramp_ps = 9865636;
dchub->latencies[0].t_trip_ps = 12650172;
dchub->latencies[0].meta_trip_to_mem_ps = 11227505;
dchub->latencies[0].max_req_latency_urg_ps = 2531615;
dchub->latencies[0].avg_req_latency_urg_ps = 1772436;
dchub->latencies[0].max_req_latency_non_urg_ps = 12650171;
dchub->latencies[0].avg_req_latency_non_urg_ps = 2548107;
dchub->latencies[0].df_response_time_ps = 1000000;
dchub->latencies[1].urgent_ramp_ps = 3411495;
dchub->latencies[1].t_trip_ps = 3467378;
dchub->latencies[1].meta_trip_to_mem_ps = 2620137;
dchub->latencies[1].max_req_latency_urg_ps = 1369447;
dchub->latencies[1].avg_req_latency_urg_ps = 834368;
dchub->latencies[1].max_req_latency_non_urg_ps = 3468646;
dchub->latencies[1].avg_req_latency_non_urg_ps = 970920;
dchub->latencies[1].df_response_time_ps = 595611;
dchub->latencies[2].urgent_ramp_ps = 2388169;
dchub->latencies[2].t_trip_ps = 2594969;
dchub->latencies[2].meta_trip_to_mem_ps = 2171306;
dchub->latencies[2].max_req_latency_urg_ps = 875775;
dchub->latencies[2].avg_req_latency_urg_ps = 526390;
dchub->latencies[2].max_req_latency_non_urg_ps = 2595139;
dchub->latencies[2].avg_req_latency_non_urg_ps = 630268;
dchub->latencies[2].df_response_time_ps = 297805;
dchub->latencies[3].urgent_ramp_ps = 1896062;
dchub->latencies[3].t_trip_ps = 1934965;
dchub->latencies[3].meta_trip_to_mem_ps = 1581238;
dchub->latencies[3].max_req_latency_urg_ps = 768344;
dchub->latencies[3].avg_req_latency_urg_ps = 445581;
dchub->latencies[3].max_req_latency_non_urg_ps = 1935135;
dchub->latencies[3].avg_req_latency_non_urg_ps = 506977;
dchub->latencies[3].df_response_time_ps = 248647;
dchub->latencies[4].urgent_ramp_ps = 1769285;
dchub->latencies[4].t_trip_ps = 1769285;
dchub->latencies[4].meta_trip_to_mem_ps = 1416798;
dchub->latencies[4].max_req_latency_urg_ps = 742910;
dchub->latencies[4].avg_req_latency_urg_ps = 425284;
dchub->latencies[4].max_req_latency_non_urg_ps = 1758238;
dchub->latencies[4].avg_req_latency_non_urg_ps = 475065;
dchub->latencies[4].df_response_time_ps = 240000;
dchub->latencies[5].urgent_ramp_ps = 1652902;
dchub->latencies[5].t_trip_ps = 1652902;
dchub->latencies[5].meta_trip_to_mem_ps = 1230505;
dchub->latencies[5].max_req_latency_urg_ps = 734108;
dchub->latencies[5].avg_req_latency_urg_ps = 416888;
dchub->latencies[5].max_req_latency_non_urg_ps = 1571945;
dchub->latencies[5].avg_req_latency_non_urg_ps = 451191;
dchub->latencies[5].df_response_time_ps = 240000;
dchub->latencies[6].urgent_ramp_ps = 1582791;
dchub->latencies[6].t_trip_ps = 1582791;
dchub->latencies[6].meta_trip_to_mem_ps = 1122960;
dchub->latencies[6].max_req_latency_urg_ps = 727450;
dchub->latencies[6].avg_req_latency_urg_ps = 410145;
dchub->latencies[6].max_req_latency_non_urg_ps = 1464400;
dchub->latencies[6].avg_req_latency_non_urg_ps = 436076;
dchub->latencies[6].df_response_time_ps = 240000;
dchub->latencies[7].urgent_ramp_ps = 1520802;
dchub->latencies[7].t_trip_ps = 1520802;
dchub->latencies[7].meta_trip_to_mem_ps = 1022428;
dchub->latencies[7].max_req_latency_urg_ps = 722083;
dchub->latencies[7].avg_req_latency_urg_ps = 404088;
dchub->latencies[7].max_req_latency_non_urg_ps = 1363868;
dchub->latencies[7].avg_req_latency_non_urg_ps = 422992;
dchub->latencies[7].df_response_time_ps = 240000;
/*
* TODO: currently both utm budget percent and derate percent are both included in derate percent params. Need
* to separate them. So we can use the actual utm budget percent values below.
*/
dchub->max_nominal_utm_budget_percent = 100;
dchub->min_nominal_utm_budget_percent = 100;
dchub->max_urgent_utm_budget_percent = 100;
dchub->min_urgent_utm_budget_percent = 100;
}
static inline unsigned int dcn6a_test_initialize_sop_clocks(
struct utm_soc_operating_point *sop_clocks)
{
return 0;
}
static inline unsigned int dcn6b_test_initialize_sop_clocks(
struct utm_soc_operating_point *sop_clocks)
{
return 0;
}
/**
* dcn6_test_initialize_v3_sop_latencies - Set latencies for one SOP entry.
*/
static inline void dcn6_test_initialize_v3_sop_latencies(
struct utm_qos_model_dchub_v3_sop_entry *entry,
uint32_t urgent_ramp_ps, uint32_t t_trip_ps,
uint32_t meta_trip_to_mem_ps,
uint32_t max_urg_ps, uint32_t avg_urg_ps,
uint32_t max_non_urg_ps, uint32_t avg_non_urg_ps,
uint32_t df_response_time_ps)
{
entry->urgent_ramp_ps = urgent_ramp_ps;
entry->t_trip_ps = t_trip_ps;
entry->meta_trip_to_mem_ps = meta_trip_to_mem_ps;
entry->max_req_latency_urg_ps = max_urg_ps;
entry->avg_req_latency_urg_ps = avg_urg_ps;
entry->max_req_latency_non_urg_ps = max_non_urg_ps;
entry->avg_req_latency_non_urg_ps = avg_non_urg_ps;
entry->df_response_time_ps = df_response_time_ps;
}
/**
* dcn6_test_initialize_v3_sop_latencies_all_levels - Set identical latencies
* across all load levels for one SOP index.
*/
static inline void dcn6_test_initialize_v3_sop_latencies_all_levels(
struct utm_qos_model_dchub_v3 *dchub, unsigned int sop_index,
uint32_t urgent_ramp_ps, uint32_t t_trip_ps,
uint32_t meta_trip_to_mem_ps,
uint32_t max_urg_ps, uint32_t avg_urg_ps,
uint32_t max_non_urg_ps, uint32_t avg_non_urg_ps,
uint32_t df_response_time_ps)
{
unsigned int ll;
for (ll = 0; ll < dchub->load_level_count; ll++)
dcn6_test_initialize_v3_sop_latencies(
&dchub->sops[ll][sop_index],
urgent_ramp_ps, t_trip_ps,
meta_trip_to_mem_ps,
max_urg_ps, avg_urg_ps,
max_non_urg_ps, avg_non_urg_ps,
df_response_time_ps);
}
static inline void dcn6_test_initialize_utm_qos_model_v3(
struct utm_qos_model *qos_model,
struct utm_qos_model_dchub_v3 *dchub)
{
memset(dchub, 0, sizeof(struct utm_qos_model_dchub_v3));
memset(qos_model, 0, sizeof(struct utm_qos_model));
qos_model->version = utm_qos_model_version_v3;
qos_model->dchub_v3 = dchub;
}
static inline void dcn6b_test_initialize_utm_qos_model_v3(
struct utm_qos_model *qos_model,
struct utm_qos_model_dchub_v3 *dchub)
{
memset(dchub, 0, sizeof(struct utm_qos_model_dchub_v3));
memset(qos_model, 0, sizeof(struct utm_qos_model));
qos_model->version = utm_qos_model_version_v3;
qos_model->dchub_v3 = dchub;
}
#endif /* __DCN6_SOC_BB_H__ */

View File

@@ -0,0 +1,109 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef UTM_QOS_MODEL_DCHUB_V1_H
#define UTM_QOS_MODEL_DCHUB_V1_H
#include "utm_qos_model_types.h"
struct utm_qos_model_dchub_memory_path_latency_v1 {
uint32_t urgent_ramp_ps;
uint32_t t_trip_ps;
uint32_t meta_trip_to_mem_ps;
uint32_t max_req_latency_urg_ps;
uint32_t avg_req_latency_urg_ps;
uint32_t max_req_latency_non_urg_ps;
uint32_t avg_req_latency_non_urg_ps;
uint32_t df_response_time_ps;
};
struct utm_qos_model_dchub_memory_path_bandwidth_v1 {
uint32_t nominal_bandwidth_KBps;
uint32_t urgent_bandwidth_KBps;
};
struct utm_qos_model_dchub_memory_path_qos_v1 {
struct utm_qos_model_dchub_memory_path_latency_v1 latency_upper_bound;
struct utm_qos_model_dchub_memory_path_bandwidth_v1 bandwidth_lower_bound;
};
struct utm_qos_model_dchub_v1 {
struct utm_qos_model_dchub_memory_path_latency_v1 latencies[MAX_UTM_SOP_COUNT];
struct utm_qos_model_dchub_memory_path_bandwidth_v1 bandwidths[MAX_UTM_SOP_COUNT];
uint32_t dcfclks_khz[MAX_UTM_SOP_COUNT];
uint32_t socclks_khz[MAX_UTM_SOP_COUNT];
};
static inline bool dchub_v1_is_qos_latency_supported_by_sop(const struct utm_qos_model *model,
const struct utm_qos_model_dchub_memory_path_latency_v1 *qos_latency,
uint8_t sop_index)
{
const struct utm_qos_model_dchub_memory_path_latency_v1 *sop_latency = &model->dchub_v1->latencies[sop_index];
return (qos_latency->urgent_ramp_ps >= sop_latency->urgent_ramp_ps &&
qos_latency->t_trip_ps >= sop_latency->t_trip_ps &&
qos_latency->meta_trip_to_mem_ps >= sop_latency->meta_trip_to_mem_ps &&
qos_latency->max_req_latency_urg_ps >= sop_latency->max_req_latency_urg_ps &&
qos_latency->avg_req_latency_urg_ps >= sop_latency->avg_req_latency_urg_ps &&
qos_latency->max_req_latency_non_urg_ps >= sop_latency->max_req_latency_non_urg_ps &&
qos_latency->avg_req_latency_non_urg_ps >= sop_latency->avg_req_latency_non_urg_ps &&
qos_latency->df_response_time_ps >= sop_latency->df_response_time_ps);
}
static inline bool dchub_v1_is_qos_bandwidth_supported_by_sop(
const struct utm_qos_model *model,
const struct utm_qos_model_dchub_memory_path_bandwidth_v1 *qos_bandwidth,
uint8_t sop_index)
{
return (model->dchub_v1->bandwidths[sop_index].nominal_bandwidth_KBps >= qos_bandwidth->nominal_bandwidth_KBps
&& model->dchub_v1->bandwidths[sop_index].urgent_bandwidth_KBps >= qos_bandwidth->urgent_bandwidth_KBps);
// const struct utm_soc_operating_point *sop = &model->sops[sop_index];
// const struct utm_qos_model_socbb *socbb = &model->socbb;
// uint64_t available_bandwidth_KBps;
// uint64_t min_available_bandwidth_KBps;
//
// min_available_bandwidth_KBps = (uint64_t) sop->uclk_khz
// * socbb->dram_channel_count
// * socbb->dram_channel_width_bytes
// * socbb->dram_transactions_per_clock
// * socbb->dram_derate_percent_nominal / 100;
//
// available_bandwidth_KBps = (uint64_t) sop->fclk_khz
// * socbb->fabric_datapath_to_dcn_data_return_bytes
// * socbb->fabric_derate_percent_nominal / 100;
// if (min_available_bandwidth_KBps > available_bandwidth_KBps)
// min_available_bandwidth_KBps = available_bandwidth_KBps;
//
// available_bandwidth_KBps = (uint64_t) model->dchub_v1->dcfclks_khz[sop_index]
// * model->dchub_v1->return_bus_width_bytes
// * model->dchub_v1->sdp_derate_percent_nominal / 100;
// if (min_available_bandwidth_KBps > available_bandwidth_KBps)
// min_available_bandwidth_KBps = available_bandwidth_KBps;
//
// if ((min_available_bandwidth_KBps * nominal_utm_budget_percent / 100) < qos_bandwidth->nominal_bandwidth_KBps)
// return false;
//
// min_available_bandwidth_KBps = (uint64_t) sop->uclk_khz
// * socbb->dram_channel_count
// * socbb->dram_channel_width_bytes
// * socbb->dram_transactions_per_clock
// * socbb->dram_derate_percent_urgent / 100;
//
// available_bandwidth_KBps = (uint64_t) sop->fclk_khz
// * socbb->fabric_datapath_to_dcn_data_return_bytes
// * socbb->fabric_derate_percent_urgent / 100;
// if (min_available_bandwidth_KBps > available_bandwidth_KBps)
// min_available_bandwidth_KBps = available_bandwidth_KBps;
//
// available_bandwidth_KBps = (uint64_t) model->dchub_v1->dcfclks_khz[sop_index]
// * model->dchub_v1->return_bus_width_bytes
// * model->dchub_v1->sdp_derate_percent_urgent / 100;
// if (min_available_bandwidth_KBps > available_bandwidth_KBps)
// min_available_bandwidth_KBps = available_bandwidth_KBps;
//
// if ((min_available_bandwidth_KBps * urgent_utm_budget_percent / 100) < qos_bandwidth->urgent_bandwidth_KBps)
// return false;
//
// return true;
}
#endif /* #ifndef UTM_QOS_MODEL_DCHUB_V1_H */

View File

@@ -0,0 +1,122 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef UTM_QOS_MODEL_DCHUB_V2_H
#define UTM_QOS_MODEL_DCHUB_V2_H
#include "utm_qos_model_types.h"
struct utm_qos_model_dchub_memory_path_latency_v2 {
uint32_t urgent_ramp_ps;
uint32_t t_trip_ps;
uint32_t meta_trip_to_mem_ps;
uint32_t max_req_latency_urg_ps;
uint32_t avg_req_latency_urg_ps;
uint32_t max_req_latency_non_urg_ps;
uint32_t avg_req_latency_non_urg_ps;
uint32_t df_response_time_ps;
};
struct utm_qos_model_dchub_memory_path_bandwidth_v2 {
uint32_t nominal_bandwidth_KBps;
uint32_t urgent_bandwidth_KBps;
};
struct utm_qos_model_dchub_memory_path_qos_v2 {
struct utm_qos_model_dchub_memory_path_latency_v2 latency_upper_bound;
struct utm_qos_model_dchub_memory_path_bandwidth_v2 bandwidth_lower_bound;
};
struct utm_qos_model_dchub_v2 {
struct utm_qos_model_dchub_memory_path_latency_v2 latencies[MAX_UTM_SOP_COUNT];
uint8_t max_nominal_utm_budget_percent;
uint8_t min_nominal_utm_budget_percent;
uint8_t max_urgent_utm_budget_percent;
uint8_t min_urgent_utm_budget_percent;
};
static inline bool dchub_v2_is_qos_latency_supported_by_sop(const struct utm_qos_model *model,
const struct utm_qos_model_dchub_memory_path_latency_v2 *qos_latency,
uint8_t sop_index)
{
const struct utm_qos_model_dchub_memory_path_latency_v2 *sop_latency = &model->dchub_v2->latencies[sop_index];
return (qos_latency->urgent_ramp_ps >= sop_latency->urgent_ramp_ps &&
qos_latency->t_trip_ps >= sop_latency->t_trip_ps &&
qos_latency->meta_trip_to_mem_ps >= sop_latency->meta_trip_to_mem_ps &&
qos_latency->max_req_latency_urg_ps >= sop_latency->max_req_latency_urg_ps &&
qos_latency->avg_req_latency_urg_ps >= sop_latency->avg_req_latency_urg_ps &&
qos_latency->max_req_latency_non_urg_ps >= sop_latency->max_req_latency_non_urg_ps &&
qos_latency->avg_req_latency_non_urg_ps >= sop_latency->avg_req_latency_non_urg_ps &&
qos_latency->df_response_time_ps >= sop_latency->df_response_time_ps);
}
static inline void dchub_v2_get_sop_total_available_bandwidth_KBps(
const struct utm_qos_model *model,
struct utm_qos_model_dchub_memory_path_bandwidth_v2 *total_available_bandwidth,
uint8_t sop_index)
{
const struct utm_soc_operating_point *sop = &model->sops[sop_index];
const struct utm_qos_model_socbb *socbb = &model->socbb;
uint64_t dram_available_bandwidth_KBps_nominal;
uint64_t fabric_available_bandwidth_KBps_nominal;
uint64_t dram_available_bandwidth_KBps_urgent;
uint64_t fabric_available_bandwidth_KBps_urgent;
dram_available_bandwidth_KBps_nominal = (uint64_t) sop->uclk_khz
* socbb->dram_channel_count
* socbb->dram_channel_width_bytes
* socbb->dram_transactions_per_clock
* socbb->dram_derate_percent_nominal / 100;
dram_available_bandwidth_KBps_urgent = (uint64_t) sop->uclk_khz
* socbb->dram_channel_count
* socbb->dram_channel_width_bytes
* socbb->dram_transactions_per_clock
* socbb->dram_derate_percent_urgent / 100;
fabric_available_bandwidth_KBps_nominal = (uint64_t) sop->fclk_khz
* socbb->fabric_datapath_to_dcn_data_return_bytes
* socbb->fabric_derate_percent_nominal / 100;
fabric_available_bandwidth_KBps_urgent = (uint64_t) sop->fclk_khz
* socbb->fabric_datapath_to_dcn_data_return_bytes
* socbb->fabric_derate_percent_urgent / 100;
total_available_bandwidth->nominal_bandwidth_KBps =
dram_available_bandwidth_KBps_nominal < fabric_available_bandwidth_KBps_nominal ?
(uint32_t) dram_available_bandwidth_KBps_nominal :
(uint32_t) fabric_available_bandwidth_KBps_nominal;
total_available_bandwidth->urgent_bandwidth_KBps =
dram_available_bandwidth_KBps_urgent < fabric_available_bandwidth_KBps_urgent ?
(uint32_t) dram_available_bandwidth_KBps_urgent :
(uint32_t) fabric_available_bandwidth_KBps_urgent;
}
static inline bool dchub_v2_is_qos_bandwidth_supported_by_sop(
const struct utm_qos_model *model,
const struct utm_qos_model_dchub_memory_path_bandwidth_v2 *qos_bandwidth,
uint8_t sop_index,
uint8_t nominal_utm_budget_percent,
uint8_t urgent_utm_budget_percent)
{
struct utm_qos_model_dchub_memory_path_bandwidth_v2 available_bandwidth = {0};
const struct utm_qos_model_dchub_v2 *dchub = model->dchub_v2;
uint64_t nominal_available_bandwidth_KBps;
uint64_t urgent_available_bandwidth_KBps;
if (nominal_utm_budget_percent > dchub->max_nominal_utm_budget_percent ||
nominal_utm_budget_percent < dchub->min_nominal_utm_budget_percent ||
urgent_utm_budget_percent > dchub->max_urgent_utm_budget_percent ||
urgent_utm_budget_percent < dchub->min_urgent_utm_budget_percent)
return false;
dchub_v2_get_sop_total_available_bandwidth_KBps(model, &available_bandwidth, sop_index);
nominal_available_bandwidth_KBps = available_bandwidth.nominal_bandwidth_KBps;
urgent_available_bandwidth_KBps = available_bandwidth.urgent_bandwidth_KBps;
if ((nominal_available_bandwidth_KBps * nominal_utm_budget_percent / 100) < qos_bandwidth->nominal_bandwidth_KBps)
return false;
else if ((urgent_available_bandwidth_KBps * urgent_utm_budget_percent / 100) < qos_bandwidth->urgent_bandwidth_KBps)
return false;
else
return true;
}
#endif /* #ifndef UTM_QOS_MODEL_DCHUB_V2_H */

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef UTM_QOS_MODEL_DCHUB_V3_H
#define UTM_QOS_MODEL_DCHUB_V3_H
/* Must match DALSMC_MAX_UTM_SOP_COUNT in dalsmc.h without including it */
#define UTM_QOS_MODEL_V3_MAX_LOAD_LEVEL_COUNT 3
#define UTM_QOS_MODEL_V3_MAX_SOP_COUNT 5
#define UTM_QOS_MODEL_V3_LOAD_LEVEL_IDLE 0
#define UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE_ALTERNATE_PSTATE 1
#define UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE 2
/**
* utm_qos_model_dchub_v3_sop_entry - Per-SOP QoS parameters for one load level.
*
* All latency fields are in picoseconds. All bandwidth fields are in KBps.
* Budget percentage and derate are pre-applied callers use values
* directly without further scaling.
*/
struct utm_qos_model_dchub_v3_sop_entry {
/* latencies */
uint32_t urgent_ramp_ps;
uint32_t t_trip_ps;
uint32_t meta_trip_to_mem_ps;
uint32_t max_req_latency_urg_ps;
uint32_t avg_req_latency_urg_ps;
uint32_t max_req_latency_non_urg_ps;
uint32_t avg_req_latency_non_urg_ps;
uint32_t df_response_time_ps;
/* bandwidths (budget allocation and derate pre-applied) */
uint32_t urgent_bandwidth_KBps;
uint32_t nominal_bandwidth_KBps;
uint32_t lsdma_bandwidth_KBps;
};
/**
* utm_qos_model_dchub_v3 - DCN6 flat UTM QoS table.
*
* Indexed as sops[load_level][sop_index]. Load level constants:
* UTM_QOS_MODEL_V3_LOAD_LEVEL_IDLE (max budget %)
* UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE_ALTERNATE_PSTATE (min budget %)
* UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE (same as alt pstate, lsdma=0)
*/
struct utm_qos_model_dchub_v3 {
uint8_t load_level_count;
uint8_t sop_count;
struct utm_qos_model_dchub_v3_sop_entry
sops[UTM_QOS_MODEL_V3_MAX_LOAD_LEVEL_COUNT][UTM_QOS_MODEL_V3_MAX_SOP_COUNT];
};
#endif /* #ifndef UTM_QOS_MODEL_DCHUB_V3_H */

View File

@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef UTM_QOS_MODEL_TYPES_H
#define UTM_QOS_MODEL_TYPES_H
struct utm_soc_operating_point {
uint32_t uclk_khz;
uint32_t fclk_khz;
};
struct utm_qos_model_socbb {
uint8_t fabric_datapath_to_dcn_data_return_bytes;
uint8_t dram_channel_width_bytes;
uint8_t dram_channel_count;
uint8_t dram_transactions_per_clock;
uint8_t fabric_derate_percent_nominal;
uint8_t fabric_derate_percent_urgent;
uint8_t dram_derate_percent_nominal;
uint8_t dram_derate_percent_urgent;
uint8_t lsdma_fabric_derate_percent;
uint8_t lsdma_dram_derate_percent;
uint8_t fabric_datapath_to_lsdma_data_return_bytes;
};
#define MAX_UTM_SOP_COUNT 20
enum utm_qos_model_version {
utm_qos_model_version_v1,
utm_qos_model_version_v2,
utm_qos_model_version_v3,
};
struct utm_qos_model_dchub_v1;
struct utm_qos_model_dchub_v2;
struct utm_qos_model_dchub_v3;
struct utm_qos_model_lsdma;
struct utm_qos_model {
int version;
struct utm_soc_operating_point sops[MAX_UTM_SOP_COUNT];
union {
const struct utm_qos_model_dchub_v1 *dchub_v1;
const struct utm_qos_model_dchub_v2 *dchub_v2;
const struct utm_qos_model_dchub_v3 *dchub_v3;
};
const struct utm_qos_model_lsdma *lsdma;
struct utm_qos_model_socbb socbb;
uint8_t sop_count;
};
#endif /* #ifndef UTM_QOS_MODEL_TYPES_H */

View File

@@ -0,0 +1,502 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef DML_DMUB_CMD_H
#define DML_DMUB_CMD_H
/* always include for now */
#include <asm/byteorder.h>
#include <linux/types.h>
#include <linux/string.h>
#define DMUB_MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define DMUB_MIN(X, Y) ((X) < (Y) ? (X) : (Y))
/* Define to ensure that the "common" members always appear in the same
* order in different structs for back compat purposes
*/
#define COMMON_STREAM_STATIC_SUB_STATE \
struct dmub_fams2_cmd_legacy_stream_static_state legacy; \
struct dmub_fams2_cmd_subvp_stream_static_state subvp; \
struct dmub_fams2_cmd_drr_stream_static_state drr;
/* Maximum number of streams on any ASIC. */
#define DMUB_MAX_STREAMS 6
/* Maximum number of planes on any ASIC. */
#define DMUB_MAX_PLANES 6
/* Maximum number of phantom planes on any ASIC */
#define DMUB_MAX_PHANTOM_PLANES (DMUB_MAX_PLANES) / 2
/* Flattened structure containing SOC BB parameters stored in the VBIOS
* It is not practical to store the entire bounding box in VBIOS since the bounding box struct can gain new parameters.
* This also prevents alighment issues when new parameters are added to the SoC BB.
* The following parameters should be added since these values can't be obtained elsewhere:
* -dml2_soc_power_management_parameters
* -dml2_soc_vmin_clock_limits
*/
struct dmub_soc_bb_params {
uint32_t dram_clk_change_blackout_ns;
uint32_t dram_clk_change_read_only_ns;
uint32_t dram_clk_change_write_only_ns;
uint32_t fclk_change_blackout_ns;
uint32_t g7_ppt_blackout_ns;
uint32_t stutter_enter_plus_exit_latency_ns;
uint32_t stutter_exit_latency_ns;
uint32_t z8_stutter_enter_plus_exit_latency_ns;
uint32_t z8_stutter_exit_latency_ns;
uint32_t z8_min_idle_time_ns;
uint32_t type_b_dram_clk_change_blackout_ns;
uint32_t type_b_ppt_blackout_ns;
uint32_t vmin_limit_dispclk_khz;
uint32_t vmin_limit_dcfclk_khz;
uint32_t g7_temperature_read_blackout_ns;
};
struct dmub_rect16 {
/**
* Dirty rect x offset.
*/
uint16_t x; // src_x
/**
* Dirty rect y offset.
*/
uint16_t y; // src_y
/**
* Dirty rect width.
*/
uint16_t width; // dest_width, rect_x
/**
* Dirty rect height.
*/
uint16_t height; // dest_height, rect_y
};
union fw_assisted_mclk_switch_version {
struct {
uint8_t minor : 5;
uint8_t major : 3;
};
uint8_t ver;
};
/* generic structures and enums */
struct dmub_optc_position {
uint32_t vpos;
uint32_t hpos;
uint32_t frame;
};
/* HW and FW global configuration data for FAMS2 */
/* FAMS2 types and structs */
enum fams2_stream_type {
FAMS2_STREAM_TYPE_NONE = 0,
FAMS2_STREAM_TYPE_VBLANK = 1,
FAMS2_STREAM_TYPE_VACTIVE = 2,
FAMS2_STREAM_TYPE_DRR = 3,
FAMS2_STREAM_TYPE_SUBVP = 4,
FAMS2_STREAM_TYPE_ALTERNATE = 5,
};
struct plane_pipe_rect {
struct dmub_rect16 luma;
struct dmub_rect16 chroma;
};
/**
* Structure to hold the LSDMA source / dest copy parameters.
* Each field is an array of [2][4]:
* [2] - Instance 0 is the copy for current frame, instance 1 is the copy for next frame (instance 1 potentially unused if no next)
* [4] - One instance per pipe
*/
struct lsdma_outputs {
uint16_t src_x[2][4]; // src x position for the copy. Array of [2][4] for curr vs. next and each pipe
uint16_t src_y[2][4]; // src y position for the copy
uint16_t dst_x[2][4]; // dst x position for the copy (can change for curr vs. next)
uint16_t dst_y[2][4]; // dst y position for the copy (can change for curr vs. next)
uint16_t width[2][4]; // src and dst width for the copy (src and dst must match)
uint16_t height[2][4]; // src and dst height for the copy (src and dst must match)
uint16_t dst_pitch[4]; // dst pitch for the copy (same for curr and next)
};
struct dmub_fams2_alternate_stream_dynamic_state {
uint64_t earliest_init_tick; // track earliest possible init tick for calculating is_tick_in_allow
uint32_t otg_frame_pending_clear[3]; // In this context pending means prefetch has never been completed for this frame yet
uint8_t flip_pending_clear_order[3];
uint8_t num_pending_flips;
uint32_t prefetch_start_line_x1000[3]; // can compute from existing params, but store because we use this multiple times
uint16_t prefetch_end_line[3]; // can compute from existing params, but store because we use this multiple times
uint16_t recout_y[3];
uint8_t flip_pending[3];
uint8_t copy_from_earliest[3];
uint16_t lsdma_bandwidth_mbps;
uint16_t vstartup_line;
uint16_t vready_line;
uint8_t cursor_size[3]; // Cursor array per plane for now - if we assume a single cursor, then we don't need an array
uint8_t pad; // to maintain alignment for below fields - re-arrange structure once all fields are finalized
/* outputs: */
uint16_t subvp_start_line_a[3];
uint16_t subvp_height_a[3];
uint16_t subvp_next_start_line_a[3];
uint16_t subvp_next_height_a[3];
uint16_t subvp_start_line_b[3];
uint16_t subvp_height_b[3];
uint16_t subvp_next_start_line_b[3];
uint16_t subvp_next_height_b[3];
uint16_t subvp_c_start_line_a[3];
uint16_t subvp_c_height_a[3];
uint16_t subvp_c_next_start_line_a[3];
uint16_t subvp_c_next_height_a[3];
uint16_t subvp_c_start_line_b[3];
uint16_t subvp_c_height_b[3];
uint16_t subvp_c_next_start_line_b[3];
uint16_t subvp_c_next_height_b[3];
uint8_t subvp_position[3];
uint8_t copy_from_primary[3];
uint8_t pad1[2]; // to maintain alignment for below fields - re-arrange structure once all fields are finalized
uint32_t program_go_line;
uint32_t program_go_frame_count;
uint16_t svp0_start_dst_line;
uint16_t svp0_end_dst_line;
uint16_t svp1_start_dst_line;
uint16_t svp1_end_dst_line;
struct lsdma_outputs lsdma[2]; // [2] - instance per SVP0 and SVP1
struct lsdma_outputs lsdma_c[2]; // [2] - instance per SVP0 and SVP1
};
/* dynamic stream state */
struct dmub_fams2_legacy_stream_dynamic_state {
uint8_t force_allow_at_vblank;
uint8_t pad[3];
};
struct dmub_fams2_subvp_stream_dynamic_state {
uint16_t viewport_start_hubp_vline;
uint16_t viewport_height_hubp_vlines;
uint16_t viewport_start_c_hubp_vline;
uint16_t viewport_height_c_hubp_vlines;
uint16_t phantom_viewport_height_hubp_vlines;
uint16_t phantom_viewport_height_c_hubp_vlines;
uint16_t microschedule_start_otg_vline;
uint16_t mall_start_otg_vline;
uint16_t mall_start_hubp_vline;
uint16_t mall_start_c_hubp_vline;
uint8_t force_allow_at_vblank_only;
uint8_t swath_height;
uint8_t swath_height_c;
uint8_t pad;
};
struct dmub_fams2_drr_stream_dynamic_state {
uint16_t stretched_vtotal;
uint8_t use_cur_vtotal;
uint8_t pad;
};
struct dmub_fams2_cmd_alternate_stream_static_state {
uint32_t total_bytes_to_copy;
uint16_t svp0_dst_lines; // per stream
uint16_t svp1_dst_lines; // per stream
uint16_t min_lead_dst_lines; // per stream, should be max(nominal_req_limit, vstartup_to_vactive). Does not have to be maxed over all planes
uint16_t svp_req_limit; // per stream, should be the same value in time between all streams max(2 swaths, dst_y_pre) over all planes
uint16_t fw_delays;
uint16_t vstartup_start;
uint16_t rec_height[3];
uint16_t viewport_start[3];
uint16_t viewport_size[3]; // for now size will be the number of lines perpendicular to scan direction (height for 0 / 180, width for 90 and 270)
uint16_t viewport_start_c[3];
uint16_t viewport_size_c[3];
uint16_t surface_pitch[3];
uint16_t surface_pitch_c[3];
uint16_t surface_height[3];
uint16_t surface_height_c[3];
uint8_t element_size[3];
uint8_t element_size_c[3];
uint8_t swizzle_mode[3]; // TODO: Add mapping, should be value used in LSDMA command
uint8_t vready_offset_lines; // vready offset from vstartup in lines (rounded up, as the actual offset may be a fraction of a line)
uint16_t dst_y_prefetch_x1000[3];
uint16_t total_swaths[3];
uint16_t total_swaths_c[3];
uint8_t prefetch_swaths[3];
uint8_t prefetch_swaths_c[3];
uint8_t swath_height[3];
uint8_t swath_height_c[3];
uint16_t block_256b_width[3];
uint16_t block_256b_height[3];
uint16_t block_256b_width_c[3];
uint16_t block_256b_height_c[3];
uint16_t macro_tile_width[3];
uint16_t macro_tile_width_c[3];
union {
struct {
uint8_t is_multi_planar : 1;
uint8_t is_yuv420 : 1;
uint8_t prefetch_relative_vblank : 1;
uint8_t vertical_access : 1; // vertical_access = 1 means 90 or 270 rotation
uint8_t access_direction : 1; // access_direction = 1 means bigger to smaller coordinations (e.g., scan from 2160 to 0 as opposed to regular 0 to 2160)
uint8_t dcc : 1;
uint8_t tmz : 1; // TODO: Need to assign outside of DML (DML not aware of TMZ)
} bits;
uint8_t all;
} config[3];
uint8_t max_cursor_size;
uint16_t pre_hdl_delta_x1000[3];
uint16_t pre_hdl_delta_c_x1000[3];
uint16_t rec_hdl_delta_x1000[3];
uint16_t rec_hdl_delta_c_x1000[3];
uint16_t dst_y_per_vm_vblank_x1000[3];
uint16_t dst_y_per_row_vblank_x1000[3];
uint16_t dst_y_after_scaler[3];
uint16_t vinit_prefill[3];
uint16_t vinit_prefill_c[3];
uint16_t vratio_x1000[3];
uint16_t vratio_c_x1000[3];
struct plane_pipe_rect pipe_viewports[4];
/* TODO - remove these deprecated vars */
uint32_t pipe_copy_offset[2][4]; // [2] - SVP0/1, [4] - 4 pipes
uint32_t pipe_copy_offset_c[2][4];
/* bits 47:16 of the surface address */
uint32_t pipe_copy_addr_47_16[2][4]; // [2] - SVP0/1, [4] - 4 pipes
uint32_t pipe_copy_addr_47_16_c[2][4];
uint32_t pipe_copy_max_size[2][4];
uint32_t pipe_copy_max_size_c[2][4];
};
struct dmub_fams2_stream_dynamic_state {
uint64_t ref_tick;
uint32_t cur_vtotal;
uint16_t adjusted_allow_end_otg_vline;
uint8_t pad[2];
struct dmub_optc_position ref_otg_pos;
struct dmub_optc_position target_otg_pos;
union {
struct dmub_fams2_legacy_stream_dynamic_state legacy;
struct dmub_fams2_subvp_stream_dynamic_state subvp;
struct dmub_fams2_drr_stream_dynamic_state drr;
struct dmub_fams2_alternate_stream_dynamic_state alternate;
} sub_state;
};
/* static stream state */
struct dmub_fams2_legacy_stream_static_state {
uint8_t vactive_det_fill_delay_otg_vlines;
uint8_t programming_delay_otg_vlines;
}; //v0
struct dmub_fams2_subvp_stream_static_state {
uint16_t vratio_numerator;
uint16_t vratio_denominator;
uint16_t phantom_vtotal;
uint16_t phantom_vactive;
union {
struct {
uint8_t is_multi_planar : 1;
uint8_t is_yuv420 : 1;
} bits;
uint8_t all;
} config;
uint8_t programming_delay_otg_vlines;
uint8_t prefetch_to_mall_otg_vlines;
uint8_t phantom_otg_inst;
uint8_t phantom_pipe_mask;
uint8_t phantom_plane_pipe_masks[DMUB_MAX_PHANTOM_PLANES]; // phantom pipe mask per plane (for flip passthrough)
}; //v0
struct dmub_fams2_drr_stream_static_state {
uint16_t nom_stretched_vtotal;
uint8_t programming_delay_otg_vlines;
uint8_t only_stretch_if_required;
uint8_t pad[2];
}; //v0
struct dmub_fams2_cmd_legacy_stream_static_state {
uint16_t vactive_det_fill_delay_otg_vlines;
uint16_t programming_delay_otg_vlines;
uint32_t disallow_time_us;
}; //v1
struct dmub_fams2_cmd_subvp_stream_static_state {
uint16_t vratio_numerator;
uint16_t vratio_denominator;
uint16_t phantom_vtotal;
uint16_t phantom_vactive;
uint16_t programming_delay_otg_vlines;
uint16_t prefetch_to_mall_otg_vlines;
union {
struct {
uint8_t is_multi_planar : 1;
uint8_t is_yuv420 : 1;
} bits;
uint8_t all;
} config;
uint8_t phantom_otg_inst;
uint8_t phantom_pipe_mask;
uint8_t pad0;
uint8_t phantom_plane_pipe_masks[DMUB_MAX_PHANTOM_PLANES]; // phantom pipe mask per plane (for flip passthrough)
uint8_t pad1[4 - (DMUB_MAX_PHANTOM_PLANES % 4)];
}; //v1
struct dmub_fams2_cmd_drr_stream_static_state {
uint16_t nom_stretched_vtotal;
uint16_t programming_delay_otg_vlines;
uint8_t only_stretch_if_required;
uint8_t pad[3];
}; //v1
union dmub_fams2_stream_static_sub_state {
struct dmub_fams2_legacy_stream_static_state legacy;
struct dmub_fams2_subvp_stream_static_state subvp;
struct dmub_fams2_drr_stream_static_state drr;
}; //v0
union dmub_fams2_cmd_stream_static_sub_state {
COMMON_STREAM_STATIC_SUB_STATE
}; //v1
union dmub_fams2_stream_static_sub_state_v2 {
COMMON_STREAM_STATIC_SUB_STATE
struct dmub_fams2_cmd_alternate_stream_static_state alternate;
}; //v2
struct dmub_fams2_stream_static_state {
enum fams2_stream_type type;
uint32_t otg_vline_time_ns;
uint32_t otg_vline_time_ticks;
uint16_t htotal;
uint16_t vtotal; // nominal vtotal
uint16_t vblank_start;
uint16_t vblank_end;
uint16_t max_vtotal;
uint16_t allow_start_otg_vline;
uint16_t allow_end_otg_vline;
uint16_t drr_keepout_otg_vline; // after this vline, vtotal cannot be changed
uint8_t scheduling_delay_otg_vlines; // min time to budget for ready to microschedule start
uint8_t contention_delay_otg_vlines; // time to budget for contention on execution
uint8_t vline_int_ack_delay_otg_vlines; // min time to budget for vertical interrupt firing
uint8_t allow_to_target_delay_otg_vlines; // time from allow vline to target vline
union {
struct {
uint8_t is_drr : 1; // stream is DRR enabled
uint8_t clamp_vtotal_min : 1; // clamp vtotal to min instead of nominal
uint8_t min_ttu_vblank_usable : 1; // if min ttu vblank is above wm, no force pstate is needed in blank
} bits;
uint8_t all;
} config;
uint8_t otg_inst;
uint8_t pipe_mask; // pipe mask for the whole config
uint8_t num_planes;
uint8_t plane_pipe_masks[DMUB_MAX_PLANES]; // pipe mask per plane (for flip passthrough)
uint8_t pad[DMUB_MAX_PLANES % 4];
union dmub_fams2_stream_static_sub_state sub_state;
}; //v0
struct dmub_fams2_cmd_stream_static_base_state {
enum fams2_stream_type type;
uint32_t otg_vline_time_ns;
uint32_t otg_vline_time_ticks;
uint16_t htotal;
uint16_t vtotal; // nominal vtotal
uint16_t vblank_start;
uint16_t vblank_end;
uint16_t max_vtotal;
uint16_t allow_start_otg_vline;
uint16_t allow_end_otg_vline;
uint16_t drr_keepout_otg_vline; // after this vline, vtotal cannot be changed
uint16_t scheduling_delay_otg_vlines; // min time to budget for ready to microschedule start
uint16_t contention_delay_otg_vlines; // time to budget for contention on execution
uint16_t vline_int_ack_delay_otg_vlines; // min time to budget for vertical interrupt firing
uint16_t allow_to_target_delay_otg_vlines; // time from allow vline to target vline
union {
struct {
uint8_t is_drr : 1; // stream is DRR enabled
uint8_t clamp_vtotal_min : 1; // clamp vtotal to min instead of nominal
uint8_t min_ttu_vblank_usable : 1; // if min ttu vblank is above wm, no force pstate is needed in blank
} bits;
uint8_t all;
} config;
uint8_t otg_inst;
uint8_t pipe_mask; // pipe mask for the whole config
uint8_t num_planes;
uint8_t plane_pipe_masks[DMUB_MAX_PLANES]; // pipe mask per plane (for flip passthrough)
uint8_t pad[DMUB_MAX_PLANES % 4];
}; //v1
struct dmub_fams2_stream_static_state_v1 {
struct dmub_fams2_cmd_stream_static_base_state base;
union dmub_fams2_stream_static_sub_state_v2 sub_state;
}; //v1
/**
* enum dmub_fams2_allow_delay_check_mode - macroscheduler mode for breaking on excessive
* p-state request to allow latency
*/
enum dmub_fams2_allow_delay_check_mode {
/* No check for request to allow delay */
FAMS2_ALLOW_DELAY_CHECK_NONE = 0,
/* Check for request to allow delay */
FAMS2_ALLOW_DELAY_CHECK_FROM_START = 1,
/* Check for prepare to allow delay */
FAMS2_ALLOW_DELAY_CHECK_FROM_PREPARE = 2,
};
union dmub_fams2_global_feature_config {
struct {
uint32_t enable : 1;
uint32_t enable_ppt_check : 1;
uint32_t enable_stall_recovery : 1;
uint32_t enable_debug : 1;
uint32_t enable_offload_flip : 1;
uint32_t enable_visual_confirm : 1;
uint32_t allow_delay_check_mode : 2;
uint32_t legacy_method_no_fams2 : 1;
uint32_t reserved : 23;
} bits;
uint32_t all;
};
struct dmub_cmd_fams2_global_config {
uint32_t max_allow_delay_us; // max delay to assert allow from uclk change begin
uint32_t lock_wait_time_us; // time to forecast acquisition of lock
uint32_t num_streams;
union dmub_fams2_global_feature_config features;
uint32_t recovery_timeout_us;
uint32_t hwfq_flip_programming_delay_us;
uint32_t max_allow_to_target_delta_us; // how early DCN could assert P-State allow compared to the P-State target
};
union dmub_cmd_fams2_config {
struct dmub_cmd_fams2_global_config global;
struct dmub_fams2_stream_static_state stream; //v0
union {
struct dmub_fams2_cmd_stream_static_base_state base;
union dmub_fams2_cmd_stream_static_sub_state sub_state;
} stream_v1; //v1
};
struct dmub_fams2_config_v2 {
struct dmub_cmd_fams2_global_config global;
struct dmub_fams2_stream_static_state_v1 stream_v1[DMUB_MAX_STREAMS]; //v1
};
/**
* OS/FW agnostic memcpy
*/
#ifndef dmub_memcpy
#define dmub_memcpy(dest, source, bytes) memcpy((dest), (source), (bytes))
#endif
/**
* OS/FW agnostic memset
*/
#ifndef dmub_memset
#define dmub_memset(dest, val, bytes) memset((dest), (val), (bytes))
#endif
//#endif
#endif /* _DML_DMUB_CMD_H_ */

View File

@@ -0,0 +1,152 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dml2_cga_dcn6.h"
#include "lib_float_math.h"
#include "dml2_debug.h"
#define DFS_DIVIDER_RANGE_SCALE_FACTOR 4.0
#define CLOCK_UNIT_GRANULARITY 0.001
#define DPPREFCLK_DIVIDER 255
static double cga_dcn6_add_overhead_percent(double clk, double overhead_percent)
{
return clk * (1 + overhead_percent / 100.0);
}
static double cga_dcn6_calculate_refclk_mhz(const struct dml2_clock_granularity_adjuster *adjuster,
const double *clks_mhz, unsigned int count)
{
unsigned int i;
double max_clk_mhz = 0;
double refclk_mhz;
for (i = 0; i < count; i++)
max_clk_mhz = math_max2(clks_mhz[i], max_clk_mhz);
refclk_mhz = math_floor2(max_clk_mhz, CLOCK_UNIT_GRANULARITY);
refclk_mhz = cga_dcn6_add_overhead_percent(refclk_mhz, adjuster->dcn_downspread_percent);
refclk_mhz = math_floor2(refclk_mhz, CLOCK_UNIT_GRANULARITY);
return refclk_mhz;
}
static double cga_dcn6_calculate_actual_dispclk_mhz(const struct dml2_clock_granularity_adjuster *adjuster, double dispclk_mhz)
{
double dispclk_with_downspread_mhz;
double dispclk_with_ramp_margin_mhz;
dispclk_mhz = math_floor2(dispclk_mhz, CLOCK_UNIT_GRANULARITY);
dispclk_with_downspread_mhz = cga_dcn6_add_overhead_percent(dispclk_mhz, adjuster->dcn_downspread_percent);
dispclk_with_ramp_margin_mhz = cga_dcn6_add_overhead_percent(
dispclk_with_downspread_mhz, adjuster->dispclk_ramp_margin_percent);
if (dispclk_with_downspread_mhz <= adjuster->max_dispclk_mhz &&
dispclk_with_ramp_margin_mhz > adjuster->max_dispclk_mhz)
/* when dispclk with ramp margin is slightly over max, clamp the ramp margin to the max dispclk */
return math_floor2(adjuster->max_dispclk_mhz, CLOCK_UNIT_GRANULARITY);
else if (dispclk_with_downspread_mhz > adjuster->max_dispclk_mhz)
return math_floor2(dispclk_with_downspread_mhz, CLOCK_UNIT_GRANULARITY);
else
return math_floor2(dispclk_with_ramp_margin_mhz, CLOCK_UNIT_GRANULARITY);
}
static double cga_dcn6_adjust_to_dfs_clock_value_mhz(const struct dml2_clock_granularity_adjuster *adjuster, double clk_mhz)
{
double vco_speed_scaled_mhz;
double vco_divider;
double adjusted_clock_mhz;
DML_ASSERT_MSG(adjuster->dispclk_dppclk_vco_speed_mhz > 1, "invalid dispclk_dppclk_vco_speed_mhz value!\n");
if (clk_mhz == 0)
/* There are cases when a clock is not needed */
return 0;
vco_speed_scaled_mhz = math_floor2(adjuster->dispclk_dppclk_vco_speed_mhz, 0.001);
vco_speed_scaled_mhz *= DFS_DIVIDER_RANGE_SCALE_FACTOR;
vco_divider = vco_speed_scaled_mhz / clk_mhz;
vco_divider = math_floor(vco_divider);
adjusted_clock_mhz = vco_speed_scaled_mhz / vco_divider;
adjusted_clock_mhz = math_floor2(adjusted_clock_mhz, CLOCK_UNIT_GRANULARITY);
return adjusted_clock_mhz;
}
static double dga_dcn6_calculate_adjusted_dppclk_mhz(const struct dml2_clock_granularity_adjuster *adjuster,
double dpprefclk_mhz, double dppclk_mhz)
{
double granularity_mhz = dpprefclk_mhz / DPPREFCLK_DIVIDER;
dppclk_mhz = math_floor2(dppclk_mhz, CLOCK_UNIT_GRANULARITY);
dppclk_mhz = cga_dcn6_add_overhead_percent(dppclk_mhz, adjuster->dcn_downspread_percent);
dppclk_mhz = math_ceil2(dppclk_mhz, granularity_mhz);
dppclk_mhz = math_floor2(dppclk_mhz, CLOCK_UNIT_GRANULARITY);
return dppclk_mhz;
}
static double dga_dcn6_calculate_adjusted_dtbclk_mhz(
const struct dml2_clock_granularity_adjuster *adjuster, double dppclk_mhz)
{
(void)adjuster;
return math_floor2(dppclk_mhz, CLOCK_UNIT_GRANULARITY);
}
static double cga_dcn6_adjust_dispclk_mhz(const struct dml2_clock_granularity_adjuster *adjuster, double dispclk_mhz)
{
double adjusted_dispclk_mhz;
adjusted_dispclk_mhz = cga_dcn6_calculate_actual_dispclk_mhz(adjuster, dispclk_mhz);
adjusted_dispclk_mhz = cga_dcn6_adjust_to_dfs_clock_value_mhz(adjuster, adjusted_dispclk_mhz);
return adjusted_dispclk_mhz;
}
static void cga_dcn6_adjust_dppclks_mhz(const struct dml2_clock_granularity_adjuster *adjuster, unsigned int count,
const double *dppclks_mhz, double *adjusted_dppclks_mhz, double *adjusted_dpprefclk_mhz)
{
unsigned int i;
double dpprefclk_mhz;
dpprefclk_mhz = cga_dcn6_calculate_refclk_mhz(adjuster, dppclks_mhz, count);
*adjusted_dpprefclk_mhz = cga_dcn6_adjust_to_dfs_clock_value_mhz(adjuster, dpprefclk_mhz);
for (i = 0; i < count; i++)
adjusted_dppclks_mhz[i] = dga_dcn6_calculate_adjusted_dppclk_mhz(
adjuster, *adjusted_dpprefclk_mhz, dppclks_mhz[i]);
}
static void cga_dcn6_adjust_dtbclks_mhz(const struct dml2_clock_granularity_adjuster *adjuster, unsigned int count,
const double *dtbclks_mhz, double *adjusted_dtbclks_mhz, double *adjusted_dtbrefclk_mhz)
{
unsigned int i;
double dtbrefclk_mhz;
dtbrefclk_mhz = cga_dcn6_calculate_refclk_mhz(adjuster, dtbclks_mhz, count);
*adjusted_dtbrefclk_mhz = cga_dcn6_adjust_to_dfs_clock_value_mhz(adjuster, dtbrefclk_mhz);
for (i = 0; i < count; i++)
adjusted_dtbclks_mhz[i] = dga_dcn6_calculate_adjusted_dtbclk_mhz(
adjuster, dtbclks_mhz[i]);
}
static double cga_dcn6_adjust_dcfclk_deepsleep_mhz(const struct dml2_clock_granularity_adjuster *adjuster,
double dcfclk_deepsleep_mhz)
{
(void)adjuster;
return math_ceil2(dcfclk_deepsleep_mhz, CLOCK_UNIT_GRANULARITY);
}
static void cga_dcn6_initialize(const struct dml2_cga_initialize_in_out *in_out)
{
in_out->adjuster->dcn_downspread_percent = in_out->soc_bb->dcn_downspread_percent;
in_out->adjuster->dispclk_dppclk_vco_speed_mhz = in_out->soc_bb->dispclk_dppclk_vco_speed_mhz;
in_out->adjuster->dispclk_ramp_margin_percent = in_out->ip->dispclk_ramp_margin_percent;
in_out->adjuster->max_dispclk_mhz =
in_out->soc_bb->clk_table.dispclk.clk_values_khz[in_out->soc_bb->clk_table.dispclk.num_clk_values - 1] / 1000.0;
}
void cga_dcn6_create(struct dml2_clock_granularity_adjuster *adjuster)
{
adjuster->initialize = cga_dcn6_initialize;
adjuster->adjust_dispclk_mhz = cga_dcn6_adjust_dispclk_mhz;
adjuster->adjust_dppclks_mhz = cga_dcn6_adjust_dppclks_mhz;
adjuster->adjust_dtbclks_mhz = cga_dcn6_adjust_dtbclks_mhz;
adjuster->adjust_dcfclk_deepsleep_mhz = cga_dcn6_adjust_dcfclk_deepsleep_mhz;
}

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DML2_CGA_DCN6_H__
#define __DML2_CGA_DCN6_H__
#include "dml2_internal_shared_types.h"
void cga_dcn6_create(struct dml2_clock_granularity_adjuster *adjuster);
#endif /* #ifndef __DML2_CGA_DCN6_H__ */

View File

@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dml2_cga_factory.h"
#include "dml2_cga_dcn6.h"
bool dml2_cga_create(enum dml2_project_id project_id, struct dml2_clock_granularity_adjuster *adjuster)
{
bool result = false;
if (adjuster == NULL)
return false;
memset(adjuster, 0, sizeof(struct dml2_clock_granularity_adjuster));
switch (project_id) {
case dml2_project_dcn4x_stage1:
case dml2_project_dcn42:
case dml2_project_dcn4x_stage2:
case dml2_project_dcn4x_stage2_auto_drr_svp:
case dml2_project_dcn4x_utm:
case dml2_project_dcn5x:
case dml2_project_dcn5x_utm:
memset(adjuster, 0, sizeof(*adjuster));
result = true;
break;
case dml2_project_dcn6x_soc_var_a:
case dml2_project_dcn6x_soc_var_b:
cga_dcn6_create(adjuster);
result = true;
break;
case dml2_project_invalid:
default:
break;
}
return result;
}

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DML2_CGA_FACTORY_H__
#define __DML2_CGA_FACTORY_H__
#include "dml2_internal_shared_types.h"
bool dml2_cga_create(enum dml2_project_id project_id, struct dml2_clock_granularity_adjuster *adjuster);
#endif /* #ifndef __DML2_CGA_FACTORY_H__ */

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_CALCS_DSC_SHARED_TYPES_H__
#define __DML2_CORE_CALCS_DSC_SHARED_TYPES_H__
#include "dml_top_display_cfg_types.h"
// Delay and uncertainty structure
typedef struct {
int delay;
int uncertainty;
} delay_uncertainty_t;
// Latency structure with group, pipeline, and pixel delays
typedef struct {
int groups; // latency in groups - Number of groups needed to be sent before output can begin
int pipeline; // pipeline delay latency - Propagation delay through the bitstream construction layer in number of pixel containers
int pixels; // latency in pixels - Number of groups multiplied by cycles per group
// Extra variables needed for functional coverage
int additional_group_delay;
int lines_to_reach_ixd;
int groups_to_reach_ixd;
int slice_width_groups;
int initial_xmit_delay;
int number_of_lines_to_reach_ixd;
int slice_width_modified;
} latency_t;
#endif /* __DML2_CORE_CALCS_DSC_SHARED_TYPES_H__ */

View File

@@ -0,0 +1,426 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN5_CALCS_DCHUB_H__
#define __DML2_CORE_DCN5_CALCS_DCHUB_H__
#include "dml2_internal_shared_types.h"
void dcn5_calculate_max_det_and_min_compressed_buffer_size(
unsigned int ConfigReturnBufferSizeInKByte,
unsigned int ConfigReturnBufferSegmentSizeInKByte,
unsigned int ROBBufferSizeInKByte,
unsigned int MaxNumDPP,
unsigned int nomDETInKByteOverrideEnable, // VBA_DELTA, allow DV to override default DET size
unsigned int nomDETInKByteOverrideValue, // VBA_DELTA
bool is_mrq_present,
// Output
unsigned int *MaxTotalDETInKByte,
unsigned int *nomDETInKByte,
unsigned int *MinCompressedBufferSizeInKByte);
// ???
void dcn5_adjust_pixel_clock_for_progressive_to_interlace_unit(const struct dml2_display_cfg *display_cfg, bool ptoi_supported, double *PixelClockBackEnd);
void dcn5_calculate_swath_width(
const struct dml2_display_cfg *display_cfg,
bool ForceSingleDPP,
unsigned int NumberOfActiveSurfaces,
enum dml2_odm_mode ODMMode[],
unsigned int BytePerPixY[],
unsigned int BytePerPixC[],
unsigned int Read256BytesBlockHeightY[],
unsigned int Read256BytesBlockHeightC[],
unsigned int Read256BytesBlockWidthY[],
unsigned int Read256BytesBlockWidthC[],
bool surf_linear128_l[],
bool surf_linear128_c[],
unsigned int DPPPerSurface[],
// Output
unsigned int req_per_swath_ub_l[],
unsigned int req_per_swath_ub_c[],
unsigned int SwathWidthSingleDPPY[],
unsigned int SwathWidthSingleDPPC[],
unsigned int SwathWidthY[], // per-pipe
unsigned int SwathWidthC[], // per-pipe
unsigned int MaximumSwathHeightY[],
unsigned int MaximumSwathHeightC[],
unsigned int swath_width_luma_ub[], // per-pipe
unsigned int swath_width_chroma_ub[], // per-pipe
unsigned int swath_width_luma_ub_single_dpp[],
unsigned int swath_width_chroma_ub_single_dpp[]);
void dcn5_calculate_swath_and_det_configuration(struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_CalculateSwathAndDETConfiguration_params *p);
void dcn5_calculate_vm_row_and_swath(struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_CalculateVMRowAndSwath_params *p);
void dcn5_calculate_bytes_to_fetch_required_to_hide_latency(
struct dml2_core_calcs_calculate_bytes_to_fetch_required_to_hide_latency_params *p);
void dcn5_calculate_excess_vactive_bandwidth_required(
const struct dml2_display_cfg *display_cfg,
unsigned int num_active_planes,
unsigned int bytes_required_l[],
unsigned int bytes_required_c[],
/* outputs */
double excess_vactive_fill_bw_l[],
double excess_vactive_fill_bw_c[]);
void dcn5_calculate_cursor_req_attributes(
unsigned int cursor_width,
unsigned int cursor_bpp,
// output
unsigned int *cursor_lines_per_chunk,
unsigned int *cursor_bytes_per_line,
unsigned int *cursor_bytes_per_chunk,
unsigned int *cursor_bytes);
void dcn5_calculate_cursor_urgent_burst_factor(
unsigned int CursorBufferSize,
unsigned int CursorWidth,
unsigned int cursor_bytes_per_chunk,
unsigned int cursor_lines_per_chunk,
double LineTime,
double UrgentLatency,
double *UrgentBurstFactorCursor,
bool *NotEnoughUrgentLatencyHiding);
void dcn5_calculate_urgent_burst_factor(
const struct dml2_plane_parameters *plane_cfg,
unsigned int swath_width_luma_ub,
unsigned int swath_width_chroma_ub,
unsigned int SwathHeightY,
unsigned int SwathHeightC,
double LineTime,
double UrgentLatency,
double VRatio,
double VRatioC,
double BytePerPixelInDETY,
double BytePerPixelInDETC,
unsigned int DETBufferSizeY,
unsigned int DETBufferSizeC,
// Output
double *UrgentBurstFactorLuma,
double *UrgentBurstFactorChroma,
bool *NotEnoughUrgentLatencyHiding);
void dcn5_calculate_dcfclk_deep_sleep(
const struct dml2_display_cfg *display_cfg,
unsigned int NumberOfActiveSurfaces,
unsigned int BytePerPixelY[],
unsigned int BytePerPixelC[],
unsigned int SwathWidthY[],
unsigned int SwathWidthC[],
unsigned int DPPPerSurface[],
double PSCL_THROUGHPUT[],
double PSCL_THROUGHPUT_CHROMA[],
double Dppclk[],
double ReadBandwidthLuma[],
double ReadBandwidthChroma[],
unsigned int ReturnBusWidth,
// Output
double *DCFClkDeepSleep);
unsigned int dcn5_calculate_max_vstartup(
bool ptoi_supported,
unsigned int vblank_nom_default_us,
const struct dml2_timing_cfg *timing,
double write_back_delay_us);
void dcn5_calculate_mcache_setting(
struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_calculate_mcache_setting_params *p);
void dcn5_calculate_avg_bandwidth_required(
double *avg_bandwidth_required,
// input
unsigned int num_active_planes,
double ReadBandwidthLuma[],
double ReadBandwidthChroma[],
double cursor_bw[],
double dcc_dram_bw_nom_overhead_factor_p0[],
double dcc_dram_bw_nom_overhead_factor_p1[]);
void dcn5_calculate_hostvm_inefficiency_factor(
double *HostVMInefficiencyFactor,
double *HostVMInefficiencyFactorPrefetch,
bool gpuvm_enable,
bool hostvm_enable,
unsigned int remote_iommu_outstanding_translations,
unsigned int max_outstanding_reqs,
double urg_bandwidth_avail_active_pixel_and_vm,
double urg_bandwidth_avail_active_vm_only);
void dcn5_calculate_tdlut_setting(
struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_calculate_tdlut_setting_params *p);
void dcn5_calculate_extra_latency(
const struct dml2_display_cfg *display_cfg,
unsigned int ROBBufferSizeInKByte,
unsigned int RoundTripPingLatencyCycles,
unsigned int ReorderingBytes,
double DCFCLK,
double FabricClock,
unsigned int PixelChunkSizeInKByte,
double ReturnBW,
unsigned int NumberOfActiveSurfaces,
unsigned int NumberOfDPP[],
unsigned int dpte_group_bytes[],
unsigned int tdlut_bytes_per_group[],
double HostVMInefficiencyFactor,
double HostVMInefficiencyFactorPrefetch,
enum dml2_qos_param_type qos_type,
bool max_outstanding_when_urgent_expected,
unsigned int max_outstanding_requests,
unsigned int request_size_bytes_luma[],
unsigned int request_size_bytes_chroma[],
unsigned int MetaChunkSize,
unsigned int dchub_arb_to_ret_delay,
double Ttrip,
unsigned int hostvm_mode,
// output
double *ExtraLatency, // Tex
double *ExtraLatency_sr, // Tex_sr
double *ExtraLatencyPrefetch);
double dcn5_calculate_t_wait(
long reserved_vblank_time_ns,
double UrgentLatency,
double Ttrip,
double temp_read_or_ppt_blackout_us,
bool drr_enabled);
bool dcn5_calculate_prefetch_schedule(struct dml2_core_internal_scratch *scratch, struct dml2_core_calcs_CalculatePrefetchSchedule_params *p);
void dcn5_calculate_peak_bandwidth_required(
struct dml2_core_internal_scratch *s,
struct dml2_core_calcs_calculate_peak_bandwidth_required_params *p);
// ???
void dcn5_check_urgent_bandwidth_support(
double *frac_urg_bandwidth_nom,
bool *bandwidth_support_ok, // max of vm, prefetch, vactive all ok
double non_urg_bandwidth_required,
double urg_bandwidth_required,
double urg_bandwidth_available);
// ???
double dcn5_get_bandwidth_available_for_immediate_flip(
double urg_bandwidth_required, // no flip
double urg_bandwidth_available);
// ???
unsigned int dcn5_get_pipe_flip_bytes(
double hostvm_inefficiency_factor,
unsigned int vm_bytes,
unsigned int dpte_row_bytes,
unsigned int meta_row_bytes);
// ???
void dcn5_check_immediate_flip_bandwidth_support(
// Output
double *frac_urg_bandwidth_flip,
bool *flip_bandwidth_support_ok,
// Input
double urg_bandwidth_required_flip,
double non_urg_bandwidth_required_flip,
double urg_bandwidth_available);
void dcn5_calculate_dcc_configuration(
bool DCCEnabled,
bool DCCProgrammingAssumesScanDirectionUnknown,
enum dml2_source_format_class SourcePixelFormat,
unsigned int SurfaceWidthLuma,
unsigned int SurfaceWidthChroma,
unsigned int SurfaceHeightLuma,
unsigned int SurfaceHeightChroma,
unsigned int nomDETInKByte,
unsigned int RequestHeight256ByteLuma,
unsigned int RequestHeight256ByteChroma,
enum dml2_swizzle_mode TilingFormat,
unsigned int BytePerPixelY,
unsigned int BytePerPixelC,
double BytePerPixelDETY,
double BytePerPixelDETC,
enum dml2_rotation_angle RotationAngle,
// Output
enum dml2_core_internal_request_type *RequestLuma,
enum dml2_core_internal_request_type *RequestChroma,
unsigned int *MaxUncompressedBlockLuma,
unsigned int *MaxUncompressedBlockChroma,
unsigned int *MaxCompressedBlockLuma,
unsigned int *MaxCompressedBlockChroma,
unsigned int *IndependentBlockLuma,
unsigned int *IndependentBlockChroma);
void dcn5_calculate_flip_schedule(
struct dml2_core_internal_scratch *s,
bool iflip_enable,
bool use_lb_flip_bw,
double HostVMInefficiencyFactor,
double Tvm_trips_flip,
double Tr0_trips_flip,
double Tvm_trips_flip_rounded,
double Tr0_trips_flip_rounded,
bool GPUVMEnable,
double vm_bytes, // vm_bytes
double DPTEBytesPerRow, // dpte_row_bytes
double BandwidthAvailableForImmediateFlip,
unsigned int TotImmediateFlipBytes,
enum dml2_source_format_class SourcePixelFormat,
double LineTime,
double VRatio,
double VRatioChroma,
double Tno_bw_flip,
unsigned int dpte_row_height,
unsigned int dpte_row_height_chroma,
bool use_one_row_for_frame_flip,
unsigned int max_flip_time_us,
unsigned int max_flip_time_lines,
unsigned int per_pipe_flip_bytes,
unsigned int meta_row_bytes,
unsigned int meta_row_height,
unsigned int meta_row_height_chroma,
bool dcc_mrq_enable,
// Output
double *dst_y_per_vm_flip,
double *dst_y_per_row_flip,
double *final_flip_bw,
bool *ImmediateFlipSupportedForPipe);
void dcn5_calculate_watermarks_and_dram_speed_change_support(
struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_params *p);
bool dcn5_calculate_pstate_support_method(
enum dml2_pstate_method method,
double vactive_margin_us,
double reserved_vblank_us,
double blackout_us,
bool all_streams_blanked,
/* output */
enum dml2_pstate_change_support *surface_pstate_change_support);
void dcn5_calculate_pstate_keepout_dst_lines(
const struct dml2_display_cfg *display_cfg,
const struct dml2_core_internal_watermarks *watermarks,
unsigned int pstate_keepout_dst_lines[]);
void dcn5_calculate_vactive_det_fill_latency(
const struct dml2_display_cfg *display_cfg,
unsigned int num_active_planes,
unsigned int bytes_required_l[],
unsigned int bytes_required_c[],
double dcc_dram_bw_nom_overhead_factor_p0[],
double dcc_dram_bw_nom_overhead_factor_p1[],
double surface_read_bw_l[],
double surface_read_bw_c[],
double surface_avg_vactive_required_bw[],
double surface_peak_required_bw[],
/* output */
double vactive_det_fill_delay_us[]);
double dcn5_calculate_write_back_delay(
enum dml2_source_format_class WritebackPixelFormat,
double WritebackHRatio,
double WritebackVRatio,
unsigned int WritebackVTaps,
unsigned int WritebackVTapsChroma,
unsigned int WritebackDestinationWidth,
unsigned int WritebackDestinationHeight,
unsigned int WritebackSourceWidth,
unsigned int WritebackSourceHeight,
unsigned int HTotal);
void dcn5_calculate_meta_and_pte_times(struct dml2_core_shared_CalculateMetaAndPTETimes_params *p);
void dcn5_calculate_vm_group_and_request_times(
const struct dml2_display_cfg *display_cfg,
unsigned int NumberOfActiveSurfaces,
unsigned int BytePerPixelC[],
double dst_y_per_vm_vblank[],
double dst_y_per_vm_flip[],
unsigned int dpte_row_width_luma_ub[],
unsigned int dpte_row_width_chroma_ub[],
unsigned int vm_group_bytes[],
unsigned int dpde0_bytes_per_frame_ub_l[],
unsigned int dpde0_bytes_per_frame_ub_c[],
unsigned int tdlut_pte_bytes_per_frame[],
unsigned int meta_pte_bytes_per_frame_ub_l[],
unsigned int meta_pte_bytes_per_frame_ub_c[],
bool mrq_present,
// Output
double TimePerVMGroupVBlank[],
double TimePerVMGroupFlip[],
double TimePerVMRequestVBlank[],
double TimePerVMRequestFlip[]);
void dcn5_calculate_stutter_efficiency(struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_CalculateStutterEfficiency_params *p);
void dcn5_calculate_byte_per_pixel_and_block_sizes(
enum dml2_source_format_class SourcePixelFormat,
enum dml2_swizzle_mode SurfaceTiling,
unsigned int pitch_y,
unsigned int pitch_c,
// Output
unsigned int *BytePerPixelY,
unsigned int *BytePerPixelC,
double *BytePerPixelDETY,
double *BytePerPixelDETC,
unsigned int *BlockHeight256BytesY,
unsigned int *BlockHeight256BytesC,
unsigned int *BlockWidth256BytesY,
unsigned int *BlockWidth256BytesC,
unsigned int *MacroTileHeightY,
unsigned int *MacroTileHeightC,
unsigned int *MacroTileWidthY,
unsigned int *MacroTileWidthC,
bool *surf_linear128_l,
bool *surf_linear128_c);
void dml2_core_dcn5_calcs_cursor_dlg_reg(struct dml2_cursor_dlg_regs *cursor_dlg_regs, const struct dml2_get_cursor_dlg_reg *p);
unsigned int dcn5_calculate_vm_and_row_bytes(struct dml2_core_shared_calculate_vm_and_row_bytes_params *p);
void dcn5_get_pipe_regs(const struct dml2_display_cfg *display_cfg,
const struct dml2_core_internal_display_mode_lib *mode_lib,
struct dml2_dchub_per_pipe_register_set *out, int pipe_index, const struct dml2_utm_soc_bb *utm_soc_bb,
struct dml2_core_internal_scratch *s);
void dcn5_get_arb_params(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, const struct dml2_utm_soc_bb *utm_soc_bb, struct dml2_display_arb_regs *out);
void dcn5_get_watermarks(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, const struct dml2_utm_soc_bb *utm_soc_bb, struct dml2_dchub_watermark_regs *out);
void dcn5_rq_dlg_get_rq_reg(struct dml2_display_rq_regs *rq_regs,
const struct dml2_display_cfg *display_cfg,
const struct dml2_core_internal_display_mode_lib *mode_lib,
unsigned int pipe_idx);
void dcn5_get_mcif_arb_params(const struct dml2_core_internal_display_mode_lib *mode_lib,
struct dml2_mcif_global_register_set *out);
void dcn5_get_per_dwb_params(const struct dml2_display_cfg *display_cfg,
const struct dml2_core_internal_display_mode_lib *mode_lib,
struct dml2_mcif_per_pipe_register_set *out,
int stream_index,
int dwb_index);
#endif /* __DML2_CORE_DCN5_CALCS_DCHUB_H__ */

View File

@@ -0,0 +1,151 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN5_CALCS_DISPLAY_PIPE_H__
#define __DML2_CORE_DCN5_CALCS_DISPLAY_PIPE_H__
#include "dml2_internal_shared_types.h"
void dcn5_calculate_output_link(
struct dml2_core_internal_scratch *s,
double PHYCLK,
double PHYCLKD18,
double PHYCLKD32,
double Downspreading,
enum dml2_output_encoder_class Output,
enum dml2_output_format_class OutputFormat,
unsigned int HTotal,
unsigned int HActive,
double PixelClockBackEnd,
double ForcedOutputLinkBPP,
unsigned int DSCInputBitPerComponent,
unsigned int NumberOfDSCSlices,
double AudioSampleRate,
unsigned int AudioSampleLayout,
enum dml2_odm_mode ODMModeNoDSC,
enum dml2_odm_mode ODMModeDSC,
enum dml2_dsc_enable_option DSCEnable,
unsigned int OutputLinkDPLanes,
enum dml2_output_link_dp_rate OutputLinkDPRate,
// Output
bool *RequiresDSC,
bool *RequiresFEC,
double *OutBpp,
enum dml2_core_internal_output_type *OutputType,
enum dml2_core_internal_output_type_rate *OutputRate,
unsigned int *RequiredSlots);
void dcn5_calculate_odm_mode(
unsigned int MaximumPixelsPerLinePerDSCUnit,
unsigned int HActive,
enum dml2_output_format_class OutFormat,
enum dml2_output_encoder_class Output,
enum dml2_odm_mode ODMUse,
double MaxDispclk,
bool DSCEnable,
unsigned int TotalNumberOfActiveDPP,
unsigned int MaxNumDPP,
double PixelClock,
unsigned int MaximumSlicesPerDSCUnit,
unsigned int NumberOfDSCSlices,
unsigned int odm_combine_support_mask,
// Output
bool *TotalAvailablePipesSupport,
unsigned int *NumberOfDPP,
enum dml2_odm_mode *ODMMode,
double *RequiredDISPCLKPerSurface);
double dcn5_calculate_required_dtbclk(
bool DSCEnable,
double PixelClock,
enum dml2_output_format_class OutputFormat,
double OutputBpp,
unsigned int DSCSlices,
unsigned int HTotal,
unsigned int HActive,
unsigned int AudioRate,
unsigned int AudioLayout);
double dcn5_calculate_required_dispclk(
enum dml2_odm_mode ODMMode,
double PixelClock,
bool isTMDS420);
double dcn5_calculate_write_back_dispclk(
enum dml2_source_format_class WritebackPixelFormat,
double PixelClock,
enum dml2_odm_mode ODMMode,
double WritebackHRatio,
double WritebackVRatio,
unsigned int WritebackHTaps,
unsigned int WritebackVTaps,
unsigned int WritebackHTapsChroma,
unsigned int WritebackVTapsChroma,
unsigned int WritebackSourceWidth,
unsigned int WritebackDestinationWidth,
unsigned int HTotal,
unsigned int WritebackLineBufferSize);
unsigned int dcn5_calculate_dsc_delay_requirement(
bool DSCEnabled,
enum dml2_odm_mode ODMMode,
unsigned int DSCInputBitPerComponent,
double OutputBpp,
unsigned int HActive,
unsigned int HTotal,
unsigned int NumberOfDSCSlices,
enum dml2_output_format_class OutputFormat,
enum dml2_output_encoder_class Output,
double PixelClock,
double PixelClockBackEnd,
bool use_legacy_dsc_delay_formula);
void dcn5_calculate_single_pipe_dppclk_and_scl_throughput(
double HRatio,
double HRatioChroma,
double VRatio,
double VRatioChroma,
double MaxDCHUBToPSCLThroughput,
double MaxPSCLToLBThroughput,
double PixelClock,
enum dml2_source_format_class SourcePixelFormat,
unsigned int HTaps,
unsigned int HTapsChroma,
unsigned int VTaps,
unsigned int VTapsChroma,
// Output
double *PSCL_THROUGHPUT,
double *PSCL_THROUGHPUT_CHROMA,
double *DPPCLKUsingSingleDPP);
void dcn5_calculate_pixel_delivery_times(
const struct dml2_display_cfg *display_cfg,
unsigned int NoOfDPP[DML2_MAX_PLANES],
unsigned int NumberOfActiveSurfaces,
double VRatioPrefetchY[],
double VRatioPrefetchC[],
unsigned int swath_width_luma_ub[],
unsigned int swath_width_chroma_ub[],
double PSCL_THROUGHPUT[],
double PSCL_THROUGHPUT_CHROMA[],
double Dppclk[],
double DCFCLKDeepSleep,
unsigned int BytePerPixelY[],
unsigned int BytePerPixelC[],
unsigned int req_per_swath_ub_l[],
unsigned int req_per_swath_ub_c[],
// Output
double DisplayPipeLineDeliveryTimeLuma[],
double DisplayPipeLineDeliveryTimeChroma[],
double DisplayPipeLineDeliveryTimeLumaPrefetch[],
double DisplayPipeLineDeliveryTimeChromaPrefetch[],
double DisplayPipeRequestDeliveryTimeLuma[],
double DisplayPipeRequestDeliveryTimeChroma[],
double DisplayPipeRequestDeliveryTimeLumaPrefetch[],
double DisplayPipeRequestDeliveryTimeChromaPrefetch[]);
#endif /* __DML2_CORE_DCN5_CALCS_DISPLAY_PIPE_H__ */

View File

@@ -0,0 +1,501 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved.
#include "dml2_debug.h"
#include "dml2_core_dcn5_calcs_dsc_latency.h"
#include "lib_float_math.h"
/* -------------------------------------------------------------------------
* Shared DSC sub-functions (static) identical for legacy and updated paths
* ------------------------------------------------------------------------- */
// function to compute the dscc_pcl (i.e., pixel compression layer) latency in terms of groups (output is actually in terms of dispclk)
static int dscc_pcl_compute_delay(enum dml2_output_format_class pixel_format, int num_slices)
{
int dispclk_per_dscclk;
int delay;
//1 slice configuration uses a single slice processor (/3 clock)
if (num_slices == 1) {
dispclk_per_dscclk = 3;
} else { //greater than 1 slice configuration uses two slice processor (/6 clock)
dispclk_per_dscclk = 6;
}
// N422 and N420 process 2x pixels per clock
if (pixel_format == dml2_420 || pixel_format == dml2_n422) {
dispclk_per_dscclk *= 2;
}
//fixed delay though dscc_pcl
delay = 7;
delay *= dispclk_per_dscclk;
return delay;
}
// function to compute dscc_bcl layer delay in terms of groups + pipeline delay and pixels (444 format pixels)
// returns the delay in groups of pixels, pipeline delay in cycles, and individual pixels
// valid bpc = source bits per component in the set of {8, 10, 12}
// valid bpp = increments of 1/16 of a bit
// min = 6/7/8 in N420/N422/444, respectively
// max = such that compression is 1:1
// valid slice_width = number of pixels per slice line, must be less than or equal to `DSC_MAX_WIDTH/num_slices (or 4096/num_slices in 420 mode)
// valid num_slices = number of slices in the horiziontal direction per DSC engine in the set of {1, 2, 3, 4}
// valid pixel_format = pixel/color format in the set of {dml2_444, dml2_s422, dml2_n422, dml2_420}
// note: implementation takes 4 cycles to process a group in N422 mode or 3 cycles in all other pixel formats
static void dscc_bcl_compute_delay(latency_t *p, int bpc, float bpp, int slice_width, int num_slices, enum dml2_output_format_class pixel_format, int initial_xmit_delay_offset, int group_delay_after_initial_xmit_delay_override_en, int group_delay_after_initial_xmit_delay)
{
//fixed value
int rc_model_size = 8192;
//latency calculation variables
int pixels_per_clock;
int padding_pixels;
int ssm_group_priming_delay;
int ssm_pipeline_delay;
int obsm_pipeline_delay;
int slice_padded_pixels;
int ixd_plus_padding;
int ixd_plus_padding_groups;
int cycles_per_group;
int groups_per_bcl_cycle;
int syntax_elements_per_group;
int group_delay;
int pipeline_delay;
int pixel_delay;
int additional_group_delay;
int lines_to_reach_ixd_adjusted;
int groups_to_reach_ixd_adjusted;
int slice_width_groups;
int initial_xmit_delay;
int lines_to_reach_ixd;
int slice_width_modified;
//N422/N420 operate at 2 pixels per clock
if (pixel_format == dml2_n422 || pixel_format == dml2_420) {
pixels_per_clock = 2;
} else { //all other modes operate at 1 pixel per clock
pixels_per_clock = 1;
}
//initial transmit delay as per PPS. If debugging, ensure register's
//initial_xmit delay matches the final initial_xmit_delay below
initial_xmit_delay = (int)math_round((double)(rc_model_size / 2.0 / bpp / pixels_per_clock));
//slice width as seen by dscc_bcl in pixels or pixels pairs (depending on number of pixels per pixel container based on pixel format)
slice_width_modified = (pixel_format == dml2_n422 || pixel_format == dml2_420) ? slice_width/2 : slice_width;
//initial_xmit_delay is increased by one under specific conditions as per pps spreadsheet
padding_pixels = ((slice_width_modified % 3) != 0) ? (3 - (slice_width_modified % 3)) * (initial_xmit_delay / slice_width_modified) : 0;
if ((3.0 * pixels_per_clock * bpp) >= (((initial_xmit_delay + 2) / 3) * (3 + (pixel_format == dml2_n422)))) {
if ((initial_xmit_delay + padding_pixels) % 3 == 1)
initial_xmit_delay++;
}
//increase initial xmit delay by the offset value
initial_xmit_delay += initial_xmit_delay_offset;
//sub-stream multiplexer balance fifo priming delay in groups as per dsc standard
switch (bpc) {
case 8:
ssm_group_priming_delay = 83;
break;
case 10:
ssm_group_priming_delay = 91;
break;
case 12:
ssm_group_priming_delay = 115;
break;
case 14:
ssm_group_priming_delay = 123;
break;
case 16:
ssm_group_priming_delay = 128;
break;
default:
DML_LOG_VERBOSE("ERROR: BPC is not a valid value. bpc = %d", bpc);
ssm_group_priming_delay = 83; // Default to 8bpc value
break;
}
//slice width in groups is rounded up to the nearest group as DSC adds padded pixels such that there are an integer number of groups per slice
slice_width_groups = (slice_width_modified + 2) / 3;
//determine number of padded pixels in the last group of a slice line, computed as
slice_padded_pixels = 3 * slice_width_groups - slice_width_modified;
//determine integer number of complete slice lines required to reach initial transmit delay without ssm delay considered
lines_to_reach_ixd = initial_xmit_delay / slice_width_modified;
//increase initial transmit delay by the number of padded pixels added to a slice line multiplied by the integer number of complete lines to reach initial transmit delay
//this step is necessary as each padded pixel added takes up a clock cycle but is not included in the initialXmitDelay and, therefore, adds to the overall delay
ixd_plus_padding = initial_xmit_delay + slice_padded_pixels * lines_to_reach_ixd;
//convert the the padded initial transmit delay from pixels to groups by rounding up to the nearest group as DSC processes in groups of pixels
ixd_plus_padding_groups = (ixd_plus_padding + 2) / 3;
//number of groups required for a slice to reach initial transmit delay is the sum of the padded initial transmit delay plus the ssm group priming delay
groups_to_reach_ixd_adjusted = ixd_plus_padding_groups + ssm_group_priming_delay;
//number of lines required to reach padded initial transmit delay in groups in slices to the left of the last horizontal slice
//needs to be rounded up as a complete slice lines are buffered prior to initial transmit delay being reached in the last horizontal slice
lines_to_reach_ixd_adjusted = (groups_to_reach_ixd_adjusted + slice_width_groups - 1) / slice_width_groups; //round up lines to reach ixd to next
//determine if there are non-zero number of pixels reached in the group where initial transmit delay is reached
//an additional group time (i.e., 3 pixel times) is required before the first output if there are no additional pixels beyond initial transmit delay
additional_group_delay = ((initial_xmit_delay - lines_to_reach_ixd * slice_width_modified) % 3) == 0 ? 1 : 0;
//number of pipeline delay cycles in the ssm block (can be determined empirically or analytically by inspecting the ssm block), 1 cycle for mg_dm_ra flopping, 1 cycle for ssefc flopping, 2 cycles for memory read pipeline
ssm_pipeline_delay = 4;
//number of pipe delay cycles in the obsm block (can be determined empirically or analytically by inspecting the obsm block), 1 cycle for flopping data out
obsm_pipeline_delay = 1;
//a group of pixels is worth 6 pixels in N422/N420 mode or 3 pixels in all other modes
cycles_per_group = (pixel_format == dml2_n422 || pixel_format == dml2_420) ? 6 : 3;
//number of groups processed per bcl cycle where a bcl cycle consists of processing the set of syntax elements at the input (1 syntax element in 1 slice config or 2 syntax elements in a 2 or more slice config)
groups_per_bcl_cycle = (num_slices > 1) ? 2 : 1;
//number of syntax elements per group is 4 in N422 or 3 in all other pixel formats
syntax_elements_per_group = (pixel_format == dml2_n422) ? 4 : 3;
//delay of the bit stream contruction layer in pixels is the sum of:
//1. number of pixel containers in a slice line multiplied by the number of lines required to reach initial transmit delay multiplied by number of slices to the left of the last horizontal slice
group_delay = (lines_to_reach_ixd_adjusted * slice_width_groups * (num_slices - 1));
//2. number of pixel containers required to reach initial transmit delay (specifically, in the last horizontal slice), value of groups_to_reach_ixd_adjusted is multiplied by groups_per_bcl_cycle (processing rate is 1/2 in 2 or more slice config)
group_delay += (lines_to_reach_ixd_adjusted - 1) * slice_width_groups;
group_delay += groups_per_bcl_cycle * (groups_to_reach_ixd_adjusted - ((lines_to_reach_ixd_adjusted - 1) * slice_width_groups));
//3. additional group of delay if initial transmit delay is reached exactly in a group
group_delay += additional_group_delay;
//4. additional group delay if slice width is not evenly divisible by 2, applicable when initial xmit delay is met on the ssm output 1
if (num_slices >= 2) {
if ((num_slices % 2) == 0 || lines_to_reach_ixd_adjusted % 2 == 0) {
group_delay += (slice_width_groups % 2) != 0;
}
}
//5. additional 1 group if slice count is 3 or more, slice count is odd, and initial transmit delay is reached on ssm output 0
if (group_delay_after_initial_xmit_delay_override_en == 0) {
if (num_slices >= 3) {
if ((num_slices % 2) == 1) {
if (lines_to_reach_ixd_adjusted % 2 == 1) {
group_delay += 1;
}
}
}
} else { //use programmed delay
group_delay += group_delay_after_initial_xmit_delay;
//reduce group delay by 1 if initial xmit delay is reached on the first slice stream
if (num_slices >= 3) {
if ((num_slices % 2) == 1) {
if (lines_to_reach_ixd_adjusted % 2 == 1) {
group_delay -= -1;
}
}
}
}
//6. ssm and obsm pipeline delay (i.e., clock cycles of delay)
pipeline_delay = ssm_pipeline_delay + obsm_pipeline_delay;
//pixel delay is group_delay (converted to pixels) + pipeline, however, first group (or first pair) of groups in 1 slice config (or 2 or more slice config) is a special case since it is processed as soon as it arrives (i.e., in syntax_elements_per_group cycles * groups_per_bcl_cycle)
pixel_delay = ((group_delay - groups_per_bcl_cycle) * cycles_per_group) + (syntax_elements_per_group * groups_per_bcl_cycle) + pipeline_delay;
//map delay values to return data structure
p->groups = group_delay;
p->pipeline = pipeline_delay;
p->pixels = pixel_delay;
// Extra variables for functional coverage
p->additional_group_delay = additional_group_delay;
p->lines_to_reach_ixd = lines_to_reach_ixd_adjusted;
p->groups_to_reach_ixd = groups_to_reach_ixd_adjusted;
p->slice_width_groups = slice_width_groups;
p->initial_xmit_delay = initial_xmit_delay;
p->number_of_lines_to_reach_ixd = lines_to_reach_ixd;
p->slice_width_modified = slice_width_modified;
return;
}
// function to compute input delay (delay from DSC pixel input to DSCCIF output)
// returns the delay
// valid pixel_format = pixel/color format in the set of {dml2_444, dml2_s422, dml2_n422, dml2_420}
static int dsc_compute_input_pixel_delay(enum dml2_output_format_class pixel_format, int num_slices, int dispclk_dynamic_gating_en)
{
// initialize latency value
int delay = 0;
// sfr
delay += 2;
// dscc - vblank clock control for dispclk
if (dispclk_dynamic_gating_en == 1) {
//in N420, pixel containers arrive every other cycle so the downstream ends up getting 2 pixel containers back to back for which the logic can absorb (i.e., hide the stall)
if (pixel_format != dml2_420) {
delay += 1; //1 cycle delay from first set of pixels until the clock turns on
}
}
// dsccif, delay values for N422/S422 only, no delay for N444/N420
if (pixel_format == dml2_n422) {
// extra delay required to collect a pair of pixels
delay += 1;
} else if (pixel_format == dml2_s422) {
// extra delay required to collect pixels for interpolation
delay += 4;
}
//dsccif, base delay in derasterization block
delay += 1;
//2 slices or more configuration, derasterization enabled
if (num_slices >= 2) {
delay += 4; // ram 1 cycle write, ram 2 cycle read, 1 cycle prefetch buffer
};
// return result
return delay;
}
/* -------------------------------------------------------------------------
* Output pixel delay legacy and updated formulas differ here
* ------------------------------------------------------------------------- */
// function to compute output pixel delay (delay from DSCCIF output to DSC output) — legacy DCN5 formula
// returns the delay and uncertainty
// valid pixel_format = pixel/color format in the set of {dml2_444, dml2_s422, dml2_n422, dml2_420}
static delay_uncertainty_t legacy_dsc_compute_output_pixel_delay(enum dml2_output_format_class pixel_format, int num_slices, int dscclk_dynamic_gating_en)
{
// initialize latency value
int dispclk_per_dscclk;
int delay = 0;
int uncertainty = 0;
delay_uncertainty_t delay_uncertainty;
//1 slice configuration uses a single slice processor (/3 clock)
if (num_slices == 1) {
dispclk_per_dscclk = 3;
} else { //greater than 1 slice configuration uses two slice processor (/6 clock)
dispclk_per_dscclk = 6;
}
// N422 and N420 process 2x pixels per clock
if (pixel_format == dml2_420 || pixel_format == dml2_n422) {
dispclk_per_dscclk *= 2;
}
// dscc - input deserializer
//1 slice configuration has a single slice stream, 3 cycles (multiplied by pixels per container) to accumulate 1 group
if (num_slices == 1) {
delay += 3;
//N422/N420 single slice configuration is a special case; pixel containers arrive every other cycle and data is output on the cycle after every 3rd data transfer
//this causes 2 extra cycles of delay (i.e., not 3)
if (pixel_format == dml2_420 || pixel_format == dml2_n422) {
delay += 2;
}
} else { //greater than 1 slice configration has two slice streams, 6 cycles to accumulate 2 groups
//no need to multiply by pixels per container as first half of first slice line is output faster by dscc_if as
//the second slice stream has no started yet so we do not need to wait for those pixels to appear at the input
delay += 6;
}
// dscc - input cdc fifo begin
delay += 1; // flop data/update address
uncertainty += 2 * dispclk_per_dscclk; //(2 cycles of transport + metastability delay) * x dscclks per dispclk
uncertainty += 1 * dispclk_per_dscclk; // 1st stage of sync cell flopping has 1 cycle of uncertainty due to clock skew * dscclks per dispclk
delay += 2 * dispclk_per_dscclk; // 2nd and 3rd stage of sync cell flopping have 2 cycles * x dscclks per dispclk
delay += 1 * dispclk_per_dscclk; // 1 flop data out * x dscclks per dispclk
// dscc - vblank clock control for dscclk
if (dscclk_dynamic_gating_en == 1) {
delay += 1 * dispclk_per_dscclk; //1 cycle delay from first set of pixels until the clock turns on
}
// dscc_top - engine logic excluded, see other formula
// dscc - syntax element cdc fifo begin
delay += 1 * dispclk_per_dscclk; // flop data/update address * 6 dscclks per dispclk
uncertainty += 2; // 2 cycles of transport + metastability delay
uncertainty += 1; // 1st stage of sync cell flopping has 1 cycle of uncertainty due to clock skew
delay += 2; // 2nd and 3rd stage of sync cell flopping have 2 cycles * x dscclks per dispclk
delay += 1; // 1 flop data out
// dscc_bcl - bitstream construction layer logic exclued, see other formula
// sft
delay += 1;
// return delay and uncertainty
delay_uncertainty.delay = delay;
delay_uncertainty.uncertainty = uncertainty;
return delay_uncertainty;
}
// function to compute output pixel delay (delay from DSCCIF output to DSC output) — updated formula (DCN5.1 and newer)
// returns the delay and uncertainty
// valid pixel_format = pixel/color format in the set of {N444, S422, N422, N420}
static delay_uncertainty_t dsc_compute_output_pixel_delay(enum dml2_output_format_class pixel_format, int num_slices, int dscclk_dynamic_gating_en)
{
// initialize latency value
int dispclk_per_dscclk;
int delay = 0;
int uncertainty = 0;
delay_uncertainty_t delay_uncertainty;
//1 slice configuration uses a single slice processor (/3 clock)
if (num_slices == 1) {
dispclk_per_dscclk = 3;
} else { //greater than 1 slice configuration uses two slice processor (/6 clock)
dispclk_per_dscclk = 6;
}
// N422 and N420 process 2x pixels per clock
if (pixel_format == dml2_420 || pixel_format == dml2_n422) {
dispclk_per_dscclk *= 2;
}
// dscc - input deserializer
//1 slice configuration has a single slice stream, 3 cycles (multiplied by pixels per container) to accumulate 1 group
if (num_slices == 1) {
delay += 3;
//N422/N420 single slice configuration is a special case; pixel containers arrive every other cycle and data is output on the cycle after every 3rd data transfer
//this causes 2 extra cycles of delay (i.e., not 3)
if (pixel_format == dml2_420 || pixel_format == dml2_n422) {
delay += 2;
}
} else { //greater than 1 slice configration has two slice streams, 6 cycles to accumulate 2 groups
//no need to multiply by pixels per container as first half of first slice line is output faster by dscc_if as
//the second slice stream has no started yet so we do not need to wait for those pixels to appear at the input
//it takes 12 cycles for 6 pairs to arrive
if (pixel_format == dml2_n422) {
delay += 12;
} else {
delay += 6;
}
}
// dscc - input cdc fifo begin
delay += 1; // flop data/update address
uncertainty += 1 * dispclk_per_dscclk; // 1st stage of sync cell flopping has 1 cycle of uncertainty due to clock skew * dscclks per dispclk
uncertainty += 1 * dispclk_per_dscclk; //(1 cycle metastability delay, src synchronous flop) * x dscclks per dispclk
delay += 2 * dispclk_per_dscclk; // 2nd and 3rd stage of sync cell flopping have 2 cycles * x dscclks per dispclk
// dscc - vblank clock control for dscclk
if (dscclk_dynamic_gating_en == 1) {
uncertainty += 1 * dispclk_per_dscclk; //(1 cycle metastability delay, src synchronous flop) * x dscclks per dispclk
uncertainty += 1 * dispclk_per_dscclk; // 1st stage of sync cell flopping has 1 cycle of uncertainty due to clock skew * dscclks per dispclk
//counting this real synchronizer delay as uncertainty because it happens in parallel with dsccif/pixel serializer logic
uncertainty += 2 * dispclk_per_dscclk; // 2nd and 3rd stage of sync cell flopping have 2 cycles * x dscclks per dispclk
uncertainty += 1 * dispclk_per_dscclk; //1 cycle delay from first set of pixels until the clock turns on
}
// dscc_top - engine logic excluded, see other formula
// dscc - syntax element cdc fifo begin
delay += 1 * dispclk_per_dscclk; // flop data/update address * 6 dscclks per dispclk
uncertainty += 1; // 1st stage of sync cell flopping has 1 cycle of uncertainty due to clock skew
uncertainty += 1; //1 cycle metastability delay, src synchronous flop
delay += 2; // 2nd and 3rd stage of sync cell flopping have 2 cycles
delay += 1; // 1 flop data out
// dscc_bcl - bitstream construction layer logic exclued, see other formula
// sft
delay += 1;
// return delay and uncertainty
delay_uncertainty.delay = delay;
delay_uncertainty.uncertainty = uncertainty;
return delay_uncertainty;
}
/* -------------------------------------------------------------------------
* Public functions
* ------------------------------------------------------------------------- */
// dcn5_dsc_compute_delay_legacy - DSC delay using the original DCN5 formula
// valid bpc = source bits per component in the set of {8, 10, 12}
// valid bpp = increments of 1/16 of a bit
// min = 6/7/8 in N420/N422/444, respectively
// max = such that compression is 1:1
// valid slice_width = number of pixels per slice line, must be less than or equal to `DSC_MAX_WIDTH/num_slices (or 4096/num_slices in 420 mode)
// valid num_slices = number of slices in the horiziontal direction per DSC engine in the set of {1, 2, 3, 4}
// valid pixel_format = pixel/color format in the set of {N444, S422, N422, N420}
void dcn5_dsc_compute_delay_legacy(delay_uncertainty_t *p, int bpc, float bpp, int slice_width, int num_slices, enum dml2_output_format_class pixel_format, int dscclk_dynamic_gating_en, int dispclk_dynamic_gating_en, int initial_xmit_delay_offset, int group_delay_after_initial_xmit_delay_override_en, int group_delay_after_initial_xmit_delay)
{
// initialize
int total_delay = 0;
int total_uncertainty = 0;
delay_uncertainty_t delay_uncertainty;
latency_t dscc_bcl_latency;
// compute input pixel delay
total_delay += dsc_compute_input_pixel_delay(pixel_format, num_slices, dispclk_dynamic_gating_en);
// dscc_pcl delay
total_delay += dscc_pcl_compute_delay(pixel_format, num_slices);
// dscc_bcl delay
dscc_bcl_compute_delay(&dscc_bcl_latency, bpc, bpp, slice_width, num_slices, pixel_format, initial_xmit_delay_offset, group_delay_after_initial_xmit_delay_override_en, group_delay_after_initial_xmit_delay);
total_delay += dscc_bcl_latency.pixels;
// compute output delay
delay_uncertainty = legacy_dsc_compute_output_pixel_delay(pixel_format, num_slices, dscclk_dynamic_gating_en);
delay_uncertainty.delay += total_delay;
delay_uncertainty.uncertainty += total_uncertainty;
p->delay = delay_uncertainty.delay;
p->uncertainty = delay_uncertainty.uncertainty;
return;
}
// dcn5_dsc_compute_delay - DSC delay using the updated formula (DCN5.1 and newer)
// valid bpc = source bits per component in the set of {8, 10, 12}
// valid bpp = increments of 1/16 of a bit
// min = 6/7/8 in N420/N422/444, respectively
// max = such that compression is 1:1
// valid slice_width = number of pixels per slice line, must be less than or equal to `DSC_MAX_WIDTH/num_slices (or 4096/num_slices in 420 mode)
// valid num_slices = number of slices in the horiziontal direction per DSC engine in the set of {1, 2, 3, 4}
// valid pixel_format = pixel/color format in the set of {N444, S422, N422, N420}
void dcn5_dsc_compute_delay(delay_uncertainty_t *p, int bpc, float bpp, int slice_width, int num_slices, enum dml2_output_format_class pixel_format, int dscclk_dynamic_gating_en, int dispclk_dynamic_gating_en, int initial_xmit_delay_offset, int group_delay_after_initial_xmit_delay_override_en, int group_delay_after_initial_xmit_delay)
{
// initialize
int total_delay = 0;
int total_uncertainty = 0;
delay_uncertainty_t delay_uncertainty;
latency_t dscc_bcl_latency;
// compute input pixel delay
total_delay += dsc_compute_input_pixel_delay(pixel_format, num_slices, dispclk_dynamic_gating_en);
// dscc_pcl delay
total_delay += dscc_pcl_compute_delay(pixel_format, num_slices);
// dscc_bcl delay
dscc_bcl_compute_delay(&dscc_bcl_latency, bpc, bpp, slice_width, num_slices, pixel_format, initial_xmit_delay_offset, group_delay_after_initial_xmit_delay_override_en, group_delay_after_initial_xmit_delay);
total_delay += dscc_bcl_latency.pixels;
// compute output delay
delay_uncertainty = dsc_compute_output_pixel_delay(pixel_format, num_slices, dscclk_dynamic_gating_en);
delay_uncertainty.delay += total_delay;
delay_uncertainty.uncertainty += total_uncertainty;
p->delay = delay_uncertainty.delay;
p->uncertainty = delay_uncertainty.uncertainty;
return;
}

View File

@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2026 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN5_CALCS_DSC_LATENCY_H__
#define __DML2_CORE_DCN5_CALCS_DSC_LATENCY_H__
#include "dml2_external_lib_deps.h"
#include "dml2_core_calcs_dsc_shared_types.h"
// dcn5_dsc_compute_delay - DSC delay using the updated formula (DCN5.1 and newer)
void dcn5_dsc_compute_delay(delay_uncertainty_t *p, int bpc, float bpp, int slice_width, int num_slices,
enum dml2_output_format_class pixel_format, int dscclk_dynamic_gating_en, int dispclk_dynamic_gating_en,
int initial_xmit_delay_offset, int group_delay_after_initial_xmit_delay_override_en,
int group_delay_after_initial_xmit_delay);
// dcn5_dsc_compute_delay_legacy - DSC delay using the original DCN5 formula
void dcn5_dsc_compute_delay_legacy(delay_uncertainty_t *p, int bpc, float bpp, int slice_width, int num_slices,
enum dml2_output_format_class pixel_format, int dscclk_dynamic_gating_en, int dispclk_dynamic_gating_en,
int initial_xmit_delay_offset, int group_delay_after_initial_xmit_delay_override_en,
int group_delay_after_initial_xmit_delay);
#endif /* __DML2_CORE_DCN5_CALCS_DSC_LATENCY_H__ */

View File

@@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_core_dcn5_funcs_initialize.h"
#include "dml2_debug.h"
static struct dml2_core_ip_params core_dcn5_ip_caps_base = {
0
};
static void patch_ip_caps_with_explicit_ip_params(struct dml2_ip_capabilities *ip_caps, const struct dml2_core_ip_params *ip_params)
{
ip_caps->pipe_count = ip_params->max_num_dpp;
ip_caps->otg_count = ip_params->max_num_otg;
ip_caps->num_dsc = ip_params->num_dsc;
ip_caps->max_num_dp2p0_streams = ip_params->max_num_dp2p0_streams;
ip_caps->max_num_dp2p0_outputs = ip_params->max_num_dp2p0_outputs;
ip_caps->max_num_hdmi_frl_outputs = ip_params->max_num_hdmi_frl_outputs;
ip_caps->max_num_wb = ip_params->max_num_wb;
ip_caps->rob_buffer_size_kbytes = ip_params->rob_buffer_size_kbytes;
ip_caps->config_return_buffer_size_in_kbytes = ip_params->config_return_buffer_size_in_kbytes;
ip_caps->config_return_buffer_segment_size_in_kbytes = ip_params->config_return_buffer_segment_size_in_kbytes;
ip_caps->meta_fifo_size_in_kentries = ip_params->meta_fifo_size_in_kentries;
ip_caps->compressed_buffer_segment_size_in_kbytes = ip_params->compressed_buffer_segment_size_in_kbytes;
ip_caps->cursor_buffer_size = ip_params->cursor_buffer_size;
ip_caps->max_flip_time_us = ip_params->max_flip_time_us;
ip_caps->max_flip_time_lines = ip_params->max_flip_time_lines;
ip_caps->hostvm_mode = ip_params->hostvm_mode;
ip_caps->vblank_nom_default_us = ip_params->vblank_nom_default_us;
}
static void patch_ip_params_with_ip_caps(struct dml2_core_ip_params *ip_params, const struct dml2_ip_capabilities *ip_caps)
{
ip_params->max_num_dpp = ip_caps->pipe_count;
ip_params->max_num_opp = ip_caps->pipe_count;
ip_params->max_num_otg = ip_caps->otg_count;
ip_params->num_dsc = ip_caps->num_dsc;
ip_params->max_num_dp2p0_streams = ip_caps->max_num_dp2p0_streams;
ip_params->max_num_dp2p0_outputs = ip_caps->max_num_dp2p0_outputs;
ip_params->max_num_hdmi_frl_outputs = ip_caps->max_num_hdmi_frl_outputs;
ip_params->max_num_wb = ip_caps->max_num_wb;
ip_params->rob_buffer_size_kbytes = ip_caps->rob_buffer_size_kbytes;
ip_params->config_return_buffer_size_in_kbytes = ip_caps->config_return_buffer_size_in_kbytes;
ip_params->config_return_buffer_segment_size_in_kbytes = ip_caps->config_return_buffer_segment_size_in_kbytes;
ip_params->meta_fifo_size_in_kentries = ip_caps->meta_fifo_size_in_kentries;
ip_params->compressed_buffer_segment_size_in_kbytes = ip_caps->compressed_buffer_segment_size_in_kbytes;
ip_params->cursor_buffer_size = ip_caps->cursor_buffer_size;
ip_params->max_flip_time_us = ip_caps->max_flip_time_us;
ip_params->max_flip_time_lines = ip_caps->max_flip_time_lines;
ip_params->hostvm_mode = ip_caps->hostvm_mode;
ip_params->vblank_nom_default_us = ip_caps->vblank_nom_default_us;
}
bool dml2_core_dcn5_funcs_initialize(struct dml2_core_initialize_in_out *in_out)
{
struct dml2_core_instance *core = in_out->instance;
DML_LOG_DEBUG("DML_CORE::%s enter\n", __func__);
if (in_out->explicit_ip_bb && in_out->explicit_ip_bb_size > 0) {
memcpy(&core->clean_me_up.mode_lib.ip, in_out->explicit_ip_bb, in_out->explicit_ip_bb_size);
patch_ip_caps_with_explicit_ip_params(in_out->ip_caps, in_out->explicit_ip_bb);
} else {
memcpy(&core->clean_me_up.mode_lib.ip, &core_dcn5_ip_caps_base, sizeof(struct dml2_core_ip_params));
patch_ip_params_with_ip_caps(&core->clean_me_up.mode_lib.ip, in_out->ip_caps);
core->clean_me_up.mode_lib.ip.imall_supported = false;
}
memcpy(&core->clean_me_up.mode_lib.ip_caps, in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
core->utm_soc_bb = in_out->utm_soc_bb;
core->clean_me_up.mode_lib.ip.use_legacy_dsc_delay_formula =
(in_out->project_id != dml2_project_dcn5x_utm);
return true;
}

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN5_FUNCS_INITIALIZE_H__
#define __DML2_CORE_DCN5_FUNCS_INITIALIZE_H__
#include "dml2_internal_shared_types.h"
bool dml2_core_dcn5_funcs_initialize(struct dml2_core_initialize_in_out *in_out);
#endif /* __DML2_CORE_DCN5_FUNCS_INITIALIZE_H__ */

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024-2025 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN5_FUNCS_MODE_PROGRAMMING_H__
#define __DML2_CORE_DCN5_FUNCS_MODE_PROGRAMMING_H__
#include "dml2_internal_shared_types.h"
enum dml2_status dml2_core_dcn5_funcs_populate_programming(struct dml2_core_instance *core,
const struct dml2_display_solution *solution,
struct dml2_display_cfg_programming *programming);
#endif /* __DML2_CORE_DCN5_FUNCS_MODE_PROGRAMMING_H__ */

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024-2025 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN5_FUNCS_MODE_SUPPORT_H__
#define __DML2_CORE_DCN5_FUNCS_MODE_SUPPORT_H__
#include "dml2_internal_shared_types.h"
enum dml2_status dml2_core_dcn5_funcs_validate_solution(struct dml2_core_instance *core,
const struct dml2_display_solution *solution,
struct dml2_validation_result *result);
#endif /* __DML2_CORE_DCN5_FUNCS_MODE_SUPPORT_H__ */

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2026 Advanced Micro Devices, Inc.
#include "dml2_core_dcn6_calcs.h"
/*
* Placeholder for future DCN6 calcs table implementation.
* Remove this typedef once real declarations are added here.
*/
typedef int dml2_core_dcn6_calcs_placeholder;

View File

@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2026 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN6_CALCS_H__
#define __DML2_CORE_DCN6_CALCS_H__
#endif /* __DML2_CORE_DCN6_CALCS_H__ */

View File

@@ -0,0 +1,101 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN6_CALCS_DCHUB_H__
#define __DML2_CORE_DCN6_CALCS_DCHUB_H__
#include "dml2_internal_shared_types.h"
unsigned int dcn6_calculate_max_vstartup(
bool ptoi_supported,
unsigned int vblank_nom_default_us,
const struct dml2_timing_cfg *timing,
enum dml2_uclk_pstate_change_strategy pstate_strategy,
double write_back_delay_us,
unsigned int svp_lines);
void dcn6_calculate_alternate_params(struct dml2_core_calcs_calculate_alternate_params *p);
void dcn6_calculate_alternate_svp_lines(struct dml2_core_calcs_calculate_alternate_svp_lines *p);
void dcn6_calculate_alternate_lead_lines(struct dml2_core_calcs_calculate_alternate_lead_lines *p);
void dcn6_calculate_flip_schedule(
struct dml2_core_internal_scratch *s,
bool iflip_enable,
bool ihostvm_enable,
bool iffbm_enable,
double HostVMInefficiencyFactor,
double Tvm_trips_flip,
double Tr0_trips_flip,
double Tvm_trips_flip_rounded,
double Tr0_trips_flip_rounded,
bool GPUVMEnable,
double vm_bytes, // vm_bytes
double DPTEBytesPerRow, // dpte_row_bytes
enum dml2_source_format_class SourcePixelFormat,
double LineTime,
double VRatio,
double VRatioChroma,
double Tno_bw_flip,
unsigned int dpte_row_height,
unsigned int dpte_row_height_chroma,
unsigned int max_flip_time_us,
unsigned int max_flip_time_lines,
unsigned int meta_row_height,
unsigned int meta_row_height_chroma,
// Output
double *dst_y_per_vm_flip,
double *dst_y_per_row_flip,
double *final_flip_bw,
bool *ImmediateFlipSupportedForPipe);
void dcn6_get_pipe_regs(const struct dml2_display_cfg *display_cfg,
const struct dml2_core_internal_display_mode_lib *mode_lib,
struct dml2_dchub_per_pipe_register_set *out, int pipe_index, const struct dml2_utm_soc_bb *utm_soc_bb,
struct dml2_core_internal_scratch *s);
void dcn6_calculate_watermarks_and_dram_speed_change_support(
struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport_params *p);
void dcn6_calculate_stutter_efficiency(struct dml2_core_internal_scratch *scratch,
struct dml2_core_calcs_CalculateStutterEfficiency_params *p);
void dcn6_get_watermarks(const struct dml2_display_cfg *display_cfg, const struct dml2_core_internal_display_mode_lib *mode_lib, const struct dml2_utm_soc_bb *utm_soc_bb, struct dml2_dchub_watermark_regs *out);
void dcn6_calculate_excess_vactive_bandwidth_required(
const struct dml2_display_cfg *display_cfg,
unsigned int bytes_required_l[dml2_pstate_type_count][DML2_MAX_PLANES],
unsigned int bytes_required_c[dml2_pstate_type_count][DML2_MAX_PLANES],
/* outputs */
double excess_vactive_fill_bw_l[],
double excess_vactive_fill_bw_c[]);
void dcn6_calculate_pstate_schedule_windows(
int num_active_planes,
const unsigned int v_blank_start[DML2_MAX_PLANES],
const unsigned int v_blank_end[DML2_MAX_PLANES],
const double otg_vline_time_us[DML2_MAX_PLANES],
const double det_fill_delay_us[DML2_MAX_PLANES],
const double reserved_vblank_us[DML2_MAX_PLANES],
const double blackout_us,
// Outputs
double allow_start_us[DML2_MAX_PLANES],
double allow_end_us[DML2_MAX_PLANES]);
void dcn6_calculate_pstate_schedule_admissibility(
uint32_t num_active_planes,
double max_allow_delay_us,
double min_allow_width_us,
const uint32_t timing_group_id[DML2_MAX_PLANES],
uint32_t timing_group_count,
const double frame_time_us[DML2_MAX_PLANES],
const double allow_start_us[DML2_MAX_PLANES],
const double allow_end_us[DML2_MAX_PLANES],
const enum dml2_pstate_method pstate_method[DML2_MAX_PLANES],
const bool drr_enabled[DML2_MAX_DCN_PIPES],
// Output
double allow_window_us[DML2_MAX_DCN_PIPES],
double disallow_window_us[DML2_MAX_DCN_PIPES],
bool *pstate_admissible);
#endif /* __DML2_CORE_DCN6_CALCS_DCHUB_H__ */

View File

@@ -0,0 +1,165 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_core_dcn6_funcs_initialize.h"
#include "dml2_debug.h"
struct dml2_core_ip_params core_dcn6_ip_caps_base = {
// currently copied from DCN4
.vblank_nom_default_us = 668,
.remote_iommu_outstanding_translations = 512,
.rob_buffer_size_kbytes = 192,
.config_return_buffer_size_in_kbytes = 2112,
.config_return_buffer_segment_size_in_kbytes = 64,
.compressed_buffer_segment_size_in_kbytes = 64,
.dpte_buffer_size_in_pte_reqs_luma = 138,
.dpte_buffer_size_in_pte_reqs_chroma = 138,
.pixel_chunk_size_kbytes = 8,
.alpha_pixel_chunk_size_kbytes = 4,
.min_pixel_chunk_size_bytes = 1024,
.writeback_chunk_size_kbytes = 8,
.line_buffer_size_bits = 937536,
.max_line_buffer_lines = 32,
.writeback_interface_buffer_size_kbytes = 90,
//Number of pipes after DCN Pipe harvesting
.max_num_dpp = 4,
.max_num_otg = 4,
.max_num_wb = 1,
.zero_size_buffer_entries = 512,
.compbuf_reserved_space_zs = 64,
.dcc_meta_buffer_size_bytes = 6272,
.meta_chunk_size_kbytes = 2,
.min_meta_chunk_size_bytes = 256,
.max_dchub_pscl_bw_pix_per_clk = 4,
.max_pscl_lb_bw_pix_per_clk = 2,
.max_lb_vscl_bw_pix_per_clk = 4,
.max_vscl_hscl_bw_pix_per_clk = 4,
.max_hscl_ratio = 6,
.max_vscl_ratio = 6,
.max_hscl_taps = 8,
.max_vscl_taps = 8,
.dispclk_ramp_margin_percent = 1,
.dppclk_delay_subtotal = 41,
.dppclk_delay_scl = 50,
.dppclk_delay_scl_lb_only = 16,
.dppclk_delay_cnvc_formatter = 28,
.dppclk_delay_cnvc_cursor = 2,
.cursor_buffer_size = 24,
.cursor_chunk_size = 2,
.dispclk_delay_subtotal = 135,
.max_inter_dcn_tile_repeaters = 8,
.writeback_max_hscl_ratio = 1,
.writeback_max_vscl_ratio = 1,
.writeback_min_hscl_ratio = 1,
.writeback_min_vscl_ratio = 1,
.writeback_max_hscl_taps = 1,
.writeback_max_vscl_taps = 1,
.writeback_line_buffer_buffer_size = 0,
.odm_combine_support_mask = (1 << dml2_odm_mode_auto) |
(1 << dml2_odm_mode_bypass) |
(1 << dml2_odm_mode_combine_2to1) |
(1 << dml2_odm_mode_combine_3to1) |
(1 << dml2_odm_mode_combine_4to1) |
(1 << dml2_odm_mode_split_1to2) |
(1 << dml2_odm_mode_mso_1to2) |
(1 << dml2_odm_mode_mso_1to4),
.num_dsc = 4,
.maximum_dsc_slices_per_pipe = 8,
.maximum_dsc_bits_per_component = 12,
.maximum_pixels_per_line_per_dsc_unit = 5760,
.dsc422_native_support = true,
.dcc_supported = true,
.ptoi_supported = false,
.cursor_64bpp_support = true,
.dynamic_metadata_vm_enabled = false,
.max_num_hdmi_frl_outputs = 1,
.max_num_dp2p0_outputs = 4,
.max_num_dp2p0_streams = 4,
.imall_supported = 1,
.max_flip_time_us = 80,
.max_flip_time_lines = 32,
.words_per_channel = 16,
.alt_chan_fw_delay_us = 955, // Overestimate for now, can reduce later: sum of worst case throttle, programming, scheduling and contention delays
};
static void patch_ip_caps_with_explicit_ip_params(struct dml2_ip_capabilities *ip_caps, const struct dml2_core_ip_params *ip_params)
{
ip_caps->pipe_count = ip_params->max_num_dpp;
ip_caps->otg_count = ip_params->max_num_otg;
ip_caps->TDLUT_33cube_count = ip_params->TDLUT_33cube_count;
ip_caps->num_dsc = ip_params->num_dsc;
ip_caps->max_num_dp2p0_streams = ip_params->max_num_dp2p0_streams;
ip_caps->max_num_dp2p0_outputs = ip_params->max_num_dp2p0_outputs;
ip_caps->max_num_hdmi_frl_outputs = ip_params->max_num_hdmi_frl_outputs;
ip_caps->max_num_wb = ip_params->max_num_wb;
ip_caps->rob_buffer_size_kbytes = ip_params->rob_buffer_size_kbytes;
ip_caps->config_return_buffer_size_in_kbytes = ip_params->config_return_buffer_size_in_kbytes;
ip_caps->config_return_buffer_segment_size_in_kbytes = ip_params->config_return_buffer_segment_size_in_kbytes;
ip_caps->meta_fifo_size_in_kentries = ip_params->meta_fifo_size_in_kentries;
ip_caps->compressed_buffer_segment_size_in_kbytes = ip_params->compressed_buffer_segment_size_in_kbytes;
ip_caps->cursor_buffer_size = ip_params->cursor_buffer_size;
ip_caps->max_flip_time_us = ip_params->max_flip_time_us;
ip_caps->max_flip_time_lines = ip_params->max_flip_time_lines;
ip_caps->hostvm_mode = ip_params->hostvm_mode;
ip_caps->vblank_nom_default_us = ip_params->vblank_nom_default_us;
}
static void patch_ip_params_with_ip_caps(struct dml2_core_ip_params *ip_params, const struct dml2_ip_capabilities *ip_caps)
{
ip_params->max_num_dpp = ip_caps->pipe_count;
ip_params->max_num_otg = ip_caps->otg_count;
ip_params->TDLUT_33cube_count = ip_caps->TDLUT_33cube_count;
ip_params->num_dsc = ip_caps->num_dsc;
ip_params->max_num_dp2p0_streams = ip_caps->max_num_dp2p0_streams;
ip_params->max_num_dp2p0_outputs = ip_caps->max_num_dp2p0_outputs;
ip_params->max_num_hdmi_frl_outputs = ip_caps->max_num_hdmi_frl_outputs;
ip_params->max_num_wb = ip_caps->max_num_wb;
ip_params->rob_buffer_size_kbytes = ip_caps->rob_buffer_size_kbytes;
ip_params->config_return_buffer_size_in_kbytes = ip_caps->config_return_buffer_size_in_kbytes;
ip_params->config_return_buffer_segment_size_in_kbytes = ip_caps->config_return_buffer_segment_size_in_kbytes;
ip_params->meta_fifo_size_in_kentries = ip_caps->meta_fifo_size_in_kentries;
ip_params->compressed_buffer_segment_size_in_kbytes = ip_caps->compressed_buffer_segment_size_in_kbytes;
ip_params->cursor_buffer_size = ip_caps->cursor_buffer_size;
ip_params->max_flip_time_us = ip_caps->max_flip_time_us;
ip_params->max_flip_time_lines = ip_caps->max_flip_time_lines;
ip_params->hostvm_mode = ip_caps->hostvm_mode;
ip_params->alt_chan_fw_delay_us = ip_caps->fams2.scheduling_delay_us +
ip_caps->fams2.subvp_programming_delay_us +
ip_caps->fams2.subvp_df_throttle_delay_us +
(ip_caps->fams2.vertical_interrupt_ack_delay_us +
ip_caps->fams2.drr_programming_delay_us > ip_caps->fams2.allow_programming_delay_us ?
ip_caps->fams2.drr_programming_delay_us : ip_caps->fams2.allow_programming_delay_us) * (ip_caps->otg_count - 1);
ip_params->dcn_mrq_present = ip_caps->dcn_mrq_present;
ip_params->fams2_max_allow_delay_us = ip_caps->fams2.max_allow_delay_us;
ip_params->fams2_min_allow_width_us = ip_caps->fams2.min_allow_width_us;
ip_params->ppt_max_allow_delay_us = ip_caps->ppt_max_allow_delay_us;
ip_params->temp_read_max_allow_delay_us = ip_caps->temp_read_max_allow_delay_us;
}
bool dml2_core_dcn6_funcs_initialize(struct dml2_core_initialize_in_out *in_out)
{
struct dml2_core_instance *core = in_out->instance;
DML_LOG_COMP_IF_ENTER();
if (in_out->explicit_ip_bb && in_out->explicit_ip_bb_size > 0) {
memcpy(&core->clean_me_up.mode_lib.ip, in_out->explicit_ip_bb, in_out->explicit_ip_bb_size);
patch_ip_caps_with_explicit_ip_params(in_out->ip_caps, in_out->explicit_ip_bb);
} else {
memcpy(&core->clean_me_up.mode_lib.ip, &core_dcn6_ip_caps_base, sizeof(struct dml2_core_ip_params));
patch_ip_params_with_ip_caps(&core->clean_me_up.mode_lib.ip, in_out->ip_caps);
core->clean_me_up.mode_lib.ip.imall_supported = false;
}
memcpy(&core->clean_me_up.mode_lib.ip_caps, in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
core->utm_soc_bb = in_out->utm_soc_bb;
core->clock_adjuster = in_out->clock_adjuster;
DML_LOG_DEBUG("%s exit with true\n", __func__);
DML_LOG_COMP_IF_EXIT();
return true;
}

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN6_FUNCS_INITIALIZE_H__
#define __DML2_CORE_DCN6_FUNCS_INITIALIZE_H__
#include "dml2_internal_shared_types.h"
bool dml2_core_dcn6_funcs_initialize(struct dml2_core_initialize_in_out *in_out);
#endif /* __DML2_CORE_DCN6_FUNCS_INITIALIZE_H__ */

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN6_FUNCS_MODE_PROGRAMMING_H__
#define __DML2_CORE_DCN6_FUNCS_MODE_PROGRAMMING_H__
#include "dml2_internal_shared_types.h"
enum dml2_status dml2_core_dcn6_funcs_populate_programming(struct dml2_core_instance *core,
const struct dml2_display_solution *solution,
struct dml2_display_cfg_programming *programming);
#endif /* __DML2_CORE_DCN6_FUNCS_MODE_PROGRAMMING_H__ */

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DML2_CORE_DCN6_FUNCS_MODE_SUPPORT_H__
#define __DML2_CORE_DCN6_FUNCS_MODE_SUPPORT_H__
#include "dml2_internal_shared_types.h"
enum dml2_status dml2_core_dcn6_funcs_validate_solution(struct dml2_core_instance *core,
const struct dml2_display_solution *solution,
struct dml2_validation_result *result);
#endif /* __DML2_CORE_DCN6_FUNCS_MODE_SUPPORT_H__ */

View File

@@ -763,7 +763,6 @@ bool dpmm_dcn4_map_mode_to_soc_dpm(struct dml2_dpmm_map_mode_to_soc_dpm_params_i
else
in_out->programming->stutter.supported_in_blank = false;
// TODO: Fix me Sam
if (in_out->soc_bb->power_management_parameters.z8_min_idle_time > 0 &&
in_out->programming->informative.power_management.z8.stutter_period >= in_out->soc_bb->power_management_parameters.z8_min_idle_time)
in_out->programming->z8_stutter.meets_eco = true;

View File

@@ -0,0 +1,449 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_dpmm_dcn5.h"
#include "lib_float_math.h"
static bool add_margin_and_round_to_dfs_grainularity(double clock_khz, double margin, unsigned long vco_freq_khz, unsigned long *rounded_khz, uint32_t *divider_id)
{
enum dentist_divider_range {
DFS_DIVIDER_RANGE_1_START = 8, /* 2.00 */
DFS_DIVIDER_RANGE_1_STEP = 1, /* 0.25 */
DFS_DIVIDER_RANGE_2_START = 64, /* 16.00 */
DFS_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */
DFS_DIVIDER_RANGE_3_START = 128, /* 32.00 */
DFS_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */
DFS_DIVIDER_RANGE_4_START = 248, /* 62.00 */
DFS_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */
DFS_DIVIDER_RANGE_SCALE_FACTOR = 4
};
enum DFS_base_divider_id {
DFS_BASE_DID_1 = 0x08,
DFS_BASE_DID_2 = 0x40,
DFS_BASE_DID_3 = 0x60,
DFS_BASE_DID_4 = 0x7e,
DFS_MAX_DID = 0x7f
};
unsigned int divider;
if (clock_khz < 1 || vco_freq_khz < 1 || clock_khz > vco_freq_khz)
return false;
clock_khz *= 1.0 + margin;
divider = (unsigned int)((int)DFS_DIVIDER_RANGE_SCALE_FACTOR * (vco_freq_khz / clock_khz));
/* we want to floor here to get higher clock than required rather than lower */
if (divider < DFS_DIVIDER_RANGE_2_START) {
if (divider < DFS_DIVIDER_RANGE_1_START)
*divider_id = DFS_BASE_DID_1;
else
*divider_id = DFS_BASE_DID_1 + ((divider - DFS_DIVIDER_RANGE_1_START) / DFS_DIVIDER_RANGE_1_STEP);
} else if (divider < DFS_DIVIDER_RANGE_3_START) {
*divider_id = DFS_BASE_DID_2 + ((divider - DFS_DIVIDER_RANGE_2_START) / DFS_DIVIDER_RANGE_2_STEP);
} else if (divider < DFS_DIVIDER_RANGE_4_START) {
*divider_id = DFS_BASE_DID_3 + ((divider - DFS_DIVIDER_RANGE_3_START) / DFS_DIVIDER_RANGE_3_STEP);
} else {
*divider_id = DFS_BASE_DID_4 + ((divider - DFS_DIVIDER_RANGE_4_START) / DFS_DIVIDER_RANGE_4_STEP);
if (*divider_id > DFS_MAX_DID)
*divider_id = DFS_MAX_DID;
}
*rounded_khz = vco_freq_khz * DFS_DIVIDER_RANGE_SCALE_FACTOR / divider;
return true;
}
static bool round_to_non_dfs_granularity(unsigned long dispclk_khz, unsigned long dpprefclk_khz, unsigned long dtbrefclk_khz,
unsigned long *rounded_dispclk_khz, unsigned long *rounded_dpprefclk_khz, unsigned long *rounded_dtbrefclk_khz)
{
unsigned long pll_frequency_khz;
pll_frequency_khz = (unsigned long) math_max2(600000, math_ceil2(math_max3(dispclk_khz, dpprefclk_khz, dtbrefclk_khz), 1000));
*rounded_dispclk_khz = pll_frequency_khz / (unsigned long) math_min2(pll_frequency_khz / dispclk_khz, 32);
*rounded_dpprefclk_khz = pll_frequency_khz / (unsigned long) math_min2(pll_frequency_khz / dpprefclk_khz, 32);
if (dtbrefclk_khz > 0) {
*rounded_dtbrefclk_khz = pll_frequency_khz / (unsigned long) math_min2(pll_frequency_khz / dtbrefclk_khz, 32);
} else {
*rounded_dtbrefclk_khz = 0;
}
return true;
}
static bool validate_min_clocks(const struct dml2_display_solution *solution, struct dml2_display_cfg_programming *programming, const struct dml2_utm_soc_bb *utm_soc_bb)
{
unsigned int i;
if (!utm_soc_bb || !programming)
return false;
if (programming->min_clocks.dcn4x.dispclk_khz > utm_soc_bb->max_dispclk_khz)
return false;
if (programming->min_clocks.dcn4x.dpprefclk_khz > utm_soc_bb->max_dppclk_khz)
return false;
if (programming->min_clocks.dcn4x.dtbrefclk_khz > utm_soc_bb->max_dtbclk_khz)
return false;
for (i = 0; i < solution->dispcfg.num_planes; i++)
if (programming->plane_programming[i].min_clocks.dcn4x.dppclk_khz > utm_soc_bb->max_dppclk_khz)
return false;
for (i = 0; i < solution->dispcfg.num_streams; i++)
if (programming->stream_programming[i].min_clocks.dcn4x.dscclk_khz > utm_soc_bb->max_dscclk_khz)
return false;
else if (programming->stream_programming[i].min_clocks.dcn4x.dtbclk_khz > utm_soc_bb->max_dtbclk_khz)
return false;
else if (programming->stream_programming[i].min_clocks.dcn4x.phyclk_khz > utm_soc_bb->max_phyclk_khz)
return false;
return true;
}
static bool are_timings_trivially_synchronizable(const struct dml2_display_solution *solution, int mask)
{
unsigned int i;
bool identical = true;
bool contains_drr = false;
unsigned int remap_array[DML2_MAX_PLANES];
unsigned int remap_array_size = 0;
// Create a remap array to enable simple iteration through only masked stream indicies
for (i = 0; i < solution->dispcfg.num_streams; i++) {
if (mask & (0x1 << i)) {
remap_array[remap_array_size++] = i;
}
}
// 0 or 1 display is always trivially synchronizable
if (remap_array_size <= 1)
return true;
// Check that all displays timings are the same
for (i = 1; i < remap_array_size; i++) {
if (memcmp(&solution->dispcfg.stream_descriptors[remap_array[i - 1]].timing, &solution->dispcfg.stream_descriptors[remap_array[i]].timing, sizeof(struct dml2_timing_cfg))) {
identical = false;
break;
}
}
// Check if any displays are drr
for (i = 0; i < remap_array_size; i++) {
if (solution->dispcfg.stream_descriptors[remap_array[i]].timing.drr_config.enabled) {
contains_drr = true;
break;
}
}
// Trivial sync is possible if all displays are identical and none are DRR
return !contains_drr && identical;
}
static int find_smallest_idle_time_in_vblank_us(const struct dml2_display_solution *solution, int mask)
{
unsigned int i;
int min_idle_us = 0;
unsigned int remap_array[DML2_MAX_PLANES];
unsigned int remap_array_size = 0;
const struct dml2_core_mode_support_result *mode_support_result = &solution->validation_result.mode_support;
// Create a remap array to enable simple iteration through only masked stream indicies
for (i = 0; i < solution->dispcfg.num_streams; i++) {
if (mask & (0x1 << i)) {
remap_array[remap_array_size++] = i;
}
}
if (remap_array_size == 0)
return 0;
min_idle_us = mode_support_result->cfg_support_info.stream_support_info[remap_array[0]].vblank_reserved_time_us;
for (i = 1; i < remap_array_size; i++) {
if (min_idle_us > mode_support_result->cfg_support_info.stream_support_info[remap_array[i]].vblank_reserved_time_us)
min_idle_us = mode_support_result->cfg_support_info.stream_support_info[remap_array[i]].vblank_reserved_time_us;
}
return min_idle_us;
}
static int get_displays_without_vactive_margin_mask(const struct dml2_display_solution *solution, const struct dml2_utm_soc_bb *utm_soc_bb)
{
unsigned int i;
int displays_without_vactive_margin_mask = 0x0;
const struct dml2_core_mode_support_result *mode_support_result = &solution->validation_result.mode_support;
for (i = 0; i < solution->dispcfg.num_planes; i++) {
if (mode_support_result->cfg_support_info.plane_support_info[i].active_latency_hiding_us
< (int)utm_soc_bb->power_management_parameters.fclk_change_blackout_us)
displays_without_vactive_margin_mask |= (0x1 << i);
}
return displays_without_vactive_margin_mask;
}
static unsigned long calculate_dispclk_khz(const struct dml2_display_solution *solution,
const struct dml2_utm_soc_bb *utm_soc_bb, const struct dml2_core_ip_params *ip_params)
{
double dispclk_khz;
// need some massaging for the dispclk ramping cases:
dispclk_khz = solution->validation_result.mode_support.global.dispclk_khz * (1 + utm_soc_bb->dcn_downspread_percent / 100.0) * (1.0 + ip_params->dispclk_ramp_margin_percent / 100.0);
// ramping margin should not make dispclk exceed the maximum dispclk speed:
dispclk_khz = math_min2(dispclk_khz, utm_soc_bb->max_dispclk_khz);
// but still the required dispclk can be more than the maximum dispclk speed:
dispclk_khz = math_max2(dispclk_khz, solution->validation_result.mode_support.global.dispclk_khz * (1 + utm_soc_bb->dcn_downspread_percent / 100.0));
return (unsigned long) dispclk_khz;
}
static unsigned long calculate_dpprefclk_khz(const struct dml2_display_solution *solution,
const struct dml2_utm_soc_bb *utm_soc_bb)
{
unsigned long dpprefclk_khz = 0;
unsigned int i;
// DPP Ref is always set to max of all DPP clocks
for (i = 0; i < solution->dispcfg.num_planes; i++)
if (dpprefclk_khz < solution->validation_result.mode_support.per_plane[i].dppclk_khz)
dpprefclk_khz = solution->validation_result.mode_support.per_plane[i].dppclk_khz;
dpprefclk_khz = (unsigned long) (dpprefclk_khz * (1 + utm_soc_bb->dcn_downspread_percent / 100.0));
return dpprefclk_khz;
}
static unsigned long calculate_dtbrefclk_khz(const struct dml2_display_solution *solution,
const struct dml2_utm_soc_bb *utm_soc_bb)
{
unsigned long dtbrefclk_khz = 0;
unsigned int i;
// DTB Ref is always set to max of all DTB clocks
for (i = 0; i < solution->dispcfg.num_streams; i++)
if (dtbrefclk_khz < solution->validation_result.mode_support.per_stream[i].dtbclk_khz)
dtbrefclk_khz = solution->validation_result.mode_support.per_stream[i].dtbclk_khz;
dtbrefclk_khz = (unsigned long)(dtbrefclk_khz * (1 + utm_soc_bb->dcn_downspread_percent / 100.0));
return dtbrefclk_khz;
}
static unsigned long calculate_dppclk_khz_plane_index(unsigned int plane_index,
const struct dml2_display_solution *solution,
const struct dml2_utm_soc_bb *utm_soc_bb,
unsigned long dpprefclk_khz)
{
return (unsigned long)(dpprefclk_khz / 255.0
* math_ceil2(solution->validation_result.mode_support.per_plane[plane_index].dppclk_khz * (1.0 + utm_soc_bb->dcn_downspread_percent / 100.0) * 255.0 / dpprefclk_khz, 1.0));
}
static void round_min_clocks_to_granularity(struct dml2_display_cfg_programming *programming, const struct dml2_utm_soc_bb *utm_soc_bb)
{
if (utm_soc_bb->no_dfs) {
round_to_non_dfs_granularity(programming->min_clocks.dcn4x.dispclk_khz, programming->min_clocks.dcn4x.dpprefclk_khz, programming->min_clocks.dcn4x.dtbrefclk_khz,
&programming->min_clocks.dcn4x.dispclk_khz, &programming->min_clocks.dcn4x.dpprefclk_khz, &programming->min_clocks.dcn4x.dtbrefclk_khz);
} else {
add_margin_and_round_to_dfs_grainularity(programming->min_clocks.dcn4x.dispclk_khz, 0.0,
(unsigned long)(utm_soc_bb->dispclk_dppclk_vco_speed_mhz * 1000), &programming->min_clocks.dcn4x.dispclk_khz, &programming->min_clocks.dcn4x.divider_ids.dispclk_did);
add_margin_and_round_to_dfs_grainularity(programming->min_clocks.dcn4x.dpprefclk_khz, 0.0,
(unsigned long)(utm_soc_bb->dispclk_dppclk_vco_speed_mhz * 1000), &programming->min_clocks.dcn4x.dpprefclk_khz, &programming->min_clocks.dcn4x.divider_ids.dpprefclk_did);
add_margin_and_round_to_dfs_grainularity(programming->min_clocks.dcn4x.dtbrefclk_khz, 0.0,
(unsigned long)(utm_soc_bb->dispclk_dppclk_vco_speed_mhz * 1000), &programming->min_clocks.dcn4x.dtbrefclk_khz, &programming->min_clocks.dcn4x.divider_ids.dtbrefclk_did);
}
}
static bool dcn5_populate_min_clocks_in_programming(struct dml2_display_cfg_programming *programming,
const struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_core_ip_params *ip_params,
const struct dml2_display_solution *solution)
{
unsigned int i;
programming->min_clocks.dcn4x.dispclk_khz =
calculate_dispclk_khz(solution, utm_soc_bb, ip_params);
programming->min_clocks.dcn4x.dpprefclk_khz =
calculate_dpprefclk_khz(solution, utm_soc_bb);
programming->min_clocks.dcn4x.dtbrefclk_khz =
calculate_dtbrefclk_khz(solution, utm_soc_bb);
programming->min_clocks.dcn4x.deepsleep_dcfclk_khz =
(unsigned long) math_min2((double)solution->validation_result.mode_support.global.dcfclk_deepsleep_khz, (double)solution->sop_constraint.dcn5.clocks.dcfclk_khz);
programming->min_clocks.dcn4x.socclk_khz = solution->sop_constraint.dcn5.clocks.socclk_khz;
programming->min_clocks.dcn4x.active.dcfclk_khz = solution->sop_constraint.dcn5.clocks.dcfclk_khz;
programming->min_clocks.dcn4x.active.fclk_khz = solution->sop_constraint.dcn5.clocks.fclk_khz;
programming->min_clocks.dcn4x.active.uclk_khz = solution->sop_constraint.dcn5.clocks.uclk_khz;
round_min_clocks_to_granularity(programming, utm_soc_bb);
for (i = 0; i < solution->dispcfg.num_planes; i++)
programming->plane_programming[i].min_clocks.dcn4x.dppclk_khz =
calculate_dppclk_khz_plane_index(i, solution, utm_soc_bb,
programming->min_clocks.dcn4x.dpprefclk_khz);
for (i = 0; i < solution->dispcfg.num_streams; i++) {
programming->stream_programming[i].min_clocks.dcn4x.dscclk_khz =
solution->validation_result.mode_support.per_stream[i].dscclk_khz;
programming->stream_programming[i].min_clocks.dcn4x.dtbclk_khz =
solution->validation_result.mode_support.per_stream[i].dtbclk_khz;
programming->stream_programming[i].min_clocks.dcn4x.phyclk_khz =
solution->validation_result.mode_support.per_stream[i].phyclk_khz;
}
return validate_min_clocks(solution, programming, utm_soc_bb);
}
void dcn5_populate_pstate_support_in_programming(struct dml2_display_cfg_programming *programming,
const struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_display_solution *solution)
{
unsigned int plane_index;
int displays_without_vactive_margin_mask = 0x0;
bool uclk_pstate_supported = true;
int min_idle_us = 0;
for (plane_index = 0; plane_index < solution->dispcfg.num_planes; plane_index++) {
if (solution->uclk_pstate_params.pstate_switch_modes[plane_index] == dml2_pstate_method_na) {
/* UCLK P-State is supported if the pstate method is populated */
uclk_pstate_supported = false;
break;
}
}
programming->uclk_pstate_supported = uclk_pstate_supported;
programming->fclk_pstate_supported = false;
displays_without_vactive_margin_mask =
get_displays_without_vactive_margin_mask(solution, utm_soc_bb);
if (displays_without_vactive_margin_mask == 0) {
programming->fclk_pstate_supported = true;
} else {
if (are_timings_trivially_synchronizable(solution, displays_without_vactive_margin_mask)) {
min_idle_us = find_smallest_idle_time_in_vblank_us(solution, displays_without_vactive_margin_mask);
if (min_idle_us >= utm_soc_bb->power_management_parameters.fclk_change_blackout_us)
programming->fclk_pstate_supported = true;
}
}
}
void dcn5_populate_stutter_support_in_programming(struct dml2_display_cfg_programming *programming,
const struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_display_solution *solution)
{
int min_idle_us;
min_idle_us = find_smallest_idle_time_in_vblank_us(solution, 0xFF);
if (utm_soc_bb->power_management_parameters.stutter_enter_plus_exit_latency_us > 0 &&
min_idle_us >= utm_soc_bb->power_management_parameters.stutter_enter_plus_exit_latency_us)
programming->stutter.supported_in_blank = true;
else
programming->stutter.supported_in_blank = false;
if (utm_soc_bb->power_management_parameters.z8_min_idle_time > 0 &&
programming->informative.power_management.z8.stutter_period >= utm_soc_bb->power_management_parameters.z8_min_idle_time)
programming->z8_stutter.meets_eco = true;
else
programming->z8_stutter.meets_eco = false;
if (utm_soc_bb->power_management_parameters.z8_stutter_exit_latency_us > 0 &&
min_idle_us >= utm_soc_bb->power_management_parameters.z8_stutter_exit_latency_us)
programming->z8_stutter.supported_in_blank = true;
else
programming->z8_stutter.supported_in_blank = false;
}
static void dcn5_populate_qos_bound_in_programming(struct dml2_display_cfg_programming *programming,
const struct dml2_display_solution *solution)
{
programming->qos_bound.latency_ub = solution->sop_constraint.dcn5.latency;
/*
* A true UTM design enables dynamic bandwidth percentage allocation. At DPM1 when the system is idle, we can
* allocate more bandwidth percentage share to DCN. The clocks can be designed to lower values to save power.
* When the system is at its peak load. The system can still increase to the max DPM level and reduce bandwidth
* percentage share to DCN as long as it still meets DCN's QoS requirements. So other clients such as GFX may be
* given even more bandwidth at its peak load. The UTM design increases DML complicity because higher DPM level
* no longer equates to more or equal bandwidth to DCN. It now depends on the bandwidth percentage share (aka.
* bandwidth derate). DCN needs to express its true QoS bandwidth requirements without knowing bandwidth
* availability at any DPM levels.
*
* We assume that there is a top down decision that this generation of hardware has a fixed bandwidth derate
* across all DPM levels and it doesn't require a true UTM design. As such the QoS bandwidth requirement can be
* based on the fixed bandwidth availability at lowest supported DPM. This simplifies mode programming
* calculation. We are making corresponding QoS Bound change below to be compatible with the simplified mode
* programming calculation.
*/
// programming->qos_bound.bandwidth_lb = solution->validation_result.mode_support.bandwidth_upper_bound;
programming->qos_bound.bandwidth_lb.dcn5.urgent_bandwidth_kbps = solution->sop_constraint.dcn5.min_available_urgent_bandwidth_KBps;
}
bool dpmm_dcn5_map_mode_to_soc_dpm(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *in_out)
{
dcn5_populate_qos_bound_in_programming(in_out->programming, in_out->solution);
dcn5_populate_pstate_support_in_programming(in_out->programming, in_out->utm_soc_bb, in_out->solution);
dcn5_populate_stutter_support_in_programming(in_out->programming, in_out->utm_soc_bb, in_out->solution);
return dcn5_populate_min_clocks_in_programming(
in_out->programming, in_out->utm_soc_bb, in_out->ip, in_out->solution);
}
bool dpmm_dcn5_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out)
{
const struct dml2_display_cfg *display_cfg = &in_out->solution->dispcfg;
const struct dml2_core_internal_display_mode_lib *mode_lib = &in_out->core->clean_me_up.mode_lib;
struct dml2_dchub_global_register_set *dchubbub_regs = &in_out->programming->global_regs;
struct dml2_mcif_global_register_set *mcif_regs = &in_out->programming->mcif_global_regs;
double refclk_freq_in_mhz = (display_cfg->overrides.hw.dlg_ref_clk_mhz > 0) ? (double)display_cfg->overrides.hw.dlg_ref_clk_mhz : in_out->core->utm_soc_bb->dchub_refclk_mhz;
/* set A */
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].fclk_pstate = (int unsigned)(mode_lib->mp.Watermark.FCLKChangeWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].sr_enter = (int unsigned)(mode_lib->mp.Watermark.StutterEnterPlusExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].sr_exit = (int unsigned)(mode_lib->mp.Watermark.StutterExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].sr_enter_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterEnterPlusExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].sr_exit_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].temp_read_or_ppt = (int unsigned)(mode_lib->mp.Watermark.temp_read_or_ppt_watermark_us * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].uclk_pstate = (int unsigned)(mode_lib->mp.Watermark.DRAMClockChangeWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].urgent = (int unsigned)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].usr = (int unsigned)(mode_lib->mp.Watermark.USRRetrainingWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].refcyc_per_trip_to_mem = (unsigned int)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].refcyc_per_meta_trip_to_mem = (unsigned int)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].frac_urg_bw_flip = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidthImmediateFlip * 1000);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].frac_urg_bw_nom = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidth * 1000);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].frac_urg_bw_mall = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidthMALL * 1000);
/* set B */
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].fclk_pstate = (int unsigned)(mode_lib->mp.Watermark.FCLKChangeWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].sr_enter = (int unsigned)(mode_lib->mp.Watermark.StutterEnterPlusExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].sr_exit = (int unsigned)(mode_lib->mp.Watermark.StutterExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].sr_enter_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterEnterPlusExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].sr_exit_z8 = (int unsigned)(mode_lib->mp.Watermark.Z8StutterExitWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].temp_read_or_ppt = (int unsigned)(mode_lib->mp.Watermark.temp_read_or_ppt_watermark_us * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].uclk_pstate = (int unsigned)(mode_lib->mp.Watermark.DRAMClockChangeWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].urgent = (int unsigned)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].usr = (int unsigned)(mode_lib->mp.Watermark.USRRetrainingWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].refcyc_per_trip_to_mem = (unsigned int)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].refcyc_per_meta_trip_to_mem = (unsigned int)(mode_lib->mp.Watermark.UrgentWatermark * refclk_freq_in_mhz);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].frac_urg_bw_flip = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidthImmediateFlip * 1000);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].frac_urg_bw_nom = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidth * 1000);
dchubbub_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B].frac_urg_bw_mall = (unsigned int)(mode_lib->mp.FractionOfUrgentBandwidthMALL * 1000);
dchubbub_regs->num_watermark_sets = 2;
/* MCIF */
mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].urgent = (int unsigned)(mode_lib->mp.Watermark.WritebackUrgentWatermark * 1000.0);
mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].uclk_pstate = (int unsigned)(mode_lib->mp.Watermark.WritebackDRAMClockChangeWatermark * 1000.0);
mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].fclk_pstate = (int unsigned)(mode_lib->mp.Watermark.WritebackFCLKChangeWatermark * 1000.0);
mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A].temp_read_or_ppt = (int unsigned)(mode_lib->mp.Watermark.writeback_temp_read_or_ppt_watermark_us * 1000.0);
/* replicate sets A through D */
memcpy(&mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_B], &mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A], sizeof(mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A]));
memcpy(&mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_C], &mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A], sizeof(mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A]));
memcpy(&mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_D], &mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A], sizeof(mcif_regs->wm_regs[DML2_DCHUB_WATERMARK_SET_A]));
mcif_regs->num_watermark_sets = 4;
return true;
}

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_DPMM_DCN5_H__
#define __DML2_DPMM_DCN5_H__
#include "dml2_internal_shared_types.h"
bool dpmm_dcn5_map_mode_to_soc_dpm(struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *in_out);
bool dpmm_dcn5_map_watermarks(struct dml2_dpmm_map_watermarks_params_in_out *in_out);
void dcn5_populate_pstate_support_in_programming(struct dml2_display_cfg_programming *programming,
const struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_display_solution *solution);
void dcn5_populate_stutter_support_in_programming(struct dml2_display_cfg_programming *programming,
const struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_display_solution *solution);
#endif /* #ifndef __DML2_DPMM_DCN5_H__ */

View File

@@ -0,0 +1,522 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024-2025 Advanced Micro Devices, Inc.
#include "dml2_pmo_dcn5.h"
#include "dml2_pmo_dcn4_fams2.h"
#include "dml2_pmo_dcn5_stage_optimizers.h"
#include "lib_float_math.h"
#include "dml2_debug.h"
static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_1_display[] = {
// VActive Preferred
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Then VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = false,
},
// Then DRR
{
.per_stream_pstate_method = { dml2_pstate_method_fw_drr, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Finally VBlank, but allow base clocks for latency to increase
/*
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
*/
};
static const int base_pstate_strategy_list_1_display_size = sizeof(base_pstate_strategy_list_1_display) / sizeof(struct dml2_pmo_pstate_strategy);
static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_2_display[] = {
// VActive only is preferred
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Then VActive + VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = false,
},
// Then VBlank only
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = false,
},
// Then DRR + VActive
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_fw_drr, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Then DRR + DRR
{
.per_stream_pstate_method = { dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Finally VBlank, but allow base clocks for latency to increase
/*
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
*/
};
static const int base_pstate_strategy_list_2_display_size = sizeof(base_pstate_strategy_list_2_display) / sizeof(struct dml2_pmo_pstate_strategy);
static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_3_display[] = {
// All VActive
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_na },
.allow_state_increase = true,
},
// VActive + 1 VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vblank, dml2_pstate_method_na },
.allow_state_increase = false,
},
// All VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na },
.allow_state_increase = false,
},
// All DRR
{
.per_stream_pstate_method = { dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_na },
.allow_state_increase = true,
},
// All VBlank, with state increase allowed
/*
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na },
.allow_state_increase = true,
},
*/
};
static const int base_pstate_strategy_list_3_display_size = sizeof(base_pstate_strategy_list_3_display) / sizeof(struct dml2_pmo_pstate_strategy);
static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_4_display[] = {
// All VActive
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive },
.allow_state_increase = true,
},
// VActive + 1 VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vblank },
.allow_state_increase = false,
},
// All Vblank
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank },
.allow_state_increase = false,
},
// All DRR
{
.per_stream_pstate_method = { dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr },
.allow_state_increase = true,
},
// All VBlank, with state increase allowed
/*
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank },
.allow_state_increase = true,
},
*/
};
static const int base_pstate_strategy_list_4_display_size = sizeof(base_pstate_strategy_list_4_display) / sizeof(struct dml2_pmo_pstate_strategy);
static void dml2_pmo_dcn5_assign_pstate_strategies(struct dml2_pmo_instance *pmo)
{
int i = 0;
/* generate permutations of p-state configs from base strategy list */
for (i = 1; i <= PMO_DCN4_MAX_DISPLAYS; i++) {
switch (i) {
case 1:
DML_ASSERT(base_pstate_strategy_list_1_display_size <= PMO_DCN4_MAX_BASE_STRATEGIES);
/* populate list */
pmo_dcn4_fams2_expand_base_pstate_strategies(
base_pstate_strategy_list_1_display,
base_pstate_strategy_list_1_display_size,
i,
pmo->init_data.pmo_dcn4.expanded_strategy_list_1_display,
&pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i - 1]);
break;
case 2:
DML_ASSERT(base_pstate_strategy_list_2_display_size <= PMO_DCN4_MAX_BASE_STRATEGIES);
/* populate list */
pmo_dcn4_fams2_expand_base_pstate_strategies(
base_pstate_strategy_list_2_display,
base_pstate_strategy_list_2_display_size,
i,
pmo->init_data.pmo_dcn4.expanded_strategy_list_2_display,
&pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i - 1]);
break;
case 3:
DML_ASSERT(base_pstate_strategy_list_3_display_size <= PMO_DCN4_MAX_BASE_STRATEGIES);
/* populate list */
pmo_dcn4_fams2_expand_base_pstate_strategies(
base_pstate_strategy_list_3_display,
base_pstate_strategy_list_3_display_size,
i,
pmo->init_data.pmo_dcn4.expanded_strategy_list_3_display,
&pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i - 1]);
break;
case 4:
DML_ASSERT(base_pstate_strategy_list_4_display_size <= PMO_DCN4_MAX_BASE_STRATEGIES);
/* populate list */
pmo_dcn4_fams2_expand_base_pstate_strategies(
base_pstate_strategy_list_4_display,
base_pstate_strategy_list_4_display_size,
i,
pmo->init_data.pmo_dcn4.expanded_strategy_list_4_display,
&pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i - 1]);
break;
}
}
}
bool dml2_pmo_dcn5_initialize(struct dml2_pmo_initialize_in_out *in_out)
{
struct dml2_pmo_instance *pmo = in_out->instance;
pmo->ip_caps = in_out->ip_caps;
pmo->options = in_out->options;
pmo->utm_soc_bb = in_out->utm_soc_bb;
pmo->mpc_combine_limit = 2;
pmo->odm_combine_limit = 4;
pmo->fams_params.v2.drr.refresh_rate_limit_max = 1000;
pmo->fams_params.v2.drr.refresh_rate_limit_min = 119;
dml2_pmo_dcn5_assign_pstate_strategies(pmo);
dml2_pmo_dcn5_stage_optimizer_mcache_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_mcache]);
dml2_pmo_dcn5_stage_optimizer_uclk_pstate_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_uclk_pstate]);
dml2_pmo_dcn5_stage_optimizer_qos_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_qos]);
dml2_pmo_dcn5_stage_optimizer_vmin_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_vmin]);
dml2_pmo_dcn5_stage_optimizer_stutter_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_stutter]);
return true;
}
int dml2_pmo_dcn5_get_ordered_mandatory_stage_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **stages)
{
int count = 0;
if (!pmo->options->force_optional_mcache_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_mcache];
if (!pmo->options->force_optional_uclk_pstate_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_uclk_pstate];
return count;
}
int dml2_pmo_dcn5_get_ordered_optional_stages_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **stages)
{
int count = 0;
if (pmo->options->force_optional_mcache_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_mcache];
if (pmo->options->force_optional_uclk_pstate_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_uclk_pstate];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_qos];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_vmin];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_stutter];
return count;
}
static void dml2_pmo_dcn5_assign_timing_groups(struct dml2_optimization_worksheet *worksheet)
{
const struct dml2_stream_parameters *cur_stream, *other_stream;
const struct dml2_plane_parameters *plane;
unsigned int i, j;
worksheet->timing_group_count = 0;
memset(worksheet->timing_group_ids, 0xFF, sizeof(worksheet->timing_group_ids));
/* assign timing group IDs per stream using the same synchronization logic as
* dcn5_build_synchronized_timing_groups: streams with identical timings are
* placed in the same group; DRR-enabled streams are never merged with others */
for (i = 0; i < worksheet->orig_dispcfg->num_planes; i++) {
if (worksheet->timing_group_ids[i] != 0xFFFFFFFF)
/* already assigned */
continue;
worksheet->timing_group_ids[i] = worksheet->timing_group_count;
worksheet->timing_group_count++;
plane = &worksheet->orig_dispcfg->plane_descriptors[i];
cur_stream = &worksheet->orig_dispcfg->stream_descriptors[plane->stream_index];
for (j = i + 1; j < worksheet->orig_dispcfg->num_planes; j++) {
if (worksheet->timing_group_ids[j] != 0xFFFFFFFF)
/* already assigned */
continue;
plane = &worksheet->orig_dispcfg->plane_descriptors[j];
other_stream = &worksheet->orig_dispcfg->stream_descriptors[plane->stream_index];
if (cur_stream == other_stream)
/* same stream, must be in the same group */
worksheet->timing_group_ids[j] = worksheet->timing_group_ids[i];
if (memcmp(&cur_stream->timing, &other_stream->timing, sizeof(struct dml2_timing_cfg)) == 0
&& !cur_stream->timing.drr_config.enabled)
/* identical timings, should be in the same group */
worksheet->timing_group_ids[j] = worksheet->timing_group_ids[i];
}
}
}
void dml2_pmo_dcn5_initialize_worksheet(struct dml2_pmo_instance *pmo,
const struct dml2_display_cfg *dispcfg,
struct dml2_optimization_worksheet *worksheet)
{
const struct dml2_sop_table *sop_table = &pmo->utm_soc_bb->sop_table;
DML_LOG_COMP_IF_ENTER();
memset(worksheet, 0, sizeof(struct dml2_optimization_worksheet));
worksheet->orig_dispcfg = dispcfg;
worksheet->cur.config.min_sop_index = sop_table->get_highest_sop_index(sop_table);
worksheet->cur.unvalidated_change.raw = 0xFFFF;
dml2_pmo_dcn5_assign_timing_groups(worksheet);
DML_LOG_COMP_IF_EXIT();
}
static bool dml2_pmo_dcn5_check_total_pipe_usage(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_worksheet *worksheet)
{
unsigned int i;
const struct dml2_display_cfg *orig_dispcfg = worksheet->orig_dispcfg;
unsigned int total_pipe_usage = 0;
for (i = 0; i < orig_dispcfg->num_planes; i++)
if (worksheet->cur.config.mpc_combine_overrides[i])
total_pipe_usage += worksheet->cur.config.mpc_combine_overrides[i];
else if (worksheet->cur.config.odm_combine_overrides[orig_dispcfg->plane_descriptors[i].stream_index])
total_pipe_usage += worksheet->cur.config.odm_combine_overrides[orig_dispcfg->plane_descriptors[i].stream_index];
else
total_pipe_usage += worksheet->validation_result.mode_support.cfg_support_info.plane_support_info[i].dpps_used;
return total_pipe_usage <= pmo->ip_caps->pipe_count;
}
static bool is_h_timing_divisible_by(const struct dml2_timing_cfg *timing, unsigned int denominator)
{
/*
* Htotal, Hblank start/end, and Hsync start/end all must be divisible
* in order for the horizontal timing params to be considered divisible
* by 2. Hsync start is always 0.
*/
unsigned long h_blank_start = timing->h_total - timing->h_front_porch;
return (timing->h_total % denominator == 0) &&
(h_blank_start % denominator == 0) &&
(timing->h_blank_end % denominator == 0) &&
(timing->h_sync_width % denominator == 0);
}
static bool dml2_pmo_dcn5_check_odm_divisibility(const struct dml2_optimization_worksheet *worksheet)
{
unsigned int i;
const struct dml2_timing_cfg *timing;
for (i = 0; i < worksheet->orig_dispcfg->num_streams; i++) {
if (worksheet->cur.config.odm_combine_overrides[i]) {
timing = &worksheet->orig_dispcfg->stream_descriptors[i].timing;
if (!is_h_timing_divisible_by(timing, worksheet->cur.config.odm_combine_overrides[i])) {
((struct dml2_optimization_worksheet *)worksheet)->mcache.per_plane_status[i] = false;
return false;
}
if (timing->dsc.overrides.num_slices &&
timing->dsc.overrides.num_slices % worksheet->cur.config.odm_combine_overrides[i])
return false;
}
}
return true;
}
enum dml2_status dml2_pmo_dcn5_sanity_check(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_worksheet *worksheet)
{
enum dml2_status status = DML2_STATUS_OK;
DML_LOG_COMP_IF_ENTER();
if (!dml2_pmo_dcn5_check_total_pipe_usage(pmo, worksheet)) {
status = DML2_STATUS_VALIDATE_FAIL_PMO_SANITY_TOTAL_PIPE_USAGE;
goto exit;
}
if (!dml2_pmo_dcn5_check_odm_divisibility(worksheet)) {
status = DML2_STATUS_VALIDATE_FAIL_PMO_SANITY_ODM_DIVISIBILITY;
goto exit;
}
exit:
DML_LOG_DEBUG("%s exit with %s\n", __func__, dml2_status_str(status));
DML_LOG_COMP_IF_EXIT();
return status;
}
static void dml2_pmo_dcn5_apply_optimization_to_solution(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_config *optimization,
struct dml2_display_solution *solution)
{
unsigned int i;
const struct dml2_sop_table *sop_table = &pmo->utm_soc_bb->sop_table;
solution->unvalidated_change.raw = optimization->unvalidated_change.raw;
DML_LOG_DEBUG("solution->unvalidated_change.raw = 0x%X\n", solution->unvalidated_change.raw);
/* sop index */
sop_table->get_sop_constraint_at_index(sop_table,
optimization->config.min_sop_index, &solution->sop_constraint);
DML_LOG_VERBOSE("min_sop_index = %d\n", optimization->config.min_sop_index);
/* mpc overrides */
for (i = 0; i < solution->dispcfg.num_planes; i++)
if (optimization->config.mpc_combine_overrides[i]) {
solution->dispcfg.plane_descriptors[i].overrides.mpcc_combine_factor =
optimization->config.mpc_combine_overrides[i];
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.mpcc_combine_factor = %d\n",
i, solution->dispcfg.plane_descriptors[i].overrides.mpcc_combine_factor);
}
/* odm overrides */
for (i = 0; i < solution->dispcfg.num_streams; i++) {
switch (optimization->config.odm_combine_overrides[i]) {
case 1:
solution->dispcfg.stream_descriptors[i].overrides.odm_mode = dml2_odm_mode_bypass;
break;
case 2:
solution->dispcfg.stream_descriptors[i].overrides.odm_mode = dml2_odm_mode_combine_2to1;
break;
case 3:
solution->dispcfg.stream_descriptors[i].overrides.odm_mode = dml2_odm_mode_combine_3to1;
break;
case 4:
solution->dispcfg.stream_descriptors[i].overrides.odm_mode = dml2_odm_mode_combine_4to1;
break;
default:
break;
}
DML_LOG_VERBOSE("solution->dispcfg.stream_descriptors[%d].overrides.odm_mode = %d\n",
i, solution->dispcfg.stream_descriptors[i].overrides.odm_mode);
}
/* reserved vblank time */
for (i = 0; i < solution->dispcfg.num_planes; i++) {
solution->dispcfg.plane_descriptors[i].overrides.reserved_vblank_time_ns = (long) math_max2(
solution->dispcfg.plane_descriptors[i].overrides.reserved_vblank_time_ns,
optimization->config.reserved_vblank_time_ns[i]);
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.reserved_vblank_time_ns = %ld\n",
i, solution->dispcfg.plane_descriptors[i].overrides.reserved_vblank_time_ns);
}
/* mcache allocations */
for (i = 0; i < solution->dispcfg.num_planes; i++)
if (optimization->config.mcache_allocations[i].valid)
memcpy(&solution->mcache_allocations[i], &optimization->config.mcache_allocations[i],
sizeof(struct dml2_mcache_surface_allocation));
/* P-State switch method */
solution->uclk_pstate_params.support = optimization->config.uclk_pstate_support;
for (i = 0; i < solution->dispcfg.num_planes; i++) {
solution->uclk_pstate_params.pstate_switch_modes[i] = optimization->config.uclk_pstate_switch_modes[i];
DML_LOG_VERBOSE("solution->uclk_pstate_params.pstate_switch_modes[%d] = %d\n",
i, solution->uclk_pstate_params.pstate_switch_modes[i]);
}
/* P-State latency hiding */
for (i = 0; i < solution->dispcfg.num_planes; i++) {
memcpy(solution->dispcfg.plane_descriptors[i].overrides.max_vactive_det_fill_delay_us,
optimization->config.max_vactive_det_fill_delay_us[i],
sizeof(optimization->config.max_vactive_det_fill_delay_us[i]));
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.max_vactive_det_fill_delay_us[uclk] = %d\n",
i, solution->dispcfg.plane_descriptors[i].overrides.max_vactive_det_fill_delay_us[dml2_pstate_type_uclk]);
}
/* FAMS2 related */
solution->uclk_pstate_params.fams2_required = optimization->config.fams2_required;
DML_LOG_VERBOSE("solution->uclk_pstate_params.fams2_required = %s\n", solution->uclk_pstate_params.fams2_required ?
"true" : "false");
memcpy(&solution->uclk_pstate_params.stream_pstate_meta,
&optimization->config.stream_pstate_meta,
sizeof(struct dml2_pstate_meta) * DML2_MAX_PLANES);
/* fclk pstate */
solution->fclk_pstate_support = optimization->config.fclk_pstate_support;
DML_LOG_VERBOSE("solution->fclk_pstate_support = %s\n", solution->fclk_pstate_support ?
"true" : "false");
/* stutter */
solution->stutter_support_in_vblank = optimization->config.stutter_support_in_vblank;
solution->z8_stutter_support_in_vblank = optimization->config.z8_stutter_support_in_vblank;
DML_LOG_VERBOSE("solution->stutter_support_in_vblank = %s\n", solution->stutter_support_in_vblank ?
"true" : "false");
DML_LOG_VERBOSE("solution->z8_stutter_support_in_vblank = %s\n", solution->z8_stutter_support_in_vblank ?
"true" : "false");
/* dcfclk override */
if (optimization->config.enable_vmin_dcfclk) {
solution->dispcfg.overrides.hw.dcfclk_mhz = pmo->utm_soc_bb->vmin_limit.dcfclk_khz / 1000.0;
}
DML_LOG_VERBOSE("solution->dispcfg.overrides.hw.dcfclk_mhz = %f\n", solution->dispcfg.overrides.hw.dcfclk_mhz);
}
void dml2_pmo_dcn5_convert_worksheet_to_solution(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_worksheet *worksheet,
struct dml2_display_solution *solution)
{
DML_LOG_COMP_IF_ENTER();
memset(solution, 0, sizeof(struct dml2_display_solution));
solution->orig_dispcfg = worksheet->orig_dispcfg;
memcpy(&solution->dispcfg, worksheet->orig_dispcfg, sizeof(solution->dispcfg));
memcpy(&solution->validation_result, &worksheet->validation_result, sizeof(struct dml2_validation_result));
dml2_pmo_dcn5_apply_optimization_to_solution(pmo, &worksheet->cur, solution);
DML_LOG_COMP_IF_EXIT();
}
void dml2_pmo_dcn5_clear_pre_validation_states(struct dml2_pmo_instance *pmo,
struct dml2_optimization_worksheet *worksheet)
{
(void)pmo;
DML_LOG_COMP_IF_ENTER();
worksheet->cur.unvalidated_change.raw = 0;
DML_LOG_DEBUG("worksheet->cur.unvalidated_change.raw = %d\n", worksheet->cur.unvalidated_change.raw);
DML_LOG_COMP_IF_EXIT();
}

View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_PMO_DCN5_H__
#define __DML2_PMO_DCN5_H__
#include "dml2_internal_shared_types.h"
bool dml2_pmo_dcn5_initialize(struct dml2_pmo_initialize_in_out *in_out);
int dml2_pmo_dcn5_get_ordered_mandatory_stage_optimizers(struct dml2_pmo_instance *pmo, struct dml2_pmo_stage_optimizer **optimers);
int dml2_pmo_dcn5_get_ordered_optional_stages_optimizers(struct dml2_pmo_instance *pmo, struct dml2_pmo_stage_optimizer **optimers);
void dml2_pmo_dcn5_initialize_worksheet(struct dml2_pmo_instance *pmo,
const struct dml2_display_cfg *dispcfg,
struct dml2_optimization_worksheet *worksheet);
enum dml2_status dml2_pmo_dcn5_sanity_check(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_worksheet *worksheet);
void dml2_pmo_dcn5_convert_worksheet_to_solution(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_worksheet *worksheet,
struct dml2_display_solution *solution);
void dml2_pmo_dcn5_clear_pre_validation_states(struct dml2_pmo_instance *pmo,
struct dml2_optimization_worksheet *worksheet);
#endif /* __DML2_PMO_DCN5_H__ */

View File

@@ -0,0 +1,97 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024-2025 Advanced Micro Devices, Inc.
#ifndef __DML2_PMO_DCN5_STAGE_OPTIMIZERS_H__
#define __DML2_PMO_DCN5_STAGE_OPTIMIZERS_H__
#include "dml2_internal_shared_types.h"
void set_bit_in_bitfield(unsigned int *bit_field, unsigned int bit_offset);
bool is_bit_set_in_bitfield(unsigned int bit_field, unsigned int bit_offset);
int dcn5_get_vactive_pstate_margin(const struct dml2_validation_result *validation_res, int plane_mask);
void dcn5_build_method_scheduling_params(
struct dml2_pstate_per_method_common_meta *stream_method_pstate_meta,
const struct dml2_pstate_meta *stream_pstate_meta);
void dcn5_build_synchronized_timing_groups(
// Output
struct dml2_pmo_synchronized_timing_groups *s,
// Input
const struct dml2_display_cfg *display_config);
void dcn5_insert_strategy_into_expanded_list(
const struct dml2_pmo_pstate_strategy *per_stream_pstate_strategy,
const int stream_count,
struct dml2_pmo_pstate_strategy *expanded_strategy_list,
unsigned int *num_expanded_strategies);
bool dcn5_is_variant_method_valid(const struct dml2_pmo_pstate_strategy *base_strategy,
const struct dml2_pmo_pstate_strategy *variant_strategy,
const unsigned int num_streams_per_base_method[PMO_DCN4_MAX_DISPLAYS],
const unsigned int num_streams_per_variant_method[PMO_DCN4_MAX_DISPLAYS],
const unsigned int stream_count);
void dcn5_expand_base_strategy(
const struct dml2_pmo_pstate_strategy *base_strategy,
const unsigned int stream_count,
struct dml2_pmo_pstate_strategy *expanded_strategy_list,
unsigned int *num_expanded_strategies);
void dcn5_expand_variant_strategy(
const struct dml2_pmo_pstate_strategy *base_strategy,
const unsigned int stream_count,
const bool should_permute,
struct dml2_pmo_pstate_strategy *expanded_strategy_list,
unsigned int *num_expanded_strategies);
const struct dml2_pmo_pstate_strategy *dcn5_get_expanded_strategy_list(struct dml2_pmo_stage_optimizer *stage, int stream_count);
unsigned int dcn5_get_num_expanded_strategies(
struct dml2_pmo_stage_optimizer *stage,
int stream_count);
bool dcn5_stream_matches_drr_policy(struct dml2_pmo_stage_optimizer *stage,
const struct dml2_display_cfg *display_cfg,
const enum dml2_pstate_method stream_pstate_method,
unsigned int stream_index);
bool dcn5_all_timings_support_vactive(struct dml2_pmo_stage_optimizer *stage,
const struct dml2_display_cfg *display_config,
unsigned int mask);
bool dcn5_all_timings_support_vblank(struct dml2_pmo_stage_optimizer *stage,
const struct dml2_display_cfg *display_config,
unsigned int mask);
bool dcn5_all_timings_support_drr(struct dml2_pmo_stage_optimizer *stage,
const struct dml2_optimization_worksheet *worksheet,
const struct dml2_display_cfg *display_config,
unsigned int mask);
void dcn5_insert_into_candidate_list(const struct dml2_pmo_pstate_strategy *pstate_strategy, int stream_count, struct dml2_optimization_worksheet *worksheet);
void dcn5_reset_worksheet_for_uclk_pstate(struct dml2_optimization_worksheet *worksheet);
void dcn5_setup_planes_for_vactive_by_mask(struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet, int plane_mask);
void dcn5_setup_planes_for_vblank_by_mask(struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet, int plane_mask);
void dcn5_setup_planes_for_vactive_drr_by_mask(struct dml2_pmo_stage_optimizer *stage,
struct dml2_optimization_worksheet *worksheet,
int plane_mask);
void dcn5_setup_planes_for_vblank_drr_by_mask(struct dml2_pmo_stage_optimizer *stage,
struct dml2_optimization_worksheet *worksheet,
int plane_mask);
void dcn5_setup_planes_for_drr_by_mask(struct dml2_pmo_stage_optimizer *stage,
struct dml2_optimization_worksheet *worksheet,
int plane_mask);
int dcn5_get_vactive_det_fill_latency_delay_us(const struct dml2_validation_result *validation_res, int plane_mask);
int dcn5_get_minimum_reserved_time_us_for_planes(const struct dml2_optimization_worksheet *worksheet, int plane_mask);
/* Public DCN5 PMO optimizers */
void dml2_pmo_dcn5_stage_optimizer_qos_create(struct dml2_pmo_instance *pmo_inst,
struct dml2_pmo_stage_optimizer *optimizer);
void dml2_pmo_dcn5_stage_optimizer_mcache_create(struct dml2_pmo_instance *pmo_inst,
struct dml2_pmo_stage_optimizer *optimizer);
void dml2_pmo_dcn5_stage_optimizer_uclk_pstate_create(struct dml2_pmo_instance *pmo_inst,
struct dml2_pmo_stage_optimizer *optimizer);
void dml2_pmo_dcn5_stage_optimizer_vmin_create(struct dml2_pmo_instance *pmo_inst,
struct dml2_pmo_stage_optimizer *optimizer);
void dml2_pmo_dcn5_stage_optimizer_stutter_create(struct dml2_pmo_instance *pmo_inst,
struct dml2_pmo_stage_optimizer *optimizer);
void dml2_pmo_dcn5_stage_optimizer_mcache_init(
struct dml2_pmo_stage_optimizer *stage, struct dml2_optimization_worksheet *worksheet);
bool dml2_pmo_dcn5_stage_optimizer_mcache_test_total_mcache_limit(struct dml2_pmo_stage_optimizer *stage,
const struct dml2_optimization_worksheet *worksheet);
bool dml2_pmo_dcn5_stage_optimizer_mcache_test_mcache_status(struct dml2_pmo_stage_optimizer *stage,
const struct dml2_optimization_worksheet *worksheet);
bool dml2_pmo_dcn5_stage_optimizer_mcache_increment_pipe_usage(struct dml2_pmo_stage_optimizer *stage,
struct dml2_optimization_worksheet *worksheet);
void dml2_pmo_dcn5_stage_optimizer_mcache_apply_default_pipe_usage(struct dml2_pmo_stage_optimizer *stage,
struct dml2_optimization_worksheet *worksheet);
#endif /* __DML2_PMO_DCN5_STAGE_OPTIMIZERS_H__ */

View File

@@ -0,0 +1,506 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dml2_pmo_dcn6.h"
#include "dml2_pmo_dcn4_fams2.h"
#include "dml2_pmo_dcn5_stage_optimizers.h"
#include "dml2_pmo_dcn6_stage_optimizers.h"
#include "dml2_debug.h"
#include "lib_float_math.h"
static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_1_display[] = {
// VActive Preferred
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Then VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = false,
},
// Then DRR
{
.per_stream_pstate_method = { dml2_pstate_method_fw_drr, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Even-Odd
{
.per_stream_pstate_method = { dml2_pstate_method_alternate, dml2_pstate_method_na, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
};
static const int base_pstate_strategy_list_1_display_size = sizeof(base_pstate_strategy_list_1_display) / sizeof(struct dml2_pmo_pstate_strategy);
static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_2_display[] = {
// VActive only is preferred
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Then VActive + VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = false,
},
// Then VBlank only
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = false,
},
// Then DRR + VActive
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_fw_drr, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Then DRR + DRR
{
.per_stream_pstate_method = { dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Even-Odd
{
.per_stream_pstate_method = { dml2_pstate_method_alternate, dml2_pstate_method_alternate, dml2_pstate_method_na, dml2_pstate_method_na },
.allow_state_increase = true,
},
};
static const int base_pstate_strategy_list_2_display_size = sizeof(base_pstate_strategy_list_2_display) / sizeof(struct dml2_pmo_pstate_strategy);
static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_3_display[] = {
// All VActive
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_na },
.allow_state_increase = true,
},
// VActive + 1 VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vblank, dml2_pstate_method_na },
.allow_state_increase = false,
},
// All VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_na },
.allow_state_increase = false,
},
// All DRR
{
.per_stream_pstate_method = { dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_na },
.allow_state_increase = true,
},
// Even-Odd
{
.per_stream_pstate_method = { dml2_pstate_method_alternate, dml2_pstate_method_alternate, dml2_pstate_method_alternate, dml2_pstate_method_na },
.allow_state_increase = true,
},
};
static const int base_pstate_strategy_list_3_display_size = sizeof(base_pstate_strategy_list_3_display) / sizeof(struct dml2_pmo_pstate_strategy);
static const struct dml2_pmo_pstate_strategy base_pstate_strategy_list_4_display[] = {
// All VActive
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive },
.allow_state_increase = true,
},
// VActive + 1 VBlank
{
.per_stream_pstate_method = { dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vactive, dml2_pstate_method_vblank },
.allow_state_increase = false,
},
// All Vblank
{
.per_stream_pstate_method = { dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank, dml2_pstate_method_vblank },
.allow_state_increase = false,
},
// All DRR
{
.per_stream_pstate_method = { dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr, dml2_pstate_method_fw_drr },
.allow_state_increase = true,
},
// Even-Odd
{
.per_stream_pstate_method = { dml2_pstate_method_alternate, dml2_pstate_method_alternate, dml2_pstate_method_alternate, dml2_pstate_method_alternate },
.allow_state_increase = true,
},
};
static const int base_pstate_strategy_list_4_display_size = sizeof(base_pstate_strategy_list_4_display) / sizeof(struct dml2_pmo_pstate_strategy);
static void dml2_pmo_dcn6_assign_pstate_strategies(struct dml2_pmo_instance *pmo)
{
int i = 0;
/* generate permutations of p-state configs from base strategy list */
for (i = 1; i <= PMO_DCN4_MAX_DISPLAYS; i++) {
switch (i) {
case 1:
DML_ASSERT(base_pstate_strategy_list_1_display_size <= PMO_DCN4_MAX_BASE_STRATEGIES);
/* populate list */
pmo_dcn4_fams2_expand_base_pstate_strategies(
base_pstate_strategy_list_1_display,
base_pstate_strategy_list_1_display_size,
i,
pmo->init_data.pmo_dcn4.expanded_strategy_list_1_display,
&pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i - 1]);
break;
case 2:
DML_ASSERT(base_pstate_strategy_list_2_display_size <= PMO_DCN4_MAX_BASE_STRATEGIES);
/* populate list */
pmo_dcn4_fams2_expand_base_pstate_strategies(
base_pstate_strategy_list_2_display,
base_pstate_strategy_list_2_display_size,
i,
pmo->init_data.pmo_dcn4.expanded_strategy_list_2_display,
&pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i - 1]);
break;
case 3:
DML_ASSERT(base_pstate_strategy_list_3_display_size <= PMO_DCN4_MAX_BASE_STRATEGIES);
/* populate list */
pmo_dcn4_fams2_expand_base_pstate_strategies(
base_pstate_strategy_list_3_display,
base_pstate_strategy_list_3_display_size,
i,
pmo->init_data.pmo_dcn4.expanded_strategy_list_3_display,
&pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i - 1]);
break;
case 4:
DML_ASSERT(base_pstate_strategy_list_4_display_size <= PMO_DCN4_MAX_BASE_STRATEGIES);
/* populate list */
pmo_dcn4_fams2_expand_base_pstate_strategies(
base_pstate_strategy_list_4_display,
base_pstate_strategy_list_4_display_size,
i,
pmo->init_data.pmo_dcn4.expanded_strategy_list_4_display,
&pmo->init_data.pmo_dcn4.num_expanded_strategies_per_list[i - 1]);
break;
}
}
}
int dml2_pmo_dcn6a_get_ordered_mandatory_stage_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **stages)
{
int count = 0;
DML_LOG_COMP_IF_ENTER();
if (!pmo->options->force_optional_ppt_temp_read_admissibility)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_fclk_ppt_temp_read_pstate];
if (!pmo->options->force_optional_mcache_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_mcache];
if (!pmo->options->force_optional_uclk_pstate_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_uclk_pstate];
DML_LOG_DEBUG("%s exit with %d\n", __func__, count);
DML_LOG_COMP_IF_EXIT();
return count;
}
int dml2_pmo_dcn6a_get_ordered_optional_stages_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **stages)
{
int count = 0;
DML_LOG_COMP_IF_ENTER();
if (pmo->options->force_optional_ppt_temp_read_admissibility)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_fclk_ppt_temp_read_pstate];
if (pmo->options->force_optional_mcache_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_mcache];
if (pmo->options->force_optional_uclk_pstate_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_uclk_pstate];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_qos];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_vmin];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_stutter];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_vmin_dcfclk];
DML_LOG_DEBUG("%s exit with %d\n", __func__, count);
DML_LOG_COMP_IF_EXIT();
return count;
}
int dml2_pmo_dcn6b_get_ordered_mandatory_stage_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **stages)
{
int count = 0;
DML_LOG_COMP_IF_ENTER();
if (!pmo->options->force_optional_ppt_temp_read_admissibility)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_fclk_ppt_temp_read_pstate];
if (!pmo->options->force_optional_mcache_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_mcache];
DML_LOG_DEBUG("%s exit with %d\n", __func__, count);
DML_LOG_COMP_IF_EXIT();
return count;
}
int dml2_pmo_dcn6b_get_ordered_optional_stages_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **stages)
{
int count = 0;
DML_LOG_COMP_IF_ENTER();
if (pmo->options->force_optional_ppt_temp_read_admissibility)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_fclk_ppt_temp_read_pstate];
if (pmo->options->force_optional_mcache_support)
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_mcache];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_uclk_pstate];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_qos];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_vmin];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_stutter];
stages[count++] = &pmo->stage_optimizers[dml2_pmo_stage_index_vmin_dcfclk];
DML_LOG_DEBUG("%s exit with %d\n", __func__, count);
DML_LOG_COMP_IF_EXIT();
return count;
}
static enum dml2_uclk_pstate_change_strategy pstate_method_to_uclk_pstate_strategy_override(const enum dml2_pstate_method method)
{
enum dml2_uclk_pstate_change_strategy override_strategy = dml2_uclk_pstate_change_strategy_auto;
switch (method) {
case dml2_pstate_method_vactive:
case dml2_pstate_method_fw_vactive_drr:
override_strategy = dml2_uclk_pstate_change_strategy_force_vactive;
break;
case dml2_pstate_method_vblank:
case dml2_pstate_method_fw_vblank_drr:
override_strategy = dml2_uclk_pstate_change_strategy_force_vblank;
break;
case dml2_pstate_method_fw_drr:
override_strategy = dml2_uclk_pstate_change_strategy_force_drr;
break;
case dml2_pstate_method_alternate:
override_strategy = dml2_uclk_pstate_change_strategy_force_alternate;
break;
case dml2_pstate_method_fw_svp:
case dml2_pstate_method_fw_svp_drr:
case dml2_pstate_method_reserved_hw:
case dml2_pstate_method_reserved_fw:
case dml2_pstate_method_reserved_fw_drr_clamped:
case dml2_pstate_method_reserved_fw_drr_var:
case dml2_pstate_method_count:
case dml2_pstate_method_na:
default:
override_strategy = dml2_uclk_pstate_change_strategy_auto;
}
return override_strategy;
}
static void dml2_pmo_dcn6_apply_optimization_to_solution(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_config *optimization,
struct dml2_display_solution *solution)
{
unsigned int i;
const struct dml2_sop_table *sop_table = &pmo->utm_soc_bb->sop_table;
solution->unvalidated_change.raw = optimization->unvalidated_change.raw;
DML_LOG_DEBUG("solution->unvalidated_change.raw = 0x%X\n", solution->unvalidated_change.raw);
/* sop index */
sop_table->get_sop_constraint_at_index(sop_table,
optimization->config.min_sop_index, &solution->sop_constraint);
DML_LOG_VERBOSE("min_sop_index = %d\n", optimization->config.min_sop_index);
/* mpc overrides */
for (i = 0; i < solution->dispcfg.num_planes; i++)
if (optimization->config.mpc_combine_overrides[i]) {
solution->dispcfg.plane_descriptors[i].overrides.mpcc_combine_factor =
optimization->config.mpc_combine_overrides[i];
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.mpcc_combine_factor = %d\n",
i, solution->dispcfg.plane_descriptors[i].overrides.mpcc_combine_factor);
}
/* odm overrides */
for (i = 0; i < solution->dispcfg.num_streams; i++) {
switch (optimization->config.odm_combine_overrides[i]) {
case 1:
solution->dispcfg.stream_descriptors[i].overrides.odm_mode = dml2_odm_mode_bypass;
break;
case 2:
solution->dispcfg.stream_descriptors[i].overrides.odm_mode = dml2_odm_mode_combine_2to1;
break;
case 3:
solution->dispcfg.stream_descriptors[i].overrides.odm_mode = dml2_odm_mode_combine_3to1;
break;
case 4:
solution->dispcfg.stream_descriptors[i].overrides.odm_mode = dml2_odm_mode_combine_4to1;
break;
default:
break;
}
DML_LOG_VERBOSE("solution->dispcfg.stream_descriptors[%d].overrides.odm_mode = %d\n",
i, solution->dispcfg.stream_descriptors[i].overrides.odm_mode);
}
/* reserved vblank time */
for (i = 0; i < solution->dispcfg.num_planes; i++) {
solution->dispcfg.plane_descriptors[i].overrides.reserved_vblank_time_ns = (long) math_max2(
solution->dispcfg.plane_descriptors[i].overrides.reserved_vblank_time_ns,
optimization->config.reserved_vblank_time_ns[i]);
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.reserved_vblank_time_ns = %ld\n",
i, solution->dispcfg.plane_descriptors[i].overrides.reserved_vblank_time_ns);
}
/* mcache allocations */
for (i = 0; i < solution->dispcfg.num_planes; i++)
if (optimization->config.mcache_allocations[i].valid)
memcpy(&solution->mcache_allocations[i], &optimization->config.mcache_allocations[i],
sizeof(struct dml2_mcache_surface_allocation));
/* P-State switch method */
solution->uclk_pstate_params.support = optimization->config.uclk_pstate_support;
for (i = 0; i < solution->dispcfg.num_planes; i++) {
solution->uclk_pstate_params.pstate_switch_modes[i] = optimization->config.uclk_pstate_switch_modes[i];
solution->dispcfg.plane_descriptors[i].overrides.uclk_pstate_change_strategy
= pstate_method_to_uclk_pstate_strategy_override(optimization->config.uclk_pstate_switch_modes[i]);
DML_LOG_VERBOSE("solution->uclk_pstate_params.pstate_switch_modes[%d] = %d\n",
i, solution->uclk_pstate_params.pstate_switch_modes[i]);
}
/* VActive P-State DET fill time */
for (i = 0; i < solution->dispcfg.num_planes; i++) {
memcpy(solution->dispcfg.plane_descriptors[i].overrides.max_vactive_det_fill_delay_us,
optimization->config.max_vactive_det_fill_delay_us[i],
sizeof(optimization->config.max_vactive_det_fill_delay_us[i]));
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.max_vactive_det_fill_delay_us[uclk] = %d\n",
i, solution->dispcfg.plane_descriptors[i].overrides.max_vactive_det_fill_delay_us[dml2_pstate_type_uclk]);
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.max_vactive_det_fill_delay_us[fclk] = %d\n",
i, solution->dispcfg.plane_descriptors[i].overrides.max_vactive_det_fill_delay_us[dml2_pstate_type_fclk]);
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.max_vactive_det_fill_delay_us[ppt] = %d\n",
i, solution->dispcfg.plane_descriptors[i].overrides.max_vactive_det_fill_delay_us[dml2_pstate_type_ppt]);
DML_LOG_VERBOSE("solution->dispcfg.plane_descriptors[%d].overrides.max_vactive_det_fill_delay_us[temp] = %d\n",
i, solution->dispcfg.plane_descriptors[i].overrides.max_vactive_det_fill_delay_us[dml2_pstate_type_temp_read]);
}
/* FAMS2 related */
solution->uclk_pstate_params.fams2_required = optimization->config.fams2_required;
solution->uclk_pstate_params.legacy_pstate_info_for_dmu = optimization->config.legacy_pstate_info_for_dmu;
DML_LOG_VERBOSE("solution->uclk_pstate_params.fams2_required = %s\n", solution->uclk_pstate_params.fams2_required ?
"true" : "false");
memcpy(&solution->uclk_pstate_params.stream_pstate_meta,
&optimization->config.stream_pstate_meta,
sizeof(struct dml2_pstate_meta) * DML2_MAX_PLANES);
/* fclk pstate */
solution->fclk_pstate_support = optimization->config.fclk_pstate_support;
DML_LOG_VERBOSE("solution->fclk_pstate_support = %s\n", solution->fclk_pstate_support ?
"true" : "false");
/* ppt and temp read pstate */
solution->ppt_temp_read_support = optimization->config.ppt_temp_read_support;
DML_LOG_VERBOSE("solution->ppt_temp_read_support = %s\n", solution->ppt_temp_read_support ?
"true" : "false");
/* stutter */
solution->stutter_support_in_vblank = optimization->config.stutter_support_in_vblank;
solution->z8_stutter_support_in_vblank = optimization->config.z8_stutter_support_in_vblank;
DML_LOG_VERBOSE("solution->stutter_support_in_vblank = %s\n", solution->stutter_support_in_vblank ?
"true" : "false");
DML_LOG_VERBOSE("solution->z8_stutter_support_in_vblank = %s\n", solution->z8_stutter_support_in_vblank ?
"true" : "false");
/* dcfclk override */
if (optimization->config.enable_vmin_dcfclk) {
solution->dispcfg.overrides.hw.dcfclk_mhz = pmo->utm_soc_bb->vmin_limit.dcfclk_khz / 1000.0;
}
DML_LOG_VERBOSE("solution->dispcfg.overrides.hw.dcfclk_mhz = %f\n", solution->dispcfg.overrides.hw.dcfclk_mhz);
}
void dml2_pmo_dcn6_convert_worksheet_to_solution(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_worksheet *worksheet,
struct dml2_display_solution *solution)
{
DML_LOG_COMP_IF_ENTER();
memset(solution, 0, sizeof(struct dml2_display_solution));
solution->orig_dispcfg = worksheet->orig_dispcfg;
memcpy(&solution->dispcfg, worksheet->orig_dispcfg, sizeof(solution->dispcfg));
memcpy(solution->timing_group_ids, worksheet->timing_group_ids, sizeof(solution->timing_group_ids));
solution->timing_group_count = worksheet->timing_group_count;
memcpy(&solution->validation_result, &worksheet->validation_result, sizeof(struct dml2_validation_result));
dml2_pmo_dcn6_apply_optimization_to_solution(pmo, &worksheet->cur, solution);
DML_LOG_COMP_IF_EXIT();
}
bool dml2_pmo_dcn6a_initialize(struct dml2_pmo_initialize_in_out *in_out)
{
struct dml2_pmo_instance *pmo = in_out->instance;
DML_LOG_COMP_IF_ENTER();
pmo->ip_caps = in_out->ip_caps;
pmo->options = in_out->options;
pmo->utm_soc_bb = in_out->utm_soc_bb;
pmo->mpc_combine_limit = 2;
pmo->odm_combine_limit = 4;
pmo->fams_params.v2.drr.refresh_rate_limit_max = 1000;
pmo->fams_params.v2.drr.refresh_rate_limit_min = 119;
dml2_pmo_dcn6_assign_pstate_strategies(pmo);
dml2_pmo_dcn6_stage_optimizer_mcache_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_mcache]);
dml2_pmo_dcn6_stage_optimizer_uclk_pstate_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_uclk_pstate]);
dml2_pmo_dcn5_stage_optimizer_qos_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_qos]);
dml2_pmo_dcn5_stage_optimizer_vmin_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_vmin]);
dml2_pmo_dcn5_stage_optimizer_stutter_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_stutter]);
dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_vmin_dcfclk]);
dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_fclk_ppt_temp_read_pstate]);
DML_LOG_DEBUG("%s exit with true\n", __func__);
DML_LOG_COMP_IF_EXIT();
return true;
}
bool dml2_pmo_dcn6b_initialize(struct dml2_pmo_initialize_in_out *in_out)
{
struct dml2_pmo_instance *pmo = in_out->instance;
DML_LOG_COMP_IF_ENTER();
pmo->ip_caps = in_out->ip_caps;
pmo->options = in_out->options;
pmo->options->disable_alternate_memory_training = true;
pmo->utm_soc_bb = in_out->utm_soc_bb;
pmo->mpc_combine_limit = 2;
pmo->odm_combine_limit = 4;
pmo->fams_params.v2.drr.refresh_rate_limit_max = 1000;
pmo->fams_params.v2.drr.refresh_rate_limit_min = 119;
dml2_pmo_dcn6_assign_pstate_strategies(pmo);
dml2_pmo_dcn6_stage_optimizer_mcache_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_mcache]);
dml2_pmo_dcn6_stage_optimizer_uclk_pstate_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_uclk_pstate]);
dml2_pmo_dcn5_stage_optimizer_qos_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_qos]);
dml2_pmo_dcn5_stage_optimizer_vmin_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_vmin]);
dml2_pmo_dcn5_stage_optimizer_stutter_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_stutter]);
dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_vmin_dcfclk]);
dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_create(pmo, &pmo->stage_optimizers[dml2_pmo_stage_index_fclk_ppt_temp_read_pstate]);
DML_LOG_DEBUG("%s exit with true\n", __func__);
DML_LOG_COMP_IF_EXIT();
return true;
}

View File

@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DML2_PMO_DCN6_H__
#define __DML2_PMO_DCN6_H__
#include "dml2_internal_shared_types.h"
bool dml2_pmo_dcn6a_initialize(struct dml2_pmo_initialize_in_out *in_out);
int dml2_pmo_dcn6a_get_ordered_mandatory_stage_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **optimers);
int dml2_pmo_dcn6a_get_ordered_optional_stages_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **optimers);
bool dml2_pmo_dcn6b_initialize(struct dml2_pmo_initialize_in_out *in_out);
int dml2_pmo_dcn6b_get_ordered_mandatory_stage_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **optimers);
int dml2_pmo_dcn6b_get_ordered_optional_stages_optimizers(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer **optimers);
void dml2_pmo_dcn6_convert_worksheet_to_solution(struct dml2_pmo_instance *pmo,
const struct dml2_optimization_worksheet *worksheet,
struct dml2_display_solution *solution);
#endif /* __DML2_PMO_DCN6_H__ */

View File

@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DML2_PMO_DCN6_STAGE_OPTIMIZERS_H__
#define __DML2_PMO_DCN6_STAGE_OPTIMIZERS_H__
#include "dml2_internal_shared_types.h"
void dml2_pmo_dcn6_stage_optimizer_uclk_pstate_create(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer *stage);
void dml2_pmo_dcn6_stage_optimizer_vmin_dcfclk_create(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer *stage);
void dml2_pmo_dcn6_stage_optimizer_mcache_create(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer *stage);
void dml2_pmo_dcn6_stage_optimizer_fclk_ppt_temp_read_pstate_create(struct dml2_pmo_instance *pmo,
struct dml2_pmo_stage_optimizer *stage);
#endif /* __DML2_PMO_DCN6_STAGE_OPTIMIZERS_H__ */

View File

@@ -0,0 +1,109 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved.
*/
#ifndef ALT_PSTATE_SHARED_H
#define ALT_PSTATE_SHARED_H
#include "dmub_cmd.h"
#define END_SWATH_REC 0xFFFF
#define END_SWATH_PRE 0xFFFFF
#define NEXT_FRAME_MASK 0x80000000
#define SWATH_MASK 0x7FFFFFFF
#define MAX_FRAME_COUNT 0xFFFFFF
#define PROGRAM_GO_IMMEDIATE 0xFFFFFFFF
#define MAX_SUBVP_HEIGHT 0xFFF
#define MAX_SUBVP_START_LINE 0xFFFF
struct get_swath_deadlines_params {
/* inputs */
struct dmub_fams2_cmd_stream_static_base_state *base;
struct dmub_fams2_cmd_alternate_stream_static_state *alternate_static_state;
uint8_t plane_index;
uint16_t vtotal;
uint16_t rec_y_start;
bool chroma_plane;
/* outputs */
uint16_t *swath_array; // caller must allocate it's own memory for the output
uint16_t *array_size;
};
struct calculate_hubp_start_end_lines_params {
/* inputs */
struct dmub_fams2_cmd_stream_static_base_state *base;
struct dmub_fams2_cmd_alternate_stream_static_state *alternate_static_state;
uint32_t current_otg_line; // [dst line]
uint32_t current_frame_count; // reference frame count
uint32_t otg_pstate_target; // [dst line]
uint32_t target_frame_count; // target frame count that we expect to assert P-State allow
uint16_t vtotal;
uint16_t rec_y_start;
uint8_t plane_index;
uint8_t cursor_size;
bool chroma_plane;
/* outputs */
uint16_t svp0_start_line;
uint16_t svp0_height;
uint16_t svp0_height_next;
uint16_t svp1_start_line;
uint16_t svp1_height;
uint16_t svp1_height_next;
uint8_t svp_position;
uint32_t program_go_line;
uint32_t program_go_frame_count;
/* for debug */
uint16_t svp0_start_dst_line;
uint16_t svp0_end_dst_line;
uint16_t svp1_start_dst_line;
uint16_t svp1_end_dst_line;
};
struct calculate_copy_from_primary_params {
/* inputs */
uint32_t target_frame;
uint32_t flip_pending;
uint32_t flip_pending_clear_frame;
/* outputs */
bool copy_from_primary;
};
struct svp_params {
uint16_t start_line;
uint16_t height;
uint16_t height_next;
};
struct calculate_lsdma_copy_params {
/* inputs */
struct dmub_fams2_cmd_stream_static_base_state *base;
struct dmub_fams2_cmd_alternate_stream_static_state *alternate_static_state;
uint8_t plane_index;
struct svp_params svp[2]; // array of 2 for svp0 and svp1
struct svp_params svp_c[2]; // array of 2 for svp0 and svp1
/* outputs */
struct lsdma_outputs out[2]; // array of 2 for svp0 and svp1
struct lsdma_outputs out_c[2]; // array of 2 for svp0 and svp1
};
void calculate_lsdma_copy(struct calculate_lsdma_copy_params *p);
void calculate_copy_from_primary(struct calculate_copy_from_primary_params *p);
void get_swath_deadlines(struct get_swath_deadlines_params *p);
void calculate_hubp_start_end_lines(struct calculate_hubp_start_end_lines_params *p);
int32_t get_prefetch_start_line_x1000(uint32_t vtotal, uint16_t vblank_end, uint16_t recout_y, uint16_t dst_y_prefetch_x1000, uint8_t prefetch_relative_vblank, uint16_t dst_y_after_scaler);
int32_t get_prefetch_end_line(uint32_t vtotal, uint16_t vblank_end, uint16_t recout_y, uint8_t prefetch_relative_vblank, uint16_t dst_y_after_scaler);
uint16_t get_effective_vblank_start(uint16_t vblank_start, uint16_t vblank_end, uint16_t recout_y, uint16_t recout_height);
bool in_circular_range(uint32_t start, uint32_t end, uint32_t value);
#endif /* ALT_PSTATE_SHARED_H */

View File

@@ -0,0 +1,394 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_top_utm.h"
#include "dml2_top_soc15.h"
#include "dml2_mcg_factory.h"
#include "dml2_dpmm_factory.h"
#include "dml2_core_factory.h"
#include "dml2_pmo_factory.h"
#include "dml2_utm_soc_bb_factory.h"
#include "dml2_cga_factory.h"
#include "dml2_debug.h"
static void dml2_top_backup_worksheet(struct dml2_instance *dml, const struct dml2_optimization_worksheet *worksheet)
{
memcpy(&dml->scratch.worksheet_backup, worksheet, sizeof(struct dml2_optimization_worksheet));
}
static void dml2_top_restore_worksheet(struct dml2_instance *dml, struct dml2_optimization_worksheet *worksheet)
{
memcpy(worksheet, &dml->scratch.worksheet_backup, sizeof(struct dml2_optimization_worksheet));
}
static enum dml2_status dml2_top_validate_worksheet(struct dml2_instance *dml,
struct dml2_optimization_worksheet *worksheet)
{
struct dml2_pmo_instance *pmo = &dml->pmo_instance;
struct dml2_core_instance *core = &dml->core_instance;
struct dml2_display_solution *solution = &dml->scratch.solution;
enum dml2_status status;
/*
* validate_solution is time consuming. So this sanity check is a performance optimization so we can rule out
* some common configuration problems during PMO optimization without running the whole core sequence. It is a
* subset of validation_solution interface. For example, it may check if pipe usage exceeds total pipe
* availability. Ideally validate_solution should have done a better job of optimizing its performance so this
* PMO interface is not necessary.
*/
status = pmo->optional_sanity_check(pmo, worksheet);
if (status == DML2_STATUS_OK) {
pmo->convert_worksheet_to_solution(pmo, worksheet, solution);
status = core->validate_solution(core, solution, &worksheet->validation_result);
pmo->clear_pre_validation_states(pmo, worksheet);
} else
worksheet->validation_result.is_mode_support_valid = false;
return status;
}
static enum dml2_status dml2_top_perform_stage_optimization(struct dml2_instance *dml,
struct dml2_pmo_stage_optimizer *optimizer,
struct dml2_optimization_worksheet *worksheet)
{
static const unsigned int MAX_OPTIMIZATION_ITERATIONS = 20;
unsigned int iteration = 0;
enum dml2_status cur_validate_status = DML2_STATUS_OK;
enum dml2_status cur_optimize_status = DML2_STATUS_UNKNOWN;
/*
* true if the function finds at least one validated worksheet passing permissibility test from current stage
* optimizer.
*/
bool is_permissible_found = false;
dml2_top_backup_worksheet(dml, worksheet);
/*
* init interface builds the initial states associated with the current stage optimizer into the worksheet. It
* is for state initialization only. It should not apply new optimization or cause changes to current validation
* result. It is safe to assume that the worksheet passed in or exited from this interface is always validated.
*/
optimizer->init(optimizer, worksheet);
/*
* optimize_next interface controls current optimization's stop conditions. When the interface returns false, it
* means the stage optimizer no longer needs to attempt further optimization. The current worksheet should be
* left unmodified. When the interface returns true, it means the stage optimizer applied new optimization to
* the worksheet. DML top will need to validate and test permissibility again. The worksheet passed in is based
* off the optimization decision from last attempt. It may or may not be validated or permissible. It is upto
* DML top to keep track of the last valid permissible worksheet. This interface is also responsible to clear
* corresponding valid bits in worksheet's validation result based on what optimization it gets applied. When
* the valid bits are cleared, it will be revalidated by top. Otherwise, DML top will assume it is safe to skip
* certain re-validations based on the remaining valid bits. Stage optimizers should clear only the necessary
* valid bits based on the optimization applied to speed up the process.
*/
while (optimizer->optimize_next(optimizer, worksheet)) {
if (++iteration >= MAX_OPTIMIZATION_ITERATIONS) {
cur_optimize_status = DML2_STATUS_OPTIMIZE_FAIL_EXCEED_MAX_ITERATION;
break;
}
cur_optimize_status = DML2_STATUS_UNKNOWN;
cur_validate_status = dml2_top_validate_worksheet(dml, worksheet);
if (cur_validate_status == DML2_STATUS_OK)
/*
* test_permissibility interface should only check against current optimizer policy specific
* minimum requirements. Test permissibility result is orthogonal to validation result. It is
* safe to assume the worksheet constant passed in is always validated. The interface checks if
* the validated result fulfills the minimum requirements additionally imposed by current stage
* optimizer in order to consider the current optimization as a potential candidate. Stage
* optimizer may still attempt further optimization even if the current one is permissible.
*/
cur_optimize_status = optimizer->test_permissibility(optimizer, worksheet);
if (cur_validate_status == DML2_STATUS_OK && cur_optimize_status == DML2_STATUS_OK) {
is_permissible_found = true;
dml2_top_backup_worksheet(dml, worksheet);
}
}
/*
* When optimize next returns false in the first iteration, test permissibility interface is never called. In
* this case, we need to call it and check if current worksheet is already permissible.
*/
if (cur_validate_status == DML2_STATUS_OK && cur_optimize_status == DML2_STATUS_UNKNOWN) {
cur_optimize_status = optimizer->test_permissibility(optimizer, worksheet);
if (cur_optimize_status == DML2_STATUS_OK)
is_permissible_found = true;
}
if (cur_validate_status != DML2_STATUS_OK || cur_optimize_status != DML2_STATUS_OK)
dml2_top_restore_worksheet(dml, worksheet);
DML_ASSERT_MSG(worksheet->validation_result.is_mode_support_valid
&& worksheet->validation_result.is_mcache_allocation_valid
&& worksheet->validation_result.is_prefetch_valid,
"worksheet must be valid on exit independent from optmization resul!\n");
// DML_ASSERT_MSG(iteration <= MAX_OPTIMIZATION_ITERATIONS,
// "exceeds max optimization iterations!\n"
// "\t is_permissible_found = %s\n"
// "\t cur_validate_status = %s\n"
// "\t cur_optimize_status = %s\n",
// is_permissible_found ? "true" : "false",
// dml2_status_str(cur_validate_status),
// dml2_status_str(cur_optimize_status));
return is_permissible_found ? DML2_STATUS_OK :
(cur_validate_status != DML2_STATUS_OK) ? cur_validate_status : cur_optimize_status;
}
static enum dml2_status dml2_top_build_and_validate_unoptimized_worksheet(
struct dml2_instance *dml,
const struct dml2_display_cfg *orig_dispcfg,
struct dml2_optimization_worksheet *worksheet)
{
enum dml2_status status = DML2_STATUS_OK;
struct dml2_pmo_instance *pmo = &dml->pmo_instance;
struct dml2_pmo_stage_optimizer *optimizers[dml2_pmo_stage_index_max];
int count;
int i;
if (status == DML2_STATUS_OK) {
pmo->initialize_worksheet(pmo, orig_dispcfg, worksheet);
status = dml2_top_validate_worksheet(dml, worksheet);
}
if (status == DML2_STATUS_OK) {
count = pmo->get_ordered_mandatory_stage_optimizers(pmo, optimizers);
for (i = 0; i < count; i++) {
status = dml2_top_perform_stage_optimization(dml, optimizers[i], worksheet);
if (status != DML2_STATUS_OK)
break;
}
}
return status;
}
static void dml2_top_optimize_worksheet(struct dml2_instance *dml,
struct dml2_optimization_worksheet *worksheet)
{
struct dml2_pmo_instance *pmo = &dml->pmo_instance;
struct dml2_pmo_stage_optimizer *ordered_optional_stage_optimizers[dml2_pmo_stage_index_max];
int count;
int i;
DML_ASSERT(worksheet->validation_result.is_mode_support_valid);
count = pmo->get_ordered_optional_stage_optimizers(pmo, ordered_optional_stage_optimizers);
for (i = 0; i < count; i++)
dml2_top_perform_stage_optimization(dml, ordered_optional_stage_optimizers[i], worksheet);
}
static enum dml2_status dml2_top_map_minimum_clock_state(struct dml2_instance *dml,
struct dml2_display_solution *solution,
struct dml2_display_cfg_programming *programming)
{
bool result;
struct dml2_dpmm_map_mode_to_soc_dpm_params_in_out *params =
&dml->scratch.build_mode_programming_locals.dppm_map_mode_params;
struct dml2_dpmm_instance *dpmm = &dml->dpmm_instance;
if (!dpmm->map_mode_to_soc_dpm)
return DML2_STATUS_OK;
params->utm_soc_bb = &dml->utm_soc_bb;
params->ip = &dml->core_instance.clean_me_up.mode_lib.ip;
params->solution = solution;
params->programming = programming;
result = dpmm->map_mode_to_soc_dpm(params);
return result ? DML2_STATUS_OK : DML2_STATUS_POPULATE_FAIL_MIN_CLOCK_STATE;
}
static enum dml2_status dml2_top_populate_mode_programming(struct dml2_instance *dml,
const struct dml2_display_solution *solution,
struct dml2_display_cfg_programming *programming)
{
enum dml2_status status;
struct dml2_core_instance *core = &dml->core_instance;
status = core->populate_programming(core, solution, programming);
return status;
}
static void dml2_top_populate_informative(struct dml2_instance *dml,
enum dml2_status status,
struct dml2_display_cfg_programming *programming)
{
struct dml2_core_populate_informative_in_out *params = &dml->scratch.build_mode_programming_locals.informative_params;
struct dml2_core_instance *core = &dml->core_instance;
params->instance = core;
params->programming = programming;
params->mode_is_supported = (status == DML2_STATUS_OK);
params->instance->scratch.mode_programming_locals.mode_programming_ex_params.min_clk_index =
dml->scratch.solution.sop_constraint.dcn5.min_sop_index;
dml->core_instance.populate_informative(params);
if (status == DML2_STATUS_POPULATE_FAIL_PROGRAMMING ||
status == DML2_STATUS_VALIDATE_FAIL_MODE_SUPPORT_PREFETCH ||
status == DML2_STATUS_VALIDATE_FAIL_MODE_SUPPORT_PREFETCH_URGENT)
programming->informative.failed_mode_programming_prefetch = true;
else if (status == DML2_STATUS_POPULATE_FAIL_PROGRAMMING_DCFCLK)
programming->informative.failed_mode_programming_dcfclk = true;
else if (status == DML2_STATUS_POPULATE_FAIL_PROGRAMMING_FLIP_BANDWIDTH ||
status == DML2_STATUS_VALIDATE_FAIL_MODE_SUPPORT_QOS_BANDWIDTH)
programming->informative.failed_mode_programming_flip = true;
else if (status == DML2_STATUS_POPULATE_FAIL_MIN_CLOCK_STATE)
programming->informative.failed_dpmm = true;
else if (status == DML2_STATUS_VALIDATE_FAIL_MCACHE ||
status == DML2_STATUS_OPTIMIZE_FAIL_MCACHE ||
status == DML2_STATUS_VALIDATE_FAIL_PMO_SANITY_TOTAL_PIPE_USAGE)
programming->informative.failed_mcache_validation = true;
else if (status == DML2_STATUS_OPTIMIZE_FAIL_UCLK_PSTATE)
programming->informative.failed_uclk_pstate = true;
else if (status == DML2_STATUS_VALIDATE_FAIL_PREFETCH)
programming->informative.failed_prefetch = true;
}
static enum dml2_status dml2_top_build_programming_for_worksheet(
struct dml2_instance *dml, const struct dml2_optimization_worksheet *worksheet,
struct dml2_display_cfg_programming *programming)
{
enum dml2_status status = DML2_STATUS_OK;
struct dml2_display_solution *solution = &dml->scratch.solution;
struct dml2_pmo_instance *pmo = &dml->pmo_instance;
memset(programming, 0, sizeof(struct dml2_display_cfg_programming));
pmo->convert_worksheet_to_solution(pmo, worksheet, solution);
if (status == DML2_STATUS_OK)
status = dml2_top_map_minimum_clock_state(dml, solution, programming);
if (status == DML2_STATUS_OK)
status = dml2_top_populate_mode_programming(dml, solution, programming);
return status;
}
static bool dml2_top_utm_check_mode_supported(struct dml2_check_mode_supported_in_out *in_out)
{
enum dml2_status status = DML2_STATUS_OK;
struct dml2_instance *dml = in_out->dml2_instance;
DML_LOG_TOP_IF_ENTER();
/*
* Design Policy Note:
* To keep the consistency of check mode support and build mode programming interfaces, the returned status
* should be both based on the unified function below. Check mode support should not make coding assumptions in
* an effort to optimize check mode support performance. If A comes out as the unoptimized worksheet in check
* mode support interface, build mode programming must regenerate A with the same logic and then execute extra
* (i.e A->B->C->D). If check mode support does A->C', while build mode programming does A->B->C->D, then the
* design is considered as compromised. We are making the assumption that C' is always equal to C. This
* assumption can not be universally guaranteed for all DCNs by current design.
*/
status = dml2_top_build_and_validate_unoptimized_worksheet(
dml, in_out->display_config, &dml->scratch.worksheet);
in_out->is_supported = (status == DML2_STATUS_OK);
DML_LOG_INFO("%s exit with %s\n", __func__, dml2_status_str(status));
DML_LOG_TOP_IF_EXIT();
return true;
}
static bool dml2_top_utm_build_mode_programming(struct dml2_build_mode_programming_in_out *in_out)
{
struct dml2_instance *dml = in_out->dml2_instance;
struct dml2_optimization_worksheet *worksheet = &dml->scratch.worksheet;
enum dml2_status status = DML2_STATUS_OK;
DML_LOG_TOP_IF_ENTER();
if (status == DML2_STATUS_OK)
status = dml2_top_build_and_validate_unoptimized_worksheet(dml, in_out->display_config, worksheet);
if (status == DML2_STATUS_OK) {
dml2_top_optimize_worksheet(dml, worksheet);
status = dml2_top_build_programming_for_worksheet(dml, worksheet, in_out->programming);
if (status != DML2_STATUS_OK)
DML_LOG_ERROR("build mode programming fails for a supported display config! (%s)\n",
dml2_status_str(status));
}
dml2_top_populate_informative(dml, status, in_out->programming);
if (status == DML2_STATUS_OK)
DML_LOG_INFO("%s exit with %s\n", __func__, dml2_status_str(status));
else
DML_LOG_WARN("%s exit with %s\n", __func__, dml2_status_str(status));
DML_LOG_TOP_IF_EXIT();
return status == DML2_STATUS_OK;
}
static const struct dml2_top_funcs utm_funcs = {
.check_mode_supported = dml2_top_utm_check_mode_supported,
.build_mode_programming = dml2_top_utm_build_mode_programming,
.build_mcache_programming = dml2_top_soc15_build_mcache_programming,
};
bool dml2_top_utm_initialize_instance(struct dml2_initialize_instance_in_out *in_out)
{
struct dml2_instance *dml = in_out->dml2_instance;
struct dml2_core_initialize_in_out core_init_params = { 0 };
struct dml2_pmo_initialize_in_out pmo_init_params = { 0 };
struct dml2_cga_initialize_in_out cga_init_params = { 0 };
bool result = true;
DML_LOG_TOP_IF_ENTER();
memset(dml, 0, sizeof(struct dml2_instance));
if (result) {
memcpy(&dml->ip_caps, &in_out->ip_caps, sizeof(struct dml2_ip_capabilities));
dml->project_id = in_out->options.project_id;
dml->pmo_options = in_out->options.pmo_options;
dml->funcs = utm_funcs;
}
if (result)
result = dml2_dpmm_create(in_out->options.project_id, &dml->dpmm_instance);
if (result)
result = dml2_core_create(in_out->options.project_id, &dml->core_instance);
if (result)
result = dml2_pmo_create(in_out->options.project_id, &dml->pmo_instance);
if (result)
result = dml2_utm_soc_bb_create(in_out->options.project_id, &dml->utm_soc_bb,
&in_out->soc_bb, in_out->overrides.explicit_qos_model);
if (result)
result = dml2_cga_create(in_out->options.project_id, &dml->clock_adjuster);
if (result) {
core_init_params.project_id = in_out->options.project_id;
core_init_params.instance = &dml->core_instance;
core_init_params.explicit_ip_bb = in_out->overrides.explicit_ip_bb;
core_init_params.explicit_ip_bb_size = in_out->overrides.explicit_ip_bb_size;
core_init_params.ip_caps = &dml->ip_caps;
core_init_params.utm_soc_bb = &dml->utm_soc_bb;
core_init_params.clock_adjuster = &dml->clock_adjuster;
result = dml->core_instance.initialize(&core_init_params);
}
if (result) {
pmo_init_params.instance = &dml->pmo_instance;
pmo_init_params.ip_caps = &dml->ip_caps;
pmo_init_params.utm_soc_bb = &dml->utm_soc_bb;
pmo_init_params.options = &dml->pmo_options;
dml->pmo_instance.initialize(&pmo_init_params);
}
if (result && dml->clock_adjuster.initialize) {
cga_init_params.adjuster = &dml->clock_adjuster;
cga_init_params.soc_bb = &in_out->soc_bb;
cga_init_params.ip = &dml->core_instance.clean_me_up.mode_lib.ip;
dml->clock_adjuster.initialize(&cga_init_params);
}
DML_LOG_DEBUG("%s exit with %s\n", __func__, result ? "true":"false");
DML_LOG_TOP_IF_EXIT();
return result;
}

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_TOP_UTM_H__
#define __DML2_TOP_UTM_H__
#include "dml2_internal_shared_types.h"
bool dml2_top_utm_initialize_instance(struct dml2_initialize_instance_in_out *in_out);
#endif /* __DML2_TOP_UTM_H__ */

View File

@@ -0,0 +1,144 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_utm_soc_bb_dcn5.h"
#include "bounding_boxes/dcn5_soc_bb.h"
#include "dml2_debug.h"
static unsigned int dcn5_sop_table_get_highest_index(const struct dml2_sop_table *table)
{
return table->model->sop_count - 1;
}
static void dcn5_sop_table_get_sop_constraint_at_index(const struct dml2_sop_table *table,
unsigned int index, struct dml2_sop_constraint *constraint)
{
const struct utm_qos_model *model = table->model;
const struct utm_qos_model_dchub_v1 *dchub = model->dchub_v1;
DML_ASSERT_MSG(index < model->sop_count, "unsupported sop index\n");
constraint->dcn5.clocks.fclk_khz = model->sops[index].fclk_khz;
constraint->dcn5.clocks.uclk_khz = model->sops[index].uclk_khz;
constraint->dcn5.clocks.dcfclk_khz = dchub->dcfclks_khz[index];
constraint->dcn5.clocks.socclk_khz = dchub->socclks_khz[index];
constraint->dcn5.latency.dcn5.urgent_ramp = dchub->latencies[index].urgent_ramp_ps / 1000000.0;
constraint->dcn5.latency.dcn5.t_trip = dchub->latencies[index].t_trip_ps / 1000000.0;
constraint->dcn5.latency.dcn5.meta_trip_to_mem = dchub->latencies[index].meta_trip_to_mem_ps / 1000000.0;
constraint->dcn5.latency.dcn5.max_req_latency_urg = dchub->latencies[index].max_req_latency_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.avg_req_latency_urg = dchub->latencies[index].avg_req_latency_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.max_req_latency_non_urg = dchub->latencies[index].max_req_latency_non_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.avg_req_latency_non_urg = dchub->latencies[index].avg_req_latency_non_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.df_response_time_us = dchub->latencies[index].df_response_time_ps / 1000000.0;
constraint->dcn5.min_available_urgent_bandwidth_KBps = dchub->bandwidths[index].urgent_bandwidth_KBps;
constraint->dcn5.min_sop_index = index;
}
static bool dcn5_sop_table_is_bandwidth_supported_at_index(
const struct dml2_sop_table *table, const struct dml2_memory_path_bandwidth *bw, unsigned int index)
{
struct utm_qos_model_dchub_memory_path_bandwidth_v1 qos_bandwidth;
bool result = true;
qos_bandwidth.nominal_bandwidth_KBps = (uint32_t) bw->dcn5.non_urgent_bandwidth_kbps;
qos_bandwidth.urgent_bandwidth_KBps = (uint32_t) bw->dcn5.urgent_bandwidth_kbps;
if (!dchub_v1_is_qos_bandwidth_supported_by_sop(table->model, &qos_bandwidth, (uint8_t) index))
result = false;
return result;
}
static void dcn5_sop_table_get_max_sop(const struct dml2_sop_table *table, struct dml2_soc_operating_point *sop)
{
const struct utm_qos_model *model = table->model;
const struct utm_qos_model_dchub_v1 *dchub = model->dchub_v1;
DML_ASSERT_MSG(model->sop_count > 0, "utm_qos_model must contain at least 1 sop\n");
if (model->sop_count > 0) {
sop->fclk_khz = model->sops[model->sop_count-1].fclk_khz;
sop->uclk_khz = model->sops[model->sop_count-1].uclk_khz;
sop->dcfclk_khz = dchub->dcfclks_khz[model->sop_count-1];
sop->socclk_khz = dchub->socclks_khz[model->sop_count-1];
}
}
static void dcn5_sop_table_get_min_sop(const struct dml2_sop_table *table, struct dml2_soc_operating_point *sop)
{
const struct utm_qos_model *model = table->model;
const struct utm_qos_model_dchub_v1 *dchub = model->dchub_v1;
sop->fclk_khz = model->sops[0].fclk_khz;
sop->uclk_khz = model->sops[0].uclk_khz;
sop->dcfclk_khz = dchub->dcfclks_khz[0];
sop->socclk_khz = dchub->socclks_khz[0];
}
void dml2_utm_soc_bb_dcn5_build_sop_table(struct dml2_sop_table *table, const struct dml2_utm_soc_bb *utm_soc_bb)
{
table->get_highest_sop_index = dcn5_sop_table_get_highest_index;
table->get_sop_constraint_at_index = dcn5_sop_table_get_sop_constraint_at_index;
table->is_bw_supported_at_index = dcn5_sop_table_is_bandwidth_supported_at_index;
table->get_max_sop = dcn5_sop_table_get_max_sop;
table->get_min_sop = dcn5_sop_table_get_min_sop;
table->model = &utm_soc_bb->qos_model;
DML_ASSERT_MSG(table->model->sop_count > 0, "qos_model must contain at least 1 sop\n");
}
static void dcn5_copy_utm_qos_model(struct utm_qos_model *dest, struct utm_qos_model_dchub_v1 *dest_dchub, const struct utm_qos_model *src)
{
*dest = *src;
*dest_dchub = *src->dchub_v1;
dest->dchub_v1 = dest_dchub;
}
bool dml2_utm_soc_bb_dcn5_create(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *explicit_qos_model)
{
const struct utm_qos_model *qos_model = &utm_soc_bb->qos_model;
if (explicit_qos_model)
dcn5_copy_utm_qos_model(&utm_soc_bb->qos_model, &utm_soc_bb->qos_model_dchub_v1, explicit_qos_model);
else
dcn5_initialize_utm_qos_model(&utm_soc_bb->qos_model, &utm_soc_bb->qos_model_dchub_v1);
/* initialize based on soc bb */
utm_soc_bb->max_dispclk_khz = soc_bb->clk_table.dispclk.clk_values_khz[soc_bb->clk_table.dispclk.num_clk_values - 1];
utm_soc_bb->max_dppclk_khz = soc_bb->clk_table.dppclk.clk_values_khz[soc_bb->clk_table.dppclk.num_clk_values - 1];
utm_soc_bb->max_dtbclk_khz = (soc_bb->clk_table.dtbclk.num_clk_values > 0) ?
soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values - 1] : 0;
utm_soc_bb->max_phyclk_khz = (soc_bb->clk_table.phyclk.num_clk_values > 0) ?
soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values - 1] : 0;
utm_soc_bb->max_dscclk_khz = (soc_bb->clk_table.dscclk.num_clk_values > 0) ?
soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values - 1] : 0;
utm_soc_bb->max_phyclk_d18_khz = (soc_bb->clk_table.phyclk_d18.num_clk_values > 0) ?
soc_bb->clk_table.phyclk_d18.clk_values_khz[soc_bb->clk_table.phyclk_d18.num_clk_values - 1] : 0;
utm_soc_bb->max_phyclk_d32_khz = (soc_bb->clk_table.phyclk_d32.num_clk_values > 0) ?
soc_bb->clk_table.phyclk_d32.clk_values_khz[soc_bb->clk_table.phyclk_d32.num_clk_values - 1] : 0;
utm_soc_bb->power_management_parameters = soc_bb->power_management_parameters;
utm_soc_bb->writeback_base_latency_us = soc_bb->qos_parameters.writeback.base_latency_us;
utm_soc_bb->vmin_limit = soc_bb->vmin_limit;
utm_soc_bb->dchub_refclk_mhz = soc_bb->dchub_refclk_mhz;
utm_soc_bb->max_outstanding_reqs = soc_bb->max_outstanding_reqs;
utm_soc_bb->return_bus_width_bytes = soc_bb->return_bus_width_bytes;
utm_soc_bb->phy_downspread_percent = soc_bb->phy_downspread_percent;
utm_soc_bb->dcn_downspread_percent = soc_bb->dcn_downspread_percent;
utm_soc_bb->dispclk_dppclk_vco_speed_mhz = soc_bb->dispclk_dppclk_vco_speed_mhz;
utm_soc_bb->no_dfs = soc_bb->no_dfs;
utm_soc_bb->mem_word_bytes = soc_bb->mem_word_bytes;
utm_soc_bb->num_dcc_mcaches = soc_bb->num_dcc_mcaches;
utm_soc_bb->mcache_size_bytes = soc_bb->mcache_size_bytes;
utm_soc_bb->mcache_line_size_bytes = soc_bb->mcache_line_size_bytes;
utm_soc_bb->lower_bound_bandwidth_dchub = soc_bb->lower_bound_bandwidth_dchub;
/* initialize based on qos model */
utm_soc_bb->dram_config.channel_width_bytes = qos_model->socbb.dram_channel_width_bytes;
utm_soc_bb->dram_config.channel_count = qos_model->socbb.dram_channel_count;
utm_soc_bb->dram_config.transactions_per_clock = qos_model->socbb.dram_transactions_per_clock;
utm_soc_bb->max_dtbclk_khz = qos_model->dchub_v1->dcfclks_khz[qos_model->sop_count-1];
dml2_utm_soc_bb_dcn5_build_sop_table(&utm_soc_bb->sop_table, utm_soc_bb);
return true;
}

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_UTM_SOC_BB_DCN5_H__
#define __DML2_UTM_SOC_BB_DCN5_H__
#include "dml2_internal_shared_types.h"
bool dml2_utm_soc_bb_dcn5_create(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *explicit_qos_model);
void dml2_utm_soc_bb_dcn5_build_sop_table(struct dml2_sop_table *table, const struct dml2_utm_soc_bb *utm_soc_bb);
#endif /* __DML2_UTM_SOC_BB_DCN5_H__ */

View File

@@ -0,0 +1,405 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dml2_utm_soc_bb_dcn6.h"
#include "bounding_boxes/dcn6_soc_bb.h"
#include "lib_float_math.h"
#include "dml2_debug.h"
static unsigned int dcn6_sop_table_get_highest_index(const struct dml2_sop_table *table)
{
return table->model->sop_count - 1;
}
static void dcn6_sop_table_get_sop_constraint_at_index(const struct dml2_sop_table *table,
unsigned int index, struct dml2_sop_constraint *constraint)
{
const struct utm_qos_model *model = table->model;
const struct utm_qos_model_dchub_v2 *dchub = model->dchub_v2;
DML_ASSERT_MSG(index < model->sop_count, "unsupported sop index\n");
constraint->dcn5.clocks.fclk_khz = model->sops[index].fclk_khz;
constraint->dcn5.clocks.uclk_khz = model->sops[index].uclk_khz;
constraint->dcn5.clocks.dcfclk_khz = table->sop_optimal_dcfclks_khz[index];
constraint->dcn5.latency.dcn5.urgent_ramp = dchub->latencies[index].urgent_ramp_ps / 1000000.0;
constraint->dcn5.latency.dcn5.t_trip = dchub->latencies[index].t_trip_ps / 1000000.0;
constraint->dcn5.latency.dcn5.meta_trip_to_mem = dchub->latencies[index].meta_trip_to_mem_ps / 1000000.0;
constraint->dcn5.latency.dcn5.max_req_latency_urg = dchub->latencies[index].max_req_latency_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.avg_req_latency_urg = dchub->latencies[index].avg_req_latency_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.max_req_latency_non_urg = dchub->latencies[index].max_req_latency_non_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.avg_req_latency_non_urg = dchub->latencies[index].avg_req_latency_non_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.df_response_time_us = dchub->latencies[index].df_response_time_ps / 1000000.0;
constraint->dcn5.min_available_urgent_bandwidth_KBps = table->sop_min_available_urgent_bandwidths_KBps[index];
constraint->dcn5.min_sop_index = index;
}
static bool dcn6_sop_table_is_bandwidth_supported_at_index(
const struct dml2_sop_table *table, const struct dml2_memory_path_bandwidth *bw, unsigned int index)
{
const struct utm_qos_model *model = table->model;
struct utm_qos_model_dchub_memory_path_bandwidth_v2 qos_bandwidth;
bool result = true;
unsigned int highest_sop_index = table->model->sop_count - 1;
qos_bandwidth.nominal_bandwidth_KBps = (uint32_t) bw->dcn5.non_urgent_bandwidth_kbps;
qos_bandwidth.urgent_bandwidth_KBps = (uint32_t) bw->dcn5.urgent_bandwidth_kbps;
/* check if the bandwidth is supported by current sop at idle */
if (!dchub_v2_is_qos_bandwidth_supported_by_sop(table->model, &qos_bandwidth, (uint8_t) index,
model->dchub_v2->max_nominal_utm_budget_percent, model->dchub_v2->max_urgent_utm_budget_percent))
result = false;
/* check if the bandwidth is supported by the highest sop at active */
if (!dchub_v2_is_qos_bandwidth_supported_by_sop(table->model, &qos_bandwidth, (uint8_t) highest_sop_index,
model->dchub_v2->min_nominal_utm_budget_percent, model->dchub_v2->min_urgent_utm_budget_percent))
result = false;
return result;
}
static void dcn6_sop_table_get_max_sop(const struct dml2_sop_table *table, struct dml2_soc_operating_point *sop)
{
const struct utm_qos_model *model = table->model;
DML_ASSERT_MSG(model->sop_count > 0, "utm_qos_model must contain at least 1 sop\n");
if (model->sop_count > 0) {
sop->fclk_khz = model->sops[model->sop_count-1].fclk_khz;
sop->uclk_khz = model->sops[model->sop_count-1].uclk_khz;
sop->dcfclk_khz = table->sop_optimal_dcfclks_khz[model->sop_count - 1];
}
}
static void dcn6_sop_table_get_min_sop(const struct dml2_sop_table *table, struct dml2_soc_operating_point *sop)
{
const struct utm_qos_model *model = table->model;
sop->fclk_khz = model->sops[0].fclk_khz;
sop->uclk_khz = model->sops[0].uclk_khz;
sop->dcfclk_khz = table->sop_optimal_dcfclks_khz[0];
}
#define SDP_DERATE_PERCENT_NOMINAL 76.0
#define SDP_DERATE_PERCENT_URGENT 100.0
static uint32_t dcn6_sop_table_calculate_optimal_dcfclk_khz(
const struct dml2_sop_table *table,
const struct dml2_utm_soc_bb *utm_soc_bb,
struct utm_qos_model_dchub_memory_path_bandwidth_v2 *total_available_bandwidth)
{
const struct utm_qos_model *model = table->model;
double nominal_dcfclk_khz;
double urgent_dcfclk_khz;
uint32_t sop_optimal_dcfclk_khz;
/* calculate the optimal dcfclk based on the available bandwidth */
nominal_dcfclk_khz = total_available_bandwidth->nominal_bandwidth_KBps
* (model->dchub_v2->max_nominal_utm_budget_percent / 100.0)
/ (SDP_DERATE_PERCENT_NOMINAL / 100.0)
/ utm_soc_bb->return_bus_width_bytes;
urgent_dcfclk_khz = total_available_bandwidth->urgent_bandwidth_KBps
* (model->dchub_v2->max_urgent_utm_budget_percent / 100.0)
/ (SDP_DERATE_PERCENT_URGENT / 100.0)
/ utm_soc_bb->return_bus_width_bytes;
sop_optimal_dcfclk_khz = (uint32_t)math_ceil(math_max2(urgent_dcfclk_khz, nominal_dcfclk_khz));
/* ensure the calculated dcfclk is within dcfclk limits */
if (sop_optimal_dcfclk_khz > utm_soc_bb->max_dcfclk_khz)
sop_optimal_dcfclk_khz = utm_soc_bb->max_dcfclk_khz;
else if (sop_optimal_dcfclk_khz < utm_soc_bb->min_dcfclk_khz)
sop_optimal_dcfclk_khz = utm_soc_bb->min_dcfclk_khz;
return sop_optimal_dcfclk_khz;
}
static void dml2_utm_soc_bb_dcn6_build_sop_table(struct dml2_sop_table *table,
const struct dml2_utm_soc_bb *utm_soc_bb)
{
unsigned int i;
struct utm_qos_model_dchub_memory_path_bandwidth_v2 total_available_bandwidth;
table->get_highest_sop_index = dcn6_sop_table_get_highest_index;
table->get_sop_constraint_at_index = dcn6_sop_table_get_sop_constraint_at_index;
table->is_bw_supported_at_index = dcn6_sop_table_is_bandwidth_supported_at_index;
table->get_max_sop = dcn6_sop_table_get_max_sop;
table->get_min_sop = dcn6_sop_table_get_min_sop;
table->model = &utm_soc_bb->qos_model;
for (i = 0; i < table->model->sop_count; i++) {
dchub_v2_get_sop_total_available_bandwidth_KBps(table->model, &total_available_bandwidth, (uint8_t) i);
table->sop_optimal_dcfclks_khz[i] =
dcn6_sop_table_calculate_optimal_dcfclk_khz(table, utm_soc_bb, &total_available_bandwidth);
table->sop_min_available_urgent_bandwidths_KBps[i] = (uint32_t) math_floor(
total_available_bandwidth.urgent_bandwidth_KBps
* (utm_soc_bb->qos_model.dchub_v2->min_urgent_utm_budget_percent / 100.0));
}
DML_ASSERT_MSG(table->model->sop_count > 0, "qos_model must contain at least 1 sop\n");
}
/*
* v3 SOP table functions flat pre-computed bandwidth/latency model
*/
static unsigned int dcn6_v3_sop_table_get_highest_index(const struct dml2_sop_table *table)
{
return table->model->dchub_v3->sop_count - 1;
}
static void dcn6_v3_sop_table_get_sop_constraint_at_index(const struct dml2_sop_table *table,
unsigned int index, struct dml2_sop_constraint *constraint)
{
const struct utm_qos_model_dchub_v3 *dchub = table->model->dchub_v3;
const struct utm_qos_model_dchub_v3_sop_entry *entry =
&dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE_ALTERNATE_PSTATE][index];
DML_ASSERT_MSG(index < dchub->sop_count, "unsupported sop index\n");
constraint->dcn5.clocks.fclk_khz = 0;
constraint->dcn5.clocks.uclk_khz = 0;
constraint->dcn5.clocks.dcfclk_khz = table->sop_optimal_dcfclks_khz[index];
constraint->dcn5.latency.dcn5.urgent_ramp = entry->urgent_ramp_ps / 1000000.0;
constraint->dcn5.latency.dcn5.t_trip = entry->t_trip_ps / 1000000.0;
constraint->dcn5.latency.dcn5.meta_trip_to_mem = entry->meta_trip_to_mem_ps / 1000000.0;
constraint->dcn5.latency.dcn5.max_req_latency_urg = entry->max_req_latency_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.avg_req_latency_urg = entry->avg_req_latency_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.max_req_latency_non_urg = entry->max_req_latency_non_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.avg_req_latency_non_urg = entry->avg_req_latency_non_urg_ps / 1000000.0;
constraint->dcn5.latency.dcn5.df_response_time_us = entry->df_response_time_ps / 1000000.0;
constraint->dcn5.min_available_urgent_bandwidth_KBps = table->sop_min_available_urgent_bandwidths_KBps[index];
constraint->dcn5.min_sop_index = index;
}
static bool dcn6_v3_sop_table_is_bandwidth_supported_at_index(
const struct dml2_sop_table *table, const struct dml2_memory_path_bandwidth *bw, unsigned int index)
{
const struct utm_qos_model_dchub_v3 *dchub = table->model->dchub_v3;
unsigned int highest_sop_index = dchub->sop_count - 1;
const struct utm_qos_model_dchub_v3_sop_entry *idle_entry =
&dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_IDLE][index];
const struct utm_qos_model_dchub_v3_sop_entry *active_entry =
&dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE_ALTERNATE_PSTATE][highest_sop_index];
if (bw->dcn5.non_urgent_bandwidth_kbps > idle_entry->nominal_bandwidth_KBps
|| bw->dcn5.urgent_bandwidth_kbps > idle_entry->urgent_bandwidth_KBps)
return false;
if (bw->dcn5.non_urgent_bandwidth_kbps > active_entry->nominal_bandwidth_KBps
|| bw->dcn5.urgent_bandwidth_kbps > active_entry->urgent_bandwidth_KBps)
return false;
return true;
}
static void dcn6_v3_sop_table_get_max_sop(const struct dml2_sop_table *table, struct dml2_soc_operating_point *sop)
{
const struct utm_qos_model_dchub_v3 *dchub = table->model->dchub_v3;
const struct dml2_utm_soc_bb *utm_soc_bb =
(const struct dml2_utm_soc_bb *)((const char *)table - offsetof(struct dml2_utm_soc_bb, sop_table));
DML_ASSERT_MSG(dchub->sop_count > 0, "utm_qos_model must contain at least 1 sop\n");
sop->fclk_khz = utm_soc_bb->max_fclk_khz;
sop->uclk_khz = utm_soc_bb->max_uclk_khz;
sop->dcfclk_khz = table->sop_optimal_dcfclks_khz[dchub->sop_count - 1];
}
static void dcn6_v3_sop_table_get_min_sop(const struct dml2_sop_table *table, struct dml2_soc_operating_point *sop)
{
const struct dml2_utm_soc_bb *utm_soc_bb =
(const struct dml2_utm_soc_bb *)((const char *)table - offsetof(struct dml2_utm_soc_bb, sop_table));
sop->fclk_khz = utm_soc_bb->max_fclk_khz;
sop->uclk_khz = utm_soc_bb->max_uclk_khz;
sop->dcfclk_khz = table->sop_optimal_dcfclks_khz[0];
}
static uint32_t dcn6_v3_sop_table_calculate_optimal_dcfclk_khz(
const struct dml2_utm_soc_bb *utm_soc_bb,
const struct utm_qos_model_dchub_v3_sop_entry *idle_entry)
{
double nominal_dcfclk_khz;
double urgent_dcfclk_khz;
uint32_t optimal;
nominal_dcfclk_khz = (double)idle_entry->nominal_bandwidth_KBps
/ (utm_soc_bb->nominal_sdp_derate_percent / 100.0)
/ utm_soc_bb->return_bus_width_bytes;
urgent_dcfclk_khz = (double)idle_entry->urgent_bandwidth_KBps
/ (utm_soc_bb->urgent_sdp_derate_percent / 100.0)
/ utm_soc_bb->return_bus_width_bytes;
optimal = (uint32_t)math_ceil(math_max2(urgent_dcfclk_khz, nominal_dcfclk_khz));
if (optimal > utm_soc_bb->max_dcfclk_khz)
optimal = utm_soc_bb->max_dcfclk_khz;
else if (optimal < utm_soc_bb->min_dcfclk_khz)
optimal = utm_soc_bb->min_dcfclk_khz;
return optimal;
}
static void dml2_utm_soc_bb_dcn6_v3_build_sop_table(struct dml2_sop_table *table,
const struct dml2_utm_soc_bb *utm_soc_bb)
{
const struct utm_qos_model_dchub_v3 *dchub = utm_soc_bb->qos_model.dchub_v3;
unsigned int i;
table->get_highest_sop_index = dcn6_v3_sop_table_get_highest_index;
table->get_sop_constraint_at_index = dcn6_v3_sop_table_get_sop_constraint_at_index;
table->is_bw_supported_at_index = dcn6_v3_sop_table_is_bandwidth_supported_at_index;
table->get_max_sop = dcn6_v3_sop_table_get_max_sop;
table->get_min_sop = dcn6_v3_sop_table_get_min_sop;
table->model = &utm_soc_bb->qos_model;
DML_ASSERT_MSG(dchub->sop_count > 0, "qos_model must contain at least 1 sop\n");
for (i = 0; i < dchub->sop_count; i++) {
const struct utm_qos_model_dchub_v3_sop_entry *idle_entry =
&dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_IDLE][i];
const struct utm_qos_model_dchub_v3_sop_entry *active_entry =
&dchub->sops[UTM_QOS_MODEL_V3_LOAD_LEVEL_ACTIVE_ALTERNATE_PSTATE][i];
table->sop_optimal_dcfclks_khz[i] =
dcn6_v3_sop_table_calculate_optimal_dcfclk_khz(utm_soc_bb, idle_entry);
table->sop_min_available_urgent_bandwidths_KBps[i] =
active_entry->urgent_bandwidth_KBps;
}
}
static void dcn6_copy_utm_qos_model(struct utm_qos_model *dest, struct utm_qos_model_dchub_v2 *dest_dchub, const struct utm_qos_model *src)
{
*dest = *src;
*dest_dchub = *src->dchub_v2;
dest->dchub_v2 = dest_dchub;
}
static void dcn6_initialize_from_soc_bb(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb)
{
DML_ASSERT_MSG(soc_bb->clk_table.dcfclk.num_clk_values == 2, "soc_bb must provide min and max dcfclk values!\n");
/* initialize based on soc bb */
utm_soc_bb->max_dispclk_khz = soc_bb->clk_table.dispclk.clk_values_khz[soc_bb->clk_table.dispclk.num_clk_values - 1];
utm_soc_bb->max_dppclk_khz = soc_bb->clk_table.dppclk.clk_values_khz[soc_bb->clk_table.dppclk.num_clk_values - 1];
utm_soc_bb->max_dtbclk_khz = (soc_bb->clk_table.dtbclk.num_clk_values > 0) ?
soc_bb->clk_table.dtbclk.clk_values_khz[soc_bb->clk_table.dtbclk.num_clk_values - 1] : 0;
utm_soc_bb->max_phyclk_khz = (soc_bb->clk_table.phyclk.num_clk_values > 0) ?
soc_bb->clk_table.phyclk.clk_values_khz[soc_bb->clk_table.phyclk.num_clk_values - 1] : 0;
utm_soc_bb->max_dscclk_khz = (soc_bb->clk_table.dscclk.num_clk_values > 0) ?
soc_bb->clk_table.dscclk.clk_values_khz[soc_bb->clk_table.dscclk.num_clk_values - 1] : 0;
utm_soc_bb->max_phyclk_d18_khz = (soc_bb->clk_table.phyclk_d18.num_clk_values > 0) ?
soc_bb->clk_table.phyclk_d18.clk_values_khz[soc_bb->clk_table.phyclk_d18.num_clk_values - 1] : 0;
utm_soc_bb->max_phyclk_d32_khz = (soc_bb->clk_table.phyclk_d32.num_clk_values > 0) ?
soc_bb->clk_table.phyclk_d32.clk_values_khz[soc_bb->clk_table.phyclk_d32.num_clk_values - 1] : 0;
utm_soc_bb->min_socclk_khz = soc_bb->clk_table.socclk.clk_values_khz[0];
utm_soc_bb->max_dcfclk_khz = soc_bb->clk_table.dcfclk.clk_values_khz[soc_bb->clk_table.dcfclk.num_clk_values - 1];
utm_soc_bb->min_dcfclk_khz = soc_bb->clk_table.dcfclk.clk_values_khz[0];
utm_soc_bb->max_uclk_khz = (soc_bb->clk_table.uclk.num_clk_values > 0) ?
soc_bb->clk_table.uclk.clk_values_khz[soc_bb->clk_table.uclk.num_clk_values - 1] : 0;
utm_soc_bb->max_fclk_khz = (soc_bb->clk_table.fclk.num_clk_values > 0) ?
soc_bb->clk_table.fclk.clk_values_khz[soc_bb->clk_table.fclk.num_clk_values - 1] : 0;
utm_soc_bb->dram_config.channel_width_bytes = soc_bb->clk_table.dram_config.channel_width_bytes;
utm_soc_bb->dram_config.channel_count = soc_bb->clk_table.dram_config.channel_count;
utm_soc_bb->dram_config.transactions_per_clock = soc_bb->clk_table.dram_config.transactions_per_clock;
utm_soc_bb->power_management_parameters = soc_bb->power_management_parameters;
utm_soc_bb->writeback_base_latency_us = soc_bb->qos_parameters.writeback.base_latency_us;
utm_soc_bb->vmin_limit = soc_bb->vmin_limit;
utm_soc_bb->dchub_refclk_mhz = soc_bb->dchub_refclk_mhz;
utm_soc_bb->max_outstanding_reqs = soc_bb->max_outstanding_reqs;
utm_soc_bb->return_bus_width_bytes = soc_bb->return_bus_width_bytes;
utm_soc_bb->phy_downspread_percent = soc_bb->phy_downspread_percent;
utm_soc_bb->dcn_downspread_percent = soc_bb->dcn_downspread_percent;
utm_soc_bb->nominal_sdp_derate_percent = SDP_DERATE_PERCENT_NOMINAL;
utm_soc_bb->urgent_sdp_derate_percent = SDP_DERATE_PERCENT_URGENT;
utm_soc_bb->dispclk_dppclk_vco_speed_mhz = soc_bb->dispclk_dppclk_vco_speed_mhz;
utm_soc_bb->no_dfs = soc_bb->no_dfs;
utm_soc_bb->mem_word_bytes = soc_bb->mem_word_bytes;
utm_soc_bb->num_dcc_mcaches = soc_bb->num_dcc_mcaches;
utm_soc_bb->mcache_size_bytes = soc_bb->mcache_size_bytes;
utm_soc_bb->mcache_line_size_bytes = soc_bb->mcache_line_size_bytes;
utm_soc_bb->lower_bound_bandwidth_dchub = soc_bb->lower_bound_bandwidth_dchub;
utm_soc_bb->fraction_of_urgent_bandwidth_nominal_target = soc_bb->fraction_of_urgent_bandwidth_nominal_target;
utm_soc_bb->fraction_of_urgent_bandwidth_flip_target = soc_bb->fraction_of_urgent_bandwidth_flip_target;
}
static void dcn6_initialize_from_qos_model(struct dml2_utm_soc_bb *utm_soc_bb,
const struct utm_qos_model *qos_model)
{
utm_soc_bb->dram_config.channel_width_bytes = qos_model->socbb.dram_channel_width_bytes;
utm_soc_bb->dram_config.channel_count = qos_model->socbb.dram_channel_count;
utm_soc_bb->dram_config.transactions_per_clock = qos_model->socbb.dram_transactions_per_clock;
}
static void dcn6a_initialize_qos_model(struct dml2_utm_soc_bb *utm_soc_bb,
const struct utm_qos_model *explicit_qos_model)
{
if (explicit_qos_model)
dcn6_copy_utm_qos_model(&utm_soc_bb->qos_model, &utm_soc_bb->qos_model_dchub_v2, explicit_qos_model);
else
dcn6_test_initialize_utm_qos_model(&utm_soc_bb->qos_model, &utm_soc_bb->qos_model_dchub_v2);
}
static void dcn6b_initialize_qos_model(struct dml2_utm_soc_bb *utm_soc_bb,
const struct utm_qos_model *explicit_qos_model)
{
if (explicit_qos_model)
dcn6_copy_utm_qos_model(&utm_soc_bb->qos_model, &utm_soc_bb->qos_model_dchub_v2, explicit_qos_model);
else
dcn6b_test_initialize_utm_qos_model(&utm_soc_bb->qos_model, &utm_soc_bb->qos_model_dchub_v2);
}
static bool dml2_utm_soc_bb_dcn6a_create_legacy(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *explicit_qos_model)
{
dcn6_initialize_from_soc_bb(utm_soc_bb, soc_bb);
dcn6a_initialize_qos_model(utm_soc_bb, explicit_qos_model);
dcn6_initialize_from_qos_model(utm_soc_bb, &utm_soc_bb->qos_model);
dml2_utm_soc_bb_dcn6_build_sop_table(&utm_soc_bb->sop_table, utm_soc_bb);
return true;
}
static bool dml2_utm_soc_bb_dcn6b_create_legacy(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *explicit_qos_model)
{
dcn6_initialize_from_soc_bb(utm_soc_bb, soc_bb);
dcn6b_initialize_qos_model(utm_soc_bb, explicit_qos_model);
dcn6_initialize_from_qos_model(utm_soc_bb, &utm_soc_bb->qos_model);
dml2_utm_soc_bb_dcn6_build_sop_table(&utm_soc_bb->sop_table, utm_soc_bb);
return true;
}
bool dml2_utm_soc_bb_dcn6a_create(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *explicit_qos_model)
{
if (explicit_qos_model && explicit_qos_model->version == utm_qos_model_version_v3) {
dcn6_initialize_from_soc_bb(utm_soc_bb, soc_bb);
utm_soc_bb->qos_model_dchub_v3 = *explicit_qos_model->dchub_v3;
utm_soc_bb->qos_model.version = utm_qos_model_version_v3;
utm_soc_bb->qos_model.dchub_v3 = &utm_soc_bb->qos_model_dchub_v3;
dml2_utm_soc_bb_dcn6_v3_build_sop_table(&utm_soc_bb->sop_table, utm_soc_bb);
} else {
return dml2_utm_soc_bb_dcn6a_create_legacy(utm_soc_bb, soc_bb, explicit_qos_model);
}
return true;
}
bool dml2_utm_soc_bb_dcn6b_create(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *explicit_qos_model)
{
if (explicit_qos_model && explicit_qos_model->version == utm_qos_model_version_v3) {
dcn6_initialize_from_soc_bb(utm_soc_bb, soc_bb);
utm_soc_bb->qos_model_dchub_v3 = *explicit_qos_model->dchub_v3;
utm_soc_bb->qos_model.version = utm_qos_model_version_v3;
utm_soc_bb->qos_model.dchub_v3 = &utm_soc_bb->qos_model_dchub_v3;
dml2_utm_soc_bb_dcn6_v3_build_sop_table(&utm_soc_bb->sop_table, utm_soc_bb);
} else {
return dml2_utm_soc_bb_dcn6b_create_legacy(utm_soc_bb, soc_bb, explicit_qos_model);
}
return true;
}

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DML2_UTM_SOC_BB_DCN6_H__
#define __DML2_UTM_SOC_BB_DCN6_H__
#include "dml2_internal_shared_types.h"
bool dml2_utm_soc_bb_dcn6a_create(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *explicit_qos_model);
bool dml2_utm_soc_bb_dcn6b_create(struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *explicit_qos_model);
#endif /* __DML2_UTM_SOC_BB_DCN6_H__ */

View File

@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dml2_utm_soc_bb_factory.h"
#include "dml2_utm_soc_bb_dcn5.h"
#include "dml2_utm_soc_bb_dcn6.h"
bool dml2_utm_soc_bb_create(enum dml2_project_id project_id, struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *qos_model)
{
switch (project_id) {
case dml2_project_dcn5x_utm:
return dml2_utm_soc_bb_dcn5_create(utm_soc_bb, soc_bb, qos_model);
case dml2_project_dcn6x_soc_var_a:
return dml2_utm_soc_bb_dcn6a_create(utm_soc_bb, soc_bb, qos_model);
case dml2_project_dcn6x_soc_var_b:
return dml2_utm_soc_bb_dcn6b_create(utm_soc_bb, soc_bb, qos_model);
case dml2_project_dcn4x_utm:
case dml2_project_dcn5x:
case dml2_project_dcn4x_stage1:
case dml2_project_dcn42:
case dml2_project_dcn4x_stage2:
case dml2_project_dcn4x_stage2_auto_drr_svp:
case dml2_project_invalid:
default:
return false;
}
}

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DML2_UTM_SOC_BB_FACTORY_H__
#define __DML2_UTM_SOC_BB_FACTORY_H__
#include "dml2_internal_shared_types.h"
bool dml2_utm_soc_bb_create(enum dml2_project_id project_id, struct dml2_utm_soc_bb *utm_soc_bb,
const struct dml2_soc_bb *soc_bb, const struct utm_qos_model *qos_model);
#endif /* __DML2_UTM_SOC_BB_FACTORY_H__ */

View File

@@ -0,0 +1,391 @@
// SPDX-License-Identifier: MIT
//
// Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved.
#include "dm_services.h"
#include "core_types.h"
#include "reg_helper.h"
#include "dcn401/dcn401_dpp.h"
#include "dcn50_dpp.h"
#include "basics/conversion.h"
#include "dcn30/dcn30_cm_common.h"
#include "dcn32/dcn32_dpp.h"
#include "dcn35/dcn35_dpp.h"
#define REG(reg)\
dpp->tf_regs->reg
#define CTX \
dpp->base.ctx
#undef FN
#define FN(reg_name, field_name) \
dpp->tf_shift->field_name, dpp->tf_mask->field_name
void dpp50_set_pregam_state(
struct dpp *dpp_base,
enum dc_transfer_func_predefined tr,
enum dc_scaling_linearity scaling)
{
struct dcn50_dpp *dpp = TO_DCN50_DPP(dpp_base);
enum pregam_mode pre_degam_en = PREGAM_DEGAM;
enum degam_lut degamma_lut_selection = 0;
if (scaling == DC_SCALING_LINEARITY_SOURCE) {
//If scaling in non-linear, apply regamma
REG_SET_2(PRE_GAM, 0,
PRE_GAM_MODE, PREGAM_REGAM,
PRE_REGAM_SELECT, REGAM_20);
} else {
//If scaling in linear, apply degamma based on TF
switch (tr) {
case TRANSFER_FUNCTION_SRGB:
degamma_lut_selection = DEGAM_SRGB;
break;
case TRANSFER_FUNCTION_GAMMA22:
degamma_lut_selection = DEGAM_GAMMA_22;
break;
case TRANSFER_FUNCTION_GAMMA24:
degamma_lut_selection = DEGAM_GAMMA_24;
break;
case TRANSFER_FUNCTION_GAMMA26:
degamma_lut_selection = DEGAM_GAMMA_26;
break;
case TRANSFER_FUNCTION_BT709:
degamma_lut_selection = DEGAM_BT2020;
break;
case TRANSFER_FUNCTION_PQ:
degamma_lut_selection = DEGAM_BT2100PQ;
break;
case TRANSFER_FUNCTION_HLG:
degamma_lut_selection = DEGAM_BT2100HLG;
break;
case TRANSFER_FUNCTION_LINEAR:
case TRANSFER_FUNCTION_UNITY:
case TRANSFER_FUNCTION_HLG12:
default:
pre_degam_en = PREGAM_BYPASS;
break;
}
REG_SET_2(PRE_GAM, 0,
PRE_GAM_MODE, pre_degam_en,
PRE_DEGAM_SELECT, degamma_lut_selection);
}
}
void dpp50_dpp_setup(
struct dpp *dpp_base,
enum surface_pixel_format format,
enum expansion_mode mode,
struct dc_csc_transform input_csc_color_matrix,
enum dc_color_space input_color_space,
struct cnv_alpha_2bit_lut *alpha_2bit_lut)
{
struct dcn50_dpp *dpp = TO_DCN50_DPP(dpp_base);
uint32_t pixel_format = 0;
uint32_t alpha_en = 1;
enum dc_color_space color_space = COLOR_SPACE_SRGB;
enum dcn10_input_csc_select select = INPUT_CSC_SELECT_BYPASS;
uint32_t is_2bit = 0;
uint32_t alpha_plane_enable = 0;
uint32_t dealpha_en = 0, dealpha_ablnd_en = 0;
uint32_t realpha_en = 0, realpha_ablnd_en = 0;
struct out_csc_color_matrix tbl_entry;
int i;
REG_SET_2(FORMAT_CONTROL, 0,
CNVC_BYPASS, 0,
FORMAT_EXPANSION_MODE, mode);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CNV16, 0);
REG_UPDATE(FORMAT_CONTROL, CNVC_BYPASS_MSB_ALIGN, 0);
REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE, 0);
REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE_C, 0);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_R, 0);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_G, 1);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_B, 2);
switch (format) {
case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
pixel_format = 1;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
pixel_format = 3;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
pixel_format = 8;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
pixel_format = 10;
is_2bit = 1;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P208:
pixel_format = 64;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P208:
pixel_format = 65;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P210:
pixel_format = 66;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P210:
pixel_format = 67;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P212:
pixel_format = 68;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P212:
pixel_format = 69;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
/* Packed 422 formats*/
case SURFACE_PIXEL_FORMAT_VIDEO_422_YCrYCb:
pixel_format = 72;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_YCbYCr:
pixel_format = 73;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrYCbY:
pixel_format = 74;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbYCrY:
pixel_format = 75;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCrYCb:
pixel_format = 76;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCbYCr:
pixel_format = 77;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CrYCbY:
pixel_format = 78;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CbYCrY:
pixel_format = 79;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCrYCb:
pixel_format = 80;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCbYCr:
pixel_format = 81;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CrYCbY:
pixel_format = 82;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CbYCrY:
pixel_format = 83;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
pixel_format = 26; /* ARGB16161616_UNORM */
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
pixel_format = 24;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
pixel_format = 25;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888:
pixel_format = 12;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX:
pixel_format = 112;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX:
pixel_format = 113;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010:
pixel_format = 114;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
is_2bit = 1;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102:
pixel_format = 115;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
is_2bit = 1;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
pixel_format = 116;
alpha_plane_enable = 0;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
pixel_format = 116;
alpha_plane_enable = 1;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT:
pixel_format = 118;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT:
pixel_format = 119;
alpha_en = 0;
break;
default:
break;
}
/* Set default color space based on format if none is given. */
color_space = input_color_space ? input_color_space : color_space;
if (is_2bit == 1 && alpha_2bit_lut != NULL) {
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT0, alpha_2bit_lut->lut0);
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT1, alpha_2bit_lut->lut1);
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT2, alpha_2bit_lut->lut2);
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT3, alpha_2bit_lut->lut3);
}
REG_SET_2(CNVC_SURFACE_PIXEL_FORMAT, 0,
CNVC_SURFACE_PIXEL_FORMAT, pixel_format,
CNVC_ALPHA_PLANE_ENABLE, alpha_plane_enable);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CONTROL__ALPHA_EN, alpha_en);
REG_SET_2(PRE_DEALPHA, 0,
PRE_DEALPHA_EN, dealpha_en,
PRE_DEALPHA_ABLND_EN, dealpha_ablnd_en);
REG_SET_2(PRE_REALPHA, 0,
PRE_REALPHA_EN, realpha_en,
PRE_REALPHA_ABLND_EN, realpha_ablnd_en);
/* If input adjustment exists, program the ICSC with those values. */
if (input_csc_color_matrix.enable_adjustment == true) {
for (i = 0; i < 12; i++)
tbl_entry.regval[i] = input_csc_color_matrix.matrix[i];
tbl_entry.color_space = input_color_space;
if (dpp3_should_bypass_post_csc_for_colorspace(color_space))
select = INPUT_CSC_SELECT_BYPASS;
else
select = INPUT_CSC_SELECT_ICSC;
dpp3_program_post_csc(dpp_base, color_space, select,
&tbl_entry);
} else {
dpp3_program_post_csc(dpp_base, color_space, select, NULL);
}
}
static struct dpp_funcs dcn50_dpp_funcs = {
.dpp_program_gamcor_lut = dpp3_program_gamcor_lut,
.dpp_read_state = dpp401_read_state,
.dpp_reset = dpp_reset,
.dpp_set_scaler = dpp401_dscl_set_scaler_manual_scale,
.dpp_get_optimal_number_of_taps = dpp3_get_optimal_number_of_taps,
.dpp_set_gamut_remap = NULL,
.dpp_set_csc_adjustment = NULL,
.dpp_set_csc_default = NULL,
.dpp_program_regamma_pwl = NULL,
.dpp_set_pre_degam = NULL,
.dpp_program_input_lut = NULL,
.dpp_full_bypass = NULL,
.dpp_setup = dpp50_dpp_setup,
.dpp_program_degamma_pwl = NULL,
.dpp_program_cm_dealpha = dpp3_program_cm_dealpha,
.dpp_program_cm_bias = dpp3_program_cm_bias,
.dpp_program_blnd_lut = NULL, // BLNDGAM is removed completely in DCN3.2 DPP
.dpp_program_shaper_lut = NULL, // CM SHAPER block is removed in DCN3.2 DPP,
//(it is in MPCC, programmable before or after BLND)
.dpp_program_3dlut = NULL, // CM 3DLUT block is removed in DCN3.2 DPP,
//(it is in MPCC, programmable before or after BLND)
.dpp_program_bias_and_scale = dpp35_program_bias_and_scale_fcnv,
.dpp_cnv_set_alpha_keyer = dpp2_cnv_set_alpha_keyer,
.set_cursor_attributes = dpp401_set_cursor_attributes,
.set_cursor_position = dpp401_set_cursor_position,
.set_optional_cursor_attributes = dpp401_set_optional_cursor_attributes,
.dpp_dppclk_control = dpp1_dppclk_control,
.dpp_set_hdr_multiplier = dpp3_set_hdr_multiplier,
.dpp_read_reg_state = dpp30_read_reg_state,
.set_cursor_matrix = dpp401_set_cursor_matrix,
.dpp_set_pregam_state = dpp50_set_pregam_state,
};
static struct dpp_caps dcn50_dpp_cap = {
.dscl_data_proc_format = DSCL_DATA_PRCESSING_FLOAT_FORMAT,
.max_lb_partitions = 63,
.dscl_calc_lb_num_partitions = dscl401_calc_lb_num_partitions,
};
bool dpp50_construct(
struct dcn50_dpp *dpp,
struct dc_context *ctx,
uint32_t inst,
const struct dcn50_dpp_registers *tf_regs,
const struct dcn50_dpp_shift *tf_shift,
const struct dcn50_dpp_mask *tf_mask)
{
dpp->base.ctx = ctx;
dpp->base.inst = inst;
dpp->base.funcs = &dcn50_dpp_funcs;
dpp->base.caps = &dcn50_dpp_cap;
dpp->tf_regs = tf_regs;
dpp->tf_shift = tf_shift;
dpp->tf_mask = tf_mask;
return true;
}

View File

@@ -0,0 +1,86 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved.
*/
#ifndef __DCN50_DPP_H__
#define __DCN50_DPP_H__
#include "dcn20/dcn20_dpp.h"
#include "dcn30/dcn30_dpp.h"
#include "dcn32/dcn32_dpp.h"
#include "dcn401/dcn401_dpp.h"
#define TO_DCN50_DPP(dpp)\
container_of(dpp, struct dcn50_dpp, base)
#define DPP_REG_LIST_SH_MASK_DCN50_COMMON(mask_sh)\
DPP_REG_LIST_SH_MASK_DCN401_COMMON(mask_sh), \
TF_SF(CNVC_CFG0_PRE_GAM, PRE_GAM_MODE, mask_sh), \
TF_SF(CNVC_CFG0_PRE_GAM, PRE_DEGAM_SELECT, mask_sh), \
TF_SF(CNVC_CFG0_PRE_GAM, PRE_REGAM_SELECT, mask_sh)
#define DPP_REG_FIELD_LIST_DCN50(type) \
DPP_REG_FIELD_LIST_DCN401(type); \
type PRE_GAM_MODE; \
type PRE_REGAM_SELECT
#define DPP_REG_VARIABLE_LIST_DCN50 \
DPP_REG_VARIABLE_LIST_DCN401; \
uint32_t PRE_GAM;
struct dcn50_dpp_registers {
DPP_REG_VARIABLE_LIST_DCN50
};
struct dcn50_dpp_shift {
DPP_REG_FIELD_LIST_DCN50(uint8_t);
};
struct dcn50_dpp_mask {
DPP_REG_FIELD_LIST_DCN50(uint32_t);
};
struct dcn50_dpp {
struct dpp base;
const struct dcn50_dpp_registers *tf_regs;
const struct dcn50_dpp_shift *tf_shift;
const struct dcn50_dpp_mask *tf_mask;
const uint16_t *filter_v;
const uint16_t *filter_h;
const uint16_t *filter_v_c;
const uint16_t *filter_h_c;
int lb_pixel_depth_supported;
int lb_memory_size;
int lb_bits_per_entry;
bool is_write_to_ram_a_safe;
struct scaler_data scl_data;
struct pwl_params pwl_data;
};
bool dpp50_construct(
struct dcn50_dpp *dpp50,
struct dc_context *ctx,
uint32_t inst,
const struct dcn50_dpp_registers *tf_regs,
const struct dcn50_dpp_shift *tf_shift,
const struct dcn50_dpp_mask *tf_mask);
void dpp50_dpp_setup(
struct dpp *dpp_base,
enum surface_pixel_format format,
enum expansion_mode mode,
struct dc_csc_transform input_csc_color_matrix,
enum dc_color_space input_color_space,
struct cnv_alpha_2bit_lut *alpha_2bit_lut);
void dpp50_set_pregam_state(
struct dpp *dpp_base,
enum dc_transfer_func_predefined tr,
enum dc_scaling_linearity scaling);
#endif /* __DCN50_DPP_H__ */

View File

@@ -0,0 +1,346 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dm_services.h"
#include "core_types.h"
#include "reg_helper.h"
#include "basics/conversion.h"
#include "dcn60/dcn60_dpp.h"
#define REG(reg)\
dpp->tf_regs->reg
#define CTX \
dpp->base.ctx
#undef FN
#define FN(reg_name, field_name) \
dpp->tf_shift->field_name, dpp->tf_mask->field_name
void dpp60_dpp_setup(
struct dpp *dpp_base,
enum surface_pixel_format format,
enum expansion_mode mode,
struct dc_csc_transform input_csc_color_matrix,
enum dc_color_space input_color_space,
struct cnv_alpha_2bit_lut *alpha_2bit_lut)
{
struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
uint32_t pixel_format = 8;
uint32_t alpha_en = 1;
enum dc_color_space color_space = COLOR_SPACE_SRGB;
enum dcn10_input_csc_select select = INPUT_CSC_SELECT_BYPASS;
uint32_t is_2bit = 0;
uint32_t dealpha_en = 0, dealpha_ablnd_en = 0;
uint32_t realpha_en = 0, realpha_ablnd_en = 0;
struct out_csc_color_matrix tbl_entry;
int i;
REG_SET_2(FORMAT_CONTROL, 0,
CNVC_BYPASS, 0,
FORMAT_EXPANSION_MODE, mode);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CNV16, 0);
REG_UPDATE(FORMAT_CONTROL, CNVC_BYPASS_MSB_ALIGN, 0);
REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE, 0);
REG_UPDATE(FORMAT_CONTROL, CLAMP_POSITIVE_C, 0);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_R, 0);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_G, 1);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CROSSBAR_B, 2);
switch (format) {
case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
pixel_format = 1;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
pixel_format = 3;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
pixel_format = 8;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
pixel_format = 10;
is_2bit = 1;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P208:
pixel_format = 64;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P208:
pixel_format = 65;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P210:
pixel_format = 66;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P210:
pixel_format = 67;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P212:
pixel_format = 68;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P212:
pixel_format = 69;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
/* Packed 422 formats*/
case SURFACE_PIXEL_FORMAT_VIDEO_422_YCrYCb:
pixel_format = 72;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_YCbYCr:
pixel_format = 73;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrYCbY:
pixel_format = 74;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbYCrY:
pixel_format = 75;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCrYCb:
pixel_format = 76;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCbYCr:
pixel_format = 77;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CrYCbY:
pixel_format = 78;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CbYCrY:
pixel_format = 79;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCrYCb:
pixel_format = 80;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCbYCr:
pixel_format = 81;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CrYCbY:
pixel_format = 82;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CbYCrY:
pixel_format = 83;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
// color space and select subjected to change
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
pixel_format = 26; /* ARGB16161616_UNORM */
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
pixel_format = 24;
break;
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
pixel_format = 25;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888:
pixel_format = 12;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX:
pixel_format = 112;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX:
pixel_format = 113;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010:
pixel_format = 114;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
is_2bit = 1;
break;
case SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102:
pixel_format = 115;
color_space = COLOR_SPACE_YCBCR709;
select = INPUT_CSC_SELECT_ICSC;
is_2bit = 1;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
pixel_format = 116;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
pixel_format = 116;
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT:
pixel_format = 118;
alpha_en = 0;
break;
case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT:
pixel_format = 119;
alpha_en = 0;
break;
default:
break;
}
/* Set default color space based on format if none is given. */
color_space = input_color_space ? input_color_space : color_space;
if (is_2bit == 1 && alpha_2bit_lut != NULL) {
REG_UPDATE(ALPHA_2BIT_LUT01, ALPHA_2BIT_LUT0, alpha_2bit_lut->lut0);
REG_UPDATE(ALPHA_2BIT_LUT01, ALPHA_2BIT_LUT1, alpha_2bit_lut->lut1);
REG_UPDATE(ALPHA_2BIT_LUT23, ALPHA_2BIT_LUT2, alpha_2bit_lut->lut2);
REG_UPDATE(ALPHA_2BIT_LUT23, ALPHA_2BIT_LUT3, alpha_2bit_lut->lut3);
}
REG_SET(CNVC_SURFACE_PIXEL_FORMAT, 0,
CNVC_SURFACE_PIXEL_FORMAT, pixel_format);
REG_UPDATE(FORMAT_CONTROL, FORMAT_CONTROL__ALPHA_EN, alpha_en);
REG_SET_2(PRE_DEALPHA, 0,
PRE_DEALPHA_EN, dealpha_en,
PRE_DEALPHA_ABLND_EN, dealpha_ablnd_en);
REG_SET_2(PRE_REALPHA, 0,
PRE_REALPHA_EN, realpha_en,
PRE_REALPHA_ABLND_EN, realpha_ablnd_en);
if (format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN ||
format >= SURFACE_PIXEL_FORMAT_SUBSAMPLE_END ||
color_space != COLOR_SPACE_SRGB) {
/* If input adjustment exists, program the ICSC with those values. */
if (input_csc_color_matrix.enable_adjustment == true) {
for (i = 0; i < 12; i++)
tbl_entry.regval[i] = input_csc_color_matrix.matrix[i];
tbl_entry.color_space = input_color_space;
if (dpp3_should_bypass_post_csc_for_colorspace(color_space))
select = INPUT_CSC_SELECT_BYPASS;
else
select = INPUT_CSC_SELECT_ICSC;
dpp3_program_post_csc(dpp_base, color_space, select,
&tbl_entry);
} else {
dpp3_program_post_csc(dpp_base, color_space, select, NULL);
}
}
}
void dpp60_full_bypass(struct dpp *dpp_base)
{
struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
/* Input pixel format: ARGB8888 */
REG_SET(CNVC_SURFACE_PIXEL_FORMAT, 0,
CNVC_SURFACE_PIXEL_FORMAT, 0x8);
/* Zero expansion */
REG_SET_3(FORMAT_CONTROL, 0,
CNVC_BYPASS, 0,
FORMAT_CONTROL__ALPHA_EN, 0,
FORMAT_EXPANSION_MODE, 0);
/* COLOR_KEYER_CONTROL.COLOR_KEYER_EN = 0 this should be default */
if (dpp->tf_mask->CM_BYPASS_EN)
REG_SET(CM_CONTROL, 0, CM_BYPASS_EN, 1);
else
REG_SET(CM_CONTROL, 0, CM_BYPASS, 1);
}
static struct dpp_funcs dcn60_dpp_funcs = {
.dpp_program_gamcor_lut = dpp3_program_gamcor_lut,
.dpp_read_state = dpp401_read_state,
.dpp_reset = dpp_reset,
.dpp_set_scaler = dpp60_dscl_set_scaler_manual_scale,
.dpp_get_optimal_number_of_taps = dpp3_get_optimal_number_of_taps,
.dpp_set_pre_degam = NULL,
.dpp_full_bypass = dpp60_full_bypass,
.dpp_setup = dpp60_dpp_setup,
.dpp_program_cm_dealpha = dpp3_program_cm_dealpha,
.dpp_program_cm_bias = dpp3_program_cm_bias,
.dpp_program_bias_and_scale = dpp35_program_bias_and_scale_fcnv,
.dpp_cnv_set_alpha_keyer = dpp2_cnv_set_alpha_keyer,
.set_cursor_attributes = dpp401_set_cursor_attributes,
.set_cursor_position = dpp401_set_cursor_position,
.set_optional_cursor_attributes = dpp401_set_optional_cursor_attributes,
.dpp_dppclk_control = dpp1_dppclk_control,
.dpp_set_hdr_multiplier = dpp3_set_hdr_multiplier,
.set_cursor_matrix = dpp401_set_cursor_matrix,
.dpp_cm_hist_control = dpp42_dpp_cm_hist_control,
.dpp_cm_hist_read = dpp42_dpp_cm_hist_read,
.dpp_read_reg_state = dpp30_read_reg_state,
.dpp_set_pregam_state = dpp50_set_pregam_state,
};
static struct dpp_caps dcn60_dpp_cap = {
.dscl_data_proc_format = DSCL_DATA_PRCESSING_FLOAT_FORMAT,
.max_lb_partitions = 63,
.dscl_calc_lb_num_partitions = dscl401_calc_lb_num_partitions,
};
bool dpp60_construct(
struct dcn60_dpp *dpp,
struct dc_context *ctx,
uint32_t inst,
const struct dcn60_dpp_registers *tf_regs,
const struct dcn60_dpp_shift *tf_shift,
const struct dcn60_dpp_mask *tf_mask)
{
dpp->base.ctx = ctx;
dpp->base.inst = inst;
dpp->base.funcs = &dcn60_dpp_funcs;
dpp->base.caps = &dcn60_dpp_cap;
dpp->tf_regs = tf_regs;
dpp->tf_shift = tf_shift;
dpp->tf_mask = tf_mask;
return true;
}

View File

@@ -0,0 +1,525 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DCN60_DPP_H__
#define __DCN60_DPP_H__
#include "dcn20/dcn20_dpp.h"
#include "dcn30/dcn30_dpp.h"
#include "dcn32/dcn32_dpp.h"
#include "dcn35/dcn35_dpp.h"
#include "dcn401/dcn401_dpp.h"
#include "dcn42/dcn42_dpp.h"
#include "dcn50/dcn50_dpp.h"
#define TO_DCN60_DPP(dpp)\
container_of(dpp, struct dcn60_dpp, base)
#define DPP_REG_LIST_SH_MASK_DCN60(mask_sh)\
TF_SF(CM0_CM_MEM_PWR_STATUS, GAMCOR_MEM_PWR_STATE, mask_sh),\
TF_SF(CM0_CM_DEALPHA, CM_DEALPHA_EN, mask_sh),\
TF_SF(CM0_CM_DEALPHA, CM_DEALPHA_ABLND, mask_sh),\
TF_SF(CM0_CM_BIAS_CR_R, CM_BIAS_CR_R, mask_sh),\
TF_SF(CM0_CM_BIAS_Y_G_CB_B, CM_BIAS_Y_G, mask_sh),\
TF_SF(CM0_CM_BIAS_Y_G_CB_B, CM_BIAS_CB_B, mask_sh),\
TF_SF(CM0_CM_MEM_PWR_CTRL, GAMCOR_MEM_PWR_DIS, mask_sh),\
TF_SF(CM0_CM_MEM_PWR_CTRL, GAMCOR_MEM_PWR_FORCE, mask_sh),\
TF_SF(CM0_CM_MEM_PWR_CTRL, GAMCOR_MEM_PWR_DIS, mask_sh),\
TF_SF(CM0_CM_GAMCOR_CONTROL, CM_GAMCOR_MODE, mask_sh),\
TF_SF(CM0_CM_GAMCOR_CONTROL, CM_GAMCOR_SELECT, mask_sh),\
TF_SF(CM0_CM_GAMCOR_CONTROL, CM_GAMCOR_PWL_DISABLE, mask_sh),\
TF_SF(CM0_CM_GAMCOR_CONTROL, CM_GAMCOR_MODE_CURRENT, mask_sh),\
TF_SF(CM0_CM_GAMCOR_CONTROL, CM_GAMCOR_SELECT_CURRENT, mask_sh),\
TF_SF(CM0_CM_GAMCOR_LUT_INDEX, CM_GAMCOR_LUT_INDEX, mask_sh),\
TF_SF(CM0_CM_GAMCOR_LUT_DATA, CM_GAMCOR_LUT_DATA, mask_sh),\
TF_SF(CM0_CM_GAMCOR_LUT_CONTROL, CM_GAMCOR_LUT_WRITE_COLOR_MASK, mask_sh),\
TF_SF(CM0_CM_GAMCOR_LUT_CONTROL, CM_GAMCOR_LUT_READ_COLOR_SEL, mask_sh),\
TF_SF(CM0_CM_GAMCOR_LUT_CONTROL, CM_GAMCOR_LUT_READ_DBG, mask_sh),\
TF_SF(CM0_CM_GAMCOR_LUT_CONTROL, CM_GAMCOR_LUT_HOST_SEL, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_START_CNTL_B, CM_GAMCOR_RAMA_EXP_REGION_START_B, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_START_CNTL_B, CM_GAMCOR_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_START_SLOPE_CNTL_B, CM_GAMCOR_RAMA_EXP_REGION_START_SLOPE_B, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_START_BASE_CNTL_B, CM_GAMCOR_RAMA_EXP_REGION_START_BASE_B, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_END_CNTL1_B, CM_GAMCOR_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_END_CNTL2_B, CM_GAMCOR_RAMA_EXP_REGION_END_B, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_END_CNTL2_B, CM_GAMCOR_RAMA_EXP_REGION_END_SLOPE_B, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_OFFSET_B, CM_GAMCOR_RAMA_OFFSET_B, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_REGION_0_1, CM_GAMCOR_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_REGION_0_1, CM_GAMCOR_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_REGION_0_1, CM_GAMCOR_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
TF_SF(CM0_CM_GAMCOR_RAMA_REGION_0_1, CM_GAMCOR_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
TF_SF(DSCL0_DSCL_EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT, mask_sh),\
TF_SF(DSCL0_DSCL_EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT, mask_sh),\
TF_SF(DSCL0_DSCL_EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM, mask_sh),\
TF_SF(DSCL0_DSCL_EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP, mask_sh),\
TF_SF(DSCL0_OTG_H_BLANK, OTG_H_BLANK_START, mask_sh),\
TF_SF(DSCL0_OTG_H_BLANK, OTG_H_BLANK_END, mask_sh),\
TF_SF(DSCL0_OTG_V_BLANK, OTG_V_BLANK_START, mask_sh),\
TF_SF(DSCL0_OTG_V_BLANK, OTG_V_BLANK_END, mask_sh),\
TF2_SF(DSCL0, LB_DATA_FORMAT__ALPHA_EN, mask_sh),\
TF_SF(DSCL0_LB_MEMORY_CTRL, MEMORY_CONFIG, mask_sh),\
TF_SF(DSCL0_LB_MEMORY_CTRL, LB_MAX_PARTITIONS, mask_sh),\
TF_SF(DSCL0_DSCL_AUTOCAL, AUTOCAL_MODE, mask_sh),\
TF_SF(DSCL0_DSCL_AUTOCAL, AUTOCAL_FRAC_MODE, mask_sh),\
TF_SF(DSCL0_DSCL_AUTOCAL, AUTOCAL_NUM_PIPE, mask_sh),\
TF_SF(DSCL0_DSCL_AUTOCAL, AUTOCAL_PIPE_ID, mask_sh),\
TF_SF(DSCL0_DSCL_CONTROL, SCL_BOUNDARY_MODE, mask_sh),\
TF_SF(DSCL0_SCL_TAP_CONTROL, SCL_V_NUM_TAPS, mask_sh),\
TF_SF(DSCL0_SCL_TAP_CONTROL, SCL_H_NUM_TAPS, mask_sh),\
TF_SF(DSCL0_SCL_TAP_CONTROL, SCL_V_NUM_TAPS_C, mask_sh),\
TF_SF(DSCL0_SCL_TAP_CONTROL, SCL_H_NUM_TAPS_C, mask_sh),\
TF_SF(DSCL0_SCL_COEF_RAM_TAP_SELECT, SCL_COEF_RAM_TAP_PAIR_IDX, mask_sh),\
TF_SF(DSCL0_SCL_COEF_RAM_TAP_SELECT, SCL_COEF_RAM_PHASE, mask_sh),\
TF_SF(DSCL0_SCL_COEF_RAM_TAP_SELECT, SCL_COEF_RAM_FILTER_TYPE, mask_sh),\
TF_SF(DSCL0_SCL_COEF_RAM_TAP_DATA, SCL_COEF_RAM_EVEN_TAP_COEF, mask_sh),\
TF_SF(DSCL0_SCL_COEF_RAM_TAP_DATA, SCL_COEF_RAM_EVEN_TAP_COEF_EN, mask_sh),\
TF_SF(DSCL0_SCL_COEF_RAM_TAP_DATA, SCL_COEF_RAM_ODD_TAP_COEF, mask_sh),\
TF_SF(DSCL0_SCL_COEF_RAM_TAP_DATA, SCL_COEF_RAM_ODD_TAP_COEF_EN, mask_sh),\
TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_H_2TAP_HARDCODE_COEF_EN, mask_sh),\
TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_H_2TAP_SHARP_EN, mask_sh),\
TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_H_2TAP_SHARP_FACTOR, mask_sh),\
TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_V_2TAP_HARDCODE_COEF_EN, mask_sh),\
TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_V_2TAP_SHARP_EN, mask_sh),\
TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_V_2TAP_SHARP_FACTOR, mask_sh),\
TF_SF(DSCL0_SCL_MODE, SCL_COEF_RAM_SELECT, mask_sh),\
TF_SF(DSCL0_SCL_MODE, DSCL_MODE, mask_sh),\
TF_SF(DSCL0_RECOUT_START, RECOUT_START_X, mask_sh),\
TF_SF(DSCL0_RECOUT_START, RECOUT_START_Y, mask_sh),\
TF_SF(DSCL0_RECOUT_SIZE, RECOUT_WIDTH, mask_sh),\
TF_SF(DSCL0_RECOUT_SIZE, RECOUT_HEIGHT, mask_sh),\
TF_SF(DSCL0_MPC_SIZE, MPC_WIDTH, mask_sh),\
TF_SF(DSCL0_MPC_SIZE, MPC_HEIGHT, mask_sh),\
TF_SF(DSCL0_SCL_BLACK_COLOR, SCL_BLACK_COLOR_RGB_Y, mask_sh),\
TF_SF(DSCL0_SCL_BLACK_COLOR, SCL_BLACK_COLOR_CBCR, mask_sh),\
TF_SF(DSCL0_SCL_HORZ_FILTER_SCALE_RATIO, SCL_H_SCALE_RATIO, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_SCALE_RATIO, SCL_V_SCALE_RATIO, mask_sh),\
TF_SF(DSCL0_SCL_HORZ_FILTER_SCALE_RATIO_C, SCL_H_SCALE_RATIO_C, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_SCALE_RATIO_C, SCL_V_SCALE_RATIO_C, mask_sh),\
TF_SF(DSCL0_SCL_HORZ_FILTER_INIT, SCL_H_INIT_FRAC, mask_sh),\
TF_SF(DSCL0_SCL_HORZ_FILTER_INIT, SCL_H_INIT_INT, mask_sh),\
TF_SF(DSCL0_SCL_HORZ_FILTER_INIT_C, SCL_H_INIT_FRAC_C, mask_sh),\
TF_SF(DSCL0_SCL_HORZ_FILTER_INIT_C, SCL_H_INIT_INT_C, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_INIT, SCL_V_INIT_FRAC, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_INIT, SCL_V_INIT_INT, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_INIT_C, SCL_V_INIT_FRAC_C, mask_sh),\
TF_SF(DSCL0_SCL_VERT_FILTER_INIT_C, SCL_V_INIT_INT_C, mask_sh),\
TF_SF(DSCL0_SCL_MODE, SCL_CHROMA_COEF_MODE, mask_sh),\
TF_SF(DSCL0_SCL_MODE, SCL_COEF_RAM_SELECT_CURRENT, mask_sh), \
TF_SF(CNVC_CFG0_PRE_DEALPHA, PRE_DEALPHA_EN, mask_sh), \
TF_SF(CNVC_CFG0_PRE_DEALPHA, PRE_DEALPHA_ABLND_EN, mask_sh), \
TF_SF(CNVC_CFG0_PRE_REALPHA, PRE_REALPHA_EN, mask_sh), \
TF_SF(CNVC_CFG0_PRE_REALPHA, PRE_REALPHA_ABLND_EN, mask_sh), \
TF_SF(CNVC_CFG0_PRE_GAM, PRE_GAM_MODE, mask_sh),\
TF_SF(CNVC_CFG0_PRE_GAM, PRE_DEGAM_SELECT, mask_sh),\
TF_SF(CNVC_CFG0_PRE_GAM, PRE_REGAM_SELECT, mask_sh),\
TF_SF(CNVC_CFG0_PRE_CSC_MODE, PRE_CSC_MODE, mask_sh), \
TF_SF(CNVC_CFG0_PRE_CSC_MODE, PRE_CSC_MODE_CURRENT, mask_sh), \
TF_SF(CNVC_CFG0_PRE_CSC_C11_C12, PRE_CSC_C11, mask_sh), \
TF_SF(CNVC_CFG0_PRE_CSC_C11_C12, PRE_CSC_C12, mask_sh), \
TF_SF(CNVC_CFG0_PRE_CSC_C33_C34, PRE_CSC_C33, mask_sh), \
TF_SF(CNVC_CFG0_PRE_CSC_C33_C34, PRE_CSC_C34, mask_sh), \
TF_SF(CM0_CM_POST_CSC_CONTROL, CM_POST_CSC_MODE, mask_sh), \
TF_SF(CM0_CM_POST_CSC_CONTROL, CM_POST_CSC_MODE_CURRENT, mask_sh), \
TF_SF(CM0_CM_POST_CSC_C11_C12, CM_POST_CSC_C11, mask_sh), \
TF_SF(CM0_CM_POST_CSC_C11_C12, CM_POST_CSC_C12, mask_sh), \
TF_SF(CM0_CM_POST_CSC_C33_C34, CM_POST_CSC_C33, mask_sh), \
TF_SF(CM0_CM_POST_CSC_C33_C34, CM_POST_CSC_C34, mask_sh), \
TF_SF(CM0_CM_TEST_DEBUG_INDEX, CM_TEST_DEBUG_INDEX, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, CNVC_BYPASS, mask_sh), \
TF2_SF(CNVC_CFG0, FORMAT_CONTROL__ALPHA_EN, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_EXPANSION_MODE, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_SURFACE_PIXEL_FORMAT, CNVC_SURFACE_PIXEL_FORMAT, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_CONTROL, CUR0_MODE, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_CONTROL, CUR0_EXPANSION_MODE, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_COLOR0, CUR0_COLOR0, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y, CUR0_FP_BIAS_G_Y, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_FP_SCALE_BIAS_G_Y, CUR0_FP_SCALE_G_Y, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB, CUR0_FP_BIAS_RB_CRCB, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_FP_SCALE_BIAS_RB_CRCB, CUR0_FP_SCALE_RB_CRCB, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_MODE, CUR0_MATRIX_MODE, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_MODE, CUR0_MATRIX_MODE_CURRENT, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_MODE, CUR0_MATRIX_COEF_FORMAT, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C11_C12_A, CUR0_MATRIX_C11_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C11_C12_A, CUR0_MATRIX_C12_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C13_C14_A, CUR0_MATRIX_C13_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C13_C14_A, CUR0_MATRIX_C14_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C21_C22_A, CUR0_MATRIX_C21_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C21_C22_A, CUR0_MATRIX_C22_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C23_C24_A, CUR0_MATRIX_C23_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C23_C24_A, CUR0_MATRIX_C24_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C31_C32_A, CUR0_MATRIX_C31_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C31_C32_A, CUR0_MATRIX_C32_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C33_C34_A, CUR0_MATRIX_C33_A, mask_sh), \
TF_SF(CM_CUR0_CUR0_MATRIX_C33_C34_A, CUR0_MATRIX_C34_A, mask_sh), \
TF_SF(DPP_TOP0_DPP_CONTROL, DPP_CLOCK_ENABLE, mask_sh), \
TF_SF(CM0_CM_HDR_MULT_COEF, CM_HDR_MULT_COEF, mask_sh), \
TF_SF(CM0_CM_CONTROL, CM_BYPASS, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_SEL, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_CH_EN, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_SRC1_SEL, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_SRC2_SEL, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_SRC3_SEL, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_CH1_XBAR, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_CH2_XBAR, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_CH3_XBAR, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_FORMAT, mask_sh), \
TF_SF(CM0_CM_HIST_CNTL, CM_HIST_READ_CHANNEL_MASK, mask_sh), \
TF_SF(CM0_CM_HIST_LOCK, CM_HIST_LOCK, mask_sh), \
TF_SF(CM0_CM_HIST_INDEX, CM_HIST_INDEX, mask_sh), \
TF_SF(CM0_CM_HIST_DATA, CM_HIST_DATA, mask_sh), \
TF_SF(CM0_CM_HIST_STATUS, CM_HIST_BUFA_RDY_STATUS, mask_sh), \
TF_SF(CM0_CM_HIST_STATUS, CM_HIST_BUFB_RDY_STATUS, mask_sh), \
TF_SF(CM0_CM_HIST_SCALE_SRC1, CM_HIST_SCALE_SRC1, mask_sh), \
TF_SF(CM0_CM_HIST_COEFA_SRC2, CM_HIST_COEFA_SRC2, mask_sh), \
TF_SF(CM0_CM_HIST_COEFB_SRC2, CM_HIST_COEFB_SRC2, mask_sh), \
TF_SF(CM0_CM_HIST_COEFC_SRC2, CM_HIST_COEFC_SRC2, mask_sh), \
TF_SF(CM0_CM_HIST_SCALE_SRC3, CM_HIST_SCALE_SRC3, mask_sh), \
TF_SF(CM0_CM_HIST_BIAS_SRC1, CM_HIST_BIAS_SRC1, mask_sh), \
TF_SF(CM0_CM_HIST_BIAS_SRC2, CM_HIST_BIAS_SRC2, mask_sh), \
TF_SF(CM0_CM_HIST_BIAS_SRC3, CM_HIST_BIAS_SRC3, mask_sh), \
TF_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \
TF_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \
TF_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \
TF_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_CNV16, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, CNVC_BYPASS_MSB_ALIGN, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, CLAMP_POSITIVE, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, CLAMP_POSITIVE_C, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_CROSSBAR_R, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_CROSSBAR_G, mask_sh), \
TF_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_CROSSBAR_B, mask_sh), \
TF_SF(CNVC_CFG0_ALPHA_2BIT_LUT01, ALPHA_2BIT_LUT0, mask_sh), \
TF_SF(CNVC_CFG0_ALPHA_2BIT_LUT01, ALPHA_2BIT_LUT1, mask_sh), \
TF_SF(CNVC_CFG0_ALPHA_2BIT_LUT23, ALPHA_2BIT_LUT2, mask_sh), \
TF_SF(CNVC_CFG0_ALPHA_2BIT_LUT23, ALPHA_2BIT_LUT3, mask_sh), \
TF_SF(CNVC_CFG0_FCNV_FP_BIAS_R, FCNV_FP_BIAS_R, mask_sh), \
TF_SF(CNVC_CFG0_FCNV_FP_BIAS_G, FCNV_FP_BIAS_G, mask_sh), \
TF_SF(CNVC_CFG0_FCNV_FP_BIAS_B, FCNV_FP_BIAS_B, mask_sh), \
TF_SF(CNVC_CFG0_FCNV_FP_SCALE_R, FCNV_FP_SCALE_R, mask_sh), \
TF_SF(CNVC_CFG0_FCNV_FP_SCALE_G, FCNV_FP_SCALE_G, mask_sh), \
TF_SF(CNVC_CFG0_FCNV_FP_SCALE_B, FCNV_FP_SCALE_B, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_CONTROL, COLOR_KEYER_EN, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_CONTROL, LUMA_KEYER_EN, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_CONTROL, COLOR_KEYER_MODE, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_ALPHA, COLOR_KEYER_ALPHA_LOW, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_ALPHA, COLOR_KEYER_ALPHA_HIGH, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_RED, COLOR_KEYER_RED_LOW, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_RED, COLOR_KEYER_RED_HIGH, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_GREEN, COLOR_KEYER_GREEN_LOW, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_GREEN, COLOR_KEYER_GREEN_HIGH, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_LOW, mask_sh), \
TF_SF(CNVC_CFG0_COLOR_KEYER_BLUE, COLOR_KEYER_BLUE_HIGH, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_CONTROL, CUR0_PIX_INV_MODE, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_CONTROL, CUR0_PIXEL_ALPHA_MOD_EN, mask_sh), \
TF_SF(CM_CUR0_CURSOR0_CONTROL, CUR0_ROM_EN, mask_sh),\
TF_SF(DSCL0_OBUF_MEM_PWR_CTRL, OBUF_MEM_PWR_FORCE, mask_sh),\
TF_SF(DSCL0_DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, mask_sh),\
TF_SF(DSCL0_DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_DIS, mask_sh),\
TF_SF(DSCL0_DSCL_MEM_PWR_STATUS, LUT_MEM_PWR_STATE, mask_sh),\
TF_SF(DSCL0_DSCL_SC_MODE, SCL_SC_MATRIX_MODE, mask_sh),\
TF_SF(DSCL0_DSCL_SC_MODE, SCL_SC_LTONL_EN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_MODE, SCL_EASF_H_EN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_MODE, SCL_EASF_H_RINGEST_FORCE_EN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_MODE, SCL_EASF_H_2TAP_SHARP_FACTOR, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_CNTL, SCL_EASF_H_BF1_EN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_CNTL, SCL_EASF_H_BF2_MODE, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_CNTL, SCL_EASF_H_BF3_MODE, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_CNTL, SCL_EASF_H_BF2_FLAT1_GAIN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_CNTL, SCL_EASF_H_BF2_FLAT2_GAIN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_CNTL, SCL_EASF_H_BF2_ROC_GAIN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_RINGEST_EVENTAP_REDUCE, SCL_EASF_H_RINGEST_EVENTAP_REDUCEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_RINGEST_EVENTAP_REDUCE, SCL_EASF_H_RINGEST_EVENTAP_REDUCEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_RINGEST_EVENTAP_GAIN, SCL_EASF_H_RINGEST_EVENTAP_GAIN1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_RINGEST_EVENTAP_GAIN, SCL_EASF_H_RINGEST_EVENTAP_GAIN2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_FINAL_MAX_MIN, SCL_EASF_H_BF_MAXA, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_FINAL_MAX_MIN, SCL_EASF_H_BF_MAXB, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_FINAL_MAX_MIN, SCL_EASF_H_BF_MINA, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF_FINAL_MAX_MIN, SCL_EASF_H_BF_MINB, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG0, SCL_EASF_H_BF1_PWL_IN_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG0, SCL_EASF_H_BF1_PWL_BASE_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG0, SCL_EASF_H_BF1_PWL_SLOPE_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG1, SCL_EASF_H_BF1_PWL_IN_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG1, SCL_EASF_H_BF1_PWL_BASE_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG1, SCL_EASF_H_BF1_PWL_SLOPE_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG2, SCL_EASF_H_BF1_PWL_IN_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG2, SCL_EASF_H_BF1_PWL_BASE_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG2, SCL_EASF_H_BF1_PWL_SLOPE_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG3, SCL_EASF_H_BF1_PWL_IN_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG3, SCL_EASF_H_BF1_PWL_BASE_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG3, SCL_EASF_H_BF1_PWL_SLOPE_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG4, SCL_EASF_H_BF1_PWL_IN_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG4, SCL_EASF_H_BF1_PWL_BASE_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG4, SCL_EASF_H_BF1_PWL_SLOPE_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG5, SCL_EASF_H_BF1_PWL_IN_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG5, SCL_EASF_H_BF1_PWL_BASE_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG5, SCL_EASF_H_BF1_PWL_SLOPE_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG6, SCL_EASF_H_BF1_PWL_IN_SEG6, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG6, SCL_EASF_H_BF1_PWL_BASE_SEG6, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG6, SCL_EASF_H_BF1_PWL_SLOPE_SEG6, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG7, SCL_EASF_H_BF1_PWL_IN_SEG7, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF1_PWL_SEG7, SCL_EASF_H_BF1_PWL_BASE_SEG7, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG0, SCL_EASF_H_BF3_PWL_IN_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG0, SCL_EASF_H_BF3_PWL_BASE_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG0, SCL_EASF_H_BF3_PWL_SLOPE_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG1, SCL_EASF_H_BF3_PWL_IN_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG1, SCL_EASF_H_BF3_PWL_BASE_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG1, SCL_EASF_H_BF3_PWL_SLOPE_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG2, SCL_EASF_H_BF3_PWL_IN_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG2, SCL_EASF_H_BF3_PWL_BASE_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG2, SCL_EASF_H_BF3_PWL_SLOPE_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG3, SCL_EASF_H_BF3_PWL_IN_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG3, SCL_EASF_H_BF3_PWL_BASE_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG3, SCL_EASF_H_BF3_PWL_SLOPE_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG4, SCL_EASF_H_BF3_PWL_IN_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG4, SCL_EASF_H_BF3_PWL_BASE_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG4, SCL_EASF_H_BF3_PWL_SLOPE_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG5, SCL_EASF_H_BF3_PWL_IN_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_H_BF3_PWL_SEG5, SCL_EASF_H_BF3_PWL_BASE_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_MODE, SCL_EASF_V_EN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_MODE, SCL_EASF_V_RINGEST_FORCE_EN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_MODE, SCL_EASF_V_2TAP_SHARP_FACTOR, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_CNTL, SCL_EASF_V_BF1_EN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_CNTL, SCL_EASF_V_BF2_MODE, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_CNTL, SCL_EASF_V_BF3_MODE, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_CNTL, SCL_EASF_V_BF2_FLAT1_GAIN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_CNTL, SCL_EASF_V_BF2_FLAT2_GAIN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_CNTL, SCL_EASF_V_BF2_ROC_GAIN, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_3TAP_CNTL1, SCL_EASF_V_RINGEST_3TAP_DNTILT_UPTILT, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_3TAP_CNTL1, SCL_EASF_V_RINGEST_3TAP_UPTILT_MAXVAL, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_3TAP_CNTL2, SCL_EASF_V_RINGEST_3TAP_DNTILT_SLOPE, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_3TAP_CNTL2, SCL_EASF_V_RINGEST_3TAP_UPTILT1_SLOPE, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_3TAP_CNTL3, SCL_EASF_V_RINGEST_3TAP_UPTILT2_SLOPE, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_3TAP_CNTL3, SCL_EASF_V_RINGEST_3TAP_UPTILT2_OFFSET, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_EVENTAP_REDUCE, SCL_EASF_V_RINGEST_EVENTAP_REDUCEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_EVENTAP_REDUCE, SCL_EASF_V_RINGEST_EVENTAP_REDUCEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_EVENTAP_GAIN, SCL_EASF_V_RINGEST_EVENTAP_GAIN1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_RINGEST_EVENTAP_GAIN, SCL_EASF_V_RINGEST_EVENTAP_GAIN2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_FINAL_MAX_MIN, SCL_EASF_V_BF_MAXA, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_FINAL_MAX_MIN, SCL_EASF_V_BF_MAXB, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_FINAL_MAX_MIN, SCL_EASF_V_BF_MINA, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF_FINAL_MAX_MIN, SCL_EASF_V_BF_MINB, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG0, SCL_EASF_V_BF1_PWL_IN_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG0, SCL_EASF_V_BF1_PWL_BASE_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG0, SCL_EASF_V_BF1_PWL_SLOPE_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG1, SCL_EASF_V_BF1_PWL_IN_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG1, SCL_EASF_V_BF1_PWL_BASE_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG1, SCL_EASF_V_BF1_PWL_SLOPE_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG2, SCL_EASF_V_BF1_PWL_IN_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG2, SCL_EASF_V_BF1_PWL_BASE_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG2, SCL_EASF_V_BF1_PWL_SLOPE_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG3, SCL_EASF_V_BF1_PWL_IN_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG3, SCL_EASF_V_BF1_PWL_BASE_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG3, SCL_EASF_V_BF1_PWL_SLOPE_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG4, SCL_EASF_V_BF1_PWL_IN_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG4, SCL_EASF_V_BF1_PWL_BASE_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG4, SCL_EASF_V_BF1_PWL_SLOPE_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG5, SCL_EASF_V_BF1_PWL_IN_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG5, SCL_EASF_V_BF1_PWL_BASE_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG5, SCL_EASF_V_BF1_PWL_SLOPE_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG6, SCL_EASF_V_BF1_PWL_IN_SEG6, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG6, SCL_EASF_V_BF1_PWL_BASE_SEG6, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG6, SCL_EASF_V_BF1_PWL_SLOPE_SEG6, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG7, SCL_EASF_V_BF1_PWL_IN_SEG7, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF1_PWL_SEG7, SCL_EASF_V_BF1_PWL_BASE_SEG7, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG0, SCL_EASF_V_BF3_PWL_IN_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG0, SCL_EASF_V_BF3_PWL_BASE_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG0, SCL_EASF_V_BF3_PWL_SLOPE_SEG0, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG1, SCL_EASF_V_BF3_PWL_IN_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG1, SCL_EASF_V_BF3_PWL_BASE_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG1, SCL_EASF_V_BF3_PWL_SLOPE_SEG1, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG2, SCL_EASF_V_BF3_PWL_IN_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG2, SCL_EASF_V_BF3_PWL_BASE_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG2, SCL_EASF_V_BF3_PWL_SLOPE_SEG2, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG3, SCL_EASF_V_BF3_PWL_IN_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG3, SCL_EASF_V_BF3_PWL_BASE_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG3, SCL_EASF_V_BF3_PWL_SLOPE_SEG3, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG4, SCL_EASF_V_BF3_PWL_IN_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG4, SCL_EASF_V_BF3_PWL_BASE_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG4, SCL_EASF_V_BF3_PWL_SLOPE_SEG4, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG5, SCL_EASF_V_BF3_PWL_IN_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_EASF_V_BF3_PWL_SEG5, SCL_EASF_V_BF3_PWL_BASE_SEG5, mask_sh),\
TF_SF(DSCL0_DSCL_SC_MATRIX_C0C1, SCL_SC_MATRIX_C0, mask_sh),\
TF_SF(DSCL0_DSCL_SC_MATRIX_C0C1, SCL_SC_MATRIX_C1, mask_sh),\
TF_SF(DSCL0_DSCL_SC_MATRIX_C2C3, SCL_SC_MATRIX_C2, mask_sh),\
TF_SF(DSCL0_DSCL_SC_MATRIX_C2C3, SCL_SC_MATRIX_C3, mask_sh),\
TF_SF(DSCL0_ISHARP_DELTA_CTRL, ISHARP_DELTA_LUT_HOST_SELECT, mask_sh),\
TF_SF(DSCL0_ISHARP_DELTA_LUT_MEM_PWR_CTRL, ISHARP_DELTA_LUT_MEM_PWR_DIS, mask_sh),\
TF_SF(DSCL0_ISHARP_DELTA_LUT_MEM_PWR_CTRL, ISHARP_DELTA_LUT_MEM_PWR_FORCE, mask_sh),\
TF_SF(DSCL0_ISHARP_DELTA_LUT_MEM_PWR_CTRL, ISHARP_DELTA_LUT_MEM_PWR_STATE, mask_sh),\
TF_SF(DSCL0_ISHARP_DELTA_DATA, ISHARP_DELTA_DATA, mask_sh),\
TF_SF(DSCL0_ISHARP_DELTA_INDEX, ISHARP_DELTA_INDEX, mask_sh),\
TF_SF(DSCL0_ISHARP_MODE, ISHARP_EN, mask_sh),\
TF_SF(DSCL0_ISHARP_MODE, ISHARP_NOISEDET_EN, mask_sh),\
TF_SF(DSCL0_ISHARP_MODE, ISHARP_NOISEDET_MODE, mask_sh),\
TF_SF(DSCL0_ISHARP_MODE, ISHARP_LBA_MODE, mask_sh),\
TF_SF(DSCL0_ISHARP_MODE, ISHARP_DELTA_LUT_SELECT, mask_sh),\
TF_SF(DSCL0_ISHARP_MODE, ISHARP_FMT_MODE, mask_sh),\
TF_SF(DSCL0_ISHARP_MODE, ISHARP_FMT_NORM, mask_sh),\
TF_SF(DSCL0_ISHARP_MODE, ISHARP_DELTA_LUT_SELECT_CURRENT, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG0, ISHARP_LBA_PWL_IN_SEG0, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG0, ISHARP_LBA_PWL_BASE_SEG0, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG0, ISHARP_LBA_PWL_SLOPE_SEG0, mask_sh), \
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG1, ISHARP_LBA_PWL_IN_SEG1, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG1, ISHARP_LBA_PWL_BASE_SEG1, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG1, ISHARP_LBA_PWL_SLOPE_SEG1, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG2, ISHARP_LBA_PWL_IN_SEG2, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG2, ISHARP_LBA_PWL_BASE_SEG2, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG2, ISHARP_LBA_PWL_SLOPE_SEG2, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG3, ISHARP_LBA_PWL_IN_SEG3, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG3, ISHARP_LBA_PWL_BASE_SEG3, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG3, ISHARP_LBA_PWL_SLOPE_SEG3, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG4, ISHARP_LBA_PWL_IN_SEG4, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG4, ISHARP_LBA_PWL_BASE_SEG4, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG4, ISHARP_LBA_PWL_SLOPE_SEG4, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG5, ISHARP_LBA_PWL_IN_SEG5, mask_sh),\
TF_SF(DSCL0_ISHARP_LBA_PWL_SEG5, ISHARP_LBA_PWL_BASE_SEG5, mask_sh),\
TF_SF(DSCL0_ISHARP_NOISEDET_THRESHOLD, ISHARP_NOISEDET_UTHRE, mask_sh),\
TF_SF(DSCL0_ISHARP_NOISEDET_THRESHOLD, ISHARP_NOISEDET_DTHRE, mask_sh), \
TF_SF(DSCL0_ISHARP_NOISE_GAIN_PWL, ISHARP_NOISEDET_PWL_START_IN, mask_sh), \
TF_SF(DSCL0_ISHARP_NOISE_GAIN_PWL, ISHARP_NOISEDET_PWL_END_IN, mask_sh), \
TF_SF(DSCL0_ISHARP_NOISE_GAIN_PWL, ISHARP_NOISEDET_PWL_SLOPE, mask_sh), \
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_EN_P, mask_sh), \
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_PIVOT_P, mask_sh), \
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_SLOPE_P, mask_sh), \
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_EN_N, mask_sh), \
TF_SF(DSCL0_ISHARP_NLDELTA_SOFT_CLIP, ISHARP_NLDELTA_SCLIP_PIVOT_N, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_MODE, UPSP_MODE, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_MODE, UPSP_V_NUM_TAPS, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_MODE, UPSP_V_INIT_INT, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_MODE, UPSP_V_INIT_FRAC, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_MODE, UPSP_H_NUM_TAPS, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_MODE, UPSP_H_INIT_INT, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_MODE, UPSP_H_INIT_FRAC, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_MODE, UPSP_BOUNDARY_MODE, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_V_COEF_P0, UPSP_V_COEF_TAP0_P0, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_V_COEF_P0, UPSP_V_COEF_TAP1_P0, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_V_COEF_P0, UPSP_V_COEF_TAP2_P0, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_V_COEF_P0, UPSP_V_COEF_TAP3_P0, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_V_COEF_P1, UPSP_V_COEF_TAP0_P1, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_V_COEF_P1, UPSP_V_COEF_TAP1_P1, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_V_COEF_P1, UPSP_V_COEF_TAP2_P1, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_V_COEF_P1, UPSP_V_COEF_TAP3_P1, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_H_COEF_P0, UPSP_H_COEF_TAP0_P0, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_H_COEF_P0, UPSP_H_COEF_TAP1_P0, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_H_COEF_P0, UPSP_H_COEF_TAP2_P0, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_H_COEF_P0, UPSP_H_COEF_TAP3_P0, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_H_COEF_P1, UPSP_H_COEF_TAP0_P1, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_H_COEF_P1, UPSP_H_COEF_TAP1_P1, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_H_COEF_P1, UPSP_H_COEF_TAP2_P1, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_H_COEF_P1, UPSP_H_COEF_TAP3_P1, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_CLAMP, UPSP_CLAMP_MAX, mask_sh), \
TF_SF(CNVC_CFG0_CNVC_UPSP_CLAMP, UPSP_CLAMP_MIN, mask_sh)
#define DPP_REG_FIELD_LIST_DCN60(type) \
DPP_REG_FIELD_LIST_DCN42(type); \
type PRE_GAM_MODE; \
type PRE_REGAM_SELECT; \
type AUTOCAL_FRAC_MODE; \
type SCL_BLACK_COLOR_RGB_Y; \
type SCL_BLACK_COLOR_CBCR; \
type UPSP_MODE; \
type UPSP_V_NUM_TAPS; \
type UPSP_V_INIT_INT; \
type UPSP_V_INIT_FRAC; \
type UPSP_H_NUM_TAPS; \
type UPSP_H_INIT_INT; \
type UPSP_H_INIT_FRAC; \
type UPSP_BOUNDARY_MODE; \
type UPSP_V_COEF_TAP0_P0; \
type UPSP_V_COEF_TAP1_P0; \
type UPSP_V_COEF_TAP2_P0; \
type UPSP_V_COEF_TAP3_P0; \
type UPSP_V_COEF_TAP0_P1; \
type UPSP_V_COEF_TAP1_P1; \
type UPSP_V_COEF_TAP2_P1; \
type UPSP_V_COEF_TAP3_P1; \
type UPSP_H_COEF_TAP0_P0; \
type UPSP_H_COEF_TAP1_P0; \
type UPSP_H_COEF_TAP2_P0; \
type UPSP_H_COEF_TAP3_P0; \
type UPSP_H_COEF_TAP0_P1; \
type UPSP_H_COEF_TAP1_P1; \
type UPSP_H_COEF_TAP2_P1; \
type UPSP_H_COEF_TAP3_P1; \
type UPSP_CLAMP_MAX; \
type UPSP_CLAMP_MIN
#define DPP_REG_VARIABLE_LIST_DCN60 \
DPP_REG_VARIABLE_LIST_DCN42; \
uint32_t PRE_GAM; \
uint32_t SCL_BLACK_COLOR; \
uint32_t UPSP_MODE; \
uint32_t UPSP_V_COEF_P0; \
uint32_t UPSP_V_COEF_P1; \
uint32_t UPSP_H_COEF_P0; \
uint32_t UPSP_H_COEF_P1; \
uint32_t UPSP_CLAMP
struct dcn60_dpp_registers {
DPP_REG_VARIABLE_LIST_DCN60;
};
struct dcn60_dpp_shift {
DPP_REG_FIELD_LIST_DCN60(uint8_t);
};
struct dcn60_dpp_mask {
DPP_REG_FIELD_LIST_DCN60(uint32_t);
};
struct dcn60_dpp {
struct dpp base;
const struct dcn60_dpp_registers *tf_regs;
const struct dcn60_dpp_shift *tf_shift;
const struct dcn60_dpp_mask *tf_mask;
const uint16_t *filter_v;
const uint16_t *filter_h;
const uint16_t *filter_v_c;
const uint16_t *filter_h_c;
int lb_pixel_depth_supported;
int lb_memory_size;
int lb_bits_per_entry;
bool is_write_to_ram_a_safe;
struct scaler_data scl_data;
struct pwl_params pwl_data;
};
void dpp60_dpp_setup(
struct dpp *dpp_base,
enum surface_pixel_format format,
enum expansion_mode mode,
struct dc_csc_transform input_csc_color_matrix,
enum dc_color_space input_color_space,
struct cnv_alpha_2bit_lut *alpha_2bit_lut);
void dpp60_full_bypass(struct dpp *dpp_base);
void dpp60_dscl_set_scaler_manual_scale(
struct dpp *dpp_base,
const struct scaler_data *scl_data);
void dpp60_dscl_set_lb(
struct dcn60_dpp *dpp,
const struct line_buffer_params *lb_params,
enum lb_memory_config mem_size_config);
void dpp60_dscl_set_manual_ratio_init(
struct dcn60_dpp *dpp,
const struct scaler_data *data);
void dpp60_dscl_program_upsp(
struct dpp *dpp_base,
const struct dscl_prog_data *dscl_prog_data);
bool dpp60_construct(struct dcn60_dpp *dpp60,
struct dc_context *ctx,
uint32_t inst,
const struct dcn60_dpp_registers *tf_regs,
const struct dcn60_dpp_shift *tf_shift,
const struct dcn60_dpp_mask *tf_mask);
#endif /* __DCN60_DPP_H__ */

View File

@@ -0,0 +1,315 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dm_services.h"
#include "core_types.h"
#include "reg_helper.h"
#include "dcn60/dcn60_dpp.h"
#include "basics/conversion.h"
#define REG(reg)\
dpp->tf_regs->reg
#define CTX \
dpp->base.ctx
#undef FN
#define FN(reg_name, field_name) \
dpp->tf_shift->field_name, dpp->tf_mask->field_name
static void dpp60_power_on_dscl(struct dpp *dpp_base, bool power_on)
{
struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
if (power_on) {
REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_FORCE, 0);
REG_UPDATE(DSCL_MEM_PWR_CTRL, LUT_MEM_PWR_DIS, 1);
REG_WAIT(DSCL_MEM_PWR_STATUS, LUT_MEM_PWR_STATE, 0, 1, 100);
} else {
if (dpp->base.ctx->dc->debug.enable_mem_low_power.bits.dscl) {
dpp->base.ctx->dc->optimized_required = true;
dpp->base.deferred_reg_writes.bits.disable_dscl = true;
}
}
}
void dpp60_dscl_set_lb(
struct dcn60_dpp *dpp,
const struct line_buffer_params *lb_params,
enum lb_memory_config mem_size_config)
{
/* LB */
REG_SET(LB_DATA_FORMAT, 0,
LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */
REG_SET_2(LB_MEMORY_CTRL, 0,
MEMORY_CONFIG, mem_size_config,
LB_MAX_PARTITIONS, dpp->base.caps->max_lb_partitions);
}
void dpp60_dscl_set_manual_ratio_init(
struct dcn60_dpp *dpp, const struct scaler_data *data)
{
uint32_t init_frac = 0;
uint32_t init_int = 0;
if ((dpp->base.ctx->dc->config.use_spl) && (!dpp->base.ctx->dc->debug.disable_spl)) {
REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
SCL_H_SCALE_RATIO, data->dscl_prog_data.ratios.h_scale_ratio);
REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
SCL_V_SCALE_RATIO, data->dscl_prog_data.ratios.v_scale_ratio);
REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0,
SCL_H_SCALE_RATIO_C, data->dscl_prog_data.ratios.h_scale_ratio_c);
REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0,
SCL_V_SCALE_RATIO_C, data->dscl_prog_data.ratios.v_scale_ratio_c);
REG_SET_2(SCL_HORZ_FILTER_INIT, 0,
SCL_H_INIT_FRAC, data->dscl_prog_data.init.h_filter_init_frac,
SCL_H_INIT_INT, data->dscl_prog_data.init.h_filter_init_int);
REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0,
SCL_H_INIT_FRAC_C, data->dscl_prog_data.init.h_filter_init_frac_c,
SCL_H_INIT_INT_C, data->dscl_prog_data.init.h_filter_init_int_c);
REG_SET_2(SCL_VERT_FILTER_INIT, 0,
SCL_V_INIT_FRAC, data->dscl_prog_data.init.v_filter_init_frac,
SCL_V_INIT_INT, data->dscl_prog_data.init.v_filter_init_int);
REG_SET_2(SCL_VERT_FILTER_INIT_C, 0,
SCL_V_INIT_FRAC_C, data->dscl_prog_data.init.v_filter_init_frac_c,
SCL_V_INIT_INT_C, data->dscl_prog_data.init.v_filter_init_int_c);
return;
}
REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0,
SCL_H_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.horz) << 5);
REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0,
SCL_V_SCALE_RATIO, dc_fixpt_u3d19(data->ratios.vert) << 5);
REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0,
SCL_H_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.horz_c) << 5);
REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0,
SCL_V_SCALE_RATIO_C, dc_fixpt_u3d19(data->ratios.vert_c) << 5);
/*
* 0.24 format for fraction, first five bits zeroed
*/
init_frac = dc_fixpt_u0d19(data->inits.h) << 5;
init_int = dc_fixpt_floor(data->inits.h);
REG_SET_2(SCL_HORZ_FILTER_INIT, 0,
SCL_H_INIT_FRAC, init_frac,
SCL_H_INIT_INT, init_int);
init_frac = dc_fixpt_u0d19(data->inits.h_c) << 5;
init_int = dc_fixpt_floor(data->inits.h_c);
REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0,
SCL_H_INIT_FRAC_C, init_frac,
SCL_H_INIT_INT_C, init_int);
init_frac = dc_fixpt_u0d19(data->inits.v) << 5;
init_int = dc_fixpt_floor(data->inits.v);
REG_SET_2(SCL_VERT_FILTER_INIT, 0,
SCL_V_INIT_FRAC, init_frac,
SCL_V_INIT_INT, init_int);
init_frac = dc_fixpt_u0d19(data->inits.v_c) << 5;
init_int = dc_fixpt_floor(data->inits.v_c);
REG_SET_2(SCL_VERT_FILTER_INIT_C, 0,
SCL_V_INIT_FRAC_C, init_frac,
SCL_V_INIT_INT_C, init_int);
}
/**
* dpp60_dscl_set_scaler_manual_scale - Manually program scaler and line buffer
*
* @dpp_base: High level DPP struct
* @scl_data: scalaer_data info
*
* This is the primary function to program scaler and line buffer in manual
* scaling mode. To execute the required operations for manual scale, we need
* to disable AutoCal first.
*/
void dpp60_dscl_set_scaler_manual_scale(struct dpp *dpp_base,
const struct scaler_data *scl_data)
{
enum lb_memory_config lb_config;
struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
struct dcn401_dpp *dpp401 = TO_DCN401_DPP(dpp_base);
const struct rect *rect = &scl_data->recout;
uint32_t mpc_width = scl_data->h_active;
uint32_t mpc_height = scl_data->v_active;
uint32_t v_num_taps = scl_data->taps.v_taps - 1;
uint32_t v_num_taps_c = scl_data->taps.v_taps_c - 1;
uint32_t h_num_taps = scl_data->taps.h_taps - 1;
uint32_t h_num_taps_c = scl_data->taps.h_taps_c - 1;
enum dcn401_dscl_mode_sel dscl_mode = dpp401_dscl_get_dscl_mode(
dpp_base, scl_data, dpp_base->ctx->dc->debug.always_scale);
bool ycbcr = scl_data->format >= PIXEL_FORMAT_VIDEO_BEGIN
&& scl_data->format <= PIXEL_FORMAT_VIDEO_END;
bool program_isharp_1dlut = false;
bool bs_coeffs_updated = false;
if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0)
return;
PERF_TRACE();
/* If only sharpness has changed, then only update 1dlut, then return */
if (scl_data->dscl_prog_data.isharp_en &&
(dpp->scl_data.dscl_prog_data.sharpness_level
!= scl_data->dscl_prog_data.sharpness_level)) {
/* ISHARP_DELTA_LUT */
dpp401_dscl_set_isharp_filter(dpp401, scl_data->dscl_prog_data.isharp_delta);
dpp->scl_data.dscl_prog_data.sharpness_level = scl_data->dscl_prog_data.sharpness_level;
memcpy(dpp->scl_data.dscl_prog_data.isharp_delta, scl_data->dscl_prog_data.isharp_delta,
sizeof(uint32_t) * ISHARP_LUT_TABLE_SIZE);
if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0)
return;
program_isharp_1dlut = true;
}
dpp->scl_data = *scl_data;
if ((dpp->base.ctx->dc->config.use_spl) && (!dpp->base.ctx->dc->debug.disable_spl)) {
dscl_mode = (enum dcn401_dscl_mode_sel) scl_data->dscl_prog_data.dscl_mode;
rect = (struct rect *)&scl_data->dscl_prog_data.recout;
mpc_width = scl_data->dscl_prog_data.mpc_size.width;
mpc_height = scl_data->dscl_prog_data.mpc_size.height;
v_num_taps = scl_data->dscl_prog_data.taps.v_taps;
v_num_taps_c = scl_data->dscl_prog_data.taps.v_taps_c;
h_num_taps = scl_data->dscl_prog_data.taps.h_taps;
h_num_taps_c = scl_data->dscl_prog_data.taps.h_taps_c;
}
/* Unconditionally power on DSCL - can be in light sleep otherwise. */
if (dscl_mode != DCN401_DSCL_MODE_DSCL_BYPASS)
dpp60_power_on_dscl(dpp_base, true);
/* Autocal off */
REG_SET_4(DSCL_AUTOCAL, 0,
AUTOCAL_MODE, 0,
AUTOCAL_FRAC_MODE, 0,
AUTOCAL_NUM_PIPE, 0,
AUTOCAL_PIPE_ID, 0);
/*clean scaler boundary mode when Autocal off*/
REG_SET(DSCL_CONTROL, 0,
SCL_BOUNDARY_MODE, 0);
/* Recout */
dpp401_dscl_set_recout(dpp401, rect);
/* MPC Size */
REG_SET_2(MPC_SIZE, 0,
/* Number of horizontal pixels of MPC */
MPC_WIDTH, mpc_width,
/* Number of vertical lines of MPC */
MPC_HEIGHT, mpc_height);
/* SCL mode */
REG_UPDATE(SCL_MODE, DSCL_MODE, dscl_mode);
if (dscl_mode == DCN401_DSCL_MODE_DSCL_BYPASS) {
dpp60_power_on_dscl(dpp_base, false);
return;
}
/* LB */
lb_config = dpp401_dscl_find_lb_memory_config(dpp401, scl_data);
dpp60_dscl_set_lb(dpp, &scl_data->lb_params, lb_config);
if (dscl_mode == DCN401_DSCL_MODE_SCALING_444_BYPASS) {
if (dpp->base.ctx->dc->config.prefer_easf)
dpp401_dscl_disable_easf(dpp_base, scl_data);
dpp401_dscl_program_isharp(dpp_base, scl_data, program_isharp_1dlut, &bs_coeffs_updated);
return;
}
/* Black color */
if (ycbcr)
REG_SET_2(SCL_BLACK_COLOR, 0,
SCL_BLACK_COLOR_RGB_Y, BLACK_OFFSET_RGB_Y,
SCL_BLACK_COLOR_CBCR, BLACK_OFFSET_CBCR);
else
REG_SET_2(SCL_BLACK_COLOR, 0,
SCL_BLACK_COLOR_RGB_Y, BLACK_OFFSET_RGB_Y,
SCL_BLACK_COLOR_CBCR, BLACK_OFFSET_RGB_Y);
/* Manually calculate scale ratio and init values */
dpp60_dscl_set_manual_ratio_init(dpp, scl_data);
/* HTaps/VTaps */
REG_SET_4(SCL_TAP_CONTROL, 0,
SCL_V_NUM_TAPS, v_num_taps,
SCL_H_NUM_TAPS, h_num_taps,
SCL_V_NUM_TAPS_C, v_num_taps_c,
SCL_H_NUM_TAPS_C, h_num_taps_c);
/* ISharp configuration
* - B&S coeffs are written to same coeff RAM as WB scaler coeffs
* - coeff RAM toggle is in EASF programming
* - if we are only programming B&S coeffs, then need to reprogram
* WB scaler coeffs and toggle coeff RAM together
*/
//if (dpp->base.ctx->dc->config.prefer_easf)
dpp401_dscl_program_isharp(dpp_base, scl_data, program_isharp_1dlut, &bs_coeffs_updated);
dpp401_dscl_set_scl_filter(dpp401, scl_data, ycbcr, bs_coeffs_updated);
/* Edge adaptive scaler function configuration */
if (dpp->base.ctx->dc->config.prefer_easf)
dpp401_dscl_program_easf(dpp_base, scl_data);
PERF_TRACE();
}
/**
* dpp60_dscl_program_upsp - Manually program UPSP registers
*
* @dpp_base: High level DPP struct
* @dscl_prog_data: dscl_prog_data info
*/
void dpp60_dscl_program_upsp(struct dpp *dpp_base,
const struct dscl_prog_data *dscl_prog_data)
{
struct dcn60_dpp *dpp = TO_DCN60_DPP(dpp_base);
REG_SET_8(UPSP_MODE, 0,
UPSP_MODE, dscl_prog_data->upsp_mode,
UPSP_V_NUM_TAPS, dscl_prog_data->upsp_v_num_taps,
UPSP_V_INIT_INT, dscl_prog_data->upsp_v_init_int,
UPSP_V_INIT_FRAC, dscl_prog_data->upsp_v_init_frac,
UPSP_H_NUM_TAPS, dscl_prog_data->upsp_h_num_taps,
UPSP_H_INIT_INT, dscl_prog_data->upsp_h_init_int,
UPSP_H_INIT_FRAC, dscl_prog_data->upsp_h_init_frac,
UPSP_BOUNDARY_MODE, dscl_prog_data->upsp_boundary_mode);
REG_SET_4(UPSP_V_COEF_P0, 0,
UPSP_V_COEF_TAP0_P0, dscl_prog_data->upsp_v_coef_tap0_p0,
UPSP_V_COEF_TAP1_P0, dscl_prog_data->upsp_v_coef_tap1_p0,
UPSP_V_COEF_TAP2_P0, dscl_prog_data->upsp_v_coef_tap2_p0,
UPSP_V_COEF_TAP3_P0, dscl_prog_data->upsp_v_coef_tap3_p0);
REG_SET_4(UPSP_V_COEF_P1, 0,
UPSP_V_COEF_TAP0_P1, dscl_prog_data->upsp_v_coef_tap0_p1,
UPSP_V_COEF_TAP1_P1, dscl_prog_data->upsp_v_coef_tap1_p1,
UPSP_V_COEF_TAP2_P1, dscl_prog_data->upsp_v_coef_tap2_p1,
UPSP_V_COEF_TAP3_P1, dscl_prog_data->upsp_v_coef_tap3_p1);
REG_SET_4(UPSP_H_COEF_P0, 0,
UPSP_H_COEF_TAP0_P0, dscl_prog_data->upsp_h_coef_tap0_p0,
UPSP_H_COEF_TAP1_P0, dscl_prog_data->upsp_h_coef_tap1_p0,
UPSP_H_COEF_TAP2_P0, dscl_prog_data->upsp_h_coef_tap2_p0,
UPSP_H_COEF_TAP3_P0, dscl_prog_data->upsp_h_coef_tap3_p0);
REG_SET_4(UPSP_H_COEF_P1, 0,
UPSP_H_COEF_TAP0_P1, dscl_prog_data->upsp_h_coef_tap0_p1,
UPSP_H_COEF_TAP1_P1, dscl_prog_data->upsp_h_coef_tap1_p1,
UPSP_H_COEF_TAP2_P1, dscl_prog_data->upsp_h_coef_tap2_p1,
UPSP_H_COEF_TAP3_P1, dscl_prog_data->upsp_h_coef_tap3_p1);
REG_SET_2(UPSP_CLAMP, 0,
UPSP_CLAMP_MAX, dscl_prog_data->upsp_clamp_max,
UPSP_CLAMP_MIN, dscl_prog_data->upsp_clamp_min);
}

View File

@@ -0,0 +1,447 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include <drm/display/drm_dsc_helper.h>
#include "reg_helper.h"
#include "dcn60_dsc.h"
#include "dsc/dscc_types.h"
#include "dsc/rc_calc.h"
static const struct dsc_funcs dcn60_dsc_funcs = {
.dsc_read_state = dsc401_read_state,
.dsc_validate_stream = dsc401_validate_stream,
.dsc_set_config = dsc60_set_config,
.dsc_get_packed_pps = dsc2_get_packed_pps,
.dsc_enable = dsc401_enable,
.dsc_disable = dsc401_disable,
.dsc_disconnect = dsc401_disconnect,
.dsc_wait_disconnect_pending_clear = dsc401_wait_disconnect_pending_clear,
.dsc_get_single_enc_caps = dsc60_get_single_enc_caps,
.dsc_read_reg_state = dsc2_read_reg_state,
.set_fgcg = dsc60_set_fgcg,
};
/* Macro definitios for REG_SET macros*/
#define CTX \
dsc60->base.ctx
#define REG(reg)\
dsc60->dsc_regs->reg
#undef FN
#define FN(reg_name, field_name) \
dsc60->dsc_shift->field_name, dsc60->dsc_mask->field_name
#define DC_LOGGER \
dsc->ctx->logger
void dsc60_set_fgcg(struct display_stream_compressor *dsc, bool enable)
{
struct dcn60_dsc *dsc60 = TO_DCN60_DSC(dsc);
REG_UPDATE(DSC_TOP_CONTROL, DSC_FGCG_REP_DIS, !enable);
}
/* API functions (external or via structure->function_pointer) */
void dsc60_construct(struct dcn60_dsc *dsc,
struct dc_context *ctx,
int inst,
const struct dcn401_dsc_registers *dsc_regs,
const struct dcn60_dsc_shift *dsc_shift,
const struct dcn60_dsc_mask *dsc_mask)
{
dsc->base.ctx = ctx;
dsc->base.inst = inst;
dsc->base.funcs = &dcn60_dsc_funcs;
dsc->dsc_regs = dsc_regs;
dsc->dsc_shift = dsc_shift;
dsc->dsc_mask = dsc_mask;
dsc->max_image_width = 5184;
}
static void dsc60_init_reg_values(struct dsc60_reg_values *reg_vals)
{
int i;
memset(reg_vals, 0, sizeof(struct dsc60_reg_values));
/* Non-PPS values */
reg_vals->dsc_clock_enable = 1;
reg_vals->dsc_clock_gating_disable = 0;
reg_vals->underflow_recovery_en = 0;
reg_vals->underflow_occurred_int_en = 0;
reg_vals->underflow_occurred_status = 0;
reg_vals->ich_reset_at_eol = 0;
reg_vals->alternate_ich_encoding_en = 0;
reg_vals->rc_buffer_model_size = 0;
/*reg_vals->disable_ich = 0;*/
reg_vals->dsc_dbg_en = 0;
for (i = 0; i < 8; i++)
reg_vals->rc_buffer_model_overflow_int_en[i] = 0;
/* PPS values */
reg_vals->pps.dsc_version_minor = 2;
reg_vals->pps.dsc_version_major = 1;
reg_vals->pps.line_buf_depth = 9;
reg_vals->pps.bits_per_component = 8;
reg_vals->pps.block_pred_enable = 1;
reg_vals->pps.slice_chunk_size = 0;
reg_vals->pps.pic_width = 0;
reg_vals->pps.pic_height = 0;
reg_vals->pps.slice_width = 0;
reg_vals->pps.slice_height = 0;
reg_vals->pps.initial_xmit_delay = 170;
reg_vals->pps.initial_dec_delay = 0;
reg_vals->pps.initial_scale_value = 0;
reg_vals->pps.scale_increment_interval = 0;
reg_vals->pps.scale_decrement_interval = 0;
reg_vals->pps.nfl_bpg_offset = 0;
reg_vals->pps.slice_bpg_offset = 0;
reg_vals->pps.nsl_bpg_offset = 0;
reg_vals->pps.initial_offset = 6144;
reg_vals->pps.final_offset = 0;
reg_vals->pps.flatness_min_qp = 3;
reg_vals->pps.flatness_max_qp = 12;
reg_vals->pps.rc_model_size = 8192;
reg_vals->pps.rc_edge_factor = 6;
reg_vals->pps.rc_quant_incr_limit0 = 11;
reg_vals->pps.rc_quant_incr_limit1 = 11;
reg_vals->pps.rc_tgt_offset_low = 3;
reg_vals->pps.rc_tgt_offset_high = 3;
}
/*Updates dsc_reg_values::reg_vals::xxx fields based on the values from computed params.
* This is required because dscc_compute_dsc_parameters returns a modified PPS, which in turn
* affects non - PPS register values.
*/
static void dsc60_update_from_dsc_parameters(struct dsc60_reg_values *reg_vals, const struct dsc_parameters *dsc_params)
{
int i;
reg_vals->pps = dsc_params->pps;
// pps_computed will have the "expanded" values; need to shift them to make them fit for regs.
for (i = 0; i < NUM_BUF_RANGES - 1; i++)
reg_vals->pps.rc_buf_thresh[i] = reg_vals->pps.rc_buf_thresh[i] >> 6;
reg_vals->rc_buffer_model_size = dsc_params->rc_buffer_model_size;
}
static bool dsc60_prepare_config(const struct dsc_config *dsc_cfg, struct dsc60_reg_values *dsc_reg_vals,
struct dsc_optc_config *dsc_optc_cfg)
{
struct dsc_parameters dsc_params;
struct rc_params rc;
/* Validate input parameters */
ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_h);
ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_v);
ASSERT(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2);
ASSERT(dsc_cfg->pic_width);
ASSERT(dsc_cfg->pic_height);
ASSERT((dsc_cfg->dc_dsc_cfg.version_minor == 1 &&
(8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13)) ||
(dsc_cfg->dc_dsc_cfg.version_minor == 2 &&
((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) ||
dsc_cfg->dc_dsc_cfg.linebuf_depth == 0)));
ASSERT(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff); // 6.0 <= bits_per_pixel <= 63.9375
if (!dsc_cfg->dc_dsc_cfg.num_slices_v || !dsc_cfg->dc_dsc_cfg.num_slices_h ||
!(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2) ||
!dsc_cfg->pic_width || !dsc_cfg->pic_height ||
!((dsc_cfg->dc_dsc_cfg.version_minor == 1 && // v1.1 line buffer depth range:
8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13) ||
(dsc_cfg->dc_dsc_cfg.version_minor == 2 && // v1.2 line buffer depth range:
((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) ||
dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))) ||
!(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff)) {
dm_output_to_console("%s: Invalid parameters\n", __func__);
return false;
}
dsc60_init_reg_values(dsc_reg_vals);
/* Copy input config */
dsc_reg_vals->pixel_format = dsc_dc_pixel_encoding_to_dsc_pixel_format(dsc_cfg->pixel_encoding, dsc_cfg->dc_dsc_cfg.ycbcr422_simple);
dsc_reg_vals->num_slices_h = dsc_cfg->dc_dsc_cfg.num_slices_h;
dsc_reg_vals->num_slices_v = dsc_cfg->dc_dsc_cfg.num_slices_v;
dsc_reg_vals->pps.dsc_version_minor = (u8)dsc_cfg->dc_dsc_cfg.version_minor;
dsc_reg_vals->pps.pic_width = (u16)dsc_cfg->pic_width;
dsc_reg_vals->pps.pic_height = (u16)dsc_cfg->pic_height;
dsc_reg_vals->pps.bits_per_component = dsc_dc_color_depth_to_dsc_bits_per_comp(dsc_cfg->color_depth);
dsc_reg_vals->pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable;
dsc_reg_vals->pps.line_buf_depth = (u8)dsc_cfg->dc_dsc_cfg.linebuf_depth;
dsc_reg_vals->alternate_ich_encoding_en = dsc_reg_vals->pps.dsc_version_minor == 1 ? 0 : 1;
dsc_reg_vals->ich_reset_at_eol = (dsc_cfg->is_odm || dsc_reg_vals->num_slices_h > 1) ? 0xF : 0;
// TODO: in addition to validating slice height (pic height must be divisible by slice height),
// see what happens when the same condition doesn't apply for slice_width/pic_width.
dsc_reg_vals->pps.slice_width = (u16)(dsc_cfg->pic_width / dsc_cfg->dc_dsc_cfg.num_slices_h);
dsc_reg_vals->pps.slice_height = (u16)(dsc_cfg->pic_height / dsc_cfg->dc_dsc_cfg.num_slices_v);
ASSERT(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height);
if (!(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height)) {
dm_output_to_console("%s: pix height %d not divisible by num_slices_v %d\n\n", __func__, dsc_cfg->pic_height, dsc_cfg->dc_dsc_cfg.num_slices_v);
return false;
}
dsc_reg_vals->bpp_x32 = dsc_cfg->dc_dsc_cfg.bits_per_pixel << 1;
if (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422)
dsc_reg_vals->pps.bits_per_pixel = (u16)dsc_reg_vals->bpp_x32;
else
dsc_reg_vals->pps.bits_per_pixel = (u16)(dsc_reg_vals->bpp_x32 >> 1);
dsc_reg_vals->pps.convert_rgb = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB ? 1 : 0;
dsc_reg_vals->pps.native_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422);
dsc_reg_vals->pps.native_420 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420);
dsc_reg_vals->pps.simple_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422);
calc_rc_params(&rc, &dsc_reg_vals->pps);
if (dsc_cfg->dc_dsc_cfg.rc_params_ovrd)
dsc_override_rc_params(&rc, dsc_cfg->dc_dsc_cfg.rc_params_ovrd);
if (dscc_compute_dsc_parameters(&dsc_reg_vals->pps, &rc, &dsc_params)) {
dm_output_to_console("%s: DSC config failed\n", __func__);
return false;
}
dsc60_update_from_dsc_parameters(dsc_reg_vals, &dsc_params);
dsc_optc_cfg->bytes_per_pixel = dsc_params.bytes_per_pixel;
dsc_optc_cfg->slice_width = dsc_reg_vals->pps.slice_width;
dsc_optc_cfg->is_pixel_format_444 = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB ||
dsc_reg_vals->pixel_format == DSC_PIXFMT_YCBCR444 ||
dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422;
return true;
}
static void dsc60_write_to_registers(struct display_stream_compressor *dsc, const struct dsc60_reg_values *reg_vals)
{
uint32_t temp_int;
struct dcn60_dsc *dsc60 = TO_DCN60_DSC(dsc);
REG_SET(DSC_DEBUG_CONTROL, 0,
DSC_DBG_EN, reg_vals->dsc_dbg_en);
// dscc registers
if (dsc60->dsc_mask->ICH_RESET_AT_END_OF_LINE == 0) {
REG_SET_3(DSCC_CONFIG0, 0,
NUMBER_OF_SLICES_PER_LINE, reg_vals->num_slices_h - 1,
ALTERNATE_ICH_ENCODING_EN, reg_vals->alternate_ich_encoding_en,
NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, reg_vals->num_slices_v - 1);
} else {
REG_SET_4(DSCC_CONFIG0, 0, ICH_RESET_AT_END_OF_LINE,
reg_vals->ich_reset_at_eol, NUMBER_OF_SLICES_PER_LINE,
reg_vals->num_slices_h - 1, ALTERNATE_ICH_ENCODING_EN,
reg_vals->alternate_ich_encoding_en, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION,
reg_vals->num_slices_v - 1);
}
REG_SET(DSCC_CONFIG1, 0,
DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size);
REG_SET_8(DSCC_INTERRUPT_CONTROL0, 0,
DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN0, reg_vals->rc_buffer_model_overflow_int_en[0],
DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN1, reg_vals->rc_buffer_model_overflow_int_en[1],
DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN2, reg_vals->rc_buffer_model_overflow_int_en[2],
DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN3, reg_vals->rc_buffer_model_overflow_int_en[3],
DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN4, reg_vals->rc_buffer_model_overflow_int_en[4],
DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN5, reg_vals->rc_buffer_model_overflow_int_en[5],
DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN6, reg_vals->rc_buffer_model_overflow_int_en[6],
DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN7, reg_vals->rc_buffer_model_overflow_int_en[7]);
REG_SET_3(DSCC_PPS_CONFIG0, 0,
DSC_VERSION_MINOR, reg_vals->pps.dsc_version_minor,
LINEBUF_DEPTH, reg_vals->pps.line_buf_depth,
DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component);
if (reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422)
temp_int = reg_vals->bpp_x32;
else
temp_int = reg_vals->bpp_x32 >> 1;
REG_SET_7(DSCC_PPS_CONFIG1, 0,
BITS_PER_PIXEL, temp_int,
SIMPLE_422, reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422,
CONVERT_RGB, reg_vals->pixel_format == DSC_PIXFMT_RGB,
BLOCK_PRED_ENABLE, reg_vals->pps.block_pred_enable,
NATIVE_422, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422,
NATIVE_420, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420,
CHUNK_SIZE, reg_vals->pps.slice_chunk_size);
REG_SET_2(DSCC_PPS_CONFIG2, 0,
PIC_WIDTH, reg_vals->pps.pic_width,
PIC_HEIGHT, reg_vals->pps.pic_height);
REG_SET_2(DSCC_PPS_CONFIG3, 0,
SLICE_WIDTH, reg_vals->pps.slice_width,
SLICE_HEIGHT, reg_vals->pps.slice_height);
REG_SET(DSCC_PPS_CONFIG4, 0,
INITIAL_XMIT_DELAY, reg_vals->pps.initial_xmit_delay);
REG_SET_2(DSCC_PPS_CONFIG5, 0,
INITIAL_SCALE_VALUE, reg_vals->pps.initial_scale_value,
SCALE_INCREMENT_INTERVAL, reg_vals->pps.scale_increment_interval);
REG_SET_3(DSCC_PPS_CONFIG6, 0,
SCALE_DECREMENT_INTERVAL, reg_vals->pps.scale_decrement_interval,
FIRST_LINE_BPG_OFFSET, reg_vals->pps.first_line_bpg_offset,
SECOND_LINE_BPG_OFFSET, reg_vals->pps.second_line_bpg_offset);
REG_SET_2(DSCC_PPS_CONFIG7, 0,
NFL_BPG_OFFSET, reg_vals->pps.nfl_bpg_offset,
SLICE_BPG_OFFSET, reg_vals->pps.slice_bpg_offset);
REG_SET_2(DSCC_PPS_CONFIG8, 0,
NSL_BPG_OFFSET, reg_vals->pps.nsl_bpg_offset,
SECOND_LINE_OFFSET_ADJ, reg_vals->pps.second_line_offset_adj);
REG_SET_2(DSCC_PPS_CONFIG9, 0,
INITIAL_OFFSET, reg_vals->pps.initial_offset,
FINAL_OFFSET, reg_vals->pps.final_offset);
REG_SET_3(DSCC_PPS_CONFIG10, 0,
FLATNESS_MIN_QP, reg_vals->pps.flatness_min_qp,
FLATNESS_MAX_QP, reg_vals->pps.flatness_max_qp,
RC_MODEL_SIZE, reg_vals->pps.rc_model_size);
REG_SET_5(DSCC_PPS_CONFIG11, 0,
RC_EDGE_FACTOR, reg_vals->pps.rc_edge_factor,
RC_QUANT_INCR_LIMIT0, reg_vals->pps.rc_quant_incr_limit0,
RC_QUANT_INCR_LIMIT1, reg_vals->pps.rc_quant_incr_limit1,
RC_TGT_OFFSET_LO, reg_vals->pps.rc_tgt_offset_low,
RC_TGT_OFFSET_HI, reg_vals->pps.rc_tgt_offset_high);
REG_SET_4(DSCC_PPS_CONFIG12, 0,
RC_BUF_THRESH0, reg_vals->pps.rc_buf_thresh[0],
RC_BUF_THRESH1, reg_vals->pps.rc_buf_thresh[1],
RC_BUF_THRESH2, reg_vals->pps.rc_buf_thresh[2],
RC_BUF_THRESH3, reg_vals->pps.rc_buf_thresh[3]);
REG_SET_4(DSCC_PPS_CONFIG13, 0,
RC_BUF_THRESH4, reg_vals->pps.rc_buf_thresh[4],
RC_BUF_THRESH5, reg_vals->pps.rc_buf_thresh[5],
RC_BUF_THRESH6, reg_vals->pps.rc_buf_thresh[6],
RC_BUF_THRESH7, reg_vals->pps.rc_buf_thresh[7]);
REG_SET_4(DSCC_PPS_CONFIG14, 0,
RC_BUF_THRESH8, reg_vals->pps.rc_buf_thresh[8],
RC_BUF_THRESH9, reg_vals->pps.rc_buf_thresh[9],
RC_BUF_THRESH10, reg_vals->pps.rc_buf_thresh[10],
RC_BUF_THRESH11, reg_vals->pps.rc_buf_thresh[11]);
REG_SET_5(DSCC_PPS_CONFIG15, 0,
RC_BUF_THRESH12, reg_vals->pps.rc_buf_thresh[12],
RC_BUF_THRESH13, reg_vals->pps.rc_buf_thresh[13],
RANGE_MIN_QP0, reg_vals->pps.rc_range_params[0].range_min_qp,
RANGE_MAX_QP0, reg_vals->pps.rc_range_params[0].range_max_qp,
RANGE_BPG_OFFSET0, reg_vals->pps.rc_range_params[0].range_bpg_offset);
REG_SET_6(DSCC_PPS_CONFIG16, 0,
RANGE_MIN_QP1, reg_vals->pps.rc_range_params[1].range_min_qp,
RANGE_MAX_QP1, reg_vals->pps.rc_range_params[1].range_max_qp,
RANGE_BPG_OFFSET1, reg_vals->pps.rc_range_params[1].range_bpg_offset,
RANGE_MIN_QP2, reg_vals->pps.rc_range_params[2].range_min_qp,
RANGE_MAX_QP2, reg_vals->pps.rc_range_params[2].range_max_qp,
RANGE_BPG_OFFSET2, reg_vals->pps.rc_range_params[2].range_bpg_offset);
REG_SET_6(DSCC_PPS_CONFIG17, 0,
RANGE_MIN_QP3, reg_vals->pps.rc_range_params[3].range_min_qp,
RANGE_MAX_QP3, reg_vals->pps.rc_range_params[3].range_max_qp,
RANGE_BPG_OFFSET3, reg_vals->pps.rc_range_params[3].range_bpg_offset,
RANGE_MIN_QP4, reg_vals->pps.rc_range_params[4].range_min_qp,
RANGE_MAX_QP4, reg_vals->pps.rc_range_params[4].range_max_qp,
RANGE_BPG_OFFSET4, reg_vals->pps.rc_range_params[4].range_bpg_offset);
REG_SET_6(DSCC_PPS_CONFIG18, 0,
RANGE_MIN_QP5, reg_vals->pps.rc_range_params[5].range_min_qp,
RANGE_MAX_QP5, reg_vals->pps.rc_range_params[5].range_max_qp,
RANGE_BPG_OFFSET5, reg_vals->pps.rc_range_params[5].range_bpg_offset,
RANGE_MIN_QP6, reg_vals->pps.rc_range_params[6].range_min_qp,
RANGE_MAX_QP6, reg_vals->pps.rc_range_params[6].range_max_qp,
RANGE_BPG_OFFSET6, reg_vals->pps.rc_range_params[6].range_bpg_offset);
REG_SET_6(DSCC_PPS_CONFIG19, 0,
RANGE_MIN_QP7, reg_vals->pps.rc_range_params[7].range_min_qp,
RANGE_MAX_QP7, reg_vals->pps.rc_range_params[7].range_max_qp,
RANGE_BPG_OFFSET7, reg_vals->pps.rc_range_params[7].range_bpg_offset,
RANGE_MIN_QP8, reg_vals->pps.rc_range_params[8].range_min_qp,
RANGE_MAX_QP8, reg_vals->pps.rc_range_params[8].range_max_qp,
RANGE_BPG_OFFSET8, reg_vals->pps.rc_range_params[8].range_bpg_offset);
REG_SET_6(DSCC_PPS_CONFIG20, 0,
RANGE_MIN_QP9, reg_vals->pps.rc_range_params[9].range_min_qp,
RANGE_MAX_QP9, reg_vals->pps.rc_range_params[9].range_max_qp,
RANGE_BPG_OFFSET9, reg_vals->pps.rc_range_params[9].range_bpg_offset,
RANGE_MIN_QP10, reg_vals->pps.rc_range_params[10].range_min_qp,
RANGE_MAX_QP10, reg_vals->pps.rc_range_params[10].range_max_qp,
RANGE_BPG_OFFSET10, reg_vals->pps.rc_range_params[10].range_bpg_offset);
REG_SET_6(DSCC_PPS_CONFIG21, 0,
RANGE_MIN_QP11, reg_vals->pps.rc_range_params[11].range_min_qp,
RANGE_MAX_QP11, reg_vals->pps.rc_range_params[11].range_max_qp,
RANGE_BPG_OFFSET11, reg_vals->pps.rc_range_params[11].range_bpg_offset,
RANGE_MIN_QP12, reg_vals->pps.rc_range_params[12].range_min_qp,
RANGE_MAX_QP12, reg_vals->pps.rc_range_params[12].range_max_qp,
RANGE_BPG_OFFSET12, reg_vals->pps.rc_range_params[12].range_bpg_offset);
REG_SET_6(DSCC_PPS_CONFIG22, 0,
RANGE_MIN_QP13, reg_vals->pps.rc_range_params[13].range_min_qp,
RANGE_MAX_QP13, reg_vals->pps.rc_range_params[13].range_max_qp,
RANGE_BPG_OFFSET13, reg_vals->pps.rc_range_params[13].range_bpg_offset,
RANGE_MIN_QP14, reg_vals->pps.rc_range_params[14].range_min_qp,
RANGE_MAX_QP14, reg_vals->pps.rc_range_params[14].range_max_qp,
RANGE_BPG_OFFSET14, reg_vals->pps.rc_range_params[14].range_bpg_offset);
}
void dsc60_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg,
struct dsc_optc_config *dsc_optc_cfg)
{
bool is_config_ok;
struct dcn60_dsc *dsc60 = TO_DCN60_DSC(dsc);
DC_LOG_DSC("Setting DSC Config at DSC inst %d", dsc->inst);
dsc_config_log(dsc, dsc_cfg);
is_config_ok = dsc60_prepare_config(dsc_cfg, &dsc60->reg_vals, dsc_optc_cfg);
ASSERT(is_config_ok);
DC_LOG_DSC("programming DSC Picture Parameter Set (PPS):");
dsc_log_pps(dsc, &dsc60->reg_vals.pps);
dsc60_write_to_registers(dsc, &dsc60->reg_vals);
}
void dsc60_get_single_enc_caps(struct dsc_enc_caps *dsc_enc_caps, unsigned int max_dscclk_khz)
{
dsc_enc_caps->dsc_version = 0x21; /* v1.2 - DP spec defined it in reverse order and we kept it */
dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 1;
dsc_enc_caps->slice_caps.bits.NUM_SLICES_2 = 1;
dsc_enc_caps->slice_caps.bits.NUM_SLICES_3 = 1;
dsc_enc_caps->slice_caps.bits.NUM_SLICES_4 = 1;
dsc_enc_caps->slice_caps.bits.NUM_SLICES_8 = 1;
dsc_enc_caps->lb_bit_depth = 13;
dsc_enc_caps->is_block_pred_supported = true;
dsc_enc_caps->color_formats.bits.RGB = 1;
dsc_enc_caps->color_formats.bits.YCBCR_444 = 1;
dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1;
dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 1;
dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1;
dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1;
dsc_enc_caps->color_depth.bits.COLOR_DEPTH_10_BPC = 1;
dsc_enc_caps->color_depth.bits.COLOR_DEPTH_12_BPC = 1;
dsc_enc_caps->max_total_throughput_mps = max_dscclk_khz * 3 / 1000;
dsc_enc_caps->max_slice_width = 5760; /* (including 64 overlap pixels for eDP MSO mode) */
dsc_enc_caps->bpp_increment_div = 16; /* 1/16th of a bit */
}

View File

@@ -0,0 +1,248 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DCN60_DSC_H__
#define __DCN60_DSC_H__
#include "dsc.h"
#include "dsc/dscc_types.h"
#include "dcn20/dcn20_dsc.h"
#include "dcn401/dcn401_dsc.h"
#include <drm/display/drm_dsc.h>
#define TO_DCN60_DSC(dsc)\
container_of(dsc, struct dcn60_dsc, base)
#define DSC_REG_LIST_SH_MASK_DCN60(mask_sh)\
DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_CLOCK_EN, mask_sh), \
DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DISPCLK_R_GATE_DIS, mask_sh), \
DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DSCCLK_R_GATE_DIS, mask_sh), \
DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_FGCG_REP_DIS, mask_sh), \
DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_DBG_EN, mask_sh), \
DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_TEST_CLOCK_MUX_SEL, mask_sh), \
DSC_SF(DSCC0_DSCC_CONFIG0, ICH_RESET_AT_END_OF_LINE, mask_sh), \
DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_PER_LINE, mask_sh), \
DSC_SF(DSCC0_DSCC_CONFIG0, ALTERNATE_ICH_ENCODING_EN, mask_sh), \
DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, mask_sh), \
DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, mask_sh), \
DSC_SF(DSCC0_DSCC_STATUS, DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_CLEAR0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_CLEAR1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_CLEAR2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_CLEAR3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN4, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN5, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN6, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL0, DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN7, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS1, DSCC_OUTPUT_BUFFER_OVERFLOW_OCCURRED0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS1, DSCC_OUTPUT_BUFFER_OVERFLOW_OCCURRED1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS1, DSCC_OUTPUT_BUFFER_OVERFLOW_OCCURRED2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS1, DSCC_OUTPUT_BUFFER_OVERFLOW_OCCURRED3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS1, DSCC_OUTPUT_BUFFER_UNDERFLOW_OCCURRED0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS1, DSCC_OUTPUT_BUFFER_UNDERFLOW_OCCURRED1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS1, DSCC_OUTPUT_BUFFER_UNDERFLOW_OCCURRED2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS1, DSCC_OUTPUT_BUFFER_UNDERFLOW_OCCURRED3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_STATUS2, DSCC_END_OF_FRAME_NOT_REACHED_OCCURRED, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR1, DSCC_OUTPUT_BUFFER_OVERFLOW_CLEAR0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR1, DSCC_OUTPUT_BUFFER_OVERFLOW_CLEAR1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR1, DSCC_OUTPUT_BUFFER_OVERFLOW_CLEAR2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR1, DSCC_OUTPUT_BUFFER_OVERFLOW_CLEAR3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR1, DSCC_OUTPUT_BUFFER_UNDERFLOW_CLEAR0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR1, DSCC_OUTPUT_BUFFER_UNDERFLOW_CLEAR1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR1, DSCC_OUTPUT_BUFFER_UNDERFLOW_CLEAR2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR1, DSCC_OUTPUT_BUFFER_UNDERFLOW_CLEAR3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CLEAR2, DSCC_END_OF_FRAME_NOT_REACHED_CLEAR, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL1, DSCC_OUTPUT_BUFFER_OVERFLOW_OCCURRED_INT_EN0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL1, DSCC_OUTPUT_BUFFER_OVERFLOW_OCCURRED_INT_EN1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL1, DSCC_OUTPUT_BUFFER_OVERFLOW_OCCURRED_INT_EN2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL1, DSCC_OUTPUT_BUFFER_OVERFLOW_OCCURRED_INT_EN3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL1, DSCC_OUTPUT_BUFFER_UNDERFLOW_OCCURRED_INT_EN0, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL1, DSCC_OUTPUT_BUFFER_UNDERFLOW_OCCURRED_INT_EN1, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL1, DSCC_OUTPUT_BUFFER_UNDERFLOW_OCCURRED_INT_EN2, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL1, DSCC_OUTPUT_BUFFER_UNDERFLOW_OCCURRED_INT_EN3, mask_sh), \
DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL2, DSCC_END_OF_FRAME_NOT_REACHED_OCCURRED_INT_EN, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MINOR, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MAJOR, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG0, PPS_IDENTIFIER, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG0, LINEBUF_DEPTH, mask_sh), \
DSC2_SF(DSCC0, DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BITS_PER_PIXEL, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG1, VBR_ENABLE, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG1, SIMPLE_422, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CONVERT_RGB, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BLOCK_PRED_ENABLE, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_422, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_420, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CHUNK_SIZE, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_WIDTH, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_HEIGHT, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_WIDTH, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_HEIGHT, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_XMIT_DELAY, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_DEC_DELAY, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG5, INITIAL_SCALE_VALUE, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG5, SCALE_INCREMENT_INTERVAL, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SCALE_DECREMENT_INTERVAL, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG6, FIRST_LINE_BPG_OFFSET, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SECOND_LINE_BPG_OFFSET, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG7, NFL_BPG_OFFSET, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG8, NSL_BPG_OFFSET, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG8, SECOND_LINE_OFFSET_ADJ, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG9, INITIAL_OFFSET, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG9, FINAL_OFFSET, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MIN_QP, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MAX_QP, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG10, RC_MODEL_SIZE, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_EDGE_FACTOR, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT0, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT1, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_LO, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_HI, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH0, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH1, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH2, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH3, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH4, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH5, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH6, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH7, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH8, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH9, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH10, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH11, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH12, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH13, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MIN_QP0, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MAX_QP0, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_BPG_OFFSET0, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP1, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP1, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET1, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP2, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP2, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET2, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP3, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP3, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET3, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP4, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP4, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET4, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP5, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP5, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET5, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP6, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP6, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET6, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP7, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP7, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET7, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP8, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP8, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET8, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP9, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP9, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET9, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP10, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP10, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET10, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP11, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP11, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET11, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP12, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP12, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET12, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP13, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP13, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET13, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP14, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP14, mask_sh), \
DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET14, mask_sh), \
DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL0, DSCC_DEFAULT_MEM_LOW_POWER_STATE, mask_sh), \
DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL0, DSCC_MEM_PWR_FORCE, mask_sh), \
DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL0, DSCC_MEM_PWR_DIS, mask_sh), \
DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL0, DSCC_MEM_PWR_STATE, mask_sh), \
DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL1, DSCC_DEFAULT_MEM_LOW_POWER_STATE, mask_sh), \
DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL1, DSCC_MEM_PWR_FORCE, mask_sh), \
DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL1, DSCC_MEM_PWR_DIS, mask_sh), \
DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL1, DSCC_MEM_PWR_STATE, mask_sh), \
DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS0_ROTATE, mask_sh), \
DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS1_ROTATE, mask_sh), \
DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS2_ROTATE, mask_sh), \
DSC_SF(DSCC0_DSCC_TEST_DEBUG_BUS_ROTATE, DSCC_TEST_DEBUG_BUS3_ROTATE, mask_sh), \
DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, mask_sh), \
DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_OPP_PIPE_SOURCE, mask_sh), \
DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN_STATUS, mask_sh)
#define DSC_FIELD_LIST_DCN60(type) \
struct { \
DSC_FIELD_LIST_DCN401(type); \
type DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN4; \
type DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN5; \
type DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN6; \
type DSCC_RATE_CONTROL_BUFFER_MODEL_OVERFLOW_OCCURRED_INT_EN7; \
}
struct dcn60_dsc_shift {
DSC_FIELD_LIST_DCN60(uint8_t);
};
struct dcn60_dsc_mask {
DSC_FIELD_LIST_DCN60(uint32_t);
};
struct dsc60_reg_values {
/* PPS registers */
struct drm_dsc_config pps;
/* Additional registers */
uint32_t dsc_clock_enable;
uint32_t dsc_clock_gating_disable;
uint32_t underflow_recovery_en;
uint32_t underflow_occurred_int_en;
uint32_t underflow_occurred_status;
enum dsc_pixel_format pixel_format;
uint32_t ich_reset_at_eol;
uint32_t alternate_ich_encoding_en;
uint32_t num_slices_h;
uint32_t num_slices_v;
uint32_t rc_buffer_model_size;
uint32_t disable_ich;
uint32_t bpp_x32;
uint32_t dsc_dbg_en;
uint32_t rc_buffer_model_overflow_int_en[8];
};
struct dcn60_dsc {
struct display_stream_compressor base;
const struct dcn401_dsc_registers *dsc_regs;
const struct dcn60_dsc_shift *dsc_shift;
const struct dcn60_dsc_mask *dsc_mask;
struct dsc60_reg_values reg_vals;
int max_image_width;
};
void dsc60_construct(struct dcn60_dsc *dsc,
struct dc_context *ctx,
int inst,
const struct dcn401_dsc_registers *dsc_regs,
const struct dcn60_dsc_shift *dsc_shift,
const struct dcn60_dsc_mask *dsc_mask);
void dsc60_set_fgcg(struct display_stream_compressor *dsc, bool enable);
void dsc60_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg,
struct dsc_optc_config *dsc_optc_cfg);
void dsc60_get_single_enc_caps(struct dsc_enc_caps *dsc_enc_caps, unsigned int max_dscclk_khz);
#endif

View File

@@ -0,0 +1,228 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dm_services.h"
#include "include/gpio_types.h"
#include "../hw_factory.h"
#include "../hw_gpio.h"
#include "../hw_ddc.h"
#include "../hw_hpd.h"
#include "../hw_generic.h"
#include "dcn/dcn_6_0_0_offset.h"
#include "dcn/dcn_6_0_0_sh_mask.h"
#include "dpcs/dpcs_6_0_0_offset.h"
#include "dpcs/dpcs_6_0_0_sh_mask.h"
#include "reg_helper.h"
#include "../hpd_regs.h"
#include "hw_factory_dcn60.h"
#define DCN_BASE__INST0_SEG2 0x000034C0
/* begin *********************
* macros to expend register list macro defined in HW object header file */
/* DCN */
#define block HPD
#define reg_num 0
#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
#define REG(reg_name)\
BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name
#define SF_HPD(reg_name, field_name, post_fix)\
.field_name = HPD0_ ## reg_name ## __ ## field_name ## post_fix
#define REGI(reg_name, block, id)\
BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## reg_name
#define SF(reg_name, field_name, post_fix)\
.field_name = reg_name ## __ ## field_name ## post_fix
/* macros to expend register list macro defined in HW object header file
* end *********************/
// DC_GPIO_HPD_* registers are gone.
#undef HPD_REG_LIST
#define HPD_REG_LIST(id) \
.int_status = REGI(DC_HPD_INT_STATUS, HPD, id),\
.toggle_filt_cntl = REGI(DC_HPD_TOGGLE_FILT_CNTL, HPD, id)
#define hpd_regs(id) \
{\
HPD_REG_LIST(id)\
}
static const struct hpd_registers hpd_regs[] = {
hpd_regs(0),
hpd_regs(1),
hpd_regs(2),
hpd_regs(3),
};
static const struct hpd_sh_mask hpd_shift = {
HPD_MASK_SH_LIST(__SHIFT)
};
static const struct hpd_sh_mask hpd_mask = {
HPD_MASK_SH_LIST(_MASK)
};
#include "../ddc_regs.h"
/* set field name */
#define SF_DDC(reg_name, field_name, post_fix)\
.field_name = reg_name ## __ ## field_name ## post_fix
#define DDC_REG_LIST_DCN6(id)\
.ddc_setup = REG(DC_I2C_DDC ## id ## _SETUP),\
.phy_aux_cntl = REG(PHY_AUX_CNTL),\
.dc_gpio_aux_ctrl_5 = REG(DC_GPIO_AUX_CTRL_5)
#define I3CPAD_REG_LIST_DCN6(id) \
.dc_i3cpad_control0 = REG(DC_I3C ## id ## _DC_I3CPAD_CONTROL0),\
.dc_i3cpad_control1 = REG(DC_I3C ## id ## _DC_I3CPAD_CONTROL1)
#define ddc_regs_dcn6(id, i3cpad_id) \
{\
DDC_REG_LIST_DCN6(id), \
I3CPAD_REG_LIST_DCN6(i3cpad_id) \
}
static const struct ddc_registers ddc_regs[] = {
ddc_regs_dcn6(1, 0),
ddc_regs_dcn6(2, 1)
};
#define DDC_MASK_SH_LIST_DCN6(mask_sh) \
{SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_ENABLE, mask_sh),\
SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_EDID_DETECT_ENABLE, mask_sh),\
SF_DDC(DC_I2C_DDC1_SETUP, DC_I2C_DDC1_EDID_DETECT_MODE, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_DDCCLK_MASK, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_DDCDATA_MASK, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_CLK_A, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_DATA_A, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_CLK_EN, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_DATA_EN, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_CLK_Y, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_DATA_Y, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL0, DC_I3CPAD_PD_EN, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL1, DC_I3CPAD_STR, mask_sh),\
SF_DDC(DC_I3C0_DC_I3CPAD_CONTROL1, DC_I3CPAD_RXSEL, mask_sh)}
static const struct ddc_sh_mask ddc_shift[] = {
DDC_MASK_SH_LIST_DCN6(__SHIFT),
DDC_MASK_SH_LIST_DCN6(__SHIFT)
};
static const struct ddc_sh_mask ddc_mask[] = {
DDC_MASK_SH_LIST_DCN6(_MASK),
DDC_MASK_SH_LIST_DCN6(_MASK)
};
#include "../generic_regs.h"
/* set field name */
#define SF_GENERIC(reg_name, field_name, post_fix)\
.field_name = 0
static const struct generic_registers generic_regs[] = {
{{ 0 }},
{{ 0 }},
};
static const struct generic_sh_mask generic_shift[] = {
{ 0 },
{ 0 },
};
static const struct generic_sh_mask generic_mask[] = {
{ 0 },
{ 0 },
};
static void dcn60_define_generic_registers(struct hw_gpio_pin *pin, uint32_t en)
{
struct hw_generic *generic = HW_GENERIC_FROM_BASE(pin);
generic->regs = &generic_regs[en];
generic->shifts = &generic_shift[en];
generic->masks = &generic_mask[en];
generic->base.regs = &generic_regs[en].gpio;
}
static void dcn60_define_ddc_registers(
struct hw_gpio_pin *pin,
uint32_t en)
{
struct hw_ddc *ddc = HW_DDC_FROM_BASE(pin);
switch (pin->id) {
case GPIO_ID_DDC_DATA:
case GPIO_ID_DDC_CLOCK:
ddc->regs = &ddc_regs[en];
ddc->base.regs = &ddc_regs[en].gpio;
break;
default:
ASSERT_CRITICAL(false);
return;
}
ddc->shifts = &ddc_shift[en];
ddc->masks = &ddc_mask[en];
}
static void dcn60_define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en)
{
struct hw_hpd *hpd = HW_HPD_FROM_BASE(pin);
hpd->regs = &hpd_regs[en];
hpd->shifts = &hpd_shift;
hpd->masks = &hpd_mask;
hpd->base.regs = &hpd_regs[en].gpio;
}
/* function table */
static const struct hw_factory_funcs funcs = {
.init_ddc_data = dal_hw_ddc_init_i3cpad,
.init_generic = dal_hw_generic_init,
.init_hpd = dal_hw_hpd_init,
.get_ddc_pin = dal_hw_ddc_get_pin,
.get_hpd_pin = dal_hw_hpd_get_pin,
.get_generic_pin = dal_hw_generic_get_pin,
.define_hpd_registers = dcn60_define_hpd_registers,
.define_ddc_registers = dcn60_define_ddc_registers,
.define_generic_registers = dcn60_define_generic_registers
};
/*
* dal_hw_factory_dcn60_init
*
* @brief
* Initialize HW factory function pointers and pin info
*
* @param
* struct hw_factory *factory - [out] struct of function pointers
*/
void dal_hw_factory_dcn60_init(struct hw_factory *factory)
{
factory->number_of_pins[GPIO_ID_DDC_DATA] = 2;
factory->number_of_pins[GPIO_ID_DDC_CLOCK] = 2;
factory->number_of_pins[GPIO_ID_GENERIC] = 2;
factory->number_of_pins[GPIO_ID_HPD] = 4;
factory->number_of_pins[GPIO_ID_GPIO_PAD] = 0;
factory->number_of_pins[GPIO_ID_VIP_PAD] = 0;
factory->number_of_pins[GPIO_ID_SYNC] = 0;
factory->number_of_pins[GPIO_ID_GSL] = 0;
factory->funcs = &funcs;
}

View File

@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DAL_HW_FACTORY_DCN60_H__
#define __DAL_HW_FACTORY_DCN60_H__
/* Initialize HW factory function pointers and pin info */
void dal_hw_factory_dcn60_init(struct hw_factory *factory);
#endif /* __DAL_HW_FACTORY_DCN60_H__ */

View File

@@ -0,0 +1,168 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "hw_translate_dcn60.h"
#include "dm_services.h"
#include "include/gpio_types.h"
#include "../hw_translate.h"
#include "dcn/dcn_6_0_0_offset.h"
#include "dcn/dcn_6_0_0_sh_mask.h"
#include "dpcs/dpcs_6_0_0_offset.h"
#include "dpcs/dpcs_6_0_0_sh_mask.h"
#define DCN_BASE__INST0_SEG2 0x000034C0
/* begin *********************
* macros to expend register list macro defined in HW object header file */
/* DCN */
#define block HPD
#define reg_num 0
#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
#define BASE(seg) BASE_INNER(seg)
#undef REG
#define REG(reg_name)\
BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name
#define SF_HPD(reg_name, field_name, post_fix)\
.field_name = reg_name ## __ ## field_name ## post_fix
/* macros to expend register list macro defined in HW object header file
* end *********************/
static bool dcn60_offset_to_id(
uint32_t offset,
uint32_t mask,
enum gpio_id *id,
uint32_t *en)
{
(void)mask;
switch (offset) {
/* HPD */
case REG(HPD0_DC_HPD_INT_STATUS):
*id = GPIO_ID_HPD;
*en = GPIO_HPD_1;
return true;
case REG(HPD1_DC_HPD_INT_STATUS):
*id = GPIO_ID_HPD;
*en = GPIO_HPD_2;
return true;
case REG(HPD2_DC_HPD_INT_STATUS):
*id = GPIO_ID_HPD;
*en = GPIO_HPD_3;
return true;
case REG(HPD3_DC_HPD_INT_STATUS):
*id = GPIO_ID_HPD;
*en = GPIO_HPD_4;
return true;
/* DDC */
/* we don't care about the GPIO_ID for DDC
* it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK
* directly in the create method
*/
case REG(DC_I3C0_DC_I3CPAD_CONTROL0):
*en = GPIO_DDC_LINE_DDC1;
return true;
case REG(DC_I3C1_DC_I3CPAD_CONTROL0):
*en = GPIO_DDC_LINE_DDC2;
return true;
/* UNEXPECTED */
default:
ASSERT_CRITICAL(false);
return false;
}
}
static bool dcn60_id_to_offset(
enum gpio_id id,
uint32_t en,
struct gpio_pin_info *info)
{
bool result = true;
switch (id) {
case GPIO_ID_DDC_DATA:
switch (en) {
case GPIO_DDC_LINE_DDC1:
info->offset = REG(DC_I3C0_DC_I3CPAD_CONTROL0);
break;
case GPIO_DDC_LINE_DDC2:
info->offset = REG(DC_I3C1_DC_I3CPAD_CONTROL0);
break;
default:
ASSERT_CRITICAL(false);
result = false;
}
break;
case GPIO_ID_DDC_CLOCK:
switch (en) {
case GPIO_DDC_LINE_DDC1:
info->offset = REG(DC_I3C0_DC_I3CPAD_CONTROL0);
break;
case GPIO_DDC_LINE_DDC2:
info->offset = REG(DC_I3C1_DC_I3CPAD_CONTROL0);
break;
default:
ASSERT_CRITICAL(false);
result = false;
}
break;
case GPIO_ID_HPD:
switch (en) {
case GPIO_HPD_1:
info->offset = REG(HPD0_DC_HPD_INT_STATUS);
info->mask = HPD0_DC_HPD_INT_STATUS__DC_HPD_SENSE_MASK;
break;
case GPIO_HPD_2:
info->offset = REG(HPD1_DC_HPD_INT_STATUS);
info->mask = HPD0_DC_HPD_INT_STATUS__DC_HPD_SENSE_MASK;
break;
case GPIO_HPD_3:
info->offset = REG(HPD2_DC_HPD_INT_STATUS);
info->mask = HPD0_DC_HPD_INT_STATUS__DC_HPD_SENSE_MASK;
break;
case GPIO_HPD_4:
info->offset = REG(HPD3_DC_HPD_INT_STATUS);
info->mask = HPD0_DC_HPD_INT_STATUS__DC_HPD_SENSE_MASK;
break;
default:
ASSERT_CRITICAL(false);
result = false;
}
break;
default:
ASSERT_CRITICAL(false);
result = false;
}
return result;
}
/* function table */
static const struct hw_translate_funcs funcs = {
.offset_to_id = dcn60_offset_to_id,
.id_to_offset = dcn60_id_to_offset,
};
/*
* dal_hw_translate_dcn60_init
*
* @brief
* Initialize Hw translate function pointers.
*
* @param
* struct hw_translate *tr - [out] struct of function pointers
*
*/
void dal_hw_translate_dcn60_init(struct hw_translate *tr)
{
tr->funcs = &funcs;
}

View File

@@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DAL_HW_TRANSLATE_DCN60_H__
#define __DAL_HW_TRANSLATE_DCN60_H__
struct hw_translate;
/* Initialize Hw translate function pointers */
void dal_hw_translate_dcn60_init(struct hw_translate *tr);
#endif /* __DAL_HW_TRANSLATE_DCN60_H__ */

View File

@@ -0,0 +1,114 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dc_bios_types.h"
#include "dcn30/dcn30_hpo_frl_link_encoder.h"
#include "dcn60_hpo_frl_link_encoder.h"
#include "reg_helper.h"
#include "dcn10/dcn10_link_encoder.h"
#define DC_LOGGER enc3->base.ctx->logger
#define REG(reg) (enc3->regs->reg)
#undef FN
#define FN(reg_name, field_name) enc3->hpo_le_shift->field_name, enc3->hpo_le_mask->field_name
#define CTX enc3->base.ctx
static enum bp_result link_transmitter_control(struct dcn10_link_encoder *enc10,
struct bp_transmitter_control *cntl)
{
struct dc_bios *bp = enc10->base.ctx->dc_bios;
return bp->funcs->transmitter_control(bp, cntl);
}
static void hpo_frl_link_enc60_enable_phy_output(struct hpo_frl_link_encoder *hpo_enc,
struct link_encoder *enc,
enum clock_source_id clock_source,
enum hdmi_frl_link_rate frl_link_rate)
{
struct dcn30_hpo_frl_link_encoder *enc3 = DCN30_HPO_FRL_LINK_ENC_FROM_HPO_FRL_LINK_ENC(hpo_enc);
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
struct bp_transmitter_control cntl = { 0 };
enum bp_result result;
/* Enable the PHY */
cntl.action = TRANSMITTER_CONTROL_ENABLE;
cntl.engine_id = enc->preferred_engine;
cntl.transmitter = enc10->base.transmitter;
cntl.pll_id = clock_source;
cntl.signal = SIGNAL_TYPE_HDMI_FRL;
cntl.hpd_sel = enc10->base.hpd_source;
switch (frl_link_rate) {
case HDMI_FRL_LINK_RATE_3GBPS:
cntl.pixel_clock = 166667;
break;
case HDMI_FRL_LINK_RATE_6GBPS:
case HDMI_FRL_LINK_RATE_6GBPS_4LANE:
cntl.pixel_clock = 333333;
break;
case HDMI_FRL_LINK_RATE_8GBPS:
cntl.pixel_clock = 444444;
break;
case HDMI_FRL_LINK_RATE_10GBPS:
cntl.pixel_clock = 555555;
break;
case HDMI_FRL_LINK_RATE_12GBPS:
cntl.pixel_clock = 666667;
break;
case HDMI_FRL_LINK_RATE_16GBPS:
cntl.pixel_clock = 888889;
break;
case HDMI_FRL_LINK_RATE_20GBPS:
default:
cntl.pixel_clock = 1111111;
break;
}
cntl.hpo_engine_id = enc3->base.inst + ENGINE_ID_HPO_0;
if (frl_link_rate <= HDMI_FRL_LINK_RATE_6GBPS)
cntl.lanes_number = 3;
else
cntl.lanes_number = 4;
result = link_transmitter_control(enc10, &cntl);
if (result != BP_RESULT_OK) {
DC_LOG_HDMI_FRL("%s: Failed to execute VBIOS command table!\n", __func__);
BREAK_TO_DEBUGGER();
}
}
static struct hpo_frl_link_encoder_funcs dcn60_hpo_frl_link_encoder_funcs = {
.setup_link_encoder = hpo_frl_link_enc3_setup_link_encoder,
.set_hdmi_training_pattern = hpo_frl_link_enc3_set_training_pattern,
.get_hdmi_training_pattern = hpo_frl_link_enc3_get_training_pattern,
.enable_frl_phy_output = hpo_frl_link_enc60_enable_phy_output,
.enable_output = hpo_frl_link_enc3_enable_output,
.disable_link_encoder = hpo_frl_link_enc3_disable,
.read_state = hpo_frl_link_enc3_read_state,
.destroy = hpo_frl_link_enc3_destroy,
.apply_vsdb_rcc_wa = hpo_frl_link_enc3_apply_vsdb_rcc_wa
};
void hpo_frl_link_encoder60_construct(struct dcn30_hpo_frl_link_encoder *enc3,
struct dc_context *ctx,
uint32_t inst,
const struct dcn30_hpo_frl_link_encoder_registers *hpo_le_regs,
const struct dcn30_hpo_frl_link_encoder_shift *hpo_le_shift,
const struct dcn30_hpo_frl_link_encoder_mask *hpo_le_mask)
{
enc3->base.ctx = ctx;
enc3->base.inst = inst;
enc3->base.funcs = &dcn60_hpo_frl_link_encoder_funcs;
enc3->regs = hpo_le_regs;
enc3->hpo_le_shift = hpo_le_shift;
enc3->hpo_le_mask = hpo_le_mask;
}

View File

@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DAL_DCN60_HPO_FRL_LINK_ENCODER_H__
#define __DAL_DCN60_HPO_FRL_LINK_ENCODER_H__
#include "link_encoder.h"
#include "dcn30/dcn30_hpo_frl_link_encoder.h"
void hpo_frl_link_encoder60_construct(struct dcn30_hpo_frl_link_encoder *enc3,
struct dc_context *ctx,
uint32_t inst,
const struct dcn30_hpo_frl_link_encoder_registers *hpo_le_regs,
const struct dcn30_hpo_frl_link_encoder_shift *hpo_le_shift,
const struct dcn30_hpo_frl_link_encoder_mask *hpo_le_mask);
#endif

View File

@@ -0,0 +1,358 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dc_bios_types.h"
#include "core_types.h"
#include "dcn60_hpo_frl_stream_encoder.h"
#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
#include "dcn401/dcn401_hpo_frl_stream_encoder.h"
#include "reg_helper.h"
#include "hw_shared.h"
#include "dcn_calc_math.h"
#include "dml/dcn30/dcn30_fpu.h"
#undef DC_LOGGER
#define DC_LOGGER \
enc401->base.ctx->logger
#define DTRACE(str, ...) {DC_LOG_HDMI_FRL(str, ##__VA_ARGS__); }
#define DEBUG_FRL_CAP_CHK 1
#define REG(reg)\
(enc401->regs->reg)
#undef FN
#define FN(reg_name, field_name) \
enc401->hpo_se_shift->field_name, enc401->hpo_se_mask->field_name
#define CTX \
enc401->base.ctx
#define VBI_LINE_0 0
/* setup stream encoder in hdmi mode */
/* Precondition: link is trained */
static void hpo_enc60_set_hdmi_stream_attribute(
struct hpo_frl_stream_encoder *enc,
struct dc_crtc_timing *crtc_timing,
struct frl_borrow_params *borrow_params,
int odm_combine_num_segments)
{
(void)odm_combine_num_segments;
uint32_t h_active;
uint32_t h_blank;
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
DC_LOG_DEBUG("Entering [%s]\n", __func__);
/* Configure pixel encoding */
switch (crtc_timing->pixel_encoding) {
case PIXEL_ENCODING_YCBCR422:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 1);
REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING_TYPE, 0,
FIFO_UNCOMPRESSED_PIXEL_FORMAT, 0);
break;
case PIXEL_ENCODING_YCBCR420:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 2);
REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING_TYPE, 0,
FIFO_UNCOMPRESSED_PIXEL_FORMAT, 1);
break;
default:
REG_UPDATE(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_PIXEL_ENCODING, 0);
REG_UPDATE_2(HDMI_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0,
FIFO_PIXEL_ENCODING_TYPE, 0,
FIFO_UNCOMPRESSED_PIXEL_FORMAT, 0);
break;
}
/* Configure color depth */
switch (crtc_timing->display_color_depth) {
case COLOR_DEPTH_888:
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 0,
HDMI_DEEP_COLOR_ENABLE, 0);
break;
case COLOR_DEPTH_101010:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 1,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
case COLOR_DEPTH_121212:
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 0);
} else {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 2,
HDMI_DEEP_COLOR_ENABLE, 1);
}
break;
default:
break;
}
/* When compression active, CD/PP/Phase field shall be zero in GCP */
if (crtc_timing->flags.DSC) {
REG_UPDATE_2(HDMI_TB_ENC_PIXEL_FORMAT,
HDMI_DEEP_COLOR_DEPTH, 0,
HDMI_DEEP_COLOR_ENABLE, 0);
}
/* Configure horizontal active and blank size */
h_active = crtc_timing->h_addressable + crtc_timing->h_border_left + crtc_timing->h_border_right;
h_blank = crtc_timing->h_total - h_active;
if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ||
crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
h_active /= 2;
h_blank /= 2;
}
REG_SET_2(HDMI_TB_ENC_H_ACTIVE_BLANK, 0,
HDMI_H_ACTIVE, h_active,
HDMI_H_BLANK, h_blank);
/* Configure borrow parameters */
REG_UPDATE(HDMI_TB_ENC_MODE,
HDMI_BORROW_MODE, borrow_params->borrow_mode);
REG_UPDATE(HDMI_TB_ENC_PACKET_CONTROL,
HDMI_MAX_PACKETS_PER_LINE, borrow_params->audio_packets_line);
REG_SET_2(HDMI_TB_ENC_HC_ACTIVE_BLANK, 0,
HDMI_HC_ACTIVE, borrow_params->hc_active_target,
HDMI_HC_BLANK, borrow_params->hc_blank_target);
/* Enable transmission of General Control packet on every frame */
REG_UPDATE_2(HDMI_TB_ENC_VBI_PACKET_CONTROL1,
HDMI_GC_CONT, 1,
HDMI_GC_SEND, 1);
/* Disable Audio Content Protection packet transmission */
/* TODO: review if this needs to be here */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_ACP_SEND, 0);
/* Enable Audio InfoFrame packet transmission. */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_SEND, 1);
/* update double-buffered AUDIO_INFO registers immediately */
// ASSERT(enc->afmt);
// enc->afmt->funcs->audio_info_immediate_update(enc->afmt);
/* Select line number on which to send Audio InfoFrame packets */
REG_UPDATE(HDMI_TB_ENC_VBI_PACKET_CONTROL1, HDMI_AUDIO_INFO_LINE,
VBI_LINE_0 + 2);
/* set HDMI GC AVMUTE */
REG_UPDATE(HDMI_TB_ENC_GC_CONTROL, HDMI_GC_AVMUTE, 0);
DC_LOG_DEBUG("Exiting [%s]\n", __func__);
}
static void hpo_enc60_audio_mute_control(
struct hpo_frl_stream_encoder *enc,
bool mute)
{
ASSERT (enc->apg);
if (mute)
enc->apg->funcs->disable_apg(enc->apg);
else
enc->apg->funcs->enable_apg(enc->apg);
}
//Covered both, rounding up or rounding down from FRL Link Rate /18.
static const struct frl_audio_clock_info frl_audio_clock_info_table[16] = {
{166666, 4224, 171875, 5292, 156250, 5760, 156250},
{166667, 4224, 171875, 5292, 156250, 5760, 156250},
{333333, 4032, 328125, 5292, 312500, 6048, 328125},
{333334, 4032, 328125, 5292, 312500, 6048, 328125},
{444444, 4032, 437500, 3969, 312500, 6048, 437500},
{444445, 4032, 437500, 3969, 312500, 6048, 437500},
{555555, 3456, 468750, 3969, 390625, 5184, 468750},
{555556, 3456, 468750, 3969, 390625, 5184, 468750},
{666666, 3072, 500000, 3969, 468750, 4752, 515625},
{666667, 3072, 500000, 3969, 468750, 4752, 515625},
{888888, 4032, 875000, 3969, 625000, 6048, 875000},
{888889, 4032, 875000, 3969, 625000, 6048, 875000},
{1111110, 3456, 937500, 3969, 781250, 5184, 937500},
{1111111, 3456, 937500, 3969, 781250, 5184, 937500},
{1333332, 3072, 1000000, 3969, 937500, 4752, 1031250},
{1333333, 3072, 1000000, 3969, 937500, 4752, 1031250}
};
static void get_audio_clock_info(
enum dc_color_depth color_depth,
uint32_t frl_character_clock_kHz,
struct frl_audio_clock_info *audio_clock_info)
{
(void)color_depth;
const struct frl_audio_clock_info *clock_info;
uint32_t index;
uint32_t audio_array_size;
clock_info = frl_audio_clock_info_table;
audio_array_size = ARRAY_SIZE(
frl_audio_clock_info_table);
if (clock_info != NULL) {
/* search for exact frl character clock in table */
for (index = 0; index < audio_array_size; index++) {
if (clock_info[index].frl_character_clock_kHz >
frl_character_clock_kHz)
break; /* not match */
else if (clock_info[index].frl_character_clock_kHz ==
frl_character_clock_kHz) {
/* match found */
*audio_clock_info = clock_info[index];
return;
}
}
}
/*Only 3, 6, 8, 10 and 12 Gbps are used for FRL Link rates with character
*clocks of 166.667, 333.333, 444.444, 555.555 and 666.667 MHz are used
*so entry should be found in above table if no bugs */
BREAK_TO_DEBUGGER();
}
static void hpo_enc60_setup_hdmi_audio(
struct hpo_frl_stream_encoder *enc,
const struct audio_crtc_info *crtc_info)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
struct frl_audio_clock_info audio_clock_info = {0};
DC_LOG_DEBUG("Entering [%s]\n", __func__);
/* TODO: HDMI_AUDIO_DELAY_EN bit only in DIG -- not in HPO? */
/* HDMI_AUDIO_PACKET_CONTROL */
//REG_UPDATE(HDMI_AUDIO_PACKET_CONTROL,
// HDMI_AUDIO_DELAY_EN, 1);
/* TODO: Same programming, but using HDMI_TB_ENC register */
/* HDMI_ACR_PACKET_CONTROL */
REG_UPDATE_3(HDMI_TB_ENC_ACR_PACKET_CONTROL,
HDMI_ACR_AUTO_SEND, 1,
HDMI_ACR_SOURCE, 0,
HDMI_ACR_AUDIO_PRIORITY, 0);
/* N/CTS computed relative to FRL rate instead of video rate (TMDS character clock). */
/* Program audio clock sample/regeneration parameters */
get_audio_clock_info(crtc_info->color_depth,
crtc_info->frl_character_clock_kHz,
&audio_clock_info);
DC_LOG_HW_AUDIO(
"\n%s:Input::requested_pixel_clock_100Hz = %d" \
"calculated_pixel_clock_100Hz = %d \n", __func__, \
crtc_info->requested_pixel_clock_100Hz, \
crtc_info->calculated_pixel_clock_100Hz);
/* Same register definition, but using HDMI_TB_ENC register */
/* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_32_0, HDMI_ACR_CTS_32, audio_clock_info.cts_32khz);
/* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_32_1, HDMI_ACR_N_32, audio_clock_info.n_32khz);
/* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_44_0, HDMI_ACR_CTS_44, audio_clock_info.cts_44khz);
/* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_44_1, HDMI_ACR_N_44, audio_clock_info.n_44khz);
/* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_48_0, HDMI_ACR_CTS_48, audio_clock_info.cts_48khz);
/* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
REG_UPDATE(HDMI_TB_ENC_ACR_48_1, HDMI_ACR_N_48, audio_clock_info.n_48khz);
/* TODO: HDMI_TB_ENC_ACR_PACKET_CONTROL::ACR_N_MULTIPLE
* Same register definition, but using HDMI_TB_ENC register*/
/* Video driver cannot know in advance which sample rate will
* be used by HD Audio driver
* HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
* programmed below in interrupt callback
*/
DC_LOG_DEBUG("Exiting [%s]\n", __func__);
}
static void hpo_enc60_hdmi_audio_setup(
struct hpo_frl_stream_encoder *enc,
unsigned int az_inst,
struct audio_info *info,
struct audio_crtc_info *audio_crtc_info)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
REG_UPDATE_2(HDMI_STREAM_ENC_AUDIO_CONTROL,
HDMI_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, az_inst,
HDMI_STREAM_ENC_APG_CLOCK_EN, 1);
hpo_enc60_setup_hdmi_audio(enc, audio_crtc_info);
ASSERT (enc->apg);
enc->apg->funcs->se_audio_setup(enc->apg, az_inst, info);
}
static void hpo_enc60_hdmi_audio_disable(
struct hpo_frl_stream_encoder *enc)
{
struct dcn401_hpo_frl_stream_encoder *enc401 = DCN401_HPO_FRL_STRENC_FROM_HPO_FRL_STRENC(enc);
ASSERT (enc->apg);
if (enc->apg && enc->apg->funcs->disable_apg)
enc->apg->funcs->disable_apg(enc->apg);
REG_UPDATE(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, 0);
}
static const struct hpo_frl_stream_encoder_funcs dcn401_str_enc_funcs = {
.hdmi_frl_enable = hpo_enc401_enable,
.hdmi_frl_unblank = hpo_enc401_unblank,
.hdmi_frl_blank = hpo_enc401_blank,
.hdmi_frl_set_stream_attribute = hpo_enc60_set_hdmi_stream_attribute,
.validate_hdmi_frl_output = hpo_enc3_validate_hdmi_frl_output,
.update_hdmi_info_packets = hpo_enc401_update_hdmi_info_packets,
.stop_hdmi_info_packets = hpo_enc401_stop_hdmi_info_packets,
.audio_mute_control = hpo_enc60_audio_mute_control,
.hdmi_audio_setup = hpo_enc60_hdmi_audio_setup,
.hdmi_audio_disable = hpo_enc60_hdmi_audio_disable,
.set_avmute = enc401_stream_encoder_set_avmute,
.read_state = hpo_enc401_read_state,
.hdmi_frl_set_dsc_config = hpo_enc401_hdmi_set_dsc_config,
.set_dynamic_metadata = hpo_enc401_set_dynamic_metadata,
};
void dcn60_hpo_frl_stream_encoder_construct(
struct dcn401_hpo_frl_stream_encoder *enc401,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct apg *apg,
const struct dcn30_hpo_frl_stream_enc_registers *regs,
const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask)
{
enc401->base.funcs = &dcn401_str_enc_funcs;
enc401->base.ctx = ctx;
enc401->base.id = eng_id;
enc401->base.bp = bp;
enc401->base.vpg = vpg;
enc401->base.apg = apg;
enc401->regs = regs;
enc401->hpo_se_shift = hpo_se_shift;
enc401->hpo_se_mask = hpo_se_mask;
enc401->base.stream_enc_inst = vpg->inst;
}

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DC_HPO_FRL_STREAM_ENCODER_DCN60_H__
#define __DC_HPO_FRL_STREAM_ENCODER_DCN60_H__
#include "dcn30/dcn30_vpg.h"
#include "dcn30/dcn30_afmt.h"
#include "dcn31/dcn31_apg.h"
#include "dcn30/dcn30_hpo_frl_stream_encoder.h"
#include "dcn401/dcn401_hpo_frl_stream_encoder.h"
#include "stream_encoder.h"
#include "dml/dml1_frl_cap_chk.h"
#define DCN60_HDMI_STREAM_ENC_MASK_SH_LIST(mask_sh)\
DCN401_HPO_STREAM_ENC_MASK_SH_LIST(mask_sh),\
SE_SF(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_INPUT_MUX_AUDIO_STREAM_SOURCE_SEL, mask_sh),\
SE_SF(HDMI_STREAM_ENC_AUDIO_CONTROL, HDMI_STREAM_ENC_APG_CLOCK_EN, mask_sh)
void dcn60_hpo_frl_stream_encoder_construct(
struct dcn401_hpo_frl_stream_encoder *enc401,
struct dc_context *ctx,
struct dc_bios *bp,
enum engine_id eng_id,
struct vpg *vpg,
struct apg *apg,
const struct dcn30_hpo_frl_stream_enc_registers *regs,
const struct dcn401_hpo_frl_stream_encoder_shift *hpo_se_shift,
const struct dcn401_hpo_frl_stream_encoder_mask *hpo_se_mask);
#endif /* __DC_HPO_STREAM_ENCODER_DCN60_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,207 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DC_HUBBUB_DCN60_H__
#define __DC_HUBBUB_DCN60_H__
#include "dcn30/dcn30_hubbub.h"
#include "dcn32/dcn32_hubbub.h"
#include "dcn401/dcn401_hubbub.h"
#define DCN6_0_CRB_SIZE_KB 2112
#define DCN6_0_DEFAULT_DET_SIZE 512
#define DCN6_0_CRB_SEGMENT_SIZE_KB 64
#define HUBBUB_MASK_SH_LIST_DCN6_0(mask_sh)\
HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \
HUBBUB_SF(DCHUBBUB_SOFT_RESET, DCHUBBUB_GLOBAL_SOFT_RESET, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MAX_REQ_OUTSTAND, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_A, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_A, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_B, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK1_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_B, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK1_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_A, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_A, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_B, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK2_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_B, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK2_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_A, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_A, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_B, DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK3_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_B, DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK3_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \
HUBBUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE, mask_sh), \
HUBBUB_SF(DCN_VM_FB_LOCATION_TOP, FB_TOP, mask_sh), \
HUBBUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET, mask_sh), \
HUBBUB_SF(DCN_VM_AGP_BOT, AGP_BOT, mask_sh), \
HUBBUB_SF(DCN_VM_AGP_TOP, AGP_TOP, mask_sh), \
HUBBUB_SF(DCN_VM_AGP_BASE, AGP_BASE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, DCHUBBUB_ARB_FRAC_URG_BW_NOM_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, DCHUBBUB_ARB_FRAC_URG_BW_NOM_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_META_TRIP_A, DCHUBBUB_ARB_REFCYC_PER_META_TRIP_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_REFCYC_PER_META_TRIP_B, DCHUBBUB_ARB_REFCYC_PER_META_TRIP_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_DEBUG_CTRL_0, DET_DEPTH, mask_sh),\
HUBBUB_SF(DCHUBBUB_DET0_CTRL, DET0_SIZE, mask_sh),\
HUBBUB_SF(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, mask_sh),\
HUBBUB_SF(DCHUBBUB_DET1_CTRL, DET1_SIZE, mask_sh),\
HUBBUB_SF(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, mask_sh),\
HUBBUB_SF(DCHUBBUB_DET2_CTRL, DET2_SIZE, mask_sh),\
HUBBUB_SF(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, mask_sh),\
HUBBUB_SF(DCHUBBUB_DET3_CTRL, DET3_SIZE, mask_sh),\
HUBBUB_SF(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, mask_sh),\
HUBBUB_SF(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE, mask_sh),\
HUBBUB_SF(DCHUBBUB_COMPBUF_CTRL, COMPBUF_SIZE_CURRENT, mask_sh),\
HUBBUB_SF(DCHUBBUB_COMPBUF_CTRL, CONFIG_ERROR, mask_sh),\
HUBBUB_SF(COMPBUF_RESERVED_SPACE, COMPBUF_RESERVED_SPACE_64B, mask_sh),\
HUBBUB_SF(DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_A, DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_A, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_B, DCHUBBUB_ARB_BUFFER_FULLNESS_WATERMARK_B, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A, mask_sh),\
HUBBUB_SF(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B, mask_sh),\
HUBBUB_SF(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_A, DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_A, mask_sh),\
HUBBUB_SF(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_B, DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK1_B, mask_sh),\
HUBBUB_SF(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A, mask_sh),\
HUBBUB_SF(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B, mask_sh),\
HUBBUB_SF(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_A, DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_A, mask_sh),\
HUBBUB_SF(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_B, DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK1_B, mask_sh),\
HUBBUB_SF(DCN_VM_FAULT_ADDR_MSB, DCN_VM_FAULT_ADDR_MSB, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_ADDR_LSB, DCN_VM_FAULT_ADDR_LSB, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_CNTL, DCN_VM_ERROR_STATUS_CLEAR, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_CNTL, DCN_VM_ERROR_STATUS_MODE, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_CNTL, DCN_VM_ERROR_INTERRUPT_ENABLE, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_CNTL, DCN_VM_RANGE_FAULT_DISABLE, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_CNTL, DCN_VM_PRQ_FAULT_DISABLE, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_STATUS, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_VMID, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_TABLE_LEVEL, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_PIPE, mask_sh), \
HUBBUB_SF(DCN_VM_FAULT_STATUS, DCN_VM_ERROR_INTERRUPT_STATUS, mask_sh),\
HUBBUB_SF(SDPIF_REQUEST_RATE_LIMIT, SDPIF_REQUEST_RATE_LIMIT, mask_sh),\
HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DISPCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\
HUBBUB_SF(DCHUBBUB_CLOCK_CNTL, DCFCLK_R_DCHUBBUB_GATE_DIS, mask_sh),\
HUBBUB_SF(DCHUBBUB_SDPIF_CFG0, SDPIF_PORT_CONTROL, mask_sh),\
HUBBUB_SF(DCHUBBUB_SDPIF_CFG1, SDPIF_MAX_NUM_OUTSTANDING, mask_sh),\
HUBBUB_SF(DCHUBBUB_MEM_PWR_MODE_CTRL, DET_MEM_PWR_LS_MODE, mask_sh),\
HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL1, DCHUBBUB_TIMEOUT_ERROR_STATUS, mask_sh),\
HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL1, DCHUBBUB_TIMEOUT_REQ_STALL_THRESHOLD, mask_sh),\
HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_PSTATE_STALL_THRESHOLD, mask_sh),\
HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_DETECTION_EN, mask_sh),\
HUBBUB_SF(DCHUBBUB_TIMEOUT_DETECTION_CTRL2, DCHUBBUB_TIMEOUT_TIMER_RESET, mask_sh),\
HUBBUB_SF(DCHUBBUB_CTRL_STATUS, ROB_UNDERFLOW_STATUS, mask_sh),\
HUBBUB_SF(DCHUBBUB_CTRL_STATUS, ROB_OVERFLOW_STATUS, mask_sh),\
HUBBUB_SF(DCHUBBUB_CTRL_STATUS, ROB_OVERFLOW_CLEAR, mask_sh),\
HUBBUB_SF(DCHUBBUB_CTRL_STATUS, DCHUBBUB_HW_DEBUG, mask_sh),\
HUBBUB_SF(DCHUBBUB_CTRL_STATUS, CSTATE_SWATH_CHK_GOOD_MODE, mask_sh),\
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, DCHUBBUB_LATENCY_CNT_EN, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, DCHUBBUB_DF_REQ_CMD_LATENCY_SEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, ARB_LATENCY_PIPE_SEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, ARB_LATENCY_REQ_TYPE_SEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, ROB_FIFO_LEVEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, REQ_UNIT_ID_MASK, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL, REQ_UNIT_ID_SEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, DCHUBBUB_LATENCY_FRAME_WIN_EN, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, DCHUBBUB_LATENCY_FRAME_WIN_SRC_SEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, DCHUBBUB_LATENCY_FRAME_WIN_DUR, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, LATENCY_SOURCE_SEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, LATENCY_DEBUG_SEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, UTM_FILTER_SEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, ROB_MAX_FIFO_LEVEL, mask_sh), \
HUBBUB_SF(DCHUBBUB_PERFORMANCE_MEASUREMENT_CNTL2, ROB_MAX_FIFO_LEVEL_RESET, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_EVENT_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_CVALUE_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_INC_MODE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_HW_CNTL_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_RUNEN_MODE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_CNTOFF_START_DIS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_RESTART_EN, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_INT_EN, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_OFF_MASK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_ACTIVE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL, PERFCOUNTER_CNTL_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL2, PERFCOUNTER_COUNTED_VALUE_TYPE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL2, PERFCOUNTER_HW_STOP1_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL2, PERFCOUNTER_HW_STOP2_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL2, PERFCOUNTER_CNTOFF_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_CNTL2, PERFCOUNTER_CNTL2_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_CNT0_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_STATE_SEL0, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_CNT1_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_STATE_SEL1, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_CNT2_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_STATE_SEL2, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_CNT3_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_STATE_SEL3, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_CNT4_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_STATE_SEL4, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_CNT5_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_STATE_SEL5, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_CNT6_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_STATE_SEL6, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_CNT7_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFCOUNTER_STATE, PERFCOUNTER_STATE_SEL7, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL, PERFMON_STATE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL, PERFMON_RPT_COUNT, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL, PERFMON_CNTOFF_AND_OR, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL, PERFMON_CNTOFF_INT_EN, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL, PERFMON_CNTOFF_INT_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL, PERFMON_CNTOFF_INT_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL2, PERFMON_CNTOFF_INT_TYPE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL2, PERFMON_CLK_ENABLE, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL2, PERFMON_RUN_ENABLE_START_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CNTL2, PERFMON_RUN_ENABLE_STOP_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT0_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT1_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT2_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT3_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT4_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT5_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT6_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT7_STATUS, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT0_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT1_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT2_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT3_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT4_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT5_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT6_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFCOUNTER_INT7_ACK, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_INT_MISC, PERFMON_CVALUE_HI, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_CVALUE_LOW, PERFMON_CVALUE_LOW, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_HI, PERFMON_HI, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_HI, PERFMON_READ_SEL, mask_sh), \
HUBBUB_SF(DC_PERFMON5_PERFMON_LOW, PERFMON_LOW, mask_sh), \
HUBBUB_SF(FMON_CTRL, FMON_MODE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_URGENT, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_BANDWIDTH_OVERHEAD, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_UTM_FORCE_ENABLE, mask_sh), \
HUBBUB_SF(DCHUBBUB_ARB_QOS_FORCE, DCHUBBUB_ARB_DO_NOT_FORCE_URGENCY_DURING_PSTATE_CHANGE_REQUEST, mask_sh)
void hubbub60_construct(struct dcn20_hubbub *hubbub2,
struct dc_context *ctx,
const struct dcn_hubbub_registers *hubbub_regs,
const struct dcn_hubbub_shift *hubbub_shift,
const struct dcn_hubbub_mask *hubbub_mask,
int det_size_kb,
int pixel_chunk_size_kb,
int config_return_buffer_size_kb);
#endif

View File

@@ -0,0 +1,536 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dm_services.h"
#include "dce_calcs.h"
#include "reg_helper.h"
#include "basics/conversion.h"
#include "dcn50_hubp.h"
#define REG(reg)\
hubp2->hubp_regs->reg
#define CTX \
hubp2->base.ctx
#undef FN
#define FN(reg_name, field_name) \
hubp2->hubp_shift->field_name, hubp2->hubp_mask->field_name
bool hubp50_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
bool flip_immediate)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
//program flip type
REG_UPDATE(DCSURF_FLIP_CONTROL,
SURFACE_FLIP_TYPE, flip_immediate);
// Program VMID reg
if (flip_immediate == 0)
REG_UPDATE(VMID_SETTINGS_0,
VMID, address->vmid);
if (address->type == PLN_ADDR_TYPE_GRPH_STEREO) {
REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, 0);
REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, 0x1);
} else {
// turn off stereo if not in stereo
REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, 0x0);
REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, 0x0);
}
/* HW automatically latch rest of address register on write to
* DCSURF_PRIMARY_SURFACE_ADDRESS if SURFACE_UPDATE_LOCK is not used
*
* program high first and then the low addr, order matters!
*/
switch (address->type) {
case PLN_ADDR_TYPE_GRAPHICS:
if (address->grph.addr.quad_part == 0)
break;
REG_UPDATE(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0,
PRIMARY_SURFACE_ADDRESS_HIGH,
address->grph.addr.high_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0,
PRIMARY_SURFACE_ADDRESS,
address->grph.addr.low_part);
break;
case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
if (address->video_progressive.luma_addr.quad_part == 0
|| address->video_progressive.chroma_addr.quad_part == 0)
break;
REG_UPDATE_2(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
PRIMARY_SURFACE_TMZ_C, address->tmz_surface);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0,
PRIMARY_SURFACE_ADDRESS_HIGH_C,
address->video_progressive.chroma_addr.high_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_C, 0,
PRIMARY_SURFACE_ADDRESS_C,
address->video_progressive.chroma_addr.low_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0,
PRIMARY_SURFACE_ADDRESS_HIGH,
address->video_progressive.luma_addr.high_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0,
PRIMARY_SURFACE_ADDRESS,
address->video_progressive.luma_addr.low_part);
break;
case PLN_ADDR_TYPE_GRPH_STEREO:
if (address->grph_stereo.left_addr.quad_part == 0
|| address->grph_stereo.right_addr.quad_part == 0)
break;
REG_UPDATE_4(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
PRIMARY_SURFACE_TMZ_C, address->tmz_surface,
SECONDARY_SURFACE_TMZ, address->tmz_surface,
SECONDARY_SURFACE_TMZ_C, address->tmz_surface);
REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH_C, 0,
SECONDARY_SURFACE_ADDRESS_HIGH_C,
address->grph_stereo.right_alpha_addr.high_part);
REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS_C, 0,
SECONDARY_SURFACE_ADDRESS_C,
address->grph_stereo.right_alpha_addr.low_part);
REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, 0,
SECONDARY_SURFACE_ADDRESS_HIGH,
address->grph_stereo.right_addr.high_part);
REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS, 0,
SECONDARY_SURFACE_ADDRESS,
address->grph_stereo.right_addr.low_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0,
PRIMARY_SURFACE_ADDRESS_HIGH_C,
address->grph_stereo.left_alpha_addr.high_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_C, 0,
PRIMARY_SURFACE_ADDRESS_C,
address->grph_stereo.left_alpha_addr.low_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0,
PRIMARY_SURFACE_ADDRESS_HIGH,
address->grph_stereo.left_addr.high_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0,
PRIMARY_SURFACE_ADDRESS,
address->grph_stereo.left_addr.low_part);
break;
case PLN_ADDR_TYPE_RGBEA:
if (address->rgbea.addr.quad_part == 0
|| address->rgbea.alpha_addr.quad_part == 0)
break;
REG_UPDATE_2(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_TMZ, address->tmz_surface,
PRIMARY_SURFACE_TMZ_C, address->tmz_surface);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0,
PRIMARY_SURFACE_ADDRESS_HIGH_C,
address->rgbea.alpha_addr.high_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_C, 0,
PRIMARY_SURFACE_ADDRESS_C,
address->rgbea.alpha_addr.low_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0,
PRIMARY_SURFACE_ADDRESS_HIGH,
address->rgbea.addr.high_part);
REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0,
PRIMARY_SURFACE_ADDRESS,
address->rgbea.addr.low_part);
break;
default:
BREAK_TO_DEBUGGER();
break;
}
hubp->request_address = *address;
return true;
}
static enum swizzle_mode_values hubp50_addr3_to_swizzle_mode_mapping(enum swizzle_mode_addr3_values addr3_swizzle_mode)
{
enum swizzle_mode_values swizzle_mode = DC_SW_UNKNOWN;
switch (addr3_swizzle_mode) {
case DC_ADDR3_SW_LINEAR:
swizzle_mode = DC_SW_LINEAR;
break;
case DC_ADDR3_SW_256B_2D:
swizzle_mode = DC_SW_256_R;
break;
case DC_ADDR3_SW_4KB_2D:
swizzle_mode = DC_SW_4KB_R;
break;
case DC_ADDR3_SW_64KB_2D:
case DC_ADDR3_SW_64KB_2D_Z:
swizzle_mode = DC_SW_64KB_R;
break;
case DC_ADDR3_SW_256KB_2D:
case DC_ADDR3_SW_256KB_2D_Z:
swizzle_mode = DC_SW_VAR_R;
break;
case DC_ADDR3_SW_4KB_3D:
case DC_ADDR3_SW_64KB_3D:
case DC_ADDR3_SW_256KB_3D:
default:
BREAK_TO_DEBUGGER();
break;
}
return swizzle_mode;
}
static void hubp50_program_tiling(
struct dcn20_hubp *hubp2,
const struct dc_tiling_info *info,
const enum surface_pixel_format pixel_format)
{
(void)pixel_format;
/* Tiling address-generation compatibility level programmed into the
* DCSURF_TILING_CONFIG.COMPAT_LEVEL register field:
* 0 - gfx8 bank_height == 1
* 1 - gfx8 bank_height == 2
* 2 - gfx9/10/11
* 5 - gfx addr3
*/
unsigned int compat_level = 0;
enum swizzle_mode_values swizzle_mode;
switch (info->gfxversion) {
case DcGfxVersion7:
case DcGfxVersion8:
REG_UPDATE_8(DCSURF_LEGACY_ADDR_CONFIG,
LEGACY_NUM_BANKS, info->gfx8.num_banks,
BANK_WIDTH, info->gfx8.bank_width,
BANK_HEIGHT, info->gfx8.bank_height,
MACRO_TILE_ASPECT, info->gfx8.tile_aspect,
TILE_SPLIT, info->gfx8.tile_split,
MICRO_TILE_MODE_NEW, info->gfx8.tile_mode,
PIPE_CONFIG, info->gfx8.pipe_config,
ARRAY_MODE, info->gfx8.array_mode);
if (info->gfx8.bank_height == 1) {
compat_level = 0;
} else if (info->gfx8.bank_height == 2) {
compat_level = 1;
}
break;
case DcGfxVersion9:
case DcGfxVersion10:
case DcGfxVersion11:
REG_UPDATE_4(DCSURF_ADDR_CONFIG,
NUM_PIPES, log_2(info->gfx9.num_pipes),
PIPE_INTERLEAVE, info->gfx9.pipe_interleave,
MAX_COMPRESSED_FRAGS, log_2(info->gfx9.max_compressed_frags),
NUM_PKRS, log_2(info->gfx9.num_pkrs));
REG_UPDATE(DCSURF_TILING_CONFIG, SW_MODE, info->gfx9.swizzle);
compat_level = 2;
break;
case DcGfxAddr3:
swizzle_mode = hubp50_addr3_to_swizzle_mode_mapping(info->gfx_addr3.swizzle);
REG_UPDATE(DCSURF_TILING_CONFIG, SW_MODE, swizzle_mode);
compat_level = 5;
break;
}
REG_UPDATE(DCSURF_TILING_CONFIG, COMPAT_LEVEL, compat_level);
}
static void hubp50_program_pixel_format(
struct hubp *hubp,
enum surface_pixel_format format)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
uint32_t red_bar = 3;
uint32_t blue_bar = 2;
/* swap for ABGR format */
if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR8888
|| format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010
|| format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS
|| format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616
|| format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) {
red_bar = 2;
blue_bar = 3;
}
REG_UPDATE_2(HUBPRET_CONTROL,
CROSSBAR_SRC_CB_B, blue_bar,
CROSSBAR_SRC_CR_R, red_bar);
/* Mapping is same as ipp programming (cnvc) */
switch (format) {
case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 1);
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 3);
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 8);
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 10);
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616: /* we use crossbar already */
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 26); /* ARGB16161616_UNORM */
break;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:/*we use crossbar already*/
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 24);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 65);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 64);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 67);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 66);
break;
/* Planar 422 formats*/
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P208:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 64);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P208:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 65);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P210:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 66);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P210:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 67);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrCb_P212:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 68);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbCr_P212:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 69);
break;
/* Packed 422 formats*/
case SURFACE_PIXEL_FORMAT_VIDEO_422_YCrYCb:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 72);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_YCbYCr:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 73);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CrYCbY:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 74);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_CbYCrY:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 75);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCrYCb:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 76);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_YCbYCr:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 77);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CrYCbY:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 78);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_10bpc_CbYCrY:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 79);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCbYCr:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 80);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_YCrYCb:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 81);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CrYCbY:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 82);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_422_12bpc_CbYCrY:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 83);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 12);
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FIX:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 112);
break;
case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FIX:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 113);
break;
case SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 114);
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGB111110_FLOAT:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 118);
break;
case SURFACE_PIXEL_FORMAT_GRPH_BGR101111_FLOAT:
REG_UPDATE(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 119);
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
REG_UPDATE_2(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 116,
ALPHA_PLANE_EN, 0);
break;
case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
REG_UPDATE_2(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, 116,
ALPHA_PLANE_EN, 1);
break;
default:
BREAK_TO_DEBUGGER();
break;
}
}
void hubp50_program_surface_config(
struct hubp *hubp,
enum surface_pixel_format format,
struct dc_tiling_info *tiling_info,
struct plane_size *plane_size,
enum dc_rotation_angle rotation,
struct dc_plane_dcc_param *dcc,
bool horizontal_mirror,
unsigned int compat_level)
{
(void)compat_level;
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
hubp401_dcc_control(hubp, dcc);
hubp50_program_tiling(hubp2, tiling_info, format);
hubp401_program_size(hubp, format, plane_size, dcc);
hubp2_program_rotation(hubp, rotation, horizontal_mirror);
hubp50_program_pixel_format(hubp, format);
}
void hubp50_read_state(struct hubp *hubp)
{
hubp401_read_state(hubp);
}
static struct hubp_funcs dcn50_hubp_funcs = {
.hubp_enable_tripleBuffer = hubp2_enable_triplebuffer,
.hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled,
.hubp_program_surface_flip_and_addr = hubp50_program_surface_flip_and_addr,
.hubp_program_surface_config = hubp50_program_surface_config,
.hubp_is_flip_pending = hubp2_is_flip_pending,
.hubp_setup2 = hubp401_setup,
.hubp_setup_interdependent2 = hubp401_setup_interdependent,
.hubp_set_vm_system_aperture_settings = hubp3_set_vm_system_aperture_settings,
.set_blank = hubp2_set_blank,
.set_blank_regs = hubp2_set_blank_regs,
.hubp_reset = hubp_reset,
.mem_program_viewport = hubp401_set_viewport,
.set_cursor_attributes = hubp32_cursor_set_attributes,
.set_cursor_position = hubp401_cursor_set_position,
.hubp_clk_cntl = hubp2_clk_cntl,
.hubp_vtg_sel = hubp2_vtg_sel,
.dmdata_set_attributes = hubp3_dmdata_set_attributes,
.dmdata_load = hubp2_dmdata_load,
.dmdata_status_done = hubp2_dmdata_status_done,
.hubp_read_state = hubp50_read_state,
.hubp_clear_underflow = hubp2_clear_underflow,
.hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl,
.hubp_init = hubp401_init,
.set_unbounded_requesting = hubp401_set_unbounded_requesting,
.hubp_soft_reset = hubp31_soft_reset,
.hubp_set_flip_int = hubp401_set_flip_int,
.hubp_in_blank = hubp401_in_blank,
.phantom_hubp_post_enable = hubp32_phantom_hubp_post_enable,
.hubp_update_mall_sel = hubp401_update_mall_sel,
.hubp_prepare_subvp_buffering = hubp32_prepare_subvp_buffering,
.hubp_program_mcache_id_and_split_coordinate = hubp401_program_mcache_id_and_split_coordinate,
.hubp_update_3dlut_fl_bias_scale = hubp401_update_3dlut_fl_bias_scale,
.hubp_program_3dlut_fl_mode = hubp401_program_3dlut_fl_mode,
.hubp_program_3dlut_fl_format = hubp401_program_3dlut_fl_format,
.hubp_program_3dlut_fl_addr = hubp401_program_3dlut_fl_addr,
.hubp_program_3dlut_fl_dlg_param = hubp401_program_3dlut_fl_dlg_param,
.hubp_enable_3dlut_fl = hubp401_enable_3dlut_fl,
.hubp_program_3dlut_fl_addressing_mode = hubp401_program_3dlut_fl_addressing_mode,
.hubp_program_3dlut_fl_width = hubp401_program_3dlut_fl_width,
.hubp_program_3dlut_fl_tmz_protected = hubp401_program_3dlut_fl_tmz_protected,
.hubp_program_3dlut_fl_crossbar = hubp401_program_3dlut_fl_crossbar,
.hubp_get_3dlut_fl_done = hubp401_get_3dlut_fl_done,
.hubp_clear_tiling = hubp401_clear_tiling,
.hubp_read_reg_state = hubp3_read_reg_state
};
bool hubp50_construct(
struct dcn20_hubp *hubp2,
struct dc_context *ctx,
uint32_t inst,
const struct dcn_hubp2_registers *hubp_regs,
const struct dcn_hubp2_shift *hubp_shift,
const struct dcn_hubp2_mask *hubp_mask)
{
hubp2->base.funcs = &dcn50_hubp_funcs;
hubp2->base.ctx = ctx;
hubp2->hubp_regs = hubp_regs;
hubp2->hubp_shift = hubp_shift;
hubp2->hubp_mask = hubp_mask;
hubp2->base.inst = inst;
hubp2->base.opp_id = OPP_ID_INVALID;
hubp2->base.mpcc_id = 0xf;
return true;
}

View File

@@ -0,0 +1,48 @@
/*
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved.
*/
#ifndef __DC_HUBP_DCN50_H__
#define __DC_HUBP_DCN50_H__
#include "dcn20/dcn20_hubp.h"
#include "dcn21/dcn21_hubp.h"
#include "dcn30/dcn30_hubp.h"
#include "dcn31/dcn31_hubp.h"
#include "dcn32/dcn32_hubp.h"
#include "dcn401/dcn401_hubp.h"
#include "dml2_0/dml21/inc/dml_top_dchub_registers.h"
#define HUBP_MASK_SH_LIST_DCN50(mask_sh)\
HUBP_MASK_SH_LIST_DCN401(mask_sh)
bool hubp50_program_surface_flip_and_addr(
struct hubp *hubp,
const struct dc_plane_address *address,
bool flip_immediate);
void hubp50_program_surface_config(
struct hubp *hubp,
enum surface_pixel_format format,
struct dc_tiling_info *tiling_info,
struct plane_size *plane_size,
enum dc_rotation_angle rotation,
struct dc_plane_dcc_param *dcc,
bool horizontal_mirror,
unsigned int compat_level);
void hubp50_read_state(struct hubp *hubp);
bool hubp50_construct(
struct dcn20_hubp *hubp2,
struct dc_context *ctx,
uint32_t inst,
const struct dcn_hubp2_registers *hubp_regs,
const struct dcn_hubp2_shift *hubp_shift,
const struct dcn_hubp2_mask *hubp_mask);
#endif /* __DC_HUBP_DCN50_H__ */

View File

@@ -0,0 +1,477 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dm_services.h"
#include "dce_calcs.h"
#include "reg_helper.h"
#include "basics/conversion.h"
#include "dcn60_hubp.h"
#define REG(reg)\
hubp2->hubp_regs->reg
#define CTX \
hubp2->base.ctx
#undef FN
#define FN(reg_name, field_name) \
hubp2->hubp_shift->field_name, hubp2->hubp_mask->field_name
static void hubp60_program_deadline(
struct hubp *hubp,
struct dml2_display_dlg_regs *dlg_attr,
struct dml2_display_ttu_regs *ttu_attr)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
/* DLG - Per hubp */
REG_SET_2(BLANK_OFFSET_0, 0,
REFCYC_H_BLANK_END, dlg_attr->refcyc_h_blank_end,
DLG_V_BLANK_END, dlg_attr->dlg_vblank_end);
REG_SET(BLANK_OFFSET_1, 0,
MIN_DST_Y_NEXT_START, dlg_attr->min_dst_y_next_start);
REG_SET(DST_DIMENSIONS, 0,
REFCYC_PER_HTOTAL, dlg_attr->refcyc_per_htotal);
REG_SET_2(DST_AFTER_SCALER, 0,
REFCYC_X_AFTER_SCALER, dlg_attr->refcyc_x_after_scaler,
DST_Y_AFTER_SCALER, dlg_attr->dst_y_after_scaler);
REG_SET(REF_FREQ_TO_PIX_FREQ, 0,
REF_FREQ_TO_PIX_FREQ, dlg_attr->ref_freq_to_pix_freq);
/* DLG - Per luma/chroma */
REG_SET(VBLANK_PARAMETERS_1, 0,
REFCYC_PER_PTE_GROUP_VBLANK_L, dlg_attr->refcyc_per_pte_group_vblank_l);
if (REG(NOM_PARAMETERS_0))
REG_SET(NOM_PARAMETERS_0, 0,
DST_Y_PER_PTE_ROW_NOM_L, dlg_attr->dst_y_per_pte_row_nom_l);
if (REG(NOM_PARAMETERS_1))
REG_SET(NOM_PARAMETERS_1, 0,
REFCYC_PER_PTE_GROUP_NOM_L, dlg_attr->refcyc_per_pte_group_nom_l);
REG_SET(NOM_PARAMETERS_4, 0,
DST_Y_PER_META_ROW_NOM_L, dlg_attr->dst_y_per_meta_row_nom_l);
REG_SET(NOM_PARAMETERS_5, 0,
REFCYC_PER_META_CHUNK_NOM_L, dlg_attr->refcyc_per_meta_chunk_nom_l);
REG_SET_2(PER_LINE_DELIVERY, 0,
REFCYC_PER_LINE_DELIVERY_L, dlg_attr->refcyc_per_line_delivery_l,
REFCYC_PER_LINE_DELIVERY_C, dlg_attr->refcyc_per_line_delivery_c);
REG_SET(VBLANK_PARAMETERS_2, 0,
REFCYC_PER_PTE_GROUP_VBLANK_C, dlg_attr->refcyc_per_pte_group_vblank_c);
if (REG(NOM_PARAMETERS_2))
REG_SET(NOM_PARAMETERS_2, 0,
DST_Y_PER_PTE_ROW_NOM_C, dlg_attr->dst_y_per_pte_row_nom_c);
if (REG(NOM_PARAMETERS_3))
REG_SET(NOM_PARAMETERS_3, 0,
REFCYC_PER_PTE_GROUP_NOM_C, dlg_attr->refcyc_per_pte_group_nom_c);
REG_SET(NOM_PARAMETERS_6, 0,
DST_Y_PER_META_ROW_NOM_C, dlg_attr->dst_y_per_meta_row_nom_c);
REG_SET(NOM_PARAMETERS_7, 0,
REFCYC_PER_META_CHUNK_NOM_C, dlg_attr->refcyc_per_meta_chunk_nom_c);
/* TTU - per luma/chroma */
/* TO DO: Set URGENT_FORCE_x fields with values from DML if/when available */
REG_SET_3(DCN_SURF0_TTU_CNTL0, 0,
REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_l,
URGENT_FORCE_VALUE, 0,
URGENT_FORCE_EN, 0);
REG_SET_3(DCN_SURF1_TTU_CNTL0, 0,
REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_c,
URGENT_FORCE_VALUE, 0,
URGENT_FORCE_EN, 0);
REG_SET_3(DCN_CUR0_TTU_CNTL0, 0,
REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_cur0,
URGENT_FORCE_VALUE, 0,
URGENT_FORCE_EN, 0);
REG_SET(FLIP_PARAMETERS_1, 0,
REFCYC_PER_PTE_GROUP_FLIP_L, dlg_attr->refcyc_per_pte_group_flip_l);
REG_SET(HUBP_3DLUT_DLG_PARAM, 0, REFCYC_PER_3DLUT_GROUP, dlg_attr->refcyc_per_tdlut_group);
REG_UPDATE(DCN_DMDATA_VM_CNTL,
REFCYC_PER_VM_DMDATA, dlg_attr->refcyc_per_vm_dmdata);
}
void hubp60_setup(
struct hubp *hubp,
struct dml2_dchub_per_pipe_register_set *pipe_regs,
union dml2_global_sync_programming *pipe_global_sync,
struct dc_crtc_timing *timing)
{
/* otg is locked when this func is called. Register are double buffered.
* disable the requestors is not needed
*/
hubp401_vready_at_or_After_vsync(hubp, pipe_global_sync, timing);
hubp401_program_requestor(hubp, &pipe_regs->rq_regs);
hubp60_program_deadline(hubp, &pipe_regs->dlg_regs, &pipe_regs->ttu_regs);
}
void hubp60_setup_interdependent(
struct hubp *hubp,
struct dml2_dchub_per_pipe_register_set *pipe_regs)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
REG_SET_3(PREFETCH_SETTINGS, 0,
DST_Y_PREFETCH, pipe_regs->dlg_regs.dst_y_prefetch,
VRATIO_PREFETCH, pipe_regs->dlg_regs.vratio_prefetch,
FORCE_DISP_PREF_TO_VBLANK, pipe_regs->dlg_regs.force_prefetch_to_vblank);
REG_SET(PREFETCH_SETTINGS_C, 0,
VRATIO_PREFETCH_C, pipe_regs->dlg_regs.vratio_prefetch_c);
REG_SET_2(VBLANK_PARAMETERS_0, 0,
DST_Y_PER_VM_VBLANK, pipe_regs->dlg_regs.dst_y_per_vm_vblank,
DST_Y_PER_ROW_VBLANK, pipe_regs->dlg_regs.dst_y_per_row_vblank);
REG_SET_2(FLIP_PARAMETERS_0, 0,
DST_Y_PER_VM_FLIP, pipe_regs->dlg_regs.dst_y_per_vm_flip,
DST_Y_PER_ROW_FLIP, pipe_regs->dlg_regs.dst_y_per_row_flip);
REG_SET(VBLANK_PARAMETERS_3, 0,
REFCYC_PER_META_CHUNK_VBLANK_L, pipe_regs->dlg_regs.refcyc_per_meta_chunk_vblank_l);
REG_SET(VBLANK_PARAMETERS_4, 0,
REFCYC_PER_META_CHUNK_VBLANK_C, pipe_regs->dlg_regs.refcyc_per_meta_chunk_vblank_c);
REG_SET(FLIP_PARAMETERS_2, 0,
REFCYC_PER_META_CHUNK_FLIP_L, pipe_regs->dlg_regs.refcyc_per_meta_chunk_flip_l);
REG_SET_2(PER_LINE_DELIVERY_PRE, 0,
REFCYC_PER_LINE_DELIVERY_PRE_L, pipe_regs->dlg_regs.refcyc_per_line_delivery_pre_l,
REFCYC_PER_LINE_DELIVERY_PRE_C, pipe_regs->dlg_regs.refcyc_per_line_delivery_pre_c);
REG_SET(DCN_SURF0_TTU_CNTL1, 0,
REFCYC_PER_REQ_DELIVERY_PRE,
pipe_regs->ttu_regs.refcyc_per_req_delivery_pre_l);
REG_SET(DCN_SURF1_TTU_CNTL1, 0,
REFCYC_PER_REQ_DELIVERY_PRE,
pipe_regs->ttu_regs.refcyc_per_req_delivery_pre_c);
REG_SET(DCN_CUR0_TTU_CNTL1, 0,
REFCYC_PER_REQ_DELIVERY_PRE, pipe_regs->ttu_regs.refcyc_per_req_delivery_pre_cur0);
REG_SET(DCN_GLOBAL_TTU_CNTL, 0,
MIN_TTU_VBLANK, pipe_regs->ttu_regs.min_ttu_vblank);
REG_SET(DST_Y_DELTA_DRQ_LIMIT, 0,
DST_Y_DELTA_DRQ_LIMIT, pipe_regs->dlg_regs.dst_y_delta_drq_limit);
REG_SET(DST_Y_ALT_CH_DRQ_LIMIT, 0,
DST_Y_ALT_CH_DRQ_LIMIT, pipe_regs->dlg_regs.dst_y_svp_drq_limit);
}
void hubp60_cursor_set_attributes(
struct hubp *hubp,
const struct dc_cursor_attributes *attr)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
enum cursor_pitch hw_pitch = hubp1_get_cursor_pitch(attr->pitch);
enum cursor_lines_per_chunk lpc = hubp2_get_lines_per_chunk(
attr->width, attr->color_format);
//Round cursor width up to next multiple of 64
uint32_t cursor_width = ((attr->width + 63) / 64) * 64;
hubp->curs_attr = *attr;
if (!hubp->cursor_offload) {
REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH,
CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part);
REG_UPDATE(CURSOR_SURFACE_ADDRESS,
CURSOR_SURFACE_ADDRESS, attr->address.low_part);
REG_UPDATE_2(CURSOR_SIZE,
CURSOR_WIDTH, cursor_width,
CURSOR_HEIGHT, attr->height);
REG_UPDATE_4(CURSOR_CONTROL,
CURSOR_MODE, attr->color_format,
CURSOR_2X_MAGNIFY, attr->attribute_flags.bits.ENABLE_MAGNIFICATION,
CURSOR_PITCH, hw_pitch,
CURSOR_LINES_PER_CHUNK, lpc);
REG_SET_3(CURSOR_SETTINGS, 0,
/* no shift of the cursor HDL schedule */
CURSOR0_DST_Y_OFFSET, 0,
/* used to shift the cursor chunk request deadline */
CURSOR0_CHUNK_HDL_ADJUST, 3,
FORCE_CURSOR_TO_DISP_PREF, attr->force_cursor_to_disp_pref);
}
hubp->att.SURFACE_ADDR_HIGH = attr->address.high_part;
hubp->att.SURFACE_ADDR = attr->address.low_part;
hubp->att.size.bits.width = attr->width;
hubp->att.size.bits.height = attr->height;
hubp->att.cur_ctl.bits.mode = attr->color_format;
hubp->cur_rect.w = attr->width;
hubp->cur_rect.h = attr->height;
hubp->att.cur_ctl.bits.pitch = hw_pitch;
hubp->att.cur_ctl.bits.line_per_chunk = lpc;
hubp->att.cur_ctl.bits.cur_2x_magnify = attr->attribute_flags.bits.ENABLE_MAGNIFICATION;
hubp->att.settings.bits.dst_y_offset = 0;
hubp->att.settings.bits.chunk_hdl_adjust = 3;
hubp->att.settings.bits.force_cursor_to_disp_pref = attr->force_cursor_to_disp_pref;
}
void hubp60_read_state(struct hubp *hubp)
{
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
struct dcn_hubp_state *s = &hubp2->state;
struct _vcs_dpi_display_dlg_regs_st *dlg_attr = &s->dlg_attr;
struct _vcs_dpi_display_ttu_regs_st *ttu_attr = &s->ttu_attr;
struct _vcs_dpi_display_rq_regs_st *rq_regs = &s->rq_regs;
/* Requester */
REG_GET(HUBPRET_CONTROL,
DET_BUF_PLANE1_BASE_ADDRESS, &rq_regs->plane1_base_address);
REG_GET_4(DCN_EXPANSION_MODE,
DRQ_EXPANSION_MODE, &rq_regs->drq_expansion_mode,
PRQ_EXPANSION_MODE, &rq_regs->prq_expansion_mode,
MRQ_EXPANSION_MODE, &rq_regs->mrq_expansion_mode,
CRQ_EXPANSION_MODE, &rq_regs->crq_expansion_mode);
REG_GET_5(DCHUBP_REQ_SIZE_CONFIG,
CHUNK_SIZE, &rq_regs->rq_regs_l.chunk_size,
MIN_CHUNK_SIZE, &rq_regs->rq_regs_l.min_chunk_size,
DPTE_GROUP_SIZE, &rq_regs->rq_regs_l.dpte_group_size,
SWATH_HEIGHT, &rq_regs->rq_regs_l.swath_height,
PTE_ROW_HEIGHT_LINEAR, &rq_regs->rq_regs_l.pte_row_height_linear);
REG_GET_5(DCHUBP_REQ_SIZE_CONFIG_C,
CHUNK_SIZE_C, &rq_regs->rq_regs_c.chunk_size,
MIN_CHUNK_SIZE_C, &rq_regs->rq_regs_c.min_chunk_size,
DPTE_GROUP_SIZE_C, &rq_regs->rq_regs_c.dpte_group_size,
SWATH_HEIGHT_C, &rq_regs->rq_regs_c.swath_height,
PTE_ROW_HEIGHT_LINEAR_C, &rq_regs->rq_regs_c.pte_row_height_linear);
REG_GET(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR,
MC_VM_SYSTEM_APERTURE_HIGH_ADDR, &rq_regs->aperture_high_addr);
REG_GET(DCN_VM_SYSTEM_APERTURE_LOW_ADDR,
MC_VM_SYSTEM_APERTURE_LOW_ADDR, &rq_regs->aperture_low_addr);
/* DLG - Per hubp */
REG_GET_2(BLANK_OFFSET_0,
REFCYC_H_BLANK_END, &dlg_attr->refcyc_h_blank_end,
DLG_V_BLANK_END, &dlg_attr->dlg_vblank_end);
REG_GET(BLANK_OFFSET_1,
MIN_DST_Y_NEXT_START, &dlg_attr->min_dst_y_next_start);
REG_GET(DST_DIMENSIONS,
REFCYC_PER_HTOTAL, &dlg_attr->refcyc_per_htotal);
REG_GET_2(DST_AFTER_SCALER,
REFCYC_X_AFTER_SCALER, &dlg_attr->refcyc_x_after_scaler,
DST_Y_AFTER_SCALER, &dlg_attr->dst_y_after_scaler);
REG_GET_2(PREFETCH_SETTINGS,
DST_Y_PREFETCH, &dlg_attr->dst_y_prefetch,
VRATIO_PREFETCH, &dlg_attr->vratio_prefetch);
REG_GET_2(VBLANK_PARAMETERS_0,
DST_Y_PER_VM_VBLANK, &dlg_attr->dst_y_per_vm_vblank,
DST_Y_PER_ROW_VBLANK, &dlg_attr->dst_y_per_row_vblank);
REG_GET(REF_FREQ_TO_PIX_FREQ,
REF_FREQ_TO_PIX_FREQ, &dlg_attr->ref_freq_to_pix_freq);
/* DLG - Per luma/chroma */
REG_GET(VBLANK_PARAMETERS_1,
REFCYC_PER_PTE_GROUP_VBLANK_L, &dlg_attr->refcyc_per_pte_group_vblank_l);
REG_GET(VBLANK_PARAMETERS_3,
REFCYC_PER_META_CHUNK_VBLANK_L, &dlg_attr->refcyc_per_meta_chunk_vblank_l);
REG_GET(NOM_PARAMETERS_0,
DST_Y_PER_PTE_ROW_NOM_L, &dlg_attr->dst_y_per_pte_row_nom_l);
REG_GET(NOM_PARAMETERS_1,
REFCYC_PER_PTE_GROUP_NOM_L, &dlg_attr->refcyc_per_pte_group_nom_l);
REG_GET(NOM_PARAMETERS_4,
DST_Y_PER_META_ROW_NOM_L, &dlg_attr->dst_y_per_meta_row_nom_l);
REG_GET(NOM_PARAMETERS_5,
REFCYC_PER_META_CHUNK_NOM_L, &dlg_attr->refcyc_per_meta_chunk_nom_l);
REG_GET_2(PER_LINE_DELIVERY_PRE,
REFCYC_PER_LINE_DELIVERY_PRE_L, &dlg_attr->refcyc_per_line_delivery_pre_l,
REFCYC_PER_LINE_DELIVERY_PRE_C, &dlg_attr->refcyc_per_line_delivery_pre_c);
REG_GET_2(PER_LINE_DELIVERY,
REFCYC_PER_LINE_DELIVERY_L, &dlg_attr->refcyc_per_line_delivery_l,
REFCYC_PER_LINE_DELIVERY_C, &dlg_attr->refcyc_per_line_delivery_c);
REG_GET(PREFETCH_SETTINGS_C,
VRATIO_PREFETCH_C, &dlg_attr->vratio_prefetch_c);
REG_GET(VBLANK_PARAMETERS_2,
REFCYC_PER_PTE_GROUP_VBLANK_C, &dlg_attr->refcyc_per_pte_group_vblank_c);
REG_GET(VBLANK_PARAMETERS_4,
REFCYC_PER_META_CHUNK_VBLANK_C, &dlg_attr->refcyc_per_meta_chunk_vblank_c);
REG_GET(NOM_PARAMETERS_2,
DST_Y_PER_PTE_ROW_NOM_C, &dlg_attr->dst_y_per_pte_row_nom_c);
REG_GET(NOM_PARAMETERS_3,
REFCYC_PER_PTE_GROUP_NOM_C, &dlg_attr->refcyc_per_pte_group_nom_c);
REG_GET(NOM_PARAMETERS_6,
DST_Y_PER_META_ROW_NOM_C, &dlg_attr->dst_y_per_meta_row_nom_c);
REG_GET(NOM_PARAMETERS_7,
REFCYC_PER_META_CHUNK_NOM_C, &dlg_attr->refcyc_per_meta_chunk_nom_c);
REG_GET(DCN_GLOBAL_TTU_CNTL,
MIN_TTU_VBLANK, &ttu_attr->min_ttu_vblank);
/* TTU - per luma/chroma */
/* Assumed surf0 is luma and 1 is chroma */
REG_GET(DCN_SURF0_TTU_CNTL0,
REFCYC_PER_REQ_DELIVERY, &ttu_attr->refcyc_per_req_delivery_l);
REG_GET(DCN_SURF0_TTU_CNTL1,
REFCYC_PER_REQ_DELIVERY_PRE,
&ttu_attr->refcyc_per_req_delivery_pre_l);
REG_GET(DCN_SURF1_TTU_CNTL0,
REFCYC_PER_REQ_DELIVERY, &ttu_attr->refcyc_per_req_delivery_c);
REG_GET(DCN_SURF1_TTU_CNTL1,
REFCYC_PER_REQ_DELIVERY_PRE,
&ttu_attr->refcyc_per_req_delivery_pre_c);
/* Rest of hubp */
REG_GET(DCSURF_SURFACE_CONFIG,
SURFACE_PIXEL_FORMAT, &s->pixel_format);
REG_GET(DCSURF_SURFACE_EARLIEST_INUSE_HIGH,
SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, &s->inuse_addr_hi);
REG_GET(DCSURF_SURFACE_EARLIEST_INUSE,
SURFACE_EARLIEST_INUSE_ADDRESS, &s->inuse_addr_lo);
REG_GET_2(DCSURF_PRI_VIEWPORT_DIMENSION,
PRI_VIEWPORT_WIDTH, &s->viewport_width,
PRI_VIEWPORT_HEIGHT, &s->viewport_height);
REG_GET_2(DCSURF_SURFACE_CONFIG,
ROTATION_ANGLE, &s->rotation_angle,
H_MIRROR_EN, &s->h_mirror_en);
REG_GET(DCSURF_TILING_CONFIG,
SW_MODE, &s->sw_mode);
REG_GET(DCSURF_SURFACE_CONTROL,
PRIMARY_SURFACE_DCC_EN, &s->dcc_en);
REG_GET_3(DCHUBP_CNTL,
HUBP_BLANK_EN, &s->blank_en,
HUBP_TTU_DISABLE, &s->ttu_disable,
HUBP_UNDERFLOW_STATUS, &s->underflow_status);
REG_GET(HUBP_CLK_CNTL,
HUBP_CLOCK_ENABLE, &s->clock_en);
REG_GET(DCN_GLOBAL_TTU_CNTL,
MIN_TTU_VBLANK, &s->min_ttu_vblank);
REG_GET(DCSURF_PRIMARY_SURFACE_ADDRESS,
PRIMARY_SURFACE_ADDRESS, &s->primary_surface_addr_lo);
REG_GET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH,
PRIMARY_SURFACE_ADDRESS, &s->primary_surface_addr_hi);
s->uclk_pstate_force = REG_READ(UCLK_PSTATE_FORCE);
s->hubp_cntl = REG_READ(DCHUBP_CNTL);
s->flip_control = REG_READ(DCSURF_FLIP_CONTROL);
}
static struct hubp_funcs dcn60_hubp_funcs = {
.hubp_enable_tripleBuffer = hubp2_enable_triplebuffer,
.hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled,
.hubp_program_surface_flip_and_addr = hubp50_program_surface_flip_and_addr,
.hubp_program_surface_config = hubp50_program_surface_config,
.hubp_is_flip_pending = hubp2_is_flip_pending,
.hubp_setup2 = hubp60_setup,
.hubp_setup_interdependent2 = hubp60_setup_interdependent,
.hubp_set_vm_system_aperture_settings = hubp3_set_vm_system_aperture_settings,
.set_blank = hubp2_set_blank,
.set_blank_regs = hubp2_set_blank_regs,
.hubp_reset = hubp_reset,
.mem_program_viewport = hubp401_set_viewport,
.set_cursor_attributes = hubp60_cursor_set_attributes,
.set_cursor_position = hubp401_cursor_set_position,
.hubp_clk_cntl = hubp2_clk_cntl,
.hubp_vtg_sel = hubp2_vtg_sel,
.dmdata_set_attributes = hubp3_dmdata_set_attributes,
.dmdata_load = hubp2_dmdata_load,
.dmdata_status_done = hubp2_dmdata_status_done,
.hubp_read_state = hubp60_read_state,
.hubp_clear_underflow = hubp2_clear_underflow,
.hubp_set_flip_control_surface_gsl = hubp2_set_flip_control_surface_gsl,
.hubp_init = hubp401_init,
.set_unbounded_requesting = hubp401_set_unbounded_requesting,
.hubp_soft_reset = hubp31_soft_reset,
.hubp_set_flip_int = hubp401_set_flip_int,
.hubp_in_blank = hubp401_in_blank,
.phantom_hubp_post_enable = hubp32_phantom_hubp_post_enable,
.hubp_update_mall_sel = NULL,
.hubp_prepare_subvp_buffering = hubp32_prepare_subvp_buffering,
.hubp_program_mcache_id_and_split_coordinate = hubp401_program_mcache_id_and_split_coordinate,
.hubp_update_3dlut_fl_bias_scale = hubp401_update_3dlut_fl_bias_scale,
.hubp_program_3dlut_fl_mode = hubp401_program_3dlut_fl_mode,
.hubp_program_3dlut_fl_format = hubp401_program_3dlut_fl_format,
.hubp_program_3dlut_fl_addr = hubp401_program_3dlut_fl_addr,
.hubp_program_3dlut_fl_dlg_param = hubp401_program_3dlut_fl_dlg_param,
.hubp_enable_3dlut_fl = hubp401_enable_3dlut_fl,
.hubp_program_3dlut_fl_addressing_mode = hubp401_program_3dlut_fl_addressing_mode,
.hubp_program_3dlut_fl_width = hubp401_program_3dlut_fl_width,
.hubp_program_3dlut_fl_tmz_protected = hubp401_program_3dlut_fl_tmz_protected,
.hubp_program_3dlut_fl_crossbar = hubp42_program_3dlut_fl_crossbar,
.hubp_get_3dlut_fl_done = hubp401_get_3dlut_fl_done,
.hubp_clear_tiling = hubp401_clear_tiling,
.hubp_read_reg_state = hubp3_read_reg_state
};
bool hubp60_construct(
struct dcn20_hubp *hubp2,
struct dc_context *ctx,
uint32_t inst,
const struct dcn_hubp2_registers *hubp_regs,
const struct dcn_hubp2_shift *hubp_shift,
const struct dcn_hubp2_mask *hubp_mask)
{
hubp2->base.funcs = &dcn60_hubp_funcs;
hubp2->base.ctx = ctx;
hubp2->hubp_regs = hubp_regs;
hubp2->hubp_shift = hubp_shift;
hubp2->hubp_mask = hubp_mask;
hubp2->base.inst = inst;
hubp2->base.opp_id = OPP_ID_INVALID;
hubp2->base.mpcc_id = 0xf;
return true;
}

View File

@@ -0,0 +1,272 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DC_HUBP_DCN60_H__
#define __DC_HUBP_DCN60_H__
#include "dcn20/dcn20_hubp.h"
#include "dcn21/dcn21_hubp.h"
#include "dcn30/dcn30_hubp.h"
#include "dcn31/dcn31_hubp.h"
#include "dcn32/dcn32_hubp.h"
#include "dcn401/dcn401_hubp.h"
#include "dcn42/dcn42_hubp.h"
#include "dcn50/dcn50_hubp.h"
#include "dml2_0/dml21/inc/dml_top_dchub_registers.h"
#include "dcn/dcn_6_0_0_sh_mask.h"
#define HUBP_MASK_SH_LIST_DCN60(mask_sh)\
HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, REFCYC_PER_VM_DMDATA, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_FAULT_STATUS, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_FAULT_STATUS_CLEAR, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_UNDERFLOW_STATUS, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_LATE_STATUS, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_UNDERFLOW_STATUS_CLEAR, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_DMDATA_VM_CNTL, DMDATA_VM_DONE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_BLANK_EN, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_TTU_DISABLE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_CLEAR, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VTG_SEL, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNBOUNDED_REQ_MODE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_IN_BLANK, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_SOFT_RESET, mask_sh),\
HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_PIPES, mask_sh),\
HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, PIPE_INTERLEAVE, mask_sh),\
HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, MAX_COMPRESSED_FRAGS, mask_sh),\
HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_PKRS, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, LEGACY_PIPE_INTERLEAVE, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, ARRAY_MODE, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, PIPE_CONFIG, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, MICRO_TILE_MODE_NEW, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, TILE_SPLIT, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, BANK_WIDTH, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, BANK_HEIGHT, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, MACRO_TILE_ASPECT, mask_sh),\
HUBP_SF(HUBP0_DCSURF_LEGACY_ADDR_CONFIG, LEGACY_NUM_BANKS, mask_sh),\
HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, SW_MODE, mask_sh),\
HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, COMPAT_LEVEL, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH, PITCH, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH_C, PITCH_C, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_TYPE, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_PENDING, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_UPDATE_LOCK, mask_sh),\
HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_WIDTH, mask_sh),\
HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT, mask_sh),\
HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START, PRI_VIEWPORT_X_START, mask_sh),\
HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START, PRI_VIEWPORT_Y_START, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION, SEC_VIEWPORT_WIDTH, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION, SEC_VIEWPORT_HEIGHT, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START, SEC_VIEWPORT_X_START, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START, SEC_VIEWPORT_Y_START, mask_sh),\
HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_C, PRI_VIEWPORT_WIDTH_C, mask_sh),\
HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_C, PRI_VIEWPORT_HEIGHT_C, mask_sh),\
HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START_C, PRI_VIEWPORT_X_START_C, mask_sh),\
HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START_C, PRI_VIEWPORT_Y_START_C, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION_C, SEC_VIEWPORT_WIDTH_C, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION_C, SEC_VIEWPORT_HEIGHT_C, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START_C, SEC_VIEWPORT_X_START_C, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START_C, SEC_VIEWPORT_Y_START_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, PRIMARY_SURFACE_ADDRESS_HIGH, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS, PRIMARY_SURFACE_ADDRESS, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, SECONDARY_SURFACE_ADDRESS_HIGH, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS, SECONDARY_SURFACE_ADDRESS, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, PRIMARY_SURFACE_ADDRESS_HIGH_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_C, PRIMARY_SURFACE_ADDRESS_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH_C, SECONDARY_SURFACE_ADDRESS_HIGH_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS_C, SECONDARY_SURFACE_ADDRESS_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE, SURFACE_INUSE_ADDRESS, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_HIGH, SURFACE_INUSE_ADDRESS_HIGH, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_C, SURFACE_INUSE_ADDRESS_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_HIGH_C, SURFACE_INUSE_ADDRESS_HIGH_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE, SURFACE_EARLIEST_INUSE_ADDRESS, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_HIGH, SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_C, SURFACE_EARLIEST_INUSE_ADDRESS_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, SURFACE_EARLIEST_INUSE_ADDRESS_HIGH_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_TMZ, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_TMZ_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_EN, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_TMZ, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_TMZ_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, SECONDARY_SURFACE_DCC_EN, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, DET_BUF_PLANE1_BASE_ADDRESS, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CB_B, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CR_R, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_Y_G, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_ALPHA, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, PACK_3TO2_ELEMENT_DISABLE, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, DRQ_EXPANSION_MODE, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, PRQ_EXPANSION_MODE, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, MRQ_EXPANSION_MODE, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, CRQ_EXPANSION_MODE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, CHUNK_SIZE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MIN_CHUNK_SIZE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, DPTE_GROUP_SIZE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, SWATH_HEIGHT, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, PTE_ROW_HEIGHT_LINEAR, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, CHUNK_SIZE_C, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MIN_CHUNK_SIZE_C, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, DPTE_GROUP_SIZE_C, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, SWATH_HEIGHT_C, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, PTE_ROW_HEIGHT_LINEAR_C, mask_sh),\
HUBP_SF(HUBPREQ0_BLANK_OFFSET_0, REFCYC_H_BLANK_END, mask_sh),\
HUBP_SF(HUBPREQ0_BLANK_OFFSET_0, DLG_V_BLANK_END, mask_sh),\
HUBP_SF(HUBPREQ0_BLANK_OFFSET_1, MIN_DST_Y_NEXT_START, mask_sh),\
HUBP_SF(HUBPREQ0_DST_DIMENSIONS, REFCYC_PER_HTOTAL, mask_sh),\
HUBP_SF(HUBPREQ0_DST_AFTER_SCALER, REFCYC_X_AFTER_SCALER, mask_sh),\
HUBP_SF(HUBPREQ0_DST_AFTER_SCALER, DST_Y_AFTER_SCALER, mask_sh),\
HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_0, DST_Y_PER_VM_VBLANK, mask_sh),\
HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_0, DST_Y_PER_ROW_VBLANK, mask_sh),\
HUBP_SF(HUBPREQ0_REF_FREQ_TO_PIX_FREQ, REF_FREQ_TO_PIX_FREQ, mask_sh),\
HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_1, REFCYC_PER_PTE_GROUP_VBLANK_L, mask_sh),\
HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_3, REFCYC_PER_META_CHUNK_VBLANK_L, mask_sh),\
HUBP_SF(HUBPREQ0_NOM_PARAMETERS_4, DST_Y_PER_META_ROW_NOM_L, mask_sh),\
HUBP_SF(HUBPREQ0_NOM_PARAMETERS_5, REFCYC_PER_META_CHUNK_NOM_L, mask_sh),\
HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY_PRE, REFCYC_PER_LINE_DELIVERY_PRE_L, mask_sh),\
HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY_PRE, REFCYC_PER_LINE_DELIVERY_PRE_C, mask_sh),\
HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY, REFCYC_PER_LINE_DELIVERY_L, mask_sh),\
HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY, REFCYC_PER_LINE_DELIVERY_C, mask_sh),\
HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_2, REFCYC_PER_PTE_GROUP_VBLANK_C, mask_sh),\
HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_4, REFCYC_PER_META_CHUNK_VBLANK_C, mask_sh),\
HUBP_SF(HUBPREQ0_NOM_PARAMETERS_6, DST_Y_PER_META_ROW_NOM_C, mask_sh),\
HUBP_SF(HUBPREQ0_NOM_PARAMETERS_7, REFCYC_PER_META_CHUNK_NOM_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, MIN_TTU_VBLANK, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, ROW_TTU_MODE, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, FORCE_URGENT_FLIP, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, FORCE_URGENT_VM_PREFETCH, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, REFCYC_PER_REQ_DELIVERY, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, URGENT_FORCE_VALUE, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, URGENT_FORCE_EN, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL1, REFCYC_PER_REQ_DELIVERY_PRE, mask_sh),\
HUBP_SF(HUBP0_HUBP_CLK_CNTL, HUBP_CLOCK_ENABLE, mask_sh),\
HUBP_SF(HUBPREQ0_NOM_PARAMETERS_0, DST_Y_PER_PTE_ROW_NOM_L, mask_sh),\
HUBP_SF(HUBPREQ0_NOM_PARAMETERS_1, REFCYC_PER_PTE_GROUP_NOM_L, mask_sh),\
HUBP_SF(HUBPREQ0_NOM_PARAMETERS_2, DST_Y_PER_PTE_ROW_NOM_C, mask_sh),\
HUBP_SF(HUBPREQ0_NOM_PARAMETERS_3, REFCYC_PER_PTE_GROUP_NOM_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_VM_MX_L1_TLB_CNTL, ENABLE_L1_TLB, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ROTATION_ANGLE, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, H_MIRROR_EN, mask_sh),\
HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ALPHA_PLANE_EN, mask_sh),\
HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS, DST_Y_PREFETCH, mask_sh),\
HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS, VRATIO_PREFETCH, mask_sh),\
HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS, FORCE_DISP_PREF_TO_VBLANK, mask_sh),\
HUBP_SF(HUBPREQ0_PREFETCH_SETTINGS_C, VRATIO_PREFETCH_C, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR, MC_VM_SYSTEM_APERTURE_LOW_ADDR, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, MC_VM_SYSTEM_APERTURE_HIGH_ADDR, mask_sh),\
HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_DST_Y_OFFSET, mask_sh), \
HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, CURSOR0_CHUNK_HDL_ADJUST, mask_sh), \
HUBP_SF(HUBPREQ0_CURSOR_SETTINGS, FORCE_CURSOR_TO_DISP_PREF, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_SIZE, CURSOR_WIDTH, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_SIZE, CURSOR_HEIGHT, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_REQ_MODE, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_2X_MAGNIFY, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_POSITION, CURSOR_X_POSITION, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_POSITION, CURSOR_Y_POSITION, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \
HUBP_SF(CURSOR0_0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_ADDRESS_HIGH, DMDATA_ADDRESS_HIGH, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_MODE, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_UPDATED, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_REPEAT, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_CNTL, DMDATA_SIZE, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_UPDATED, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_REPEAT, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_SW_CNTL, DMDATA_SW_SIZE, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_QOS_CNTL, DMDATA_QOS_MODE, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_QOS_CNTL, DMDATA_DL_DELTA, mask_sh), \
HUBP_SF(CURSOR0_0_DMDATA_STATUS, DMDATA_DONE, mask_sh),\
HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_0, DST_Y_PER_VM_FLIP, mask_sh),\
HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_0, DST_Y_PER_ROW_FLIP, mask_sh),\
HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_1, REFCYC_PER_PTE_GROUP_FLIP_L, mask_sh),\
HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_2, REFCYC_PER_META_CHUNK_FLIP_L, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_VREADY_AT_OR_AFTER_VSYNC, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_DISABLE_STOP_DATA_DURING_VM, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, HUBPREQ_MASTER_UPDATE_LOCK_STATUS, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL2, SURFACE_GSL_ENABLE, mask_sh),\
HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL2, SURFACE_TRIPLE_BUFFER_ENABLE, mask_sh),\
HUBP_SF(HUBPREQ0_VMID_SETTINGS_0, VMID, mask_sh),\
HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_3, REFCYC_PER_VM_GROUP_FLIP, mask_sh),\
HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_4, REFCYC_PER_VM_REQ_FLIP, mask_sh),\
HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_5, REFCYC_PER_PTE_GROUP_FLIP_C, mask_sh),\
HUBP_SF(HUBPREQ0_FLIP_PARAMETERS_6, REFCYC_PER_META_CHUNK_FLIP_C, mask_sh),\
HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_5, REFCYC_PER_VM_GROUP_VBLANK, mask_sh),\
HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_6, REFCYC_PER_VM_REQ_VBLANK, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, VM_GROUP_SIZE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_VMPG_CONFIG, VMPG_SIZE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_VMPG_CONFIG, PTE_BUFFER_MODE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_VMPG_CONFIG, BIGK_FRAGMENT_SIZE, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_VMPG_CONFIG, FORCE_ONE_ROW_FOR_FRAME, mask_sh),\
HUBP_SF(HUBPREQ0_UCLK_PSTATE_FORCE, DATA_UCLK_PSTATE_FORCE_EN, mask_sh),\
HUBP_SF(HUBPREQ0_UCLK_PSTATE_FORCE, DATA_UCLK_PSTATE_FORCE_VALUE, mask_sh),\
HUBP_SF(HUBPREQ0_UCLK_PSTATE_FORCE, CURSOR_UCLK_PSTATE_FORCE_EN, mask_sh),\
HUBP_SF(HUBPREQ0_UCLK_PSTATE_FORCE, CURSOR_UCLK_PSTATE_FORCE_VALUE, mask_sh),\
HUBP_SF(HUBP0_3DLUT_FL_CONFIG, HUBP0_3DLUT_FL_MODE, mask_sh),\
HUBP_SF(HUBP0_3DLUT_FL_CONFIG, HUBP0_3DLUT_FL_FORMAT, mask_sh),\
HUBP_SF(HUBP0_3DLUT_FL_BIAS_SCALE, HUBP0_3DLUT_FL_BIAS, mask_sh),\
HUBP_SF(HUBP0_3DLUT_FL_BIAS_SCALE, HUBP0_3DLUT_FL_SCALE, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_ENABLE, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_DONE, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_ADDRESSING_MODE, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_WIDTH, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_MPC_WIDTH, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_TMZ, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_CROSSBAR_SEL_B, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_CROSSBAR_SEL_G, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_CONTROL, HUBP_3DLUT_CROSSBAR_SEL_R, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_ADDRESS_HIGH, HUBP_3DLUT_ADDRESS_HIGH, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_ADDRESS_LOW, HUBP_3DLUT_ADDRESS_LOW, mask_sh),\
HUBP_SF(CURSOR0_0_HUBP_3DLUT_DLG_PARAM, REFCYC_PER_3DLUT_GROUP, mask_sh),\
HUBP_SF(HUBP0_DCSURF_VIEWPORT_MCACHE_SPLIT_COORDINATE, VIEWPORT_MCACHE_SPLIT_COORDINATE, mask_sh),\
HUBP_SF(HUBP0_DCSURF_VIEWPORT_MCACHE_SPLIT_COORDINATE, VIEWPORT_MCACHE_SPLIT_COORDINATE_C, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_MCACHEID_CONFIG, MCACHEID_REG_READ_1H_P0, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_MCACHEID_CONFIG, MCACHEID_REG_READ_2H_P0, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_MCACHEID_CONFIG, MCACHEID_REG_READ_1H_P1, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_MCACHEID_CONFIG, MCACHEID_REG_READ_2H_P1, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_MCACHEID_CONFIG, MCACHEID_MALL_PREF_1H_P0, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_MCACHEID_CONFIG, MCACHEID_MALL_PREF_2H_P0, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_MCACHEID_CONFIG, MCACHEID_MALL_PREF_1H_P1, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_MCACHEID_CONFIG, MCACHEID_MALL_PREF_2H_P1, mask_sh),\
HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_SEG_ALLOC_ERR_STATUS, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_READ_LINE_VALUE, PIPE_READ_LINE, mask_sh),\
HUBP_SF(HUBPREQ0_DST_Y_DELTA_DRQ_LIMIT, DST_Y_DELTA_DRQ_LIMIT, mask_sh),\
HUBP_SF(HUBPREQ0_DST_Y_ALT_CH_DRQ_LIMIT, DST_Y_ALT_CH_DRQ_LIMIT, mask_sh),\
void hubp60_setup(
struct hubp *hubp,
struct dml2_dchub_per_pipe_register_set *pipe_regs,
union dml2_global_sync_programming *pipe_global_sync,
struct dc_crtc_timing *timing);
void hubp60_setup_interdependent(
struct hubp *hubp,
struct dml2_dchub_per_pipe_register_set *pipe_regs);
void hubp60_cursor_set_attributes(struct hubp *hubp,
const struct dc_cursor_attributes *attr);
void hubp60_read_state(struct hubp *hubp);
bool hubp60_construct(
struct dcn20_hubp *hubp2,
struct dc_context *ctx,
uint32_t inst,
const struct dcn_hubp2_registers *hubp_regs,
const struct dcn_hubp2_shift *hubp_shift,
const struct dcn_hubp2_mask *hubp_mask);
#endif /* __DC_HUBP_DCN60_H__ */

View File

@@ -0,0 +1,759 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dm_services.h"
#include "dm_helpers.h"
#include "core_types.h"
#include "resource.h"
#include "dccg.h"
#include "dce/dce_hwseq.h"
#include "reg_helper.h"
#include "abm.h"
#include "hubp.h"
#include "dchubbub.h"
#include "timing_generator.h"
#include "opp.h"
#include "ipp.h"
#include "mpc.h"
#include "mcif_wb.h"
#include "dc_dmub_srv.h"
#include "link_hwss.h"
#include "dpcd_defs.h"
#include "clk_mgr.h"
#include "dsc.h"
#include "link_service.h"
#include "dce/dmub_hw_lock_mgr.h"
#include "dcn10/dcn10_cm_common.h"
#include "dcn20/dcn20_optc.h"
#include "dcn30/dcn30_cm_common.h"
#include "dcn32/dcn32_hwseq.h"
#include "dcn50_hwseq.h"
#include "dcn60/dcn60_resource.h"
#include "dcn401/dcn401_hwseq.h"
#include "dcn401/dcn401_resource.h"
#include "dc_state_priv.h"
#include "link_enc_cfg.h"
#include "dio/dcn10/dcn10_dio.h"
#define DC_LOGGER_INIT(logger)
#define CTX \
hws->ctx
#define REG(reg)\
hws->regs->reg
#define DC_LOGGER \
dc->ctx->logger
#undef FN
#define FN(reg_name, field_name) \
hws->shifts->field_name, hws->masks->field_name
static void dcn50_initialize_min_clocks(struct dc *dc)
{
struct dc_clocks *clocks = &dc->current_state->bw_ctx.bw.dcn.clk;
clocks->dcfclk_deep_sleep_khz = DCN3_2_DCFCLK_DS_INIT_KHZ;
clocks->dcfclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz * 1000;
clocks->socclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].socclk_mhz * 1000;
clocks->dramclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].memclk_mhz * 1000;
clocks->dppclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dppclk_mhz * 1000;
if (dc->debug.disable_boot_optimizations) {
clocks->dispclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dispclk_mhz * 1000;
} else {
/* Even though DPG_EN = 1 for the connected display, it still requires the
* correct timing so we cannot set DISPCLK to min freq or it could cause
* audio corruption. Read current DISPCLK from DENTIST and request the same
* freq to ensure that the timing is valid and unchanged.
*/
clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
}
clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
clocks->fclk_p_state_change_support = true;
clocks->p_state_change_support = true;
dc->clk_mgr->funcs->update_clocks(
dc->clk_mgr,
dc->current_state,
true);
}
void dcn50_update_dchubp_dpp(
struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct dc_state *context)
{
struct dce_hwseq *hws = dc->hwseq;
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
struct dc_plane_state *plane_state = pipe_ctx->plane_state;
struct dccg *dccg = dc->res_pool->dccg;
bool viewport_changed = false;
enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe_ctx);
if (pipe_ctx->update_flags.bits.dppclk)
dpp->funcs->dpp_dppclk_control(dpp, false, true);
if (pipe_ctx->update_flags.bits.enable)
dccg->funcs->update_dpp_dto(dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz);
/* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG
* VTG is within DCHUBBUB which is commond block share by each pipe HUBP.
* VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG
*/
if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {
hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst);
if (hubp->funcs->hubp_setup2) {
hubp->funcs->hubp_setup2(
hubp,
&pipe_ctx->hubp_regs,
&pipe_ctx->global_sync,
&pipe_ctx->stream->timing);
} else {
hubp->funcs->hubp_setup(
hubp,
&pipe_ctx->dlg_regs,
&pipe_ctx->ttu_regs,
&pipe_ctx->rq_regs,
&pipe_ctx->pipe_dlg_param);
}
}
if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting)
hubp->funcs->set_unbounded_requesting(hubp, pipe_ctx->unbounded_req);
if (pipe_ctx->update_flags.bits.hubp_interdependent) {
if (hubp->funcs->hubp_setup_interdependent2) {
hubp->funcs->hubp_setup_interdependent2(
hubp,
&pipe_ctx->hubp_regs);
} else {
hubp->funcs->hubp_setup_interdependent(
hubp,
&pipe_ctx->dlg_regs,
&pipe_ctx->ttu_regs);
}
}
if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.plane_changed ||
plane_state->update_bits.bpp_change ||
plane_state->update_bits.input_csc_change ||
plane_state->update_bits.color_space_change ||
plane_state->update_bits.coeff_reduction_change) {
struct dc_bias_and_scale bns_params = plane_state->bias_and_scale;
// program the input csc
dpp->funcs->dpp_setup(dpp,
plane_state->format,
EXPANSION_MODE_ZERO,
plane_state->input_csc_color_matrix,
plane_state->color_space,
NULL);
if (dpp->funcs->set_cursor_matrix) {
dpp->funcs->set_cursor_matrix(dpp,
plane_state->color_space,
plane_state->cursor_csc_color_matrix);
}
if (dpp->funcs->dpp_program_bias_and_scale) {
//TODO :for CNVC set scale and bias registers if necessary
dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params);
}
}
if (pipe_ctx->update_flags.bits.mpcc
|| pipe_ctx->update_flags.bits.plane_changed
|| plane_state->update_bits.global_alpha_change
|| plane_state->update_bits.per_pixel_alpha_change) {
// MPCC inst is equal to pipe index in practice
hws->funcs.update_mpcc(dc, pipe_ctx);
}
if (pipe_ctx->update_flags.bits.scaler ||
plane_state->update_bits.scaling_change ||
plane_state->update_bits.position_change ||
plane_state->update_bits.per_pixel_alpha_change ||
pipe_ctx->stream->update_flags.bits.scaling) {
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha;
ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP);
/* scaler configuration */
pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler(
pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
}
if (pipe_ctx->update_flags.bits.viewport ||
(context == dc->current_state && plane_state->update_bits.position_change) ||
(context == dc->current_state && plane_state->update_bits.scaling_change) ||
(context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
hubp->funcs->mem_program_viewport(
hubp,
&pipe_ctx->plane_res.scl_data.viewport,
&pipe_ctx->plane_res.scl_data.viewport_c);
viewport_changed = true;
}
/* Any updates are handled in dc interface, just need to apply existing for plane enable */
if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
if (dc->hwss.abort_cursor_offload_update)
dc->hwss.abort_cursor_offload_update(dc, pipe_ctx);
dc->hwss.set_cursor_attribute(pipe_ctx);
dc->hwss.set_cursor_position(pipe_ctx);
if (dc->hwss.set_cursor_sdr_white_level)
dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
}
/* Any updates are handled in dc interface, just need
* to apply existing for plane enable / opp change */
if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
|| pipe_ctx->update_flags.bits.plane_changed
|| pipe_ctx->stream->update_flags.bits.gamut_remap
|| plane_state->update_bits.gamut_remap_change
|| pipe_ctx->stream->update_flags.bits.out_csc) {
/* dpp/cm gamut remap*/
hwss_program_gamut_remap(pipe_ctx);
/*call the dcn2 method which uses mpc csc*/
dc->hwss.program_output_csc(dc,
pipe_ctx,
pipe_ctx->stream->output_color_space,
pipe_ctx->stream->csc_color_matrix.matrix,
hubp->opp_id);
}
if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.plane_changed ||
plane_state->update_bits.addr_update) {
if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) &&
pipe_mall_type == SUBVP_MAIN) {
union block_sequence_params params;
params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv;
params.subvp_save_surf_addr.addr = &pipe_ctx->plane_state->address;
params.subvp_save_surf_addr.subvp_index = pipe_ctx->subvp_index;
hwss_subvp_save_surf_addr(&params);
}
dc->hwss.update_plane_addr(dc, pipe_ctx);
}
if (pipe_ctx->update_flags.bits.enable)
hubp->funcs->set_blank(hubp, false);
/* If the stream paired with this plane is phantom, the plane is also phantom */
if (pipe_mall_type == SUBVP_PHANTOM && hubp->funcs->phantom_hubp_post_enable)
hubp->funcs->phantom_hubp_post_enable(hubp);
}
void dcn50_update_dchubp_dpp_sequence(struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct dc_state *context,
struct block_sequence_state *seq_state)
{
struct dce_hwseq *hws = dc->hwseq;
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct dpp *dpp = pipe_ctx->plane_res.dpp;
struct dc_plane_state *plane_state = pipe_ctx->plane_state;
struct dccg *dccg = dc->res_pool->dccg;
bool viewport_changed = false;
enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe_ctx);
if (!hubp || !dpp || !plane_state)
return;
/* Step 1: DPP DPPCLK control */
if (pipe_ctx->update_flags.bits.dppclk)
hwss_add_dpp_dppclk_control(seq_state, dpp, false, true);
/* Step 2: DCCG update DPP DTO */
if (pipe_ctx->update_flags.bits.enable)
hwss_add_dccg_update_dpp_dto(seq_state, dccg, dpp->inst, pipe_ctx->plane_res.bw.dppclk_khz);
/* Step 3: HUBP VTG selection */
if (pipe_ctx->update_flags.bits.hubp_rq_dlg_ttu) {
hwss_add_hubp_vtg_sel(seq_state, hubp, pipe_ctx->stream_res.tg->inst);
/* Step 4: HUBP setup (choose setup2 or setup) */
if (hubp->funcs->hubp_setup2) {
hwss_add_hubp_setup2(seq_state, hubp, &pipe_ctx->hubp_regs,
&pipe_ctx->global_sync, &pipe_ctx->stream->timing);
} else if (hubp->funcs->hubp_setup) {
hwss_add_hubp_setup(seq_state, hubp, &pipe_ctx->dlg_regs,
&pipe_ctx->ttu_regs, &pipe_ctx->rq_regs, &pipe_ctx->pipe_dlg_param);
}
}
/* Step 5: Set unbounded requesting */
if (pipe_ctx->update_flags.bits.unbounded_req && hubp->funcs->set_unbounded_requesting)
hwss_add_hubp_set_unbounded_requesting(seq_state, hubp, pipe_ctx->unbounded_req);
/* Step 6: HUBP interdependent setup */
if (pipe_ctx->update_flags.bits.hubp_interdependent) {
if (hubp->funcs->hubp_setup_interdependent2)
hwss_add_hubp_setup_interdependent2(seq_state, hubp, &pipe_ctx->hubp_regs);
else if (hubp->funcs->hubp_setup_interdependent)
hwss_add_hubp_setup_interdependent(seq_state, hubp, &pipe_ctx->dlg_regs, &pipe_ctx->ttu_regs);
}
/* Step 7: DPP setup - input CSC and format setup */
if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.plane_changed ||
plane_state->update_bits.bpp_change ||
plane_state->update_bits.input_csc_change ||
plane_state->update_bits.color_space_change ||
plane_state->update_bits.coeff_reduction_change) {
hwss_add_dpp_setup_dpp(seq_state, pipe_ctx);
/* Step 8: DPP cursor matrix setup */
if (dpp->funcs->set_cursor_matrix) {
hwss_add_dpp_set_cursor_matrix(seq_state, dpp, plane_state->color_space,
&plane_state->cursor_csc_color_matrix);
}
/* Step 9: DPP program bias and scale */
if (dpp->funcs->dpp_program_bias_and_scale)
hwss_add_dpp_program_bias_and_scale(seq_state, pipe_ctx);
}
/* Step 10: MPCC updates */
if (pipe_ctx->update_flags.bits.mpcc ||
pipe_ctx->update_flags.bits.plane_changed ||
plane_state->update_bits.global_alpha_change ||
plane_state->update_bits.per_pixel_alpha_change) {
/* Check if update_mpcc_sequence is implemented and prefer it over single MPC_UPDATE_MPCC step */
if (hws->funcs.update_mpcc_sequence)
hws->funcs.update_mpcc_sequence(dc, pipe_ctx, seq_state);
}
/* Step 11: DPP scaler setup */
if (pipe_ctx->update_flags.bits.scaler ||
plane_state->update_bits.scaling_change ||
plane_state->update_bits.position_change ||
plane_state->update_bits.per_pixel_alpha_change ||
pipe_ctx->stream->update_flags.bits.scaling) {
pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha;
ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP);
hwss_add_dpp_set_scaler(seq_state, pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data);
}
/* Step 12: HUBP viewport programming */
if (pipe_ctx->update_flags.bits.viewport ||
(context == dc->current_state && plane_state->update_bits.position_change) ||
(context == dc->current_state && plane_state->update_bits.scaling_change) ||
(context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) {
hwss_add_hubp_mem_program_viewport(seq_state, hubp,
&pipe_ctx->plane_res.scl_data.viewport, &pipe_ctx->plane_res.scl_data.viewport_c);
viewport_changed = true;
}
/* Step 13: Cursor attribute setup */
if ((pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
pipe_ctx->update_flags.bits.scaler || viewport_changed == true) &&
pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
hwss_add_abort_cursor_offload_update(seq_state, dc, pipe_ctx);
hwss_add_set_cursor_attribute(seq_state, dc, pipe_ctx);
/* Step 14: Cursor position setup */
hwss_add_set_cursor_position(seq_state, dc, pipe_ctx);
/* Step 15: Cursor SDR white level */
if (dc->hwss.set_cursor_sdr_white_level)
hwss_add_set_cursor_sdr_white_level(seq_state, dc, pipe_ctx);
}
/* Step 16: Gamut remap and output CSC */
if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed ||
pipe_ctx->update_flags.bits.plane_changed ||
pipe_ctx->stream->update_flags.bits.gamut_remap ||
plane_state->update_bits.gamut_remap_change ||
pipe_ctx->stream->update_flags.bits.out_csc) {
/* Gamut remap */
hwss_add_dpp_program_gamut_remap(seq_state, pipe_ctx);
/* Output CSC */
hwss_add_program_output_csc(seq_state, dc, pipe_ctx, pipe_ctx->stream->output_color_space,
pipe_ctx->stream->csc_color_matrix.matrix, hubp->opp_id);
}
/* Step 17: Update plane address (with SubVP support) */
if (pipe_ctx->update_flags.bits.enable ||
pipe_ctx->update_flags.bits.plane_changed ||
plane_state->update_bits.addr_update) {
/* SubVP save surface address if needed */
if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_mall_type == SUBVP_MAIN) {
hwss_add_dmub_subvp_save_surf_addr(seq_state, dc->ctx->dmub_srv,
&pipe_ctx->plane_state->address, pipe_ctx->subvp_index);
}
/* Update plane address */
hwss_add_hubp_update_plane_addr(seq_state, dc, pipe_ctx);
}
/* Step 18: HUBP set blank - enable plane */
if (pipe_ctx->update_flags.bits.enable)
hwss_add_hubp_set_blank(seq_state, hubp, false);
/* Step 19: Phantom HUBP post enable */
if (pipe_mall_type == SUBVP_PHANTOM && hubp->funcs->phantom_hubp_post_enable)
hwss_add_phantom_hubp_post_enable(seq_state, hubp);
}
void dcn50_update_mpcc_sequence(struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct block_sequence_state *seq_state)
{
struct hubp *hubp = pipe_ctx->plane_res.hubp;
struct mpcc_blnd_cfg blnd_cfg = {0};
bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha;
int mpcc_id;
struct mpcc *new_mpcc;
struct mpc *mpc = dc->res_pool->mpc;
struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
if (!hubp || !pipe_ctx->plane_state)
return;
/* Initialize blend configuration */
blnd_cfg.overlap_only = false;
blnd_cfg.global_gain = 0xfff;
if (per_pixel_alpha) {
blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha;
if (pipe_ctx->plane_state->global_alpha) {
blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
} else {
blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
}
} else {
blnd_cfg.pre_multiplied_alpha = false;
blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
}
if (pipe_ctx->plane_state->global_alpha)
blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
else
blnd_cfg.global_alpha = 0xfff;
blnd_cfg.background_color_bpc = 4;
blnd_cfg.bottom_gain_mode = 0;
blnd_cfg.top_gain = 0x1f000;
blnd_cfg.bottom_inside_gain = 0x1f000;
blnd_cfg.bottom_outside_gain = 0x1f000;
if (pipe_ctx->plane_state->format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
blnd_cfg.pre_multiplied_alpha = false;
/* MPCC instance is equal to HUBP instance */
mpcc_id = hubp->inst;
/* Step 1: Update blending if no full update needed */
if (!pipe_ctx->plane_state->update_bits.full_update &&
!pipe_ctx->update_flags.bits.mpcc) {
/* Update blending configuration */
hwss_add_mpc_update_blending(seq_state, mpc, blnd_cfg, mpcc_id);
/* Update visual confirm color */
hwss_add_mpc_update_visual_confirm(seq_state, dc, pipe_ctx, mpcc_id);
return;
}
/* Step 2: Get existing MPCC for DPP */
new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id);
/* Step 3: Remove MPCC if being used */
if (new_mpcc != NULL) {
hwss_add_mpc_remove_mpcc(seq_state, mpc, mpc_tree_params, new_mpcc);
} else {
/* Step 4: Assert MPCC idle (debug only) */
if (dc->debug.sanity_checks)
hwss_add_mpc_assert_idle_mpcc(seq_state, mpc, mpcc_id);
}
/* Step 5: Insert new plane into MPC tree */
hwss_add_mpc_insert_plane(seq_state, mpc, mpc_tree_params, blnd_cfg, NULL, NULL, hubp->inst, mpcc_id);
/* Step 6: Update visual confirm color */
hwss_add_mpc_update_visual_confirm(seq_state, dc, pipe_ctx, mpcc_id);
/* Step 7: Set HUBP OPP and MPCC IDs */
hubp->opp_id = pipe_ctx->stream_res.opp->inst;
hubp->mpcc_id = mpcc_id;
}
static void dcn50_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable)
{
REG_UPDATE(HPO_TOP_HW_CONTROL, HPO_IO_EN, enable);
}
void dcn50_program_front_end_for_ctx(
struct dc *dc,
struct dc_state *context)
{
if (resource_is_pipe_topology_changed(dc->current_state, context))
resource_log_pipe_topology_update(dc, context);
hwss_build_full_sequence(dc,
context->block_sequence,
&(context->block_sequence_steps),
context, false);
hwss_execute_sequence(dc,
context->block_sequence,
context->block_sequence_steps);
}
void dcn50_post_unlock_program_front_end(
struct dc *dc,
struct dc_state *context)
{
hwss_build_post_unlock_full_sequence(dc,
context->block_sequence,
&(context->block_sequence_steps),
context);
hwss_execute_sequence(dc,
context->block_sequence,
context->block_sequence_steps);
}
void dcn50_init_hw(struct dc *dc)
{
struct abm **abms = dc->res_pool->multiple_abms;
struct dce_hwseq *hws = dc->hwseq;
struct dc_bios *dcb = dc->ctx->dc_bios;
struct resource_pool *res_pool = dc->res_pool;
unsigned int i;
unsigned int edp_num;
uint32_t backlight = MAX_BACKLIGHT_LEVEL;
uint32_t user_level = MAX_BACKLIGHT_LEVEL;
int current_dchub_ref_freq = 0;
if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) {
dc->clk_mgr->funcs->init_clocks(dc->clk_mgr);
// mark dcmode limits present if any clock has distinct AC and DC values from SMU
dc->caps.dcmode_power_limits_present = dc->clk_mgr->funcs->is_dc_mode_present &&
dc->clk_mgr->funcs->is_dc_mode_present(dc->clk_mgr);
}
// Initialize the dccg
if (res_pool->dccg->funcs->dccg_init)
res_pool->dccg->funcs->dccg_init(res_pool->dccg);
// Disable DMUB Initialization until IPS state programming is finalized
//if (!dcb->funcs->is_accelerated_mode(dcb)) {
// hws->funcs.bios_golden_init(dc);
//}
// Set default OPTC memory power states
if (dc->debug.enable_mem_low_power.bits.optc) {
// Shutdown when unassigned and light sleep in VBLANK
REG_SET_2(ODM_MEM_PWR_CTRL3, 0, ODM_MEM_UNASSIGNED_PWR_MODE, 3, ODM_MEM_VBLANK_PWR_MODE, 1);
}
if (dc->debug.enable_mem_low_power.bits.vga) {
// Power down VGA memory
REG_UPDATE(MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, 1);
}
if (dc->ctx->dc_bios->fw_info_valid) {
res_pool->ref_clocks.xtalin_clock_inKhz =
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency;
if (res_pool->hubbub) {
(res_pool->dccg->funcs->get_dccg_ref_freq)(res_pool->dccg,
dc->ctx->dc_bios->fw_info.pll_info.crystal_frequency,
&res_pool->ref_clocks.dccg_ref_clock_inKhz);
current_dchub_ref_freq = res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000;
(res_pool->hubbub->funcs->get_dchub_ref_freq)(res_pool->hubbub,
res_pool->ref_clocks.dccg_ref_clock_inKhz,
&res_pool->ref_clocks.dchub_ref_clock_inKhz);
} else {
// Not all ASICs have DCCG sw component
res_pool->ref_clocks.dccg_ref_clock_inKhz =
res_pool->ref_clocks.xtalin_clock_inKhz;
res_pool->ref_clocks.dchub_ref_clock_inKhz =
res_pool->ref_clocks.xtalin_clock_inKhz;
}
} else
ASSERT_CRITICAL(false);
for (i = 0; i < dc->link_count; i++) {
/* Power up AND update implementation according to the
* required signal (which may be different from the
* default signal on connector).
*/
struct dc_link *link = dc->links[i];
link->link_enc->funcs->hw_init(link->link_enc);
/* Check for enabled DIG to identify enabled display */
if (link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
link->link_status.link_active = true;
link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
if (link->link_enc->funcs->fec_is_active &&
link->link_enc->funcs->fec_is_active(link->link_enc))
link->fec_state = dc_link_fec_enabled;
}
}
/* enable_power_gating_plane before dsc_pg_control because
* FORCEON = 1 with hw default value on bootup, resume from s3
*/
if (hws->funcs.enable_power_gating_plane)
hws->funcs.enable_power_gating_plane(dc->hwseq, true);
/* we want to turn off all dp displays before doing detection */
dc->link_srv->blank_all_dp_displays(dc);
/* If taking control over from VBIOS, we may want to optimize our first
* mode set, so we need to skip powering down pipes until we know which
* pipes we want to use.
* Otherwise, if taking control is not possible, we need to power
* everything down.
*/
if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
/* Disable boot optimizations means power down everything including PHY, DIG,
* and OTG (i.e. the boot is not optimized because we do a full power down).
*/
if (dc->hwss.enable_accelerated_mode && dc->debug.disable_boot_optimizations)
dc->hwss.enable_accelerated_mode(dc, dc->current_state);
else
hws->funcs.init_pipes(dc, dc->current_state);
if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
!dc->res_pool->hubbub->ctx->dc->debug.disable_stutter);
dcn50_initialize_min_clocks(dc);
/* On HW init, allow idle optimizations after pipes have been turned off.
*
* In certain D3 cases (i.e. BOCO / BOMACO) it's possible that hardware state
* is reset (i.e. not in idle at the time hw init is called), but software state
* still has idle_optimizations = true, so we must disable idle optimizations first
* (i.e. set false), then re-enable (set true).
*/
dc_allow_idle_optimizations(dc, false);
dc_allow_idle_optimizations(dc, true);
}
/* In headless boot cases, DIG may be turned
* on which causes HW/SW discrepancies.
* To avoid this, power down hardware on boot
* if DIG is turned on and seamless boot not enabled
*/
if (!dc->config.seamless_boot_edp_requested) {
struct dc_link *edp_links[MAX_NUM_EDP];
struct dc_link *edp_link;
dc_get_edp_links(dc, edp_links, &edp_num);
if (edp_num) {
for (i = 0; i < edp_num; i++) {
edp_link = edp_links[i];
if (edp_link->link_enc->funcs->is_dig_enabled &&
edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc) &&
dc->hwss.edp_backlight_control &&
hws->funcs.power_down &&
dc->hwss.edp_power_control) {
dc->hwss.edp_backlight_control(edp_link, false);
hws->funcs.power_down(dc);
dc->hwss.edp_power_control(edp_link, false);
}
}
} else {
for (i = 0; i < dc->link_count; i++) {
struct dc_link *link = dc->links[i];
if (link->link_enc->funcs->is_dig_enabled &&
link->link_enc->funcs->is_dig_enabled(link->link_enc) &&
hws->funcs.power_down) {
hws->funcs.power_down(dc);
break;
}
}
}
}
for (i = 0; i < res_pool->audio_count; i++) {
struct audio *audio = res_pool->audios[i];
audio->funcs->hw_init(audio);
}
for (i = 0; i < dc->link_count; i++) {
struct dc_link *link = dc->links[i];
if (link->panel_cntl) {
backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl);
user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL;
}
}
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (abms[i] != NULL && abms[i]->funcs != NULL)
abms[i]->funcs->abm_init(abms[i], backlight, user_level);
}
/* power AFMT HDMI memory TODO: may move to dis/en output save power*/
if (dc->res_pool->dio && dc->res_pool->dio->funcs->mem_pwr_ctrl)
dc->res_pool->dio->funcs->mem_pwr_ctrl(dc->res_pool->dio, false);
if (!dc->debug.disable_clock_gate) {
/* enable all DCN clock gating */
if (dc->res_pool->dccg && dc->res_pool->dccg->funcs && dc->res_pool->dccg->funcs->allow_clock_gating)
dc->res_pool->dccg->funcs->allow_clock_gating(dc->res_pool->dccg, true);
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
}
dcn50_setup_hpo_hw_control(hws, true);
if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->notify_wm_ranges)
dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
if (dc->res_pool->hubbub->funcs->force_pstate_change_control)
dc->res_pool->hubbub->funcs->force_pstate_change_control(
dc->res_pool->hubbub, false, false);
if (dc->res_pool->hubbub->funcs->init_crb)
dc->res_pool->hubbub->funcs->init_crb(dc->res_pool->hubbub);
if (dc->res_pool->hubbub->funcs->set_request_limit && dc->config.sdpif_request_limit_words_per_umc > 0)
dc->res_pool->hubbub->funcs->set_request_limit(dc->res_pool->hubbub,
dc->ctx->dc_bios->vram_info.num_chans, dc->config.sdpif_request_limit_words_per_umc);
// Get DMCUB capabilities
if (dc->ctx->dmub_srv) {
dc_dmub_srv_query_caps_cmd(dc->ctx->dmub_srv);
dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr;
dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0;
dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver;
dc->debug.fams2_config.bits.enable &=
dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support
if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box)
|| res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) {
/* update bounding box if FAMS2 disabled, or if dchub clk has changed */
if (dc->clk_mgr)
dc->res_pool->funcs->update_bw_bounding_box(dc, dc->clk_mgr->bw_params);
}
}
}

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DC_HWSS_DCN50_H__
#define __DC_HWSS_DCN50_H__
#include "inc/core_types.h"
#include "dc.h"
#include "dc_stream.h"
#include "hw_sequencer_private.h"
#include "dcn401/dcn401_dccg.h"
struct dc;
void dcn50_init_hw(struct dc *dc);
void dcn50_update_dchubp_dpp(
struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct dc_state *context);
void dcn50_update_dchubp_dpp_sequence(struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct dc_state *context,
struct block_sequence_state *seq_state);
void dcn50_update_mpcc_sequence(struct dc *dc,
struct pipe_ctx *pipe_ctx,
struct block_sequence_state *seq_state);
void dcn50_program_front_end_for_ctx(struct dc *dc, struct dc_state *context);
void dcn50_post_unlock_program_front_end(struct dc *dc, struct dc_state *context);
#endif /* __DC_HWSS_DCN50_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DC_HWSS_DCN60_H__
#define __DC_HWSS_DCN60_H__
#include "inc/core_types.h"
#include "dc.h"
#include "dc_stream.h"
#include "hw_sequencer_private.h"
#include "dcn401/dcn401_dccg.h"
struct dc;
enum dc_status dcn60_apply_ctx_to_hw(
struct dc *dc,
struct dc_state *context);
enum dc_status dcn60_apply_single_controller_ctx_to_hw(
struct pipe_ctx *pipe_ctx,
struct dc_state *context,
struct dc *dc);
void dcn60_init_hw(struct dc *dc);
void dcn60_set_cursor_attribute(struct pipe_ctx *pipe_ctx);
void dcn60_update_cursor_offload_pipe(struct dc *dc, const struct pipe_ctx *pipe);
void dcn60_program_perfmon(struct dc *dc, struct dc_state *context);
bool dcn60_apply_idle_power_optimizations(struct dc *dc, bool enable);
#endif /* __DC_HWSS_DCN60_H__ */

View File

@@ -0,0 +1,183 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dce110/dce110_hwseq.h"
#include "dcn10/dcn10_hwseq.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn21/dcn21_hwseq.h"
#include "dcn30/dcn30_hwseq.h"
#include "dcn31/dcn31_hwseq.h"
#include "dcn32/dcn32_hwseq.h"
#include "dcn35/dcn35_hwseq.h"
#include "dcn401/dcn401_hwseq.h"
#include "dcn42/dcn42_hwseq.h"
#include "dcn50/dcn50_hwseq.h"
#include "dcn60_init.h"
#include "dcn60_hwseq.h"
static const struct hw_sequencer_funcs dcn60_funcs = {
.program_gamut_remap = dcn401_program_gamut_remap,
.init_hw = dcn60_init_hw,
.apply_ctx_to_hw = dcn60_apply_ctx_to_hw,
.apply_ctx_for_surface = NULL,
.program_front_end_for_ctx = dcn50_program_front_end_for_ctx,
.wait_for_pending_cleared = dcn10_wait_for_pending_cleared,
.post_unlock_program_front_end = dcn50_post_unlock_program_front_end,
.update_plane_addr = dcn20_update_plane_addr,
.update_dchub = dcn10_update_dchub,
.update_pending_status = dcn10_update_pending_status,
.program_output_csc = dcn20_program_output_csc,
.trigger_3dlut_dma_load = dcn401_trigger_3dlut_dma_load,
.enable_accelerated_mode = dce110_enable_accelerated_mode,
.enable_timing_synchronization = dcn10_enable_timing_synchronization,
.enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset,
.update_info_frame = dcn31_update_info_frame,
.send_immediate_sdp_message = dcn10_send_immediate_sdp_message,
.enable_stream = dcn401_enable_stream,
.disable_stream = dce110_disable_stream,
.unblank_stream = dcn401_unblank_stream,
.blank_stream = dce110_blank_stream,
.enable_audio_stream = dce110_enable_audio_stream,
.disable_audio_stream = dce110_disable_audio_stream,
.disable_plane = dcn20_disable_plane,
.disable_plane_sequence = dcn401_disable_plane_sequence,
.pipe_control_lock = dcn20_pipe_control_lock,
.interdependent_update_lock = dcn401_interdependent_update_lock,
.cursor_lock = dcn10_cursor_lock,
.prepare_bandwidth = dcn401_prepare_bandwidth,
.prepare_bandwidth_sequence = dcn401_prepare_bandwidth_sequence,
.optimize_bandwidth = dcn401_optimize_bandwidth,
.optimize_bandwidth_sequence = dcn401_optimize_bandwidth_sequence,
.update_bandwidth = dcn20_update_bandwidth,
.set_drr = dcn10_set_drr,
.get_position = dcn10_get_position,
.set_static_screen_control = dcn35_set_static_screen_control,
.setup_stereo = dcn42_setup_stereo,
.set_avmute = dcn30_set_avmute,
.log_hw_state = dcn10_log_hw_state,
.get_hw_state = dcn10_get_hw_state,
.clear_status_bits = dcn10_clear_status_bits,
.wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect,
.wait_for_mpcc_disconnect_sequence = dcn401_wait_for_mpcc_disconnect_sequence,
.edp_backlight_control = dce110_edp_backlight_control,
.edp_power_control = dce110_edp_power_control,
.edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready,
.edp_wait_for_T12 = dce110_edp_wait_for_T12,
.set_cursor_position = dcn401_set_cursor_position,
.set_cursor_attribute = dcn60_set_cursor_attribute,
.set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level,
.abort_cursor_offload_update = dcn35_abort_cursor_offload_update,
.begin_cursor_offload_update = dcn35_begin_cursor_offload_update,
.commit_cursor_offload_update = dcn35_commit_cursor_offload_update,
.update_cursor_offload_pipe = dcn60_update_cursor_offload_pipe,
.notify_cursor_offload_drr_update = dcn35_notify_cursor_offload_drr_update,
.program_cursor_offload_now = dcn35_program_cursor_offload_now,
.setup_periodic_interrupt = dcn10_setup_periodic_interrupt,
.set_clock = dcn10_set_clock,
.get_clock = dcn10_get_clock,
.program_triplebuffer = dcn20_program_triple_buffer,
.enable_writeback = dcn30_enable_writeback,
.disable_writeback = dcn30_disable_writeback,
.update_writeback = dcn30_update_writeback,
.dmdata_status_done = dcn20_dmdata_status_done,
.program_dmdata_engine = dcn30_program_dmdata_engine,
.set_dmdata_attributes = dcn20_set_dmdata_attributes,
.init_sys_ctx = dcn31_init_sys_ctx,
.init_vm_ctx = dcn20_init_vm_ctx,
.set_flip_control_gsl = dcn20_set_flip_control_gsl,
.get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync,
.calc_vupdate_position = dcn10_calc_vupdate_position,
.setup_hdmi_frl_link = dcn30_setup_hdmi_frl_link,
.apply_idle_power_optimizations = dcn60_apply_idle_power_optimizations,
.does_plane_fit_in_mall = NULL,
.set_backlight_level = dcn21_set_backlight_level,
.set_abm_immediate_disable = dcn21_set_abm_immediate_disable,
.hardware_release = dcn401_hardware_release,
.set_pipe = dcn21_set_pipe,
.enable_lvds_link_output = dce110_enable_lvds_link_output,
.enable_tmds_link_output = dce110_enable_tmds_link_output,
.enable_dp_link_output = dce110_enable_dp_link_output,
.disable_link_output = dcn401_disable_link_output,
.set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
.enable_phantom_streams = NULL,
.disable_phantom_streams = NULL,
.update_visual_confirm_color = dcn10_update_visual_confirm_color,
.update_phantom_vp_position = NULL,
.update_dsc_pg = NULL,
.apply_update_flags_for_phantom = NULL,
.wait_for_dcc_meta_propagation = dcn401_wait_for_dcc_meta_propagation,
.is_pipe_topology_transition_seamless = dcn32_is_pipe_topology_transition_seamless,
.dmub_hw_control_lock = dcn401_dmub_hw_control_lock,
.fams2_update_config = dcn401_fams2_update_config,
.dmub_hw_control_lock_fast = dcn401_dmub_hw_control_lock_fast,
.program_outstanding_updates = dcn401_program_outstanding_updates,
.wait_for_all_pending_updates = dcn30_wait_for_all_pending_updates,
.detect_pipe_changes = dcn401_detect_pipe_changes,
.enable_plane = dcn20_enable_plane,
.enable_plane_sequence = dcn401_enable_plane_sequence,
.update_dchubp_dpp = dcn50_update_dchubp_dpp,
.update_dchubp_dpp_sequence = dcn50_update_dchubp_dpp_sequence,
.post_unlock_reset_opp = dcn20_post_unlock_reset_opp,
.post_unlock_reset_opp_sequence = dcn401_post_unlock_reset_opp_sequence,
.get_underflow_debug_data = dcn30_get_underflow_debug_data,
.program_perfmon = dcn60_program_perfmon,
};
static const struct hwseq_private_funcs dcn60_private_funcs = {
.init_pipes = dcn10_init_pipes,
.plane_atomic_disconnect = dcn10_plane_atomic_disconnect,
.plane_atomic_disconnect_sequence = dcn401_plane_atomic_disconnect_sequence,
.update_mpcc = dcn42_update_mpcc,
.update_mpcc_sequence = dcn50_update_mpcc_sequence,
.set_input_transfer_func = dcn32_set_input_transfer_func,
.set_output_transfer_func = dcn401_set_output_transfer_func,
.power_down = dce110_power_down,
.enable_display_power_gating = dcn10_dummy_display_power_gating,
.blank_pixel_data = dcn20_blank_pixel_data,
.blank_pixel_data_sequence = dcn401_blank_pixel_data_sequence,
.reset_hw_ctx_wrap = dcn401_reset_hw_ctx_wrap,
.enable_stream_timing = dcn401_enable_stream_timing,
.edp_backlight_control = dce110_edp_backlight_control,
.setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt,
.setup_vupdate_interrupt_sequence = dcn401_setup_vupdate_interrupt_sequence,
.did_underflow_occur = dcn10_did_underflow_occur,
.init_blank = dcn32_init_blank,
.disable_vga = NULL,
.bios_golden_init = dcn10_bios_golden_init,
.plane_atomic_disable = dcn20_plane_atomic_disable,
.plane_atomic_power_down = dcn401_plane_atomic_power_down,
.plane_atomic_power_down_sequence = dcn401_plane_atomic_power_down_sequence,
.enable_power_gating_plane = NULL,
.hubp_pg_control = NULL,
.program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree,
.program_all_writeback_pipes_in_tree_sequence = dcn401_program_all_writeback_pipes_in_tree_sequence,
.update_odm = dcn401_update_odm,
.update_odm_sequence = dcn401_update_odm_sequence,
.dsc_pg_control = NULL,
.dsc_pg_status = NULL,
.set_hdr_multiplier = dcn10_set_hdr_multiplier,
.set_hdr_multiplier_sequence = dcn401_set_hdr_multiplier_sequence,
.wait_for_blank_complete = dcn20_wait_for_blank_complete,
.set_mcm_luts = dcn42_set_mcm_luts,
.program_mall_pipe_config = NULL,
.update_mall_sel = NULL,
.calculate_dccg_k1_k2_values = NULL,
.apply_single_controller_ctx_to_hw = dcn60_apply_single_controller_ctx_to_hw,
.reset_back_end_for_pipe = dcn401_reset_back_end_for_pipe,
.populate_mcm_luts = NULL,
.perform_3dlut_wa_unlock = dcn401_perform_3dlut_wa_unlock,
.program_cm_hist = dcn42_program_cm_hist,
.program_pipe = dcn401_program_pipe,
.program_pipe_sequence = dcn401_program_pipe_sequence,
.wait_for_pipe_update_if_needed = dcn10_wait_for_pipe_update_if_needed,
.set_wait_for_update_needed_for_pipe = dcn10_set_wait_for_update_needed_for_pipe,
};
void dcn60_hw_sequencer_init_functions(struct dc *dc)
{
dc->hwss = dcn60_funcs;
dc->hwseq->funcs = dcn60_private_funcs;
}

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DC_DCN60_INIT_H__
#define __DC_DCN60_INIT_H__
struct dc;
void dcn60_hw_sequencer_init_functions(struct dc *dc);
#endif /* __DC_DCN60_INIT_H__ */

View File

@@ -0,0 +1,417 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2026 Advanced Micro Devices, Inc.
#include "dm_services.h"
#include "include/logger_interface.h"
#include "../dce110/irq_service_dce110.h"
#include "dcn/dcn_6_0_0_offset.h"
#include "dcn/dcn_6_0_0_sh_mask.h"
#include "irq_service_dcn60.h"
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
#define DCN_BASE__INST0_SEG2 0x000034C0
static enum dc_irq_source to_dal_irq_source_dcn60(
struct irq_service *irq_service,
uint32_t src_id,
uint32_t ext_id)
{
(void)irq_service;
(void)src_id;
(void)ext_id;
switch (src_id) {
case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP:
return DC_IRQ_SOURCE_VBLANK1;
case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
return DC_IRQ_SOURCE_VBLANK2;
case DCN_1_0__SRCID__DC_D3_OTG_VSTARTUP:
return DC_IRQ_SOURCE_VBLANK3;
case DCN_1_0__SRCID__DC_D4_OTG_VSTARTUP:
return DC_IRQ_SOURCE_VBLANK4;
case DCN_1_0__SRCID__DC_D5_OTG_VSTARTUP:
return DC_IRQ_SOURCE_VBLANK5;
case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
return DC_IRQ_SOURCE_VBLANK6;
case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
return DC_IRQ_SOURCE_DC1_VLINE0;
case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
return DC_IRQ_SOURCE_DC2_VLINE0;
case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
return DC_IRQ_SOURCE_DC3_VLINE0;
case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
return DC_IRQ_SOURCE_DC4_VLINE0;
case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
return DC_IRQ_SOURCE_DC5_VLINE0;
case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
return DC_IRQ_SOURCE_DC6_VLINE0;
case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
return DC_IRQ_SOURCE_PFLIP1;
case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
return DC_IRQ_SOURCE_PFLIP2;
case DCN_1_0__SRCID__HUBP2_FLIP_INTERRUPT:
return DC_IRQ_SOURCE_PFLIP3;
case DCN_1_0__SRCID__HUBP3_FLIP_INTERRUPT:
return DC_IRQ_SOURCE_PFLIP4;
case DCN_1_0__SRCID__HUBP4_FLIP_INTERRUPT:
return DC_IRQ_SOURCE_PFLIP5;
case DCN_1_0__SRCID__HUBP5_FLIP_INTERRUPT:
return DC_IRQ_SOURCE_PFLIP6;
case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
return DC_IRQ_SOURCE_VUPDATE1;
case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
return DC_IRQ_SOURCE_VUPDATE2;
case DCN_1_0__SRCID__OTG2_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
return DC_IRQ_SOURCE_VUPDATE3;
case DCN_1_0__SRCID__OTG3_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
return DC_IRQ_SOURCE_VUPDATE4;
case DCN_1_0__SRCID__OTG4_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
return DC_IRQ_SOURCE_VUPDATE5;
case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
return DC_IRQ_SOURCE_VUPDATE6;
case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
return DC_IRQ_SOURCE_DMCUB_OUTBOX;
case DCN_1_0__SRCID__DC_HPD1_INT:
/* generic src_id for all HPD and HPDRX interrupts */
switch (ext_id) {
case DCN_1_0__CTXID__DC_HPD1_INT:
return DC_IRQ_SOURCE_HPD1;
case DCN_1_0__CTXID__DC_HPD2_INT:
return DC_IRQ_SOURCE_HPD2;
case DCN_1_0__CTXID__DC_HPD3_INT:
return DC_IRQ_SOURCE_HPD3;
case DCN_1_0__CTXID__DC_HPD4_INT:
return DC_IRQ_SOURCE_HPD4;
case DCN_1_0__CTXID__DC_HPD5_INT:
return DC_IRQ_SOURCE_HPD5;
case DCN_1_0__CTXID__DC_HPD6_INT:
return DC_IRQ_SOURCE_HPD6;
case DCN_1_0__CTXID__DC_HPD1_RX_INT:
return DC_IRQ_SOURCE_HPD1RX;
case DCN_1_0__CTXID__DC_HPD2_RX_INT:
return DC_IRQ_SOURCE_HPD2RX;
case DCN_1_0__CTXID__DC_HPD3_RX_INT:
return DC_IRQ_SOURCE_HPD3RX;
case DCN_1_0__CTXID__DC_HPD4_RX_INT:
return DC_IRQ_SOURCE_HPD4RX;
case DCN_1_0__CTXID__DC_HPD5_RX_INT:
return DC_IRQ_SOURCE_HPD5RX;
case DCN_1_0__CTXID__DC_HPD6_RX_INT:
return DC_IRQ_SOURCE_HPD6RX;
default:
return DC_IRQ_SOURCE_INVALID;
}
break;
default:
return DC_IRQ_SOURCE_INVALID;
}
}
static struct irq_source_info_funcs hpd_irq_info_funcs = {
.set = NULL,
.ack = hpd0_ack
};
static struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
static struct irq_source_info_funcs pflip_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
static struct irq_source_info_funcs vblank_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
static struct irq_source_info_funcs outbox_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
static struct irq_source_info_funcs vline0_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
static struct irq_source_info_funcs vline1_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
static struct irq_source_info_funcs vline2_irq_info_funcs = {
.set = NULL,
.ack = NULL
};
#undef BASE_INNER
#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
/* compile time expand base address. */
#define BASE(seg) \
BASE_INNER(seg)
#define SRI(reg_name, block, id)\
BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
reg ## block ## id ## _ ## reg_name
#define SRI_DMUB(reg_name)\
BASE(reg ## reg_name ## _BASE_IDX) + \
reg ## reg_name
#define IRQ_REG_ENTRY(block, reg_num, reg1, mask1, reg2, mask2)\
.enable_reg = SRI(reg1, block, reg_num),\
.enable_mask = \
block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
.enable_value = {\
block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
(uint32_t)~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \
},\
.ack_reg = SRI(reg2, block, reg_num),\
.ack_mask = \
block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\
.ack_value = \
block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK \
#define IRQ_REG_ENTRY_DMUB(reg1, mask1, reg2, mask2)\
.enable_reg = SRI_DMUB(reg1),\
.enable_mask = \
reg1 ## __ ## mask1 ## _MASK,\
.enable_value = {\
reg1 ## __ ## mask1 ## _MASK,\
(uint32_t)~reg1 ## __ ## mask1 ## _MASK \
},\
.ack_reg = SRI_DMUB(reg2),\
.ack_mask = \
reg2 ## __ ## mask2 ## _MASK,\
.ack_value = \
reg2 ## __ ## mask2 ## _MASK \
#define hpd_int_entry(reg_num)\
[DC_IRQ_SOURCE_HPD1 + reg_num] = {\
IRQ_REG_ENTRY(HPD, reg_num,\
DC_HPD_INT_CONTROL, DC_HPD_INT_EN,\
DC_HPD_INT_CONTROL, DC_HPD_INT_ACK),\
.status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\
.funcs = &hpd_irq_info_funcs\
}
#define hpd_rx_int_entry(reg_num)\
[DC_IRQ_SOURCE_HPD1RX + reg_num] = {\
IRQ_REG_ENTRY(HPD, reg_num,\
DC_HPD_INT_CONTROL, DC_HPD_RX_INT_EN,\
DC_HPD_INT_CONTROL, DC_HPD_RX_INT_ACK),\
.status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\
.funcs = &hpd_rx_irq_info_funcs\
}
#define pflip_int_entry(reg_num)\
[DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
IRQ_REG_ENTRY(HUBPREQ, reg_num,\
DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK,\
DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_CLEAR),\
.funcs = &pflip_irq_info_funcs\
}
#define vblank_int_entry(reg_num)\
[DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\
IRQ_REG_ENTRY(OTG, reg_num,\
OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\
OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\
.funcs = &vblank_irq_info_funcs\
}
/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic
* of DCE's DC_IRQ_SOURCE_VUPDATEx.
*/
#define vupdate_no_lock_int_entry(reg_num)\
[DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
IRQ_REG_ENTRY(OTG, reg_num,\
OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\
OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\
.funcs = &vupdate_no_lock_irq_info_funcs\
}
#define vline0_int_entry(reg_num)\
[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num] = {\
IRQ_REG_ENTRY(OTG, reg_num,\
OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE,\
OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
.funcs = &vline0_irq_info_funcs\
}
#define vline1_int_entry(reg_num)\
[DC_IRQ_SOURCE_DC1_VLINE1 + reg_num] = {\
IRQ_REG_ENTRY(OTG, reg_num,\
OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE,\
OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_CLEAR),\
.funcs = &vline1_irq_info_funcs\
}
#define vline2_int_entry(reg_num)\
[DC_IRQ_SOURCE_DC1_VLINE2 + reg_num] = {\
IRQ_REG_ENTRY(OTG, reg_num,\
OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE,\
OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_CLEAR),\
.funcs = &vline2_irq_info_funcs\
}
#define dmub_outbox_int_entry()\
[DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
IRQ_REG_ENTRY_DMUB(\
DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
DMCUB_INTERRUPT_ACK, DMCUB_OUTBOX1_READY_INT_ACK),\
.funcs = &outbox_irq_info_funcs\
}
#define dummy_irq_entry() \
{\
.funcs = &dummy_irq_info_funcs\
}
#define i2c_int_entry(reg_num) \
[DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
#define dp_sink_int_entry(reg_num) \
[DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
#define gpio_pad_int_entry(reg_num) \
[DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
#define dc_underflow_int_entry(reg_num) \
[DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
static struct irq_source_info_funcs dummy_irq_info_funcs = {
.set = dal_irq_service_dummy_set,
.ack = dal_irq_service_dummy_ack
};
static const struct irq_source_info
irq_source_info_dcn60[DAL_IRQ_SOURCES_NUMBER] = {
[DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
hpd_int_entry(0),
hpd_int_entry(1),
hpd_int_entry(2),
hpd_int_entry(3),
hpd_rx_int_entry(0),
hpd_rx_int_entry(1),
hpd_rx_int_entry(2),
hpd_rx_int_entry(3),
i2c_int_entry(1),
i2c_int_entry(2),
i2c_int_entry(3),
i2c_int_entry(4),
i2c_int_entry(5),
i2c_int_entry(6),
dp_sink_int_entry(1),
dp_sink_int_entry(2),
dp_sink_int_entry(3),
dp_sink_int_entry(4),
dp_sink_int_entry(5),
dp_sink_int_entry(6),
[DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
pflip_int_entry(0),
pflip_int_entry(1),
pflip_int_entry(2),
pflip_int_entry(3),
[DC_IRQ_SOURCE_PFLIP5] = dummy_irq_entry(),
[DC_IRQ_SOURCE_PFLIP6] = dummy_irq_entry(),
[DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
gpio_pad_int_entry(0),
gpio_pad_int_entry(1),
gpio_pad_int_entry(2),
gpio_pad_int_entry(3),
gpio_pad_int_entry(4),
gpio_pad_int_entry(5),
gpio_pad_int_entry(6),
gpio_pad_int_entry(7),
gpio_pad_int_entry(8),
gpio_pad_int_entry(9),
gpio_pad_int_entry(10),
gpio_pad_int_entry(11),
gpio_pad_int_entry(12),
gpio_pad_int_entry(13),
gpio_pad_int_entry(14),
gpio_pad_int_entry(15),
gpio_pad_int_entry(16),
gpio_pad_int_entry(17),
gpio_pad_int_entry(18),
gpio_pad_int_entry(19),
gpio_pad_int_entry(20),
gpio_pad_int_entry(21),
gpio_pad_int_entry(22),
gpio_pad_int_entry(23),
gpio_pad_int_entry(24),
gpio_pad_int_entry(25),
gpio_pad_int_entry(26),
gpio_pad_int_entry(27),
gpio_pad_int_entry(28),
gpio_pad_int_entry(29),
gpio_pad_int_entry(30),
dc_underflow_int_entry(1),
dc_underflow_int_entry(2),
dc_underflow_int_entry(3),
dc_underflow_int_entry(4),
dc_underflow_int_entry(5),
dc_underflow_int_entry(6),
[DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
[DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
vblank_int_entry(0),
vblank_int_entry(1),
vblank_int_entry(2),
vblank_int_entry(3),
[DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
[DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
dmub_outbox_int_entry(),
vupdate_no_lock_int_entry(0),
vupdate_no_lock_int_entry(1),
vupdate_no_lock_int_entry(2),
vupdate_no_lock_int_entry(3),
vline0_int_entry(0),
vline0_int_entry(1),
vline0_int_entry(2),
vline0_int_entry(3),
vline1_int_entry(0),
vline1_int_entry(1),
vline1_int_entry(2),
vline1_int_entry(3),
vline2_int_entry(0),
vline2_int_entry(1),
vline2_int_entry(2),
vline2_int_entry(3),
};
static const struct irq_service_funcs irq_service_funcs_dcn60 = {
.to_dal_irq_source = to_dal_irq_source_dcn60
};
static void dcn60_irq_construct(
struct irq_service *irq_service,
struct irq_service_init_data *init_data)
{
dal_irq_service_construct(irq_service, init_data);
irq_service->info = irq_source_info_dcn60;
irq_service->funcs = &irq_service_funcs_dcn60;
}
struct irq_service *dal_irq_service_dcn60_create(
struct irq_service_init_data *init_data)
{
struct irq_service *irq_service = kzalloc(sizeof(*irq_service),
GFP_KERNEL);
if (!irq_service)
return NULL;
dcn60_irq_construct(irq_service, init_data);
return irq_service;
}

View File

@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2026 Advanced Micro Devices, Inc.
#ifndef __DAL_IRQ_SERVICE_DCN60_H__
#define __DAL_IRQ_SERVICE_DCN60_H__
#include "../irq_service.h"
struct irq_service *dal_irq_service_dcn60_create(
struct irq_service_init_data *init_data);
#endif /* __DAL_IRQ_SERVICE_DCN60_H__ */

View File

@@ -0,0 +1,379 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "reg_helper.h"
#include "dc.h"
#include "dcn60_mpc.h"
#include "dcn10/dcn10_cm_common.h"
#include "basics/conversion.h"
#include "mpc.h"
#define REG(reg)\
mpc60->mpc_regs->reg
#define CTX \
mpc60->base.ctx
#undef FN
#define FN(reg_name, field_name) \
mpc60->mpc_shift->field_name, mpc60->mpc_mask->field_name
/*
* Insert DPP into MPC tree based on specified blending position.
* Only used for planes that are part of blending chain for OPP output
*
* Parameters:
* [in/out] mpc - MPC context.
* [in/out] tree - MPC tree structure that plane will be added to.
* [in] blnd_cfg - MPCC blending configuration for the new blending layer.
* [in] sm_cfg - MPCC stereo mix configuration for the new blending layer.
* stereo mix must disable for the very bottom layer of the tree config.
* [in] insert_above_mpcc - Insert new plane above this MPCC. If NULL, insert as bottom plane.
* [in] dpp_id - DPP instance for the plane to be added.
* [in] mpcc_id - The MPCC physical instance to use for blending.
*
* Return: struct mpcc* - MPCC that was added.
*/
static struct mpcc *mpc60_insert_plane(
struct mpc *mpc,
struct mpc_tree *tree,
struct mpcc_blnd_cfg *blnd_cfg,
struct mpcc_sm_cfg *sm_cfg,
struct mpcc *insert_above_mpcc,
int dpp_id,
int mpcc_id)
{
(void)sm_cfg;
struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
struct mpcc *new_mpcc = NULL;
/* sanity check parameters */
ASSERT(mpcc_id < mpc60->num_mpcc);
ASSERT(!(mpc60->mpcc_in_use_mask & 1 << mpcc_id));
if (insert_above_mpcc) {
/* check insert_above_mpcc exist in tree->opp_list */
struct mpcc *temp_mpcc = tree->opp_list;
if (temp_mpcc != insert_above_mpcc)
while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
temp_mpcc = temp_mpcc->mpcc_bot;
if (temp_mpcc == NULL)
return NULL;
}
/* Get and update MPCC struct parameters */
new_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
new_mpcc->dpp_id = dpp_id;
/* program mux and MPCC_MODE */
if (insert_above_mpcc) {
new_mpcc->mpcc_bot = insert_above_mpcc;
REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, insert_above_mpcc->mpcc_id);
REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
} else {
new_mpcc->mpcc_bot = NULL;
REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_ONLY);
}
REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id);
REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id);
/* Configure VUPDATE lock set for this MPCC to map to the OPP */
REG_SET(MPCC_UPDATE_LOCK_SEL[mpcc_id], 0, MPCC_UPDATE_LOCK_SEL, tree->opp_id);
/* update mpc tree mux setting */
if (tree->opp_list == insert_above_mpcc) {
/* insert the toppest mpcc */
tree->opp_list = new_mpcc;
REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id);
} else {
/* find insert position */
struct mpcc *temp_mpcc = tree->opp_list;
while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
temp_mpcc = temp_mpcc->mpcc_bot;
if (temp_mpcc && temp_mpcc->mpcc_bot == insert_above_mpcc) {
REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, MPCC_BOT_SEL, mpcc_id);
temp_mpcc->mpcc_bot = new_mpcc;
if (!insert_above_mpcc)
REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
}
}
/* update the blending configuration */
mpc->funcs->update_blending(mpc, blnd_cfg, mpcc_id);
/* mark this mpcc as in use */
mpc60->mpcc_in_use_mask |= 1 << mpcc_id;
return new_mpcc;
}
void mpc60_program_rmcm_lut_read_write_control(struct mpc *mpc, const enum MCM_LUT_ID id,
bool lut_bank_a, bool enabled, int mpcc_id)
{
struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
switch (id) {
case MCM_LUT_3DLUT:
REG_UPDATE(MPC_RMCM_3DLUT_MODE[mpcc_id], MPC_RMCM_3DLUT_MODE,
(!enabled) ? 0 :
(lut_bank_a) ? 1 : 2);
break;
case MCM_LUT_SHAPER:
REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, 7);
REG_UPDATE(MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK[mpcc_id],
MPC_RMCM_SHAPER_LUT_WRITE_SEL,
lut_bank_a == true ? 0 : 1);
REG_SET(MPC_RMCM_SHAPER_LUT_INDEX[mpcc_id], 0,
MPC_RMCM_SHAPER_LUT_INDEX, 0);
break;
default:
break;
}
}
void mpc60_select_3dlut_ram(
struct mpc *mpc,
enum dc_lut_mode mode,
bool is_color_channel_12bits,
uint32_t mpcc_id)
{
(void)mode;
struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
REG_UPDATE(MPCC_MCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
MPCC_MCM_3DLUT_30BIT_EN, is_color_channel_12bits == true ? 0 : 1);
}
static enum dc_lut_mode get3dlut_config(
struct mpc *mpc,
bool *is_17x17x17,
bool *is_12bits_color_channel,
int mpcc_id)
{
uint32_t i_mode, i_enable_10bits, lut_size;
enum dc_lut_mode mode;
struct dcn60_mpc *mpc60 = TO_DCN60_MPC(mpc);
REG_GET(MPCC_MCM_3DLUT_MODE[mpcc_id],
MPCC_MCM_3DLUT_MODE_CURRENT, &i_mode);
REG_GET(MPCC_MCM_3DLUT_READ_WRITE_CONTROL[mpcc_id],
MPCC_MCM_3DLUT_30BIT_EN, &i_enable_10bits);
switch (i_mode) {
case 0:
mode = LUT_BYPASS;
break;
case 1:
mode = LUT_RAM_A;
break;
case 2:
mode = LUT_RAM_B;
break;
default:
mode = LUT_BYPASS;
break;
}
if (i_enable_10bits > 0)
*is_12bits_color_channel = false;
else
*is_12bits_color_channel = true;
REG_GET(MPCC_MCM_3DLUT_MODE[mpcc_id], MPCC_MCM_3DLUT_SIZE, &lut_size);
if (lut_size == 0)
*is_17x17x17 = true;
else
*is_17x17x17 = false;
return mode;
}
bool mpc60_program_3dlut(
struct mpc *mpc,
const struct tetrahedral_params *params,
int mpcc_id)
{
enum dc_lut_mode mode;
bool is_17x17x17;
bool is_12bits_color_channel;
const struct dc_rgb *lut0;
const struct dc_rgb *lut1;
const struct dc_rgb *lut2;
const struct dc_rgb *lut3;
int lut_size0;
int lut_size;
if (params == NULL) {
mpc32_set_3dlut_mode(mpc, LUT_BYPASS, false, false, mpcc_id);
return false;
}
mpc32_power_on_shaper_3dlut(mpc, mpcc_id, true);
mode = get3dlut_config(mpc, &is_17x17x17, &is_12bits_color_channel, mpcc_id);
if (mode == LUT_BYPASS || mode == LUT_RAM_B)
mode = LUT_RAM_A;
else
mode = LUT_RAM_B;
is_17x17x17 = !params->use_tetrahedral_9;
is_12bits_color_channel = params->use_12bits;
if (is_17x17x17) {
lut0 = params->tetrahedral_17.lut0;
lut1 = params->tetrahedral_17.lut1;
lut2 = params->tetrahedral_17.lut2;
lut3 = params->tetrahedral_17.lut3;
lut_size0 = sizeof(params->tetrahedral_17.lut0) /
sizeof(params->tetrahedral_17.lut0[0]);
lut_size = sizeof(params->tetrahedral_17.lut1) /
sizeof(params->tetrahedral_17.lut1[0]);
} else {
lut0 = params->tetrahedral_9.lut0;
lut1 = params->tetrahedral_9.lut1;
lut2 = params->tetrahedral_9.lut2;
lut3 = params->tetrahedral_9.lut3;
lut_size0 = sizeof(params->tetrahedral_9.lut0) /
sizeof(params->tetrahedral_9.lut0[0]);
lut_size = sizeof(params->tetrahedral_9.lut1) /
sizeof(params->tetrahedral_9.lut1[0]);
}
mpc60_select_3dlut_ram(mpc, mode,
is_12bits_color_channel, mpcc_id);
mpc32_select_3dlut_ram_mask(mpc, 0x1, mpcc_id);
if (is_12bits_color_channel)
mpc32_set3dlut_ram12(mpc, lut0, lut_size0, mpcc_id);
else
mpc32_set3dlut_ram10(mpc, lut0, lut_size0, mpcc_id);
mpc32_select_3dlut_ram_mask(mpc, 0x2, mpcc_id);
if (is_12bits_color_channel)
mpc32_set3dlut_ram12(mpc, lut1, lut_size, mpcc_id);
else
mpc32_set3dlut_ram10(mpc, lut1, lut_size, mpcc_id);
mpc32_select_3dlut_ram_mask(mpc, 0x4, mpcc_id);
if (is_12bits_color_channel)
mpc32_set3dlut_ram12(mpc, lut2, lut_size, mpcc_id);
else
mpc32_set3dlut_ram10(mpc, lut2, lut_size, mpcc_id);
mpc32_select_3dlut_ram_mask(mpc, 0x8, mpcc_id);
if (is_12bits_color_channel)
mpc32_set3dlut_ram12(mpc, lut3, lut_size, mpcc_id);
else
mpc32_set3dlut_ram10(mpc, lut3, lut_size, mpcc_id);
mpc32_set_3dlut_mode(mpc, mode, is_12bits_color_channel,
is_17x17x17, mpcc_id);
if (mpc->ctx->dc->debug.enable_mem_low_power.bits.mpc)
mpc32_power_on_shaper_3dlut(mpc, mpcc_id, false);
return true;
}
void mpc60_program_lut_read_write_control(struct mpc *mpc, const enum MCM_LUT_ID id, bool lut_bank_a, int mpcc_id)
{
switch (id) {
case MCM_LUT_3DLUT:
mpc32_select_3dlut_ram_mask(mpc, 0xf, mpcc_id);
break;
case MCM_LUT_SHAPER:
mpc32_configure_shaper_lut(mpc, lut_bank_a, mpcc_id);
break;
case MCM_LUT_1DLUT:
mpc32_configure_post1dlut(mpc, lut_bank_a, mpcc_id);
break;
}
}
static const struct mpc_funcs dcn60_mpc_funcs = {
.read_mpcc_state = mpc1_read_mpcc_state,
.insert_plane = mpc60_insert_plane,
.remove_mpcc = mpc1_remove_mpcc,
.mpc_init = mpc32_mpc_init,
.mpc_init_single_inst = mpc3_mpc_init_single_inst,
.update_blending = mpc42_update_blending,
.cursor_lock = mpc1_cursor_lock,
.get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp,
.wait_for_idle = mpc2_assert_idle_mpcc,
.assert_mpcc_idle_before_connect = mpc2_assert_mpcc_idle_before_connect,
.init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw,
.set_denorm = mpc3_set_denorm,
.set_denorm_clamp = mpc3_set_denorm_clamp,
.set_output_csc = mpc3_set_output_csc,
.set_ocsc_default = mpc3_set_ocsc_default,
.set_output_gamma = mpc3_set_output_gamma,
.set_gamut_remap = mpc401_set_gamut_remap,
.program_shaper = mpc32_program_shaper,
.program_3dlut = mpc60_program_3dlut,
.program_1dlut = mpc32_program_post1dlut,
.power_on_mpc_mem_pwr = mpc3_power_on_ogam_lut,
.get_mpc_out_mux = mpc1_get_mpc_out_mux,
.mpc_read_reg_state = mpc3_read_reg_state,
.set_bg_color = mpc1_set_bg_color,
.set_movable_cm_location = mpc401_set_movable_cm_location,
.update_3dlut_fast_load_select = mpc401_update_3dlut_fast_load_select,
.get_3dlut_fast_load_status = mpc401_get_3dlut_fast_load_status,
.populate_lut = mpc401_populate_lut,
.program_lut_read_write_control = mpc60_program_lut_read_write_control,
.program_lut_mode = mpc401_program_lut_mode,
.mcm = {
.program_lut_read_write_control = mpc42_program_lut_read_write_control,
.program_3dlut_size = mpc42_program_3dlut_size,
.program_bias_scale = mpc42_program_3dlut_fl_bias_scale,
.program_bit_depth = mpc42_program_bit_depth,
.is_config_supported = mpc42_is_config_supported,
.populate_lut = mpc42_populate_lut,
},
.rmcm = {
.enable_3dlut_fl = mpc42_enable_3dlut_fl,
.update_3dlut_fast_load_select = mpc42_update_3dlut_fast_load_select,
.program_lut_read_write_control = mpc60_program_rmcm_lut_read_write_control,
.program_lut_mode = mpc42_program_lut_mode,
.program_3dlut_size = mpc42_program_rmcm_3dlut_size,
.program_bias_scale = mpc42_program_rmcm_3dlut_fast_load_bias_scale,
.program_bit_depth = mpc42_program_rmcm_bit_depth,
.is_config_supported = mpc42_is_rmcm_config_supported,
.power_on_shaper_3dlut = mpc42_power_on_rmcm_shaper_3dlut,
.populate_lut = mpc42_populate_rmcm_lut,
},
};
void dcn60_mpc_construct(struct dcn60_mpc *mpc60,
struct dc_context *ctx,
const struct dcn60_mpc_registers *mpc_regs,
const struct dcn60_mpc_shift *mpc_shift,
const struct dcn60_mpc_mask *mpc_mask,
int num_mpcc,
int num_rmu)
{
int i;
mpc60->base.ctx = ctx;
mpc60->base.funcs = &dcn60_mpc_funcs;
mpc60->mpc_regs = mpc_regs;
mpc60->mpc_shift = mpc_shift;
mpc60->mpc_mask = mpc_mask;
mpc60->mpcc_in_use_mask = 0;
mpc60->num_mpcc = num_mpcc;
mpc60->num_rmu = num_rmu;
for (i = 0; i < MAX_MPCC; i++)
mpc42_init_mpcc(&mpc60->base.mpcc_array[i], i);
}

View File

@@ -0,0 +1,487 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#ifndef __DC_MPCC_DCN60_H__
#define __DC_MPCC_DCN60_H__
#include "dcn401/dcn401_mpc.h"
#include "dcn42/dcn42_mpc.h"
#define TO_DCN60_MPC(mpc_base) \
container_of(mpc_base, struct dcn60_mpc, base)
#define MPC_REG_VARIABLE_LIST_DCN6_0 \
MPC_REG_VARIABLE_LIST_DCN42
#define MPC_COMMON_MASK_SH_LIST_DCN6_0(mask_sh) \
SF(MPCC0_MPCC_TOP_SEL, MPCC_TOP_SEL, mask_sh),\
SF(MPCC0_MPCC_BOT_SEL, MPCC_BOT_SEL, mask_sh),\
SF(MPCC0_MPCC_CONTROL, MPCC_MODE, mask_sh),\
SF(MPCC0_MPCC_CONTROL, MPCC_ALPHA_BLND_MODE, mask_sh),\
SF(MPCC0_MPCC_CONTROL, MPCC_ALPHA_MULTIPLIED_MODE, mask_sh),\
SF(MPCC0_MPCC_CONTROL, MPCC_BLND_ACTIVE_OVERLAP_ONLY, mask_sh),\
SF(MPCC0_MPCC_CONTROL2, MPCC_GLOBAL_ALPHA, mask_sh),\
SF(MPCC0_MPCC_CONTROL2, MPCC_GLOBAL_GAIN, mask_sh),\
SF(MPCC0_MPCC_STATUS, MPCC_IDLE, mask_sh),\
SF(MPCC0_MPCC_STATUS, MPCC_BUSY, mask_sh),\
SF(MPCC0_MPCC_OPP_ID, MPCC_OPP_ID, mask_sh),\
SF(MPCC0_MPCC_BG_G_Y, MPCC_BG_G_Y, mask_sh),\
SF(MPCC0_MPCC_BG_R_CR, MPCC_BG_R_CR, mask_sh),\
SF(MPCC0_MPCC_BG_B_CB, MPCC_BG_B_CB, mask_sh),\
SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_EN, mask_sh),\
SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_MODE, mask_sh),\
SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FRAME_ALT, mask_sh),\
SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FORCE_NEXT_FRAME_POL, mask_sh),\
SF(MPCC0_MPCC_UPDATE_LOCK_SEL, MPCC_UPDATE_LOCK_SEL, mask_sh),\
SF(MPCC0_MPCC_CONTROL, MPCC_BG_BPC, mask_sh),\
SF(MPCC0_MPCC_CONTROL, MPCC_BOT_GAIN_MODE, mask_sh),\
SF(MPCC0_MPCC_TOP_GAIN, MPCC_TOP_GAIN, mask_sh),\
SF(MPCC0_MPCC_BOT_GAIN_INSIDE, MPCC_BOT_GAIN_INSIDE, mask_sh),\
SF(MPCC0_MPCC_BOT_GAIN_OUTSIDE, MPCC_BOT_GAIN_OUTSIDE, mask_sh),\
SF(MPCC0_MPCC_MOVABLE_CM_LOCATION_CONTROL, MPCC_MOVABLE_CM_LOCATION_CNTL, mask_sh),\
SF(MPCC0_MPCC_MOVABLE_CM_LOCATION_CONTROL, MPCC_MOVABLE_CM_LOCATION_CNTL_CURRENT, mask_sh),\
SF(MPCC0_MPCC_STATUS, MPCC_DISABLED, mask_sh),\
SF(MPCC0_MPCC_MEM_PWR_CTRL, MPCC_OGAM_MEM_PWR_FORCE, mask_sh),\
SF(MPCC0_MPCC_MEM_PWR_CTRL, MPCC_OGAM_MEM_PWR_DIS, mask_sh),\
SF(MPCC0_MPCC_MEM_PWR_CTRL, MPCC_OGAM_MEM_LOW_PWR_MODE, mask_sh),\
SF(MPCC0_MPCC_MEM_PWR_CTRL, MPCC_OGAM_MEM_PWR_STATE, mask_sh),\
SF(MPCC_OGAM0_MPCC_GAMUT_REMAP_MODE, MPCC_GAMUT_REMAP_MODE, mask_sh),\
SF(MPCC_OGAM0_MPCC_GAMUT_REMAP_MODE, MPCC_GAMUT_REMAP_MODE_CURRENT, mask_sh),\
SF(MPCC_OGAM0_MPCC_GAMUT_REMAP_COEF_FORMAT, MPCC_GAMUT_REMAP_COEF_FORMAT, mask_sh),\
SF(MPCC_OGAM0_MPC_GAMUT_REMAP_C11_C12_A, MPCC_GAMUT_REMAP_C11_A, mask_sh),\
SF(MPCC_OGAM0_MPC_GAMUT_REMAP_C11_C12_A, MPCC_GAMUT_REMAP_C12_A, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_END_CNTL2_B, MPCC_OGAM_RAMA_EXP_REGION_END_SLOPE_B, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_END_CNTL2_B, MPCC_OGAM_RAMA_EXP_REGION_END_B, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_END_CNTL1_B, MPCC_OGAM_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_START_SLOPE_CNTL_B, MPCC_OGAM_RAMA_EXP_REGION_START_SLOPE_B, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_START_BASE_CNTL_B, MPCC_OGAM_RAMA_EXP_REGION_START_BASE_B, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_START_CNTL_B, MPCC_OGAM_RAMA_EXP_REGION_START_B, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_START_CNTL_B, MPCC_OGAM_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_OFFSET_B, MPCC_OGAM_RAMA_OFFSET_B, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_OFFSET_G, MPCC_OGAM_RAMA_OFFSET_G, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_RAMA_OFFSET_R, MPCC_OGAM_RAMA_OFFSET_R, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_LUT_INDEX, MPCC_OGAM_LUT_INDEX, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_CONTROL, MPCC_OGAM_MODE, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_CONTROL, MPCC_OGAM_SELECT, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_CONTROL, MPCC_OGAM_PWL_DISABLE, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_CONTROL, MPCC_OGAM_MODE_CURRENT, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_CONTROL, MPCC_OGAM_SELECT_CURRENT, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_LUT_CONTROL, MPCC_OGAM_LUT_WRITE_COLOR_MASK, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_LUT_CONTROL, MPCC_OGAM_LUT_READ_COLOR_SEL, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_LUT_CONTROL, MPCC_OGAM_LUT_HOST_SEL, mask_sh),\
SF(MPCC_OGAM0_MPCC_OGAM_LUT_DATA, MPCC_OGAM_LUT_DATA, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_MODE, MPCC_MCM_3DLUT_MODE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_MODE, MPCC_MCM_3DLUT_SIZE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_MODE, MPCC_MCM_3DLUT_MODE_CURRENT, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_READ_WRITE_CONTROL, MPCC_MCM_3DLUT_WRITE_EN_MASK, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_READ_WRITE_CONTROL, MPCC_MCM_3DLUT_30BIT_EN, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_READ_WRITE_CONTROL, MPCC_MCM_3DLUT_READ_SEL, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_INDEX, MPCC_MCM_3DLUT_INDEX, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_DATA, MPCC_MCM_3DLUT_DATA0, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_DATA, MPCC_MCM_3DLUT_DATA1, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_DATA_30BIT, MPCC_MCM_3DLUT_DATA_30BIT, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_CONTROL, MPCC_MCM_SHAPER_LUT_MODE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_CONTROL, MPCC_MCM_SHAPER_MODE_CURRENT, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_OFFSET_R, MPCC_MCM_SHAPER_OFFSET_R, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_OFFSET_G, MPCC_MCM_SHAPER_OFFSET_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_OFFSET_B, MPCC_MCM_SHAPER_OFFSET_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_SCALE_R, MPCC_MCM_SHAPER_SCALE_R, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_SCALE_G_B, MPCC_MCM_SHAPER_SCALE_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_SCALE_G_B, MPCC_MCM_SHAPER_SCALE_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_LUT_INDEX, MPCC_MCM_SHAPER_LUT_INDEX, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_LUT_DATA, MPCC_MCM_SHAPER_LUT_DATA, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_LUT_WRITE_EN_MASK, MPCC_MCM_SHAPER_LUT_WRITE_EN_MASK, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_LUT_WRITE_EN_MASK, MPCC_MCM_SHAPER_LUT_WRITE_SEL, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_RAMA_START_CNTL_B, MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_RAMA_START_CNTL_B, MPCC_MCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_RAMA_END_CNTL_B, MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_RAMA_END_CNTL_B, MPCC_MCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_RAMA_REGION_0_1, MPCC_MCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_RAMA_REGION_0_1, MPCC_MCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_RAMA_REGION_0_1, MPCC_MCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_SHAPER_RAMA_REGION_0_1, MPCC_MCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_CONTROL, MPCC_MCM_1DLUT_MODE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_CONTROL, MPCC_MCM_1DLUT_SELECT, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_CONTROL, MPCC_MCM_1DLUT_PWL_DISABLE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_CONTROL, MPCC_MCM_1DLUT_MODE_CURRENT, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_CONTROL, MPCC_MCM_1DLUT_SELECT_CURRENT, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_LUT_INDEX, MPCC_MCM_1DLUT_LUT_INDEX, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_LUT_DATA, MPCC_MCM_1DLUT_LUT_DATA, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_LUT_CONTROL, MPCC_MCM_1DLUT_LUT_WRITE_COLOR_MASK, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_LUT_CONTROL, MPCC_MCM_1DLUT_LUT_READ_COLOR_SEL, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_LUT_CONTROL, MPCC_MCM_1DLUT_LUT_HOST_SEL, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_START_CNTL_B, MPCC_MCM_1DLUT_RAMA_EXP_REGION_START_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_START_CNTL_B, MPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_B, MPCC_MCM_1DLUT_RAMA_EXP_REGION_START_SLOPE_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_B, MPCC_MCM_1DLUT_RAMA_EXP_REGION_START_BASE_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_END_CNTL1_B, MPCC_MCM_1DLUT_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_END_CNTL2_B, MPCC_MCM_1DLUT_RAMA_EXP_REGION_END_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_END_CNTL2_B, MPCC_MCM_1DLUT_RAMA_EXP_REGION_END_SLOPE_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_OFFSET_B, MPCC_MCM_1DLUT_RAMA_OFFSET_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_REGION_0_1, MPCC_MCM_1DLUT_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_REGION_0_1, MPCC_MCM_1DLUT_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_REGION_0_1, MPCC_MCM_1DLUT_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_1DLUT_RAMA_REGION_0_1, MPCC_MCM_1DLUT_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_SHAPER_MEM_PWR_FORCE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_SHAPER_MEM_PWR_DIS, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_SHAPER_MEM_LOW_PWR_MODE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_3DLUT_MEM_PWR_FORCE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_3DLUT_MEM_PWR_DIS, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_3DLUT_MEM_LOW_PWR_MODE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_1DLUT_MEM_PWR_FORCE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_1DLUT_MEM_PWR_DIS, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_1DLUT_MEM_LOW_PWR_MODE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_SHAPER_MEM_PWR_STATE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_3DLUT_MEM_PWR_STATE, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM_1DLUT_MEM_PWR_STATE, mask_sh),\
SF(CUR_VUPDATE_LOCK_SET0, CUR_VUPDATE_LOCK_SET, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_FIRST_GAMUT_REMAP_COEF_FORMAT, MPCC_MCM_FIRST_GAMUT_REMAP_COEF_FORMAT, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_FIRST_GAMUT_REMAP_MODE, MPCC_MCM_FIRST_GAMUT_REMAP_MODE, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_FIRST_GAMUT_REMAP_MODE, MPCC_MCM_FIRST_GAMUT_REMAP_MODE_CURRENT, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C11_C12_A, MPCC_MCM_FIRST_GAMUT_REMAP_C11_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C11_C12_A, MPCC_MCM_FIRST_GAMUT_REMAP_C12_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C13_C14_A, MPCC_MCM_FIRST_GAMUT_REMAP_C13_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C13_C14_A, MPCC_MCM_FIRST_GAMUT_REMAP_C14_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C21_C22_A, MPCC_MCM_FIRST_GAMUT_REMAP_C21_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C21_C22_A, MPCC_MCM_FIRST_GAMUT_REMAP_C22_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C23_C24_A, MPCC_MCM_FIRST_GAMUT_REMAP_C23_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C23_C24_A, MPCC_MCM_FIRST_GAMUT_REMAP_C24_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C31_C32_A, MPCC_MCM_FIRST_GAMUT_REMAP_C31_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C31_C32_A, MPCC_MCM_FIRST_GAMUT_REMAP_C32_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C33_C34_A, MPCC_MCM_FIRST_GAMUT_REMAP_C33_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_FIRST_GAMUT_REMAP_C33_C34_A, MPCC_MCM_FIRST_GAMUT_REMAP_C34_A, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_SECOND_GAMUT_REMAP_COEF_FORMAT, MPCC_MCM_SECOND_GAMUT_REMAP_COEF_FORMAT, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_SECOND_GAMUT_REMAP_MODE, MPCC_MCM_SECOND_GAMUT_REMAP_MODE, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_SECOND_GAMUT_REMAP_MODE, MPCC_MCM_SECOND_GAMUT_REMAP_MODE_CURRENT, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C11_C12_A, MPCC_MCM_SECOND_GAMUT_REMAP_C11_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C11_C12_A, MPCC_MCM_SECOND_GAMUT_REMAP_C12_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C13_C14_A, MPCC_MCM_SECOND_GAMUT_REMAP_C13_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C13_C14_A, MPCC_MCM_SECOND_GAMUT_REMAP_C14_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C21_C22_A, MPCC_MCM_SECOND_GAMUT_REMAP_C21_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C21_C22_A, MPCC_MCM_SECOND_GAMUT_REMAP_C22_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C23_C24_A, MPCC_MCM_SECOND_GAMUT_REMAP_C23_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C23_C24_A, MPCC_MCM_SECOND_GAMUT_REMAP_C24_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C31_C32_A, MPCC_MCM_SECOND_GAMUT_REMAP_C31_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C31_C32_A, MPCC_MCM_SECOND_GAMUT_REMAP_C32_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C33_C34_A, MPCC_MCM_SECOND_GAMUT_REMAP_C33_A, mask_sh), \
SF(MPCC_MCM0_MPC_MCM_SECOND_GAMUT_REMAP_C33_C34_A, MPCC_MCM_SECOND_GAMUT_REMAP_C34_A, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_3DLUT_FAST_LOAD_SELECT, MPCC_MCM_3DLUT_FL_SEL, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_3DLUT_FAST_LOAD_STATUS, MPCC_MCM_3DLUT_FL_DONE, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_3DLUT_FAST_LOAD_STATUS, MPCC_MCM_3DLUT_FL_SOFT_UNDERFLOW, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_3DLUT_FAST_LOAD_STATUS, MPCC_MCM_3DLUT_FL_HARD_UNDERFLOW, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_R, MPCC_MCM_3DLUT_OUT_OFFSET_R, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_R, MPCC_MCM_3DLUT_OUT_SCALE_R, mask_sh), \
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM_3DLUT_OUT_OFFSET_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM_3DLUT_OUT_SCALE_G, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_OFFSET_B, mask_sh),\
SF(MPCC_MCM0_MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM_3DLUT_OUT_SCALE_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_LUT_MODE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_CONTROL, MPC_RMCM_SHAPER_MODE_CURRENT, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_R, MPC_RMCM_SHAPER_OFFSET_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_G, MPC_RMCM_SHAPER_OFFSET_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_OFFSET_B, MPC_RMCM_SHAPER_OFFSET_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_R, MPC_RMCM_SHAPER_SCALE_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_SCALE_G_B, MPC_RMCM_SHAPER_SCALE_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_INDEX, MPC_RMCM_SHAPER_LUT_INDEX, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_DATA, MPC_RMCM_SHAPER_LUT_DATA, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_LUT_WRITE_EN_MASK, MPC_RMCM_SHAPER_LUT_WRITE_SEL, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_START_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_B, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_G, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_END_CNTL_R, MPC_RMCM_SHAPER_RAMA_EXP_REGION_END_BASE_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_0_1, MPC_RMCM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_2_3, MPC_RMCM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_4_5, MPC_RMCM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_6_7, MPC_RMCM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_8_9, MPC_RMCM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_10_11, MPC_RMCM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_12_13, MPC_RMCM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_14_15, MPC_RMCM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_16_17, MPC_RMCM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_18_19, MPC_RMCM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_20_21, MPC_RMCM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_22_23, MPC_RMCM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_24_25, MPC_RMCM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_26_27, MPC_RMCM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_28_29, MPC_RMCM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_30_31, MPC_RMCM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMA_REGION_32_33, MPC_RMCM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_START_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_B, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_G, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_END_CNTL_R, MPC_RMCM_SHAPER_RAMB_EXP_REGION_END_BASE_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_0_1, MPC_RMCM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_2_3, MPC_RMCM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_4_5, MPC_RMCM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_6_7, MPC_RMCM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_8_9, MPC_RMCM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_10_11, MPC_RMCM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_12_13, MPC_RMCM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_14_15, MPC_RMCM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_16_17, MPC_RMCM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_18_19, MPC_RMCM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_20_21, MPC_RMCM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_22_23, MPC_RMCM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_24_25, MPC_RMCM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_26_27, MPC_RMCM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_28_29, MPC_RMCM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_30_31, MPC_RMCM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_SHAPER_RAMB_REGION_32_33, MPC_RMCM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_SIZE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_MODE, MPC_RMCM_3DLUT_MODE_CURRENT, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_INDEX, MPC_RMCM_3DLUT_INDEX, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA0, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA, MPC_RMCM_3DLUT_DATA1, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_DATA_30BIT, MPC_RMCM_3DLUT_DATA_30BIT, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_WRITE_EN_MASK, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_30BIT_EN, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_READ_WRITE_CONTROL, MPC_RMCM_3DLUT_READ_SEL, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_NORM_FACTOR, MPC_RMCM_3DLUT_OUT_NORM_FACTOR, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_OFFSET_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_R, MPC_RMCM_3DLUT_OUT_SCALE_R, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_OFFSET_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_G, MPC_RMCM_3DLUT_OUT_SCALE_G, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_OFFSET_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_OUT_OFFSET_B, MPC_RMCM_3DLUT_OUT_SCALE_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, MPC_RMCM_GAMUT_REMAP_COEF_FORMAT, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_MODE, MPC_RMCM_GAMUT_REMAP_MODE_CURRENT, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C11_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_A, MPC_RMCM_GAMUT_REMAP_C12_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C13_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_A, MPC_RMCM_GAMUT_REMAP_C14_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C21_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_A, MPC_RMCM_GAMUT_REMAP_C22_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C23_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_A, MPC_RMCM_GAMUT_REMAP_C24_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C31_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_A, MPC_RMCM_GAMUT_REMAP_C32_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C33_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_A, MPC_RMCM_GAMUT_REMAP_C34_A, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C11_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C11_C12_B, MPC_RMCM_GAMUT_REMAP_C12_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C13_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C13_C14_B, MPC_RMCM_GAMUT_REMAP_C14_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C21_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C21_C22_B, MPC_RMCM_GAMUT_REMAP_C22_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C23_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C23_C24_B, MPC_RMCM_GAMUT_REMAP_C24_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C31_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C31_C32_B, MPC_RMCM_GAMUT_REMAP_C32_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C33_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_GAMUT_REMAP_C33_C34_B, MPC_RMCM_GAMUT_REMAP_C34_B, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_FORCE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_DIS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_LOW_PWR_MODE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_FORCE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_DIS, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_LOW_PWR_MODE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_SHAPER_MEM_PWR_STATE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_MEM_PWR_CTRL, MPC_RMCM_3DLUT_MEM_PWR_STATE, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_SELECT, MPC_RMCM_3DLUT_FL_SEL, mask_sh),\
SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_DONE, mask_sh), \
SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_SOFT_UNDERFLOW, mask_sh), \
SF(MPC_RMCM0_MPC_RMCM_3DLUT_FAST_LOAD_STATUS, MPC_RMCM_3DLUT_FL_HARD_UNDERFLOW, mask_sh), \
SF(MPC_RMCM0_MPC_RMCM_CNTL, MPC_RMCM_CNTL, mask_sh), \
SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_INDEX, mask_sh), \
SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_INDEX, MPC_RMCM_TEST_DEBUG_WRITE_EN, mask_sh), \
SF(MPC_RMCM0_MPC_RMCM_TEST_DEBUG_DATA, MPC_RMCM_TEST_DEBUG_DATA, mask_sh), \
SF(MPC_OUT0_CSC_MODE, MPC_OCSC_MODE, mask_sh),\
SF(MPC_OUT0_CSC_C11_C12_A, MPC_OCSC_C11_A, mask_sh),\
SF(MPC_OUT0_CSC_C11_C12_A, MPC_OCSC_C12_A, mask_sh),\
SF(MPC_OUT0_DENORM_CONTROL, MPC_OUT_DENORM_MODE, mask_sh),\
SF(MPC_OUT0_DENORM_CONTROL, MPC_OUT_DENORM_CLAMP_MAX_R_CR, mask_sh),\
SF(MPC_OUT0_DENORM_CONTROL, MPC_OUT_DENORM_CLAMP_MIN_R_CR, mask_sh),\
SF(MPC_OUT0_DENORM_CLAMP_G_Y, MPC_OUT_DENORM_CLAMP_MAX_G_Y, mask_sh),\
SF(MPC_OUT0_DENORM_CLAMP_G_Y, MPC_OUT_DENORM_CLAMP_MIN_G_Y, mask_sh),\
SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MAX_B_CB, mask_sh),\
SF(MPC_OUT0_DENORM_CLAMP_B_CB, MPC_OUT_DENORM_CLAMP_MIN_B_CB, mask_sh),\
SF(MPC_OUT0_MUX, MPC_OUT_MUX, mask_sh),\
SF(MPC_OUT0_MUX, MPC_OUT_RATE_CONTROL, mask_sh),\
SF(MPC_OUT0_MUX, MPC_OUT_RATE_CONTROL_DISABLE, mask_sh),\
SF(MPC_OUT0_MUX, MPC_OUT_FLOW_CONTROL_MODE, mask_sh),\
SF(MPC_OUT0_MUX, MPC_OUT_FLOW_CONTROL_COUNT, mask_sh)
#define MPC_REG_LIST_DCN6_0_RI(inst) \
MPC_REG_LIST_DCN42(inst)
#define MPC_REG_FIELD_LIST_DCN6_0(type) \
MPC_REG_FIELD_LIST_DCN42(type)
struct dcn60_mpc_shift {
MPC_REG_FIELD_LIST_DCN6_0(uint8_t);
};
struct dcn60_mpc_mask {
MPC_REG_FIELD_LIST_DCN6_0(uint32_t);
};
struct dcn60_mpc_registers {
MPC_REG_VARIABLE_LIST_DCN6_0;
};
struct dcn60_mpc {
struct mpc base;
int mpcc_in_use_mask;
int num_mpcc;
const struct dcn60_mpc_registers *mpc_regs;
const struct dcn60_mpc_shift *mpc_shift;
const struct dcn60_mpc_mask *mpc_mask;
int num_rmu;
};
void dcn60_mpc_construct(struct dcn60_mpc *mpc401,
struct dc_context *ctx,
const struct dcn60_mpc_registers *mpc_regs,
const struct dcn60_mpc_shift *mpc_shift,
const struct dcn60_mpc_mask *mpc_mask,
int num_mpcc,
int num_rmu);
void mpc60_program_rmcm_lut_read_write_control(struct mpc *mpc,
const enum MCM_LUT_ID id,
bool lut_bank_a,
bool enabled,
int mpcc_id);
void mpc60_select_3dlut_ram(struct mpc *mpc,
enum dc_lut_mode mode,
bool is_color_channel_12bits,
uint32_t mpcc_id);
bool mpc60_program_3dlut(struct mpc *mpc,
const struct tetrahedral_params *params,
int mpcc_id);
void mpc60_program_lut_read_write_control(struct mpc *mpc,
const enum MCM_LUT_ID id,
bool lut_bank_a,
int mpcc_id);
#endif /* DCN60_MPC_H_ */

View File

@@ -0,0 +1,25 @@
// SPDX-License-Identifier: MIT
/* Copyright 2025 Advanced Micro Devices, Inc. */
#include "dcn60_opp.h"
#include "reg_helper.h"
#define REG(reg) ((const struct dcn60_opp_registers *)(oppn20->regs))->reg
#undef FN
#define FN(reg_name, field_name) \
((const struct dcn60_opp_shift *)(oppn20->opp_shift))->field_name, \
((const struct dcn60_opp_mask *)(oppn20->opp_mask))->field_name
#define CTX oppn20->base.ctx
void dcn60_opp_construct(struct dcn20_opp *oppn20, struct dc_context *ctx,
uint32_t inst, const struct dcn60_opp_registers *regs,
const struct dcn60_opp_shift *opp_shift,
const struct dcn60_opp_mask *opp_mask)
{
dcn20_opp_construct(oppn20, ctx, inst,
(const struct dcn20_opp_registers *)regs,
(const struct dcn20_opp_shift *)opp_shift,
(const struct dcn20_opp_mask *)opp_mask);
}

View File

@@ -0,0 +1,64 @@
/* SPDX-License-Identifier: MIT */
/* Copyright 2025 Advanced Micro Devices, Inc. */
#ifndef __DCN60_OPP_H
#define __DCN60_OPP_H
#include "dcn20/dcn20_opp.h"
#include "dcn35/dcn35_opp.h"
// Separate initializer list is required for DCN6 because OPPBUF_3D_PARAMETERS_0::OPPBUF_3D_VACT_SPACE2_SIZE
// is removed in DCN6. Keep the field, but leave it uninitialized.
#define OPP_MASK_SH_LIST_DCN60(mask_sh) \
OPP_DPG_MASK_SH_LIST(mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_MODE, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_MODE, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_EN, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, mask_sh), \
OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE, mask_sh), \
OPP_SF(FMT0_FMT_CONTROL, FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, mask_sh), \
OPP_SF(FMT0_FMT_CONTROL, FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, mask_sh), \
OPP_SF(FMT0_FMT_CONTROL, FMT_PIXEL_ENCODING, mask_sh), \
OPP_SF(FMT0_FMT_CONTROL, FMT_SUBSAMPLING_MODE, mask_sh), \
OPP_SF(FMT0_FMT_CONTROL, FMT_CBCR_BIT_REDUCTION_BYPASS, mask_sh), \
OPP_SF(FMT0_FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, mask_sh), \
OPP_SF(FMT0_FMT_DITHER_RAND_R_SEED, FMT_RAND_R_SEED, mask_sh), \
OPP_SF(FMT0_FMT_DITHER_RAND_G_SEED, FMT_RAND_G_SEED, mask_sh), \
OPP_SF(FMT0_FMT_DITHER_RAND_B_SEED, FMT_RAND_B_SEED, mask_sh), \
OPP_SF(FMT0_FMT_CLAMP_CNTL, FMT_CLAMP_DATA_EN, mask_sh), \
OPP_SF(FMT0_FMT_CLAMP_CNTL, FMT_CLAMP_COLOR_FORMAT, mask_sh), \
OPP_SF(FMT0_FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN, mask_sh), \
OPP_SF(FMT0_FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE, mask_sh), \
OPP_SF(FMT0_FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, mask_sh), \
OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, mask_sh),\
OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_PIXEL_REPETITION, mask_sh),\
OPP_SF(OPPBUF0_OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, mask_sh), \
OPP_SF(OPP_PIPE0_OPP_PIPE_CONTROL, OPP_PIPE_CLOCK_EN, mask_sh), \
OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_DISPLAY_SEGMENTATION, mask_sh),\
OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_OVERLAP_PIXEL_NUM, mask_sh), \
OPP_SF(FMT0_FMT_422_CONTROL, FMT_LEFT_EDGE_EXTRA_PIXEL_COUNT, mask_sh), \
OPP_SF(OPP_TOP_CLK_CONTROL, OPP_FGCG_REP_DIS, mask_sh)
struct dcn60_opp_registers {
OPP_REG_VARIABLE_LIST_DCN3_5;
};
struct dcn60_opp_shift {
OPP_DCN35_REG_FIELD_LIST(uint8_t);
};
struct dcn60_opp_mask {
OPP_DCN35_REG_FIELD_LIST(uint32_t);
};
void dcn60_opp_construct(struct dcn20_opp *oppn20, struct dc_context *ctx,
uint32_t inst, const struct dcn60_opp_registers *regs,
const struct dcn60_opp_shift *opp_shift,
const struct dcn60_opp_mask *opp_mask);
#endif

View File

@@ -0,0 +1,107 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2025 Advanced Micro Devices, Inc.
#include "dcn30/dcn30_optc.h"
#include "dcn31/dcn31_optc.h"
#include "dcn32/dcn32_optc.h"
#include "dcn401/dcn401_optc.h"
#include "dcn42/dcn42_optc.h"
#include "dcn60_optc.h"
#include "reg_helper.h"
#include "dc.h"
#include "dcn_calc_math.h"
#include "dc_dmub_srv.h"
#define REG(reg)\
optc1->tg_regs->reg
#define CTX \
optc1->base.ctx
#undef FN
#define FN(reg_name, field_name) \
optc1->tg_shift->field_name, optc1->tg_mask->field_name
static const struct timing_generator_funcs dcn60_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
.setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0,
.setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1,
.setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2,
.program_global_sync = optc401_program_global_sync,
.enable_crtc = optc401_enable_crtc,
.disable_crtc = optc401_disable_crtc,
.phantom_crtc_post_enable = optc401_phantom_crtc_post_enable,
.disable_phantom_crtc = optc401_disable_phantom_otg,
/* used by enable_timing_synchronization. Not need for FPGA */
.is_counter_moving = optc1_is_counter_moving,
.get_position = optc1_get_position,
.get_frame_count = optc1_get_vblank_counter,
.get_scanoutpos = optc1_get_crtc_scanoutpos,
.get_otg_active_size = optc1_get_otg_active_size,
.set_early_control = optc1_set_early_control,
/* used by enable_timing_synchronization. Not need for FPGA */
.wait_for_state = optc1_wait_for_state,
.did_triggered_reset_occur = optc1_did_triggered_reset_occur,
.triplebuffer_lock = optc3_triplebuffer_lock,
.triplebuffer_unlock = optc2_triplebuffer_unlock,
.enable_reset_trigger = optc1_enable_reset_trigger,
.enable_crtc_reset = optc1_enable_crtc_reset,
.disable_reset_trigger = optc1_disable_reset_trigger,
.lock = optc3_lock,
.unlock = optc1_unlock,
.lock_doublebuffer_enable = optc3_lock_doublebuffer_enable,
.lock_doublebuffer_disable = optc3_lock_doublebuffer_disable,
.enable_optc_clock = optc1_enable_optc_clock,
.set_drr = optc401_set_drr,
.get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal,
.set_vtotal_min_max = optc401_set_vtotal_min_max,
.set_static_screen_control = optc1_set_static_screen_control,
.program_stereo = optc1_program_stereo,
.is_stereo_left_eye = optc1_is_stereo_left_eye,
.tg_init = optc3_tg_init,
.is_tg_enabled = optc1_is_tg_enabled,
.is_optc_underflow_occurred = optc1_is_optc_underflow_occurred,
.clear_optc_underflow = optc1_clear_optc_underflow,
.get_crc = optc42_get_crc,
.configure_crc = optc1_configure_crc,
.set_dsc_config = optc3_set_dsc_config,
.get_dsc_status = optc2_get_dsc_status,
.set_odm_bypass = optc401_set_odm_bypass,
.set_odm_combine = optc401_set_odm_combine,
.wait_odm_doublebuffer_pending_clear = optc32_wait_odm_doublebuffer_pending_clear,
.set_h_timing_div_manual_mode = optc401_set_h_timing_div_manual_mode,
.get_optc_source = optc2_get_optc_source,
.set_out_mux = optc401_set_out_mux,
.set_drr_trigger_window = optc3_set_drr_trigger_window,
.set_vtotal_change_limit = optc3_set_vtotal_change_limit,
.set_gsl = optc2_set_gsl,
.set_gsl_source_select = NULL,
.set_vtg_params = optc1_set_vtg_params,
.program_manual_trigger = optc2_program_manual_trigger,
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
.is_two_pixels_per_container = optc1_is_two_pixels_per_container,
.get_optc_double_buffer_pending = optc3_get_optc_double_buffer_pending,
.get_otg_double_buffer_pending = optc3_get_otg_update_pending,
.get_pipe_update_pending = optc3_get_pipe_update_pending,
.set_vupdate_keepout = optc401_set_vupdate_keepout,
.wait_update_lock_status = optc401_wait_update_lock_status,
.read_otg_state = optc31_read_otg_state,
.optc_read_reg_state = optc31_read_reg_state,
};
void dcn60_timing_generator_init(struct optc *optc1)
{
optc1->base.funcs = &dcn60_tg_funcs;
optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1;
optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1;
optc1->min_h_blank = 32;
optc1->min_v_blank = 3;
optc1->min_v_blank_interlace = 5;
optc1->min_h_sync_width = 4;
optc1->min_v_sync_width = 1;
}

Some files were not shown because too many files have changed in this diff Show More