diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dmub')
| -rw-r--r-- | drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 45 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 483 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c | 603 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h | 287 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c | 89 |
8 files changed, 1486 insertions, 28 deletions
diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index 2fde1f043d50..cd51c91a822b 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -67,10 +67,6 @@ #include "inc/dmub_cmd.h" #include "dc/dc_types.h" -#if defined(__cplusplus) -extern "C" { -#endif - #define DMUB_PC_SNAPSHOT_COUNT 10 /* Forward declarations */ @@ -115,6 +111,7 @@ enum dmub_asic { DMUB_ASIC_DCN321, DMUB_ASIC_DCN35, DMUB_ASIC_DCN351, + DMUB_ASIC_DCN401, DMUB_ASIC_MAX, }; @@ -300,6 +297,7 @@ struct dmub_srv_hw_params { bool ips_sequential_ono; enum dmub_memory_access_type mem_access_type; enum dmub_ips_disable_type disable_ips; + bool disallow_phy_access; }; /** @@ -453,6 +451,19 @@ struct dmub_srv_hw_funcs { void (*init_reg_offsets)(struct dmub_srv *dmub, struct dc_context *ctx); void (*subvp_save_surf_addr)(struct dmub_srv *dmub, const struct dc_plane_address *addr, uint8_t subvp_index); + void (*send_reg_inbox0_cmd_msg)(struct dmub_srv *dmub, + union dmub_rb_cmd *cmd); + uint32_t (*read_reg_inbox0_rsp_int_status)(struct dmub_srv *dmub); + void (*read_reg_inbox0_cmd_rsp)(struct dmub_srv *dmub, + union dmub_rb_cmd *cmd); + void (*write_reg_inbox0_rsp_int_ack)(struct dmub_srv *dmub); + uint32_t (*read_reg_outbox0_rdy_int_status)(struct dmub_srv *dmub); + void (*write_reg_outbox0_rdy_int_ack)(struct dmub_srv *dmub); + void (*read_reg_outbox0_msg)(struct dmub_srv *dmub, uint32_t *msg); + void (*write_reg_outbox0_rsp)(struct dmub_srv *dmub, uint32_t *rsp); + uint32_t (*read_reg_outbox0_rsp_int_status)(struct dmub_srv *dmub); + void (*enable_reg_inbox0_rsp_int)(struct dmub_srv *dmub, bool enable); + void (*enable_reg_outbox0_rdy_int)(struct dmub_srv *dmub, bool enable); }; /** @@ -496,6 +507,7 @@ struct dmub_srv { const struct dmub_srv_dcn31_regs *regs_dcn31; struct dmub_srv_dcn32_regs *regs_dcn32; struct dmub_srv_dcn35_regs *regs_dcn35; + const struct dmub_srv_dcn401_regs *regs_dcn401; struct dmub_srv_base_funcs funcs; struct dmub_srv_hw_funcs hw_funcs; @@ -517,6 +529,7 @@ struct dmub_srv { uint32_t psp_version; /* Feature capabilities reported by fw */ + struct dmub_fw_meta_info meta_info; struct dmub_feature_caps feature_caps; struct dmub_visual_confirm_color visual_confirm_color; @@ -927,6 +940,26 @@ enum dmub_status dmub_srv_clear_inbox0_ack(struct dmub_srv *dmub); void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_address *addr, uint8_t subvp_index); /** + * dmub_srv_send_reg_inbox0_cmd() - send a dmub command and wait for the command + * being processed by DMUB. + * @dmub: The dmub service + * @cmd: The dmub command being sent. If with_replay is true, the function will + * update cmd with replied data. + * @with_reply: true if DMUB reply needs to be copied back to cmd. false if the + * cmd doesn't need to be replied. + * @timeout_us: timeout in microseconds. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - DMUB fails to process the command within the timeout + * interval. + */ +enum dmub_status dmub_srv_send_reg_inbox0_cmd( + struct dmub_srv *dmub, + union dmub_rb_cmd *cmd, + bool with_reply, uint32_t timeout_us); + +/** * dmub_srv_set_power_state() - Track DC power state in dmub_srv * @dmub: The dmub service * @power_state: DC power state setting @@ -938,8 +971,4 @@ void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_ */ void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state); -#if defined(__cplusplus) -} -#endif - #endif /* _DMUB_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index e85fd3ac52c7..4db4c5ad5169 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -81,6 +81,16 @@ */ #define NUM_BL_CURVE_SEGS 16 +/** + * Maximum number of segments in ABM ACE curve. + */ +#define ABM_MAX_NUM_OF_ACE_SEGMENTS 64 + +/** + * Maximum number of bins in ABM histogram. + */ +#define ABM_MAX_NUM_OF_HG_BINS 64 + /* Maximum number of SubVP streams */ #define DMUB_MAX_SUBVP_STREAMS 2 @@ -150,10 +160,6 @@ #define dmub_memset(dest, val, bytes) memset((dest), (val), (bytes)) #endif -#if defined(__cplusplus) -extern "C" { -#endif - /** * OS/FW agnostic udelay */ @@ -487,10 +493,6 @@ struct dmub_visual_confirm_color { uint16_t panel_inst; }; -#if defined(__cplusplus) -} -#endif - //============================================================================== //</DMUB_TYPES>================================================================= //============================================================================== @@ -505,6 +507,17 @@ struct dmub_visual_confirm_color { #define DMUB_FW_META_OFFSET 0x24 /** + * union dmub_fw_meta_feature_bits - Static feature bits for pre-initialization + */ +union dmub_fw_meta_feature_bits { + struct { + uint32_t shared_state_link_detection : 1; /**< 1 supports link detection via shared state */ + uint32_t reserved : 31; + } bits; /**< status bits */ + uint32_t all; /**< 32-bit access to status bits */ +}; + +/** * struct dmub_fw_meta_info - metadata associated with fw binary * * NOTE: This should be considered a stable API. Fields should @@ -529,6 +542,7 @@ struct dmub_fw_meta_info { uint32_t shared_state_size; /**< size of the shared state region in bytes */ uint16_t shared_state_features; /**< number of shared state features */ uint16_t reserved2; /**< padding bytes */ + union dmub_fw_meta_feature_bits feature_bits; /**< static feature bits */ }; /** @@ -663,7 +677,7 @@ union dmub_fw_boot_options { uint32_t ips_pg_disable: 1; /* 1 to disable ONO domains power gating*/ uint32_t ips_disable: 3; /* options to disable ips support*/ uint32_t ips_sequential_ono: 1; /**< 1 to enable sequential ONO IPS sequence */ - uint32_t reserved : 9; /**< reserved */ + uint32_t reserved : 8; /**< reserved */ } bits; /**< boot bits */ uint32_t all; /**< 32-bit access to bits */ }; @@ -706,7 +720,8 @@ union dmub_shared_state_ips_fw_signals { uint32_t ips1_commit : 1; /**< 1 if in IPS1 */ uint32_t ips2_commit : 1; /**< 1 if in IPS2 */ uint32_t in_idle : 1; /**< 1 if DMCUB is in idle */ - uint32_t reserved_bits : 29; /**< Reversed */ + uint32_t detection_required : 1; /**< 1 if detection is required */ + uint32_t reserved_bits : 28; /**< Reversed */ } bits; uint32_t all; }; @@ -938,6 +953,37 @@ enum dmub_gpint_command { DMUB_GPINT__REPLAY_RESIDENCY = 14, /** + * DESC: Copy bounding box to the host. + * ARGS: Version of bounding box to copy + * RETURN: Result of copying bounding box + */ + DMUB_GPINT__BB_COPY = 96, + + /** + * DESC: Updates the host addresses bit48~bit63 for bounding box. + * ARGS: The word3 for the 64 bit address + */ + DMUB_GPINT__SET_BB_ADDR_WORD3 = 97, + + /** + * DESC: Updates the host addresses bit32~bit47 for bounding box. + * ARGS: The word2 for the 64 bit address + */ + DMUB_GPINT__SET_BB_ADDR_WORD2 = 98, + + /** + * DESC: Updates the host addresses bit16~bit31 for bounding box. + * ARGS: The word1 for the 64 bit address + */ + DMUB_GPINT__SET_BB_ADDR_WORD1 = 99, + + /** + * DESC: Updates the host addresses bit0~bit15 for bounding box. + * ARGS: The word0 for the 64 bit address + */ + DMUB_GPINT__SET_BB_ADDR_WORD0 = 100, + + /** * DESC: Updates the trace buffer lower 32-bit mask. * ARGS: The new mask * RETURN: Lower 32-bit mask. @@ -1582,6 +1628,223 @@ struct dmub_rb_cmd_fw_assisted_mclk_switch_v2 { struct dmub_cmd_fw_assisted_mclk_switch_config_v2 config_data; }; +struct dmub_flip_addr_info { + uint32_t surf_addr_lo; + uint32_t surf_addr_c_lo; + uint32_t meta_addr_lo; + uint32_t meta_addr_c_lo; + uint16_t surf_addr_hi; + uint16_t surf_addr_c_hi; + uint16_t meta_addr_hi; + uint16_t meta_addr_c_hi; +}; + +struct dmub_fams2_flip_info { + union { + struct { + uint8_t is_immediate: 1; + } bits; + uint8_t all; + } config; + uint8_t otg_inst; + uint8_t pipe_mask; + uint8_t pad; + struct dmub_flip_addr_info addr_info; +}; + +struct dmub_rb_cmd_fams2_flip { + struct dmub_cmd_header header; + struct dmub_fams2_flip_info flip_info; +}; + +struct dmub_optc_state_v2 { + uint32_t v_total_min; + uint32_t v_total_max; + uint32_t v_total_mid; + uint32_t v_total_mid_frame_num; + uint8_t program_manual_trigger; + uint8_t tg_inst; + uint8_t pad[2]; +}; + +struct dmub_optc_position { + uint32_t vpos; + uint32_t hpos; + uint32_t frame; +}; + +struct dmub_rb_cmd_fams2_drr_update { + struct dmub_cmd_header header; + struct dmub_optc_state_v2 dmub_optc_state_req; +}; + +/* 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, +}; + +/* 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 pad[3]; +}; + +struct dmub_fams2_drr_stream_dynamic_state { + uint16_t stretched_vtotal; + uint8_t use_cur_vtotal; + uint8_t pad; +}; + +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; + } 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; +}; + +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) +}; + +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]; +}; + +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 { + struct dmub_fams2_legacy_stream_static_state legacy; + struct dmub_fams2_subvp_stream_static_state subvp; + struct dmub_fams2_drr_stream_static_state drr; + } sub_state; +}; + +/** + * 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 reserved: 24; + } 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; + uint8_t pad[3]; +}; + +union dmub_cmd_fams2_config { + struct dmub_cmd_fams2_global_config global; + struct dmub_fams2_stream_static_state stream; +}; + +/** + * DMUB rb command definition for FAMS2 (merged SubVP, FPO, Legacy) + */ +struct dmub_rb_cmd_fams2 { + struct dmub_cmd_header header; + union dmub_cmd_fams2_config config; +}; + /** * enum dmub_cmd_idle_opt_type - Idle optimization command type. */ @@ -2263,6 +2526,9 @@ enum dmub_cmd_fams_type { * on (for any SubVP cases that use a DRR display) */ DMUB_CMD__FAMS_SET_MANUAL_TRIGGER = 3, + DMUB_CMD__FAMS2_CONFIG = 4, + DMUB_CMD__FAMS2_DRR_UPDATE = 5, + DMUB_CMD__FAMS2_FLIP = 6, }; /** @@ -3547,6 +3813,7 @@ enum hw_lock_client { * Replay is the client of HW Lock Manager. */ HW_LOCK_CLIENT_REPLAY = 4, + HW_LOCK_CLIENT_FAMS2 = 5, /** * Invalid client. */ @@ -3639,6 +3906,87 @@ enum dmub_cmd_abm_type { * on restore we update state with passed in data. */ DMUB_CMD__ABM_SAVE_RESTORE = 7, + + /** + * Query ABM caps. + */ + DMUB_CMD__ABM_QUERY_CAPS = 8, + + /** + * Set ABM Events + */ + DMUB_CMD__ABM_SET_EVENT = 9, +}; + +struct abm_ace_curve { + /** + * @offsets: ACE curve offsets. + */ + uint32_t offsets[ABM_MAX_NUM_OF_ACE_SEGMENTS]; + + /** + * @thresholds: ACE curve thresholds. + */ + uint32_t thresholds[ABM_MAX_NUM_OF_ACE_SEGMENTS]; + + /** + * @slopes: ACE curve slopes. + */ + uint32_t slopes[ABM_MAX_NUM_OF_ACE_SEGMENTS]; +}; + +struct fixed_pt_format { + /** + * @sign_bit: Indicates whether one bit is reserved for the sign. + */ + bool sign_bit; + + /** + * @num_int_bits: Number of bits used for integer part. + */ + uint8_t num_int_bits; + + /** + * @num_frac_bits: Number of bits used for fractional part. + */ + uint8_t num_frac_bits; + + /** + * @pad: Explicit padding to 4 byte boundary. + */ + uint8_t pad; +}; + +struct abm_caps { + /** + * @num_hg_bins: Number of histogram bins. + */ + uint8_t num_hg_bins; + + /** + * @num_ace_segments: Number of ACE curve segments. + */ + uint8_t num_ace_segments; + + /** + * @pad: Explicit padding to 4 byte boundary. + */ + uint8_t pad[2]; + + /** + * @ace_thresholds_format: Format of the ACE thresholds. If not programmable, it is set to 0. + */ + struct fixed_pt_format ace_thresholds_format; + + /** + * @ace_offsets_format: Format of the ACE offsets. If not programmable, it is set to 0. + */ + struct fixed_pt_format ace_offsets_format; + + /** + * @ace_slopes_format: Format of the ACE slopes. + */ + struct fixed_pt_format ace_slopes_format; }; /** @@ -4049,6 +4397,54 @@ struct dmub_rb_cmd_abm_pause { }; /** + * Data passed from driver to FW in a DMUB_CMD__ABM_QUERY_CAPS command. + */ +struct dmub_cmd_abm_query_caps_in { + /** + * Panel instance. + */ + uint8_t panel_inst; + + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[3]; +}; + +/** + * Data passed from FW to driver in a DMUB_CMD__ABM_QUERY_CAPS command. + */ +struct dmub_cmd_abm_query_caps_out { + /** + * SW Algorithm caps. + */ + struct abm_caps sw_caps; + + /** + * ABM HW caps. + */ + struct abm_caps hw_caps; +}; + +/** + * Definition of a DMUB_CMD__ABM_QUERY_CAPS command. + */ +struct dmub_rb_cmd_abm_query_caps { + /** + * Command header. + */ + struct dmub_cmd_header header; + + /** + * Data passed between FW and driver in a DMUB_CMD__ABM_QUERY_CAPS command. + */ + union { + struct dmub_cmd_abm_query_caps_in abm_query_caps_in; + struct dmub_cmd_abm_query_caps_out abm_query_caps_out; + } data; +}; + +/** * Definition of a DMUB_CMD__ABM_SAVE_RESTORE command. */ struct dmub_rb_cmd_abm_save_restore { @@ -4079,6 +4475,51 @@ struct dmub_rb_cmd_abm_save_restore { }; /** + * Data passed from driver to FW in a DMUB_CMD__ABM_SET_EVENT command. + */ +struct dmub_cmd_abm_set_event_data { + + /** + * VB Scaling Init. Strength Mapping + * Byte 0: 0~255 for VB level 0 + * Byte 1: 0~255 for VB level 1 + * Byte 2: 0~255 for VB level 2 + * Byte 3: 0~255 for VB level 3 + */ + uint32_t vb_scaling_strength_mapping; + /** + * VariBright Scaling Enable + */ + uint8_t vb_scaling_enable; + /** + * Panel Control HW instance mask. + * Bit 0 is Panel Control HW instance 0. + * Bit 1 is Panel Control HW instance 1. + */ + uint8_t panel_mask; + + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[2]; +}; + +/** + * Definition of a DMUB_CMD__ABM_SET_EVENT command. + */ +struct dmub_rb_cmd_abm_set_event { + /** + * Command header. + */ + struct dmub_cmd_header header; + + /** + * Data passed from driver to FW in a DMUB_CMD__ABM_SET_EVENT command. + */ + struct dmub_cmd_abm_set_event_data abm_set_event_data; +}; + +/** * Data passed from driver to FW in a DMUB_CMD__QUERY_FEATURE_CAPS command. */ struct dmub_cmd_query_feature_caps_data { @@ -4613,6 +5054,16 @@ union dmub_rb_cmd { struct dmub_rb_cmd_abm_save_restore abm_save_restore; /** + * Definition of a DMUB_CMD__ABM_QUERY_CAPS command. + */ + struct dmub_rb_cmd_abm_query_caps abm_query_caps; + + /** + * Definition of a DMUB_CMD__ABM_SET_EVENT command. + */ + struct dmub_rb_cmd_abm_set_event abm_set_event; + + /** * Definition of a DMUB_CMD__DP_AUX_ACCESS command. */ struct dmub_rb_cmd_dp_aux_access dp_aux_access; @@ -4722,7 +5173,11 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__PSP_ASSR_ENABLE command. */ struct dmub_rb_cmd_assr_enable assr_enable; + struct dmub_rb_cmd_fams2 fams2_config; + + struct dmub_rb_cmd_fams2_drr_update fams2_drr_update; + struct dmub_rb_cmd_fams2_flip fams2_flip; }; /** @@ -4759,10 +5214,6 @@ union dmub_rb_out_cmd { //< DMUB_RB>==================================================================== //============================================================================== -#if defined(__cplusplus) -extern "C" { -#endif - /** * struct dmub_rb_init_params - Initialization params for DMUB ringbuffer */ @@ -5039,10 +5490,6 @@ static inline void dmub_rb_get_return_data(struct dmub_rb *rb, dmub_memcpy(cmd, rd_ptr, DMUB_RB_CMD_SIZE); } -#if defined(__cplusplus) -} -#endif - //============================================================================== //</DMUB_RB>==================================================================== //============================================================================== diff --git a/drivers/gpu/drm/amd/display/dmub/src/Makefile b/drivers/gpu/drm/amd/display/dmub/src/Makefile index 50a98448e2e8..a00b9e992292 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/Makefile +++ b/drivers/gpu/drm/amd/display/dmub/src/Makefile @@ -26,6 +26,7 @@ DMUB += dmub_dcn31.o dmub_dcn314.o dmub_dcn315.o dmub_dcn316.o DMUB += dmub_dcn32.o DMUB += dmub_dcn35.o DMUB += dmub_dcn351.o +DMUB += dmub_dcn401.o AMD_DAL_DMUB = $(addprefix $(AMDDALPATH)/dmub/src/,$(DMUB)) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c index 70e63aeb8f89..7f53074f4e48 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn35.c @@ -410,10 +410,13 @@ union dmub_fw_boot_options dmub_dcn35_get_fw_boot_option(struct dmub_srv *dmub) void dmub_dcn35_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params) { union dmub_fw_boot_options boot_options = {0}; + union dmub_fw_boot_options cur_boot_options = {0}; + + cur_boot_options = dmub_dcn35_get_fw_boot_option(dmub); boot_options.bits.z10_disable = params->disable_z10; boot_options.bits.dpia_supported = params->dpia_supported; - boot_options.bits.enable_dpia = params->disable_dpia == true ? 0:1; + boot_options.bits.enable_dpia = cur_boot_options.bits.enable_dpia && !params->disable_dpia; boot_options.bits.usb4_cm_version = params->usb4_cm_version; boot_options.bits.dpia_hpd_int_enable_supported = params->dpia_hpd_int_enable_supported; boot_options.bits.power_optimization = params->power_optimization; diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c new file mode 100644 index 000000000000..cf139e9cc20e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2024 Advanced Micro Devices, Inc. + +#include "../dmub_srv.h" +#include "dmub_reg.h" +#include "dmub_dcn401.h" + +#include "dcn/dcn_4_1_0_offset.h" +#include "dcn/dcn_4_1_0_sh_mask.h" + +#define DCN_BASE__INST0_SEG2 0x000034C0 + +#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg +#define CTX dmub +#define REGS dmub->regs_dcn401 +#define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name) + +const struct dmub_srv_dcn401_regs dmub_srv_dcn401_regs = { +#define DMUB_SR(reg) REG_OFFSET_EXP(reg), + { + DMUB_DCN401_REGS() + DMCUB_INTERNAL_REGS() + }, +#undef DMUB_SR + +#define DMUB_SF(reg, field) FD_MASK(reg, field), + { DMUB_DCN401_FIELDS() }, +#undef DMUB_SF + +#define DMUB_SF(reg, field) FD_SHIFT(reg, field), + { DMUB_DCN401_FIELDS() }, +#undef DMUB_SF +}; + +static void dmub_dcn401_get_fb_base_offset(struct dmub_srv *dmub, + uint64_t *fb_base, + uint64_t *fb_offset) +{ + uint32_t tmp; + + if (dmub->fb_base || dmub->fb_offset) { + *fb_base = dmub->fb_base; + *fb_offset = dmub->fb_offset; + return; + } + + REG_GET(DCN_VM_FB_LOCATION_BASE, FB_BASE, &tmp); + *fb_base = (uint64_t)tmp << 24; + + REG_GET(DCN_VM_FB_OFFSET, FB_OFFSET, &tmp); + *fb_offset = (uint64_t)tmp << 24; +} + +static inline void dmub_dcn401_translate_addr(const union dmub_addr *addr_in, + uint64_t fb_base, + uint64_t fb_offset, + union dmub_addr *addr_out) +{ + addr_out->quad_part = addr_in->quad_part - fb_base + fb_offset; +} + +void dmub_dcn401_reset(struct dmub_srv *dmub) +{ + union dmub_gpint_data_register cmd; + const uint32_t timeout = 30; + uint32_t in_reset, scratch, i; + + REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset); + + if (in_reset == 0) { + cmd.bits.status = 1; + cmd.bits.command_code = DMUB_GPINT__STOP_FW; + cmd.bits.param = 0; + + dmub->hw_funcs.set_gpint(dmub, cmd); + + /** + * Timeout covers both the ACK and the wait + * for remaining work to finish. + * + * This is mostly bound by the PHY disable sequence. + * Each register check will be greater than 1us, so + * don't bother using udelay. + */ + + for (i = 0; i < timeout; ++i) { + if (dmub->hw_funcs.is_gpint_acked(dmub, cmd)) + break; + } + + for (i = 0; i < timeout; ++i) { + scratch = dmub->hw_funcs.get_gpint_response(dmub); + if (scratch == DMUB_GPINT__STOP_FW_RESPONSE) + break; + } + + /* Force reset in case we timed out, DMCUB is likely hung. */ + } + + REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1); + REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); + REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1); + REG_WRITE(DMCUB_INBOX1_RPTR, 0); + REG_WRITE(DMCUB_INBOX1_WPTR, 0); + REG_WRITE(DMCUB_OUTBOX1_RPTR, 0); + REG_WRITE(DMCUB_OUTBOX1_WPTR, 0); + REG_WRITE(DMCUB_OUTBOX0_RPTR, 0); + REG_WRITE(DMCUB_OUTBOX0_WPTR, 0); + REG_WRITE(DMCUB_SCRATCH0, 0); + + /* Clear the GPINT command manually so we don't reset again. */ + cmd.all = 0; + dmub->hw_funcs.set_gpint(dmub, cmd); +} + +void dmub_dcn401_reset_release(struct dmub_srv *dmub) +{ + REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0); + REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF); + REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1); + REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 0); +} + +void dmub_dcn401_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1) +{ + union dmub_addr offset; + uint64_t fb_base, fb_offset; + + dmub_dcn401_get_fb_base_offset(dmub, &fb_base, &fb_offset); + + REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); + + dmub_dcn401_translate_addr(&cw0->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base); + REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0, + DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top, + DMCUB_REGION3_CW0_ENABLE, 1); + + dmub_dcn401_translate_addr(&cw1->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base); + REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0, + DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top, + DMCUB_REGION3_CW1_ENABLE, 1); + + REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID, + 0x20); +} + +void dmub_dcn401_backdoor_load_zfb_mode(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1) +{ + union dmub_addr offset; + + REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); + + offset = cw0->offset; + + REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base); + REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0, + DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top, + DMCUB_REGION3_CW0_ENABLE, 1); + + offset = cw1->offset; + + REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base); + REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0, + DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top, + DMCUB_REGION3_CW1_ENABLE, 1); + + REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID, + 0x20); +} + +void dmub_dcn401_setup_windows(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6, + const struct dmub_window *region6) +{ + union dmub_addr offset; + + offset = cw3->offset; + + REG_WRITE(DMCUB_REGION3_CW3_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base); + REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0, + DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top, + DMCUB_REGION3_CW3_ENABLE, 1); + + offset = cw4->offset; + + REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base); + REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0, + DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top, + DMCUB_REGION3_CW4_ENABLE, 1); + + offset = cw5->offset; + + REG_WRITE(DMCUB_REGION3_CW5_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base); + REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0, + DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top, + DMCUB_REGION3_CW5_ENABLE, 1); + + REG_WRITE(DMCUB_REGION5_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION5_OFFSET_HIGH, offset.u.high_part); + REG_SET_2(DMCUB_REGION5_TOP_ADDRESS, 0, + DMCUB_REGION5_TOP_ADDRESS, + cw5->region.top - cw5->region.base - 1, + DMCUB_REGION5_ENABLE, 1); + + offset = cw6->offset; + + REG_WRITE(DMCUB_REGION3_CW6_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base); + REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0, + DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top, + DMCUB_REGION3_CW6_ENABLE, 1); + + offset = region6->offset; + + REG_WRITE(DMCUB_REGION6_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION6_OFFSET_HIGH, offset.u.high_part); + REG_SET_2(DMCUB_REGION6_TOP_ADDRESS, 0, + DMCUB_REGION6_TOP_ADDRESS, + region6->region.top - region6->region.base - 1, + DMCUB_REGION6_ENABLE, 1); +} + +void dmub_dcn401_setup_mailbox(struct dmub_srv *dmub, + const struct dmub_region *inbox1) +{ + REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, inbox1->base); + REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base); +} + +uint32_t dmub_dcn401_get_inbox1_wptr(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_INBOX1_WPTR); +} + +uint32_t dmub_dcn401_get_inbox1_rptr(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_INBOX1_RPTR); +} + +void dmub_dcn401_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset) +{ + REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset); +} + +void dmub_dcn401_setup_out_mailbox(struct dmub_srv *dmub, + const struct dmub_region *outbox1) +{ + REG_WRITE(DMCUB_OUTBOX1_BASE_ADDRESS, outbox1->base); + REG_WRITE(DMCUB_OUTBOX1_SIZE, outbox1->top - outbox1->base); +} + +uint32_t dmub_dcn401_get_outbox1_wptr(struct dmub_srv *dmub) +{ + /** + * outbox1 wptr register is accessed without locks (dal & dc) + * and to be called only by dmub_srv_stat_get_notification() + */ + return REG_READ(DMCUB_OUTBOX1_WPTR); +} + +void dmub_dcn401_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset) +{ + /** + * outbox1 rptr register is accessed without locks (dal & dc) + * and to be called only by dmub_srv_stat_get_notification() + */ + REG_WRITE(DMCUB_OUTBOX1_RPTR, rptr_offset); +} + +bool dmub_dcn401_is_hw_init(struct dmub_srv *dmub) +{ + union dmub_fw_boot_status status; + uint32_t is_hw_init; + + status.all = REG_READ(DMCUB_SCRATCH0); + REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_hw_init); + + return is_hw_init != 0 && status.bits.dal_fw; +} + +bool dmub_dcn401_is_supported(struct dmub_srv *dmub) +{ + uint32_t supported = 0; + + REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported); + + return supported; +} + +void dmub_dcn401_set_gpint(struct dmub_srv *dmub, + union dmub_gpint_data_register reg) +{ + REG_WRITE(DMCUB_GPINT_DATAIN1, reg.all); +} + +bool dmub_dcn401_is_gpint_acked(struct dmub_srv *dmub, + union dmub_gpint_data_register reg) +{ + union dmub_gpint_data_register test; + + reg.bits.status = 0; + test.all = REG_READ(DMCUB_GPINT_DATAIN1); + + return test.all == reg.all; +} + +uint32_t dmub_dcn401_get_gpint_response(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_SCRATCH7); +} + +uint32_t dmub_dcn401_get_gpint_dataout(struct dmub_srv *dmub) +{ + uint32_t dataout = REG_READ(DMCUB_GPINT_DATAOUT); + + REG_UPDATE(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN, 0); + + REG_WRITE(DMCUB_GPINT_DATAOUT, 0); + REG_UPDATE(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK, 1); + REG_UPDATE(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK, 0); + + REG_UPDATE(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN, 1); + + return dataout; +} + +union dmub_fw_boot_status dmub_dcn401_get_fw_boot_status(struct dmub_srv *dmub) +{ + union dmub_fw_boot_status status; + + status.all = REG_READ(DMCUB_SCRATCH0); + return status; +} + +void dmub_dcn401_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params) +{ + union dmub_fw_boot_options boot_options = {0}; + + boot_options.bits.z10_disable = params->disable_z10; + + boot_options.bits.skip_phy_access = params->disallow_phy_access; + + REG_WRITE(DMCUB_SCRATCH14, boot_options.all); +} + +void dmub_dcn401_skip_dmub_panel_power_sequence(struct dmub_srv *dmub, bool skip) +{ + union dmub_fw_boot_options boot_options; + boot_options.all = REG_READ(DMCUB_SCRATCH14); + boot_options.bits.skip_phy_init_panel_sequence = skip; + REG_WRITE(DMCUB_SCRATCH14, boot_options.all); +} + +void dmub_dcn401_setup_outbox0(struct dmub_srv *dmub, + const struct dmub_region *outbox0) +{ + REG_WRITE(DMCUB_OUTBOX0_BASE_ADDRESS, outbox0->base); + + REG_WRITE(DMCUB_OUTBOX0_SIZE, outbox0->top - outbox0->base); +} + +uint32_t dmub_dcn401_get_outbox0_wptr(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_OUTBOX0_WPTR); +} + +void dmub_dcn401_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset) +{ + REG_WRITE(DMCUB_OUTBOX0_RPTR, rptr_offset); +} + +uint32_t dmub_dcn401_get_current_time(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_TIMER_CURRENT); +} + +void dmub_dcn401_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data) +{ + uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset; + uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled; + + if (!dmub || !diag_data) + return; + + memset(diag_data, 0, sizeof(*diag_data)); + + diag_data->dmcub_version = dmub->fw_version; + + diag_data->scratch[0] = REG_READ(DMCUB_SCRATCH0); + diag_data->scratch[1] = REG_READ(DMCUB_SCRATCH1); + diag_data->scratch[2] = REG_READ(DMCUB_SCRATCH2); + diag_data->scratch[3] = REG_READ(DMCUB_SCRATCH3); + diag_data->scratch[4] = REG_READ(DMCUB_SCRATCH4); + diag_data->scratch[5] = REG_READ(DMCUB_SCRATCH5); + diag_data->scratch[6] = REG_READ(DMCUB_SCRATCH6); + diag_data->scratch[7] = REG_READ(DMCUB_SCRATCH7); + diag_data->scratch[8] = REG_READ(DMCUB_SCRATCH8); + diag_data->scratch[9] = REG_READ(DMCUB_SCRATCH9); + diag_data->scratch[10] = REG_READ(DMCUB_SCRATCH10); + diag_data->scratch[11] = REG_READ(DMCUB_SCRATCH11); + diag_data->scratch[12] = REG_READ(DMCUB_SCRATCH12); + diag_data->scratch[13] = REG_READ(DMCUB_SCRATCH13); + diag_data->scratch[14] = REG_READ(DMCUB_SCRATCH14); + diag_data->scratch[15] = REG_READ(DMCUB_SCRATCH15); + diag_data->scratch[16] = REG_READ(DMCUB_SCRATCH16); + + diag_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR); + diag_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR); + diag_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR); + + diag_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR); + diag_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR); + diag_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE); + + diag_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR); + diag_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR); + diag_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE); + + REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled); + diag_data->is_dmcub_enabled = is_dmub_enabled; + + REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset); + diag_data->is_dmcub_soft_reset = is_soft_reset; + + REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset); + diag_data->is_dmcub_secure_reset = is_sec_reset; + + REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled); + diag_data->is_traceport_en = is_traceport_enabled; + + REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled); + diag_data->is_cw0_enabled = is_cw0_enabled; + + REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled); + diag_data->is_cw6_enabled = is_cw6_enabled; + + diag_data->gpint_datain0 = REG_READ(DMCUB_GPINT_DATAIN0); + diag_data->timeout_info = dmub->debug; +} +void dmub_dcn401_configure_dmub_in_system_memory(struct dmub_srv *dmub) +{ + /* DMCUB_REGION3_TMR_AXI_SPACE values: + * 0b011 (0x3) - FB physical address + * 0b100 (0x4) - GPU virtual address + * + * Default value is 0x3 (FB Physical address for TMR). When programming + * DMUB to be in system memory, change to 0x4. The system memory allocated + * is accessible by both GPU and CPU, so we use GPU virtual address. + */ + REG_WRITE(DMCUB_REGION3_TMR_AXI_SPACE, 0x4); +} + +void dmub_dcn401_send_inbox0_cmd(struct dmub_srv *dmub, union dmub_inbox0_data_register data) +{ + REG_WRITE(DMCUB_INBOX0_WPTR, data.inbox0_cmd_common.all); +} + +void dmub_dcn401_clear_inbox0_ack_register(struct dmub_srv *dmub) +{ + REG_WRITE(DMCUB_SCRATCH17, 0); +} + +uint32_t dmub_dcn401_read_inbox0_ack_register(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_SCRATCH17); +} + +void dmub_dcn401_send_reg_inbox0_cmd_msg(struct dmub_srv *dmub, + union dmub_rb_cmd *cmd) +{ + uint32_t *dwords = (uint32_t *)cmd; + + static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch"); + + REG_WRITE(DMCUB_REG_INBOX0_MSG0, dwords[0]); + REG_WRITE(DMCUB_REG_INBOX0_MSG1, dwords[1]); + REG_WRITE(DMCUB_REG_INBOX0_MSG2, dwords[2]); + REG_WRITE(DMCUB_REG_INBOX0_MSG3, dwords[3]); + REG_WRITE(DMCUB_REG_INBOX0_MSG4, dwords[4]); + REG_WRITE(DMCUB_REG_INBOX0_MSG5, dwords[5]); + REG_WRITE(DMCUB_REG_INBOX0_MSG6, dwords[6]); + REG_WRITE(DMCUB_REG_INBOX0_MSG7, dwords[7]); + REG_WRITE(DMCUB_REG_INBOX0_MSG8, dwords[8]); + REG_WRITE(DMCUB_REG_INBOX0_MSG9, dwords[9]); + REG_WRITE(DMCUB_REG_INBOX0_MSG10, dwords[10]); + REG_WRITE(DMCUB_REG_INBOX0_MSG11, dwords[11]); + REG_WRITE(DMCUB_REG_INBOX0_MSG12, dwords[12]); + REG_WRITE(DMCUB_REG_INBOX0_MSG13, dwords[13]); + REG_WRITE(DMCUB_REG_INBOX0_MSG14, dwords[14]); + /* writing to INBOX RDY register will trigger DMUB REG INBOX0 RDY + * interrupt. + */ + REG_WRITE(DMCUB_REG_INBOX0_RDY, dwords[15]); +} + +uint32_t dmub_dcn401_read_reg_inbox0_rsp_int_status(struct dmub_srv *dmub) +{ + uint32_t status; + + REG_GET(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_STAT, &status); + return status; +} + +void dmub_dcn401_read_reg_inbox0_cmd_rsp(struct dmub_srv *dmub, + union dmub_rb_cmd *cmd) +{ + uint32_t *dwords = (uint32_t *)cmd; + + static_assert(sizeof(*cmd) == 64, "DMUB command size mismatch"); + + dwords[0] = REG_READ(DMCUB_REG_INBOX0_MSG0); + dwords[1] = REG_READ(DMCUB_REG_INBOX0_MSG1); + dwords[2] = REG_READ(DMCUB_REG_INBOX0_MSG2); + dwords[3] = REG_READ(DMCUB_REG_INBOX0_MSG3); + dwords[4] = REG_READ(DMCUB_REG_INBOX0_MSG4); + dwords[5] = REG_READ(DMCUB_REG_INBOX0_MSG5); + dwords[6] = REG_READ(DMCUB_REG_INBOX0_MSG6); + dwords[7] = REG_READ(DMCUB_REG_INBOX0_MSG7); + dwords[8] = REG_READ(DMCUB_REG_INBOX0_MSG8); + dwords[9] = REG_READ(DMCUB_REG_INBOX0_MSG9); + dwords[10] = REG_READ(DMCUB_REG_INBOX0_MSG10); + dwords[11] = REG_READ(DMCUB_REG_INBOX0_MSG11); + dwords[12] = REG_READ(DMCUB_REG_INBOX0_MSG12); + dwords[13] = REG_READ(DMCUB_REG_INBOX0_MSG13); + dwords[14] = REG_READ(DMCUB_REG_INBOX0_MSG14); + dwords[15] = REG_READ(DMCUB_REG_INBOX0_RSP); +} + +void dmub_dcn401_write_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub) +{ + REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK, 1); + REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK, 0); +} + +void dmub_dcn401_write_reg_outbox0_rdy_int_ack(struct dmub_srv *dmub) +{ + REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK, 1); + REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK, 0); +} + +void dmub_dcn401_read_reg_outbox0_msg(struct dmub_srv *dmub, uint32_t *msg) +{ + *msg = REG_READ(DMCUB_REG_OUTBOX0_MSG0); +} + +void dmub_dcn401_write_reg_outbox0_rsp(struct dmub_srv *dmub, uint32_t *rsp) +{ + REG_WRITE(DMCUB_REG_OUTBOX0_RSP, *rsp); +} + +uint32_t dmub_dcn401_read_reg_outbox0_rsp_int_status(struct dmub_srv *dmub) +{ + uint32_t status; + + REG_GET(DMCUB_INTERRUPT_STATUS, DMCUB_REG_OUTBOX0_RSP_INT_STAT, &status); + return status; +} + +void dmub_dcn401_enable_reg_inbox0_rsp_int(struct dmub_srv *dmub, bool enable) +{ + REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_EN, enable ? 1:0); +} + +void dmub_dcn401_enable_reg_outbox0_rdy_int(struct dmub_srv *dmub, bool enable) +{ + REG_UPDATE(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN, enable ? 1:0); +} + +uint32_t dmub_dcn401_read_reg_outbox0_rdy_int_status(struct dmub_srv *dmub) +{ + uint32_t status; + + REG_GET(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_STAT, &status); + return status; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h new file mode 100644 index 000000000000..4c8843b79695 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn401.h @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2024 Advanced Micro Devices, Inc. + +#ifndef _DMUB_DCN401_H_ +#define _DMUB_DCN401_H_ + +#include "dmub_dcn31.h" + +struct dmub_srv; + +/* DCN401 register definitions. */ + +#define DMUB_DCN401_REGS() \ + DMUB_SR(DMCUB_CNTL) \ + DMUB_SR(DMCUB_CNTL2) \ + DMUB_SR(DMCUB_SEC_CNTL) \ + DMUB_SR(DMCUB_INBOX0_SIZE) \ + DMUB_SR(DMCUB_INBOX0_RPTR) \ + DMUB_SR(DMCUB_INBOX0_WPTR) \ + DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_INBOX1_SIZE) \ + DMUB_SR(DMCUB_INBOX1_RPTR) \ + DMUB_SR(DMCUB_INBOX1_WPTR) \ + DMUB_SR(DMCUB_OUTBOX0_BASE_ADDRESS) \ + DMUB_SR(DMCUB_OUTBOX0_SIZE) \ + DMUB_SR(DMCUB_OUTBOX0_RPTR) \ + DMUB_SR(DMCUB_OUTBOX0_WPTR) \ + DMUB_SR(DMCUB_OUTBOX1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_OUTBOX1_SIZE) \ + DMUB_SR(DMCUB_OUTBOX1_RPTR) \ + DMUB_SR(DMCUB_OUTBOX1_WPTR) \ + DMUB_SR(DMCUB_REGION3_CW0_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW1_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW2_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW3_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW4_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW5_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW6_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW7_OFFSET) \ + DMUB_SR(DMCUB_REGION3_CW0_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW1_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW2_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW3_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW4_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW5_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW6_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW7_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION3_CW0_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW2_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW3_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW4_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW5_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW6_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW7_BASE_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW0_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW1_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW2_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW3_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW4_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW5_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW6_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION3_CW7_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION4_OFFSET) \ + DMUB_SR(DMCUB_REGION4_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION4_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION5_OFFSET) \ + DMUB_SR(DMCUB_REGION5_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION5_TOP_ADDRESS) \ + DMUB_SR(DMCUB_REGION6_OFFSET) \ + DMUB_SR(DMCUB_REGION6_OFFSET_HIGH) \ + DMUB_SR(DMCUB_REGION6_TOP_ADDRESS) \ + DMUB_SR(DMCUB_SCRATCH0) \ + DMUB_SR(DMCUB_SCRATCH1) \ + DMUB_SR(DMCUB_SCRATCH2) \ + DMUB_SR(DMCUB_SCRATCH3) \ + DMUB_SR(DMCUB_SCRATCH4) \ + DMUB_SR(DMCUB_SCRATCH5) \ + DMUB_SR(DMCUB_SCRATCH6) \ + DMUB_SR(DMCUB_SCRATCH7) \ + DMUB_SR(DMCUB_SCRATCH8) \ + DMUB_SR(DMCUB_SCRATCH9) \ + DMUB_SR(DMCUB_SCRATCH10) \ + DMUB_SR(DMCUB_SCRATCH11) \ + DMUB_SR(DMCUB_SCRATCH12) \ + DMUB_SR(DMCUB_SCRATCH13) \ + DMUB_SR(DMCUB_SCRATCH14) \ + DMUB_SR(DMCUB_SCRATCH15) \ + DMUB_SR(DMCUB_SCRATCH16) \ + DMUB_SR(DMCUB_SCRATCH17) \ + DMUB_SR(DMCUB_GPINT_DATAIN0) \ + DMUB_SR(DMCUB_GPINT_DATAIN1) \ + DMUB_SR(DMCUB_GPINT_DATAOUT) \ + DMUB_SR(CC_DC_PIPE_DIS) \ + DMUB_SR(MMHUBBUB_SOFT_RESET) \ + DMUB_SR(DCN_VM_FB_LOCATION_BASE) \ + DMUB_SR(DCN_VM_FB_OFFSET) \ + DMUB_SR(DMCUB_TIMER_CURRENT) \ + DMUB_SR(DMCUB_INST_FETCH_FAULT_ADDR) \ + DMUB_SR(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR) \ + DMUB_SR(DMCUB_DATA_WRITE_FAULT_ADDR) \ + DMUB_SR(DMCUB_REGION3_TMR_AXI_SPACE) \ + DMUB_SR(DMCUB_INTERRUPT_ENABLE) \ + DMUB_SR(DMCUB_INTERRUPT_ACK) \ + DMUB_SR(DMCUB_INTERRUPT_STATUS) \ + DMUB_SR(DMCUB_REG_INBOX0_RDY) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG0) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG1) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG2) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG3) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG4) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG5) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG6) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG7) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG8) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG9) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG10) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG11) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG12) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG13) \ + DMUB_SR(DMCUB_REG_INBOX0_MSG14) \ + DMUB_SR(DMCUB_REG_INBOX0_RSP) \ + DMUB_SR(DMCUB_REG_OUTBOX0_RDY) \ + DMUB_SR(DMCUB_REG_OUTBOX0_MSG0) \ + DMUB_SR(DMCUB_REG_OUTBOX0_RSP) \ + DMUB_SR(HOST_INTERRUPT_CSR) + +#define DMUB_DCN401_FIELDS() \ + DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \ + DMUB_SF(DMCUB_CNTL, DMCUB_TRACEPORT_EN) \ + DMUB_SF(DMCUB_CNTL2, DMCUB_SOFT_RESET) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS) \ + DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE) \ + DMUB_SF(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_ENABLE) \ + DMUB_SF(DMCUB_REGION4_TOP_ADDRESS, DMCUB_REGION4_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION4_TOP_ADDRESS, DMCUB_REGION4_ENABLE) \ + DMUB_SF(DMCUB_REGION5_TOP_ADDRESS, DMCUB_REGION5_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION5_TOP_ADDRESS, DMCUB_REGION5_ENABLE) \ + DMUB_SF(DMCUB_REGION6_TOP_ADDRESS, DMCUB_REGION6_TOP_ADDRESS) \ + DMUB_SF(DMCUB_REGION6_TOP_ADDRESS, DMCUB_REGION6_ENABLE) \ + DMUB_SF(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE) \ + DMUB_SF(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET) \ + DMUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE) \ + DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET) \ + DMUB_SF(DMCUB_INBOX0_WPTR, DMCUB_INBOX0_WPTR) \ + DMUB_SF(DMCUB_REGION3_TMR_AXI_SPACE, DMCUB_REGION3_TMR_AXI_SPACE) \ + DMUB_SF(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN) \ + DMUB_SF(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK) \ + DMUB_SF(DMCUB_INTERRUPT_STATUS, DMCUB_REG_OUTBOX0_RSP_INT_STAT) \ + DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_ACK) \ + DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_STAT) \ + DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_INBOX0_RSP_INT_EN) \ + DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_ACK) \ + DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_STAT) \ + DMUB_SF(HOST_INTERRUPT_CSR, HOST_REG_OUTBOX0_RDY_INT_EN) + +struct dmub_srv_dcn401_reg_offset { +#define DMUB_SR(reg) uint32_t reg; + DMUB_DCN401_REGS() + DMCUB_INTERNAL_REGS() +#undef DMUB_SR +}; + +struct dmub_srv_dcn401_reg_shift { +#define DMUB_SF(reg, field) uint8_t reg##__##field; + DMUB_DCN401_FIELDS() +#undef DMUB_SF +}; + +struct dmub_srv_dcn401_reg_mask { +#define DMUB_SF(reg, field) uint32_t reg##__##field; + DMUB_DCN401_FIELDS() +#undef DMUB_SF +}; + +struct dmub_srv_dcn401_regs { + const struct dmub_srv_dcn401_reg_offset offset; + const struct dmub_srv_dcn401_reg_mask mask; + const struct dmub_srv_dcn401_reg_shift shift; +}; + +extern const struct dmub_srv_dcn401_regs dmub_srv_dcn401_regs; + +void dmub_dcn401_reset(struct dmub_srv *dmub); + +void dmub_dcn401_reset_release(struct dmub_srv *dmub); + +void dmub_dcn401_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + +void dmub_dcn401_backdoor_load_zfb_mode(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + +void dmub_dcn401_setup_windows(struct dmub_srv *dmub, + const struct dmub_window *cw2, + const struct dmub_window *cw3, + const struct dmub_window *cw4, + const struct dmub_window *cw5, + const struct dmub_window *cw6, + const struct dmub_window *region6); + +void dmub_dcn401_setup_mailbox(struct dmub_srv *dmub, + const struct dmub_region *inbox1); + +uint32_t dmub_dcn401_get_inbox1_wptr(struct dmub_srv *dmub); + +uint32_t dmub_dcn401_get_inbox1_rptr(struct dmub_srv *dmub); + +void dmub_dcn401_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset); + +void dmub_dcn401_setup_out_mailbox(struct dmub_srv *dmub, + const struct dmub_region *outbox1); + +uint32_t dmub_dcn401_get_outbox1_wptr(struct dmub_srv *dmub); + +void dmub_dcn401_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); + +bool dmub_dcn401_is_hw_init(struct dmub_srv *dmub); + +bool dmub_dcn401_is_supported(struct dmub_srv *dmub); + +void dmub_dcn401_set_gpint(struct dmub_srv *dmub, + union dmub_gpint_data_register reg); + +bool dmub_dcn401_is_gpint_acked(struct dmub_srv *dmub, + union dmub_gpint_data_register reg); + +uint32_t dmub_dcn401_get_gpint_response(struct dmub_srv *dmub); + +uint32_t dmub_dcn401_get_gpint_dataout(struct dmub_srv *dmub); + +void dmub_dcn401_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params); + +void dmub_dcn401_skip_dmub_panel_power_sequence(struct dmub_srv *dmub, bool skip); + +union dmub_fw_boot_status dmub_dcn401_get_fw_boot_status(struct dmub_srv *dmub); + +void dmub_dcn401_setup_outbox0(struct dmub_srv *dmub, + const struct dmub_region *outbox0); + +uint32_t dmub_dcn401_get_outbox0_wptr(struct dmub_srv *dmub); + +void dmub_dcn401_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset); + +uint32_t dmub_dcn401_get_current_time(struct dmub_srv *dmub); + +void dmub_dcn401_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data); + +void dmub_dcn401_configure_dmub_in_system_memory(struct dmub_srv *dmub); +void dmub_dcn401_send_inbox0_cmd(struct dmub_srv *dmub, union dmub_inbox0_data_register data); +void dmub_dcn401_clear_inbox0_ack_register(struct dmub_srv *dmub); +uint32_t dmub_dcn401_read_inbox0_ack_register(struct dmub_srv *dmub); + +void dmub_dcn401_send_reg_inbox0_cmd_msg(struct dmub_srv *dmub, + union dmub_rb_cmd *cmd); +uint32_t dmub_dcn401_read_reg_inbox0_rsp_int_status(struct dmub_srv *dmub); +void dmub_dcn401_read_reg_inbox0_cmd_rsp(struct dmub_srv *dmub, + union dmub_rb_cmd *cmd); +void dmub_dcn401_write_reg_inbox0_rsp_int_ack(struct dmub_srv *dmub); +void dmub_dcn401_write_reg_outbox0_rdy_int_ack(struct dmub_srv *dmub); +void dmub_dcn401_read_reg_outbox0_msg(struct dmub_srv *dmub, uint32_t *msg); +void dmub_dcn401_write_reg_outbox0_rsp(struct dmub_srv *dmub, uint32_t *msg); +uint32_t dmub_dcn401_read_reg_outbox0_rsp_int_status(struct dmub_srv *dmub); +void dmub_dcn401_enable_reg_inbox0_rsp_int(struct dmub_srv *dmub, bool enable); +void dmub_dcn401_enable_reg_outbox0_rdy_int(struct dmub_srv *dmub, bool enable); +uint32_t dmub_dcn401_read_reg_outbox0_rdy_int_status(struct dmub_srv *dmub); + +#endif /* _DMUB_DCN401_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h index 96603d07c23d..123d1704670e 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h @@ -108,7 +108,6 @@ struct dmub_srv; FN(reg, f4), v4) /* Register field getting. */ - #define REG_GET(reg_name, field, val) \ dmub_reg_get(CTX, REG(reg_name), FN(reg_name, field), val) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index 90e878195d95..db16066bc893 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -38,6 +38,7 @@ #include "dmub_dcn32.h" #include "dmub_dcn35.h" #include "dmub_dcn351.h" +#include "dmub_dcn401.h" #include "os_types.h" /* * Note: the DMUB service is standalone. No additional headers should be @@ -360,6 +361,52 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) funcs->should_detect = dmub_dcn35_should_detect; break; + case DMUB_ASIC_DCN401: + dmub->regs_dcn401 = &dmub_srv_dcn401_regs; + funcs->configure_dmub_in_system_memory = dmub_dcn401_configure_dmub_in_system_memory; + funcs->send_inbox0_cmd = dmub_dcn401_send_inbox0_cmd; + funcs->clear_inbox0_ack_register = dmub_dcn401_clear_inbox0_ack_register; + funcs->read_inbox0_ack_register = dmub_dcn401_read_inbox0_ack_register; + funcs->reset = dmub_dcn401_reset; + funcs->reset_release = dmub_dcn401_reset_release; + funcs->backdoor_load = dmub_dcn401_backdoor_load; + funcs->backdoor_load_zfb_mode = dmub_dcn401_backdoor_load_zfb_mode; + funcs->setup_windows = dmub_dcn401_setup_windows; + funcs->setup_mailbox = dmub_dcn401_setup_mailbox; + funcs->get_inbox1_wptr = dmub_dcn401_get_inbox1_wptr; + funcs->get_inbox1_rptr = dmub_dcn401_get_inbox1_rptr; + funcs->set_inbox1_wptr = dmub_dcn401_set_inbox1_wptr; + funcs->setup_out_mailbox = dmub_dcn401_setup_out_mailbox; + funcs->get_outbox1_wptr = dmub_dcn401_get_outbox1_wptr; + funcs->set_outbox1_rptr = dmub_dcn401_set_outbox1_rptr; + funcs->is_supported = dmub_dcn401_is_supported; + funcs->is_hw_init = dmub_dcn401_is_hw_init; + funcs->set_gpint = dmub_dcn401_set_gpint; + funcs->is_gpint_acked = dmub_dcn401_is_gpint_acked; + funcs->get_gpint_response = dmub_dcn401_get_gpint_response; + funcs->get_gpint_dataout = dmub_dcn401_get_gpint_dataout; + funcs->get_fw_status = dmub_dcn401_get_fw_boot_status; + funcs->enable_dmub_boot_options = dmub_dcn401_enable_dmub_boot_options; + funcs->skip_dmub_panel_power_sequence = dmub_dcn401_skip_dmub_panel_power_sequence; + //outbox0 call stacks + funcs->setup_outbox0 = dmub_dcn401_setup_outbox0; + funcs->get_outbox0_wptr = dmub_dcn401_get_outbox0_wptr; + funcs->set_outbox0_rptr = dmub_dcn401_set_outbox0_rptr; + + funcs->get_current_time = dmub_dcn401_get_current_time; + funcs->get_diagnostic_data = dmub_dcn401_get_diagnostic_data; + funcs->send_reg_inbox0_cmd_msg = dmub_dcn401_send_reg_inbox0_cmd_msg; + funcs->read_reg_inbox0_rsp_int_status = dmub_dcn401_read_reg_inbox0_rsp_int_status; + funcs->read_reg_inbox0_cmd_rsp = dmub_dcn401_read_reg_inbox0_cmd_rsp; + funcs->write_reg_inbox0_rsp_int_ack = dmub_dcn401_write_reg_inbox0_rsp_int_ack; + funcs->write_reg_outbox0_rdy_int_ack = dmub_dcn401_write_reg_outbox0_rdy_int_ack; + funcs->read_reg_outbox0_msg = dmub_dcn401_read_reg_outbox0_msg; + funcs->write_reg_outbox0_rsp = dmub_dcn401_write_reg_outbox0_rsp; + funcs->read_reg_outbox0_rdy_int_status = dmub_dcn401_read_reg_outbox0_rdy_int_status; + funcs->read_reg_outbox0_rsp_int_status = dmub_dcn401_read_reg_outbox0_rsp_int_status; + funcs->enable_reg_inbox0_rsp_int = dmub_dcn401_enable_reg_inbox0_rsp_int; + funcs->enable_reg_outbox0_rdy_int = dmub_dcn401_enable_reg_outbox0_rdy_int; + break; default: return false; } @@ -463,6 +510,8 @@ enum dmub_status fw_info = dmub_get_fw_meta_info(params); if (fw_info) { + memcpy(&dmub->meta_info, fw_info, sizeof(*fw_info)); + fw_state_size = fw_info->fw_region_size; trace_buffer_size = fw_info->trace_buffer_size; @@ -677,6 +726,10 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, dmub->hw_funcs.setup_mailbox(dmub, &inbox1); if (dmub->hw_funcs.setup_out_mailbox) dmub->hw_funcs.setup_out_mailbox(dmub, &outbox1); + if (dmub->hw_funcs.enable_reg_inbox0_rsp_int) + dmub->hw_funcs.enable_reg_inbox0_rsp_int(dmub, true); + if (dmub->hw_funcs.enable_reg_outbox0_rdy_int) + dmub->hw_funcs.enable_reg_outbox0_rdy_int(dmub, true); dmub_memset(&rb_params, 0, sizeof(rb_params)); rb_params.ctx = dmub; @@ -1105,6 +1158,42 @@ void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_ } } +enum dmub_status dmub_srv_send_reg_inbox0_cmd( + struct dmub_srv *dmub, + union dmub_rb_cmd *cmd, + bool with_reply, uint32_t timeout_us) +{ + uint32_t rsp_ready = 0; + uint32_t i; + + dmub->hw_funcs.send_reg_inbox0_cmd_msg(dmub, cmd); + + for (i = 0; i < timeout_us; i++) { + rsp_ready = dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub); + if (rsp_ready) + break; + udelay(1); + } + if (rsp_ready == 0) + return DMUB_STATUS_TIMEOUT; + + if (with_reply) + dmub->hw_funcs.read_reg_inbox0_cmd_rsp(dmub, cmd); + + dmub->hw_funcs.write_reg_inbox0_rsp_int_ack(dmub); + + /* wait for rsp int status is cleared to initial state before exit */ + for (; i <= timeout_us; i++) { + rsp_ready = dmub->hw_funcs.read_reg_inbox0_rsp_int_status(dmub); + if (rsp_ready == 0) + break; + udelay(1); + } + ASSERT(rsp_ready == 0); + + return DMUB_STATUS_OK; +} + void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state) { if (!dmub || !dmub->hw_init) |
