diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dmub')
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 255 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_dal.h | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_vbios.h | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_fw_state.h | 73 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h | 129 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h | 522 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h | 69 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/Makefile | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c | 152 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h | 63 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c | 141 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h | 48 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c | 109 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h | 120 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c | 453 |
16 files changed, 2307 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h new file mode 100644 index 000000000000..b10728f33f62 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -0,0 +1,255 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_CMD_H_ +#define _DMUB_CMD_H_ + +#include "dmub_types.h" +#include "dmub_cmd_dal.h" +#include "dmub_cmd_vbios.h" +#include "atomfirmware.h" + +#define DMUB_RB_CMD_SIZE 64 +#define DMUB_RB_MAX_ENTRY 128 +#define DMUB_RB_SIZE (DMUB_RB_CMD_SIZE * DMUB_RB_MAX_ENTRY) +#define REG_SET_MASK 0xFFFF + +/* + * Command IDs should be treated as stable ABI. + * Do not reuse or modify IDs. + */ + +enum dmub_cmd_type { + DMUB_CMD__NULL = 0, + DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE = 1, + DMUB_CMD__REG_SEQ_FIELD_UPDATE_SEQ = 2, + DMUB_CMD__REG_SEQ_BURST_WRITE = 3, + DMUB_CMD__REG_REG_WAIT = 4, + DMUB_CMD__PSR = 64, + DMUB_CMD__VBIOS = 128, +}; + +#pragma pack(push, 1) + +struct dmub_cmd_header { + unsigned int type : 8; + unsigned int sub_type : 8; + unsigned int reserved0 : 8; + unsigned int payload_bytes : 6; /* up to 60 bytes */ + unsigned int reserved1 : 2; +}; + +/* + * Read modify write + * + * 60 payload bytes can hold up to 5 sets of read modify writes, + * each take 3 dwords. + * + * number of sequences = header.payload_bytes / sizeof(struct dmub_cmd_read_modify_write_sequence) + * + * modify_mask = 0xffff'ffff means all fields are going to be updated. in this case + * command parser will skip the read and we can use modify_mask = 0xffff'ffff as reg write + */ +struct dmub_cmd_read_modify_write_sequence { + uint32_t addr; + uint32_t modify_mask; + uint32_t modify_value; +}; + +#define DMUB_READ_MODIFY_WRITE_SEQ__MAX 5 +struct dmub_rb_cmd_read_modify_write { + struct dmub_cmd_header header; // type = DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE + struct dmub_cmd_read_modify_write_sequence seq[DMUB_READ_MODIFY_WRITE_SEQ__MAX]; +}; + +/* + * Update a register with specified masks and values sequeunce + * + * 60 payload bytes can hold address + up to 7 sets of mask/value combo, each take 2 dword + * + * number of field update sequence = (header.payload_bytes - sizeof(addr)) / sizeof(struct read_modify_write_sequence) + * + * + * USE CASE: + * 1. auto-increment register where additional read would update pointer and produce wrong result + * 2. toggle a bit without read in the middle + */ + +struct dmub_cmd_reg_field_update_sequence { + uint32_t modify_mask; // 0xffff'ffff to skip initial read + uint32_t modify_value; +}; + +#define DMUB_REG_FIELD_UPDATE_SEQ__MAX 7 + +struct dmub_rb_cmd_reg_field_update_sequence { + struct dmub_cmd_header header; + uint32_t addr; + struct dmub_cmd_reg_field_update_sequence seq[DMUB_REG_FIELD_UPDATE_SEQ__MAX]; +}; + + +/* + * Burst write + * + * support use case such as writing out LUTs. + * + * 60 payload bytes can hold up to 14 values to write to given address + * + * number of payload = header.payload_bytes / sizeof(struct read_modify_write_sequence) + */ +#define DMUB_BURST_WRITE_VALUES__MAX 14 +struct dmub_rb_cmd_burst_write { + struct dmub_cmd_header header; // type = DMUB_CMD__REG_SEQ_BURST_WRITE + uint32_t addr; + uint32_t write_values[DMUB_BURST_WRITE_VALUES__MAX]; +}; + + +struct dmub_rb_cmd_common { + struct dmub_cmd_header header; + uint8_t cmd_buffer[DMUB_RB_CMD_SIZE - sizeof(struct dmub_cmd_header)]; +}; + +struct dmub_cmd_reg_wait_data { + uint32_t addr; + uint32_t mask; + uint32_t condition_field_value; + uint32_t time_out_us; +}; + +struct dmub_rb_cmd_reg_wait { + struct dmub_cmd_header header; + struct dmub_cmd_reg_wait_data reg_wait; +}; + +struct dmub_cmd_digx_encoder_control_data { + union dig_encoder_control_parameters_v1_5 dig; +}; + +struct dmub_rb_cmd_digx_encoder_control { + struct dmub_cmd_header header; + struct dmub_cmd_digx_encoder_control_data encoder_control; +}; + +struct dmub_cmd_set_pixel_clock_data { + struct set_pixel_clock_parameter_v1_7 clk; +}; + +struct dmub_rb_cmd_set_pixel_clock { + struct dmub_cmd_header header; + struct dmub_cmd_set_pixel_clock_data pixel_clock; +}; + +struct dmub_cmd_enable_disp_power_gating_data { + struct enable_disp_power_gating_parameters_v2_1 pwr; +}; + +struct dmub_rb_cmd_enable_disp_power_gating { + struct dmub_cmd_header header; + struct dmub_cmd_enable_disp_power_gating_data power_gating; +}; + +struct dmub_cmd_dig1_transmitter_control_data { + struct dig_transmitter_control_parameters_v1_6 dig; +}; + +struct dmub_rb_cmd_dig1_transmitter_control { + struct dmub_cmd_header header; + struct dmub_cmd_dig1_transmitter_control_data transmitter_control; +}; + +struct dmub_rb_cmd_dpphy_init { + struct dmub_cmd_header header; + uint8_t reserved[60]; +}; + +struct dmub_cmd_psr_copy_settings_data { + uint32_t reg1; + uint32_t reg2; + uint32_t reg3; +}; + +struct dmub_rb_cmd_psr_copy_settings { + struct dmub_cmd_header header; + struct dmub_cmd_psr_copy_settings_data psr_copy_settings_data; +}; + +struct dmub_cmd_psr_set_level_data { + uint16_t psr_level; +}; + +struct dmub_rb_cmd_psr_set_level { + struct dmub_cmd_header header; + struct dmub_cmd_psr_set_level_data psr_set_level_data; +}; + +struct dmub_rb_cmd_psr_disable { + struct dmub_cmd_header header; +}; + +struct dmub_rb_cmd_psr_enable { + struct dmub_cmd_header header; +}; + +struct dmub_cmd_psr_notify_vblank_data { + uint32_t vblank_int; // Which vblank interrupt was triggered +}; + +struct dmub_rb_cmd_notify_vblank { + struct dmub_cmd_header header; + struct dmub_cmd_psr_notify_vblank_data psr_notify_vblank_data; +}; + +struct dmub_cmd_psr_notify_static_state_data { + uint32_t ss_int; // Which static screen interrupt was triggered + uint32_t ss_enter; // Enter (1) or exit (0) static screen +}; + +struct dmub_rb_cmd_psr_notify_static_state { + struct dmub_cmd_header header; + struct dmub_cmd_psr_notify_static_state_data psr_notify_static_state_data; +}; + +union dmub_rb_cmd { + struct dmub_rb_cmd_read_modify_write read_modify_write; + struct dmub_rb_cmd_reg_field_update_sequence reg_field_update_seq; + struct dmub_rb_cmd_burst_write burst_write; + struct dmub_rb_cmd_reg_wait reg_wait; + struct dmub_rb_cmd_common cmd_common; + struct dmub_rb_cmd_digx_encoder_control digx_encoder_control; + struct dmub_rb_cmd_set_pixel_clock set_pixel_clock; + struct dmub_rb_cmd_enable_disp_power_gating enable_disp_power_gating; + struct dmub_rb_cmd_dpphy_init dpphy_init; + struct dmub_rb_cmd_dig1_transmitter_control dig1_transmitter_control; + struct dmub_rb_cmd_psr_enable psr_enable; + struct dmub_rb_cmd_psr_disable psr_disable; + struct dmub_rb_cmd_psr_copy_settings psr_copy_settings; + struct dmub_rb_cmd_psr_set_level psr_set_level; +}; + +#pragma pack(pop) + +#endif /* _DMUB_CMD_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_dal.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_dal.h new file mode 100644 index 000000000000..14f13e8a6f3b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_dal.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_CMD_DAL_H_ +#define _DMUB_CMD_DAL_H_ + +/* + * Command IDs should be treated as stable ABI. + * Do not reuse or modify IDs. + */ + +enum dmub_cmd_psr_type { + DMUB_CMD__PSR_ENABLE = 0, + DMUB_CMD__PSR_DISABLE = 1, + DMUB_CMD__PSR_COPY_SETTINGS = 2, + DMUB_CMD__PSR_SET_LEVEL = 3, +}; + +#endif /* _DMUB_CMD_DAL_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_vbios.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_vbios.h new file mode 100644 index 000000000000..b6deb8e2590f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd_vbios.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_CMD_VBIOS_H_ +#define _DMUB_CMD_VBIOS_H_ + +/* + * Command IDs should be treated as stable ABI. + * Do not reuse or modify IDs. + */ + +enum dmub_cmd_vbios_type { + DMUB_CMD__VBIOS_DIGX_ENCODER_CONTROL = 0, + DMUB_CMD__VBIOS_DIG1_TRANSMITTER_CONTROL = 1, + DMUB_CMD__VBIOS_SET_PIXEL_CLOCK = 2, + DMUB_CMD__VBIOS_ENABLE_DISP_POWER_GATING = 3, +}; + +#endif /* _DMUB_CMD_VBIOS_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_fw_state.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_fw_state.h new file mode 100644 index 000000000000..c87b1ba7590e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_fw_state.h @@ -0,0 +1,73 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_FW_STATE_H_ +#define _DMUB_FW_STATE_H_ + +#include "dmub_types.h" + +#pragma pack(push, 1) + +struct dmub_fw_state { + /** + * @phy_initialized_during_fw_boot: + * + * Detects if VBIOS/VBL has ran before firmware boot. + * A value of 1 will usually mean S0i3 boot. + */ + uint8_t phy_initialized_during_fw_boot; + + /** + * @intialized_phy: + * + * Bit vector of initialized PHY. + */ + uint8_t initialized_phy; + + /** + * @enabled_phy: + * + * Bit vector of enabled PHY for DP alt mode switch tracking. + */ + uint8_t enabled_phy; + + /** + * @dmcu_fw_loaded: + * + * DMCU auto load state. + */ + uint8_t dmcu_fw_loaded; + + /** + * @psr_state: + * + * PSR state tracking. + */ + uint8_t psr_state; +}; + +#pragma pack(pop) + +#endif /* _DMUB_FW_STATE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h new file mode 100644 index 000000000000..ac22744eaa94 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_rb.h @@ -0,0 +1,129 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_RB_H_ +#define _DMUB_RB_H_ + +#include "dmub_types.h" +#include "dmub_cmd.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +struct dmub_cmd_header; + +struct dmub_rb_init_params { + void *ctx; + void *base_address; + uint32_t capacity; +}; + +struct dmub_rb { + void *base_address; + uint32_t data_count; + uint32_t rptr; + uint32_t wrpt; + uint32_t capacity; + + void *ctx; + void *dmub; +}; + + +static inline bool dmub_rb_empty(struct dmub_rb *rb) +{ + return (rb->wrpt == rb->rptr); +} + +static inline bool dmub_rb_full(struct dmub_rb *rb) +{ + uint32_t data_count; + + if (rb->wrpt >= rb->rptr) + data_count = rb->wrpt - rb->rptr; + else + data_count = rb->capacity - (rb->rptr - rb->wrpt); + + return (data_count == (rb->capacity - DMUB_RB_CMD_SIZE)); +} + +static inline bool dmub_rb_push_front(struct dmub_rb *rb, + const struct dmub_cmd_header *cmd) +{ + uint8_t *wt_ptr = (uint8_t *)(rb->base_address) + rb->wrpt; + + if (dmub_rb_full(rb)) + return false; + + dmub_memcpy(wt_ptr, cmd, DMUB_RB_CMD_SIZE); + rb->wrpt += DMUB_RB_CMD_SIZE; + + if (rb->wrpt >= rb->capacity) + rb->wrpt %= rb->capacity; + + return true; +} + +static inline bool dmub_rb_front(struct dmub_rb *rb, + struct dmub_cmd_header *cmd) +{ + uint8_t *rd_ptr = (uint8_t *)rb->base_address + rb->rptr; + + if (dmub_rb_empty(rb)) + return false; + + dmub_memcpy(cmd, rd_ptr, DMUB_RB_CMD_SIZE); + + return true; +} + +static inline bool dmub_rb_pop_front(struct dmub_rb *rb) +{ + if (dmub_rb_empty(rb)) + return false; + + rb->rptr += DMUB_RB_CMD_SIZE; + + if (rb->rptr >= rb->capacity) + rb->rptr %= rb->capacity; + + return true; +} + +static inline void dmub_rb_init(struct dmub_rb *rb, + struct dmub_rb_init_params *init_params) +{ + rb->base_address = init_params->base_address; + rb->capacity = init_params->capacity; + rb->rptr = 0; + rb->wrpt = 0; +} + +#if defined(__cplusplus) +} +#endif + +#endif /* _DMUB_RB_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h new file mode 100644 index 000000000000..528243e35add --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_srv.h @@ -0,0 +1,522 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_SRV_H_ +#define _DMUB_SRV_H_ + +/** + * DOC: DMUB interface and operation + * + * DMUB is the interface to the display DMCUB microcontroller on DCN hardware. + * It delegates hardware initialization and command submission to the + * microcontroller. DMUB is the shortname for DMCUB. + * + * This interface is not thread-safe. Ensure that all access to the interface + * is properly synchronized by the caller. + * + * Initialization and usage of the DMUB service should be done in the + * steps given below: + * + * 1. dmub_srv_create() + * 2. dmub_srv_has_hw_support() + * 3. dmub_srv_calc_region_info() + * 4. dmub_srv_hw_init() + * + * The call to dmub_srv_create() is required to use the server. + * + * The calls to dmub_srv_has_hw_support() and dmub_srv_calc_region_info() + * are helpers to query cache window size and allocate framebuffer(s) + * for the cache windows. + * + * The call to dmub_srv_hw_init() programs the DMCUB registers to prepare + * for command submission. Commands can be queued via dmub_srv_cmd_queue() + * and executed via dmub_srv_cmd_execute(). + * + * If the queue is full the dmub_srv_wait_for_idle() call can be used to + * wait until the queue has been cleared. + * + * Destroying the DMUB service can be done by calling dmub_srv_destroy(). + * This does not clear DMUB hardware state, only software state. + * + * The interface is intended to be standalone and should not depend on any + * other component within DAL. + */ + +#include "dmub_types.h" +#include "dmub_cmd.h" +#include "dmub_rb.h" +#include "dmub_fw_state.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Forward declarations */ +struct dmub_srv; +struct dmub_cmd_header; +struct dmcu; + +/* enum dmub_status - return code for dmcub functions */ +enum dmub_status { + DMUB_STATUS_OK = 0, + DMUB_STATUS_NO_CTX, + DMUB_STATUS_QUEUE_FULL, + DMUB_STATUS_TIMEOUT, + DMUB_STATUS_INVALID, +}; + +/* enum dmub_asic - dmub asic identifier */ +enum dmub_asic { + DMUB_ASIC_NONE = 0, + DMUB_ASIC_DCN20, + DMUB_ASIC_DCN21, + DMUB_ASIC_MAX, +}; + +/* enum dmub_window_id - dmub window identifier */ +enum dmub_window_id { + DMUB_WINDOW_0_INST_CONST = 0, + DMUB_WINDOW_1_STACK, + DMUB_WINDOW_2_BSS_DATA, + DMUB_WINDOW_3_VBIOS, + DMUB_WINDOW_4_MAILBOX, + DMUB_WINDOW_5_TRACEBUFF, + DMUB_WINDOW_6_FW_STATE, + DMUB_WINDOW_7_RESERVED, + DMUB_WINDOW_TOTAL, +}; + +/** + * struct dmub_region - dmub hw memory region + * @base: base address for region, must be 256 byte aligned + * @top: top address for region + */ +struct dmub_region { + uint32_t base; + uint32_t top; +}; + +/** + * struct dmub_window - dmub hw cache window + * @off: offset to the fb memory in gpu address space + * @r: region in uc address space for cache window + */ +struct dmub_window { + union dmub_addr offset; + struct dmub_region region; +}; + +/** + * struct dmub_fb - defines a dmub framebuffer memory region + * @cpu_addr: cpu virtual address for the region, NULL if invalid + * @gpu_addr: gpu virtual address for the region, NULL if invalid + * @size: size of the region in bytes, zero if invalid + */ +struct dmub_fb { + void *cpu_addr; + uint64_t gpu_addr; + uint32_t size; +}; + +/** + * struct dmub_srv_region_params - params used for calculating dmub regions + * @inst_const_size: size of the fw inst const section + * @bss_data_size: size of the fw bss data section + * @vbios_size: size of the vbios data + */ +struct dmub_srv_region_params { + uint32_t inst_const_size; + uint32_t bss_data_size; + uint32_t vbios_size; +}; + +/** + * struct dmub_srv_region_info - output region info from the dmub service + * @fb_size: required minimum fb size for all regions, aligned to 4096 bytes + * @num_regions: number of regions used by the dmub service + * @regions: region info + * + * The regions are aligned such that they can be all placed within the + * same framebuffer but they can also be placed into different framebuffers. + * + * The size of each region can be calculated by the caller: + * size = reg.top - reg.base + * + * Care must be taken when performing custom allocations to ensure that each + * region base address is 256 byte aligned. + */ +struct dmub_srv_region_info { + uint32_t fb_size; + uint8_t num_regions; + struct dmub_region regions[DMUB_WINDOW_TOTAL]; +}; + +/** + * struct dmub_srv_fb_params - parameters used for driver fb setup + * @region_info: region info calculated by dmub service + * @cpu_addr: base cpu address for the framebuffer + * @gpu_addr: base gpu virtual address for the framebuffer + */ +struct dmub_srv_fb_params { + const struct dmub_srv_region_info *region_info; + void *cpu_addr; + uint64_t gpu_addr; +}; + +/** + * struct dmub_srv_fb_info - output fb info from the dmub service + * @num_fbs: number of required dmub framebuffers + * @fbs: fb data for each region + * + * Output from the dmub service helper that can be used by the + * driver to prepare dmub_fb that can be passed into the dmub + * hw init service. + * + * Assumes that all regions are within the same framebuffer + * and have been setup according to the region_info generated + * by the dmub service. + */ +struct dmub_srv_fb_info { + uint8_t num_fb; + struct dmub_fb fb[DMUB_WINDOW_TOTAL]; +}; + +/** + * struct dmub_srv_base_funcs - Driver specific base callbacks + */ +struct dmub_srv_base_funcs { + /** + * @reg_read: + * + * Hook for reading a register. + * + * Return: The 32-bit register value from the given address. + */ + uint32_t (*reg_read)(void *ctx, uint32_t address); + + /** + * @reg_write: + * + * Hook for writing a value to the register specified by address. + */ + void (*reg_write)(void *ctx, uint32_t address, uint32_t value); +}; + +/** + * struct dmub_srv_hw_funcs - hardware sequencer funcs for dmub + */ +struct dmub_srv_hw_funcs { + /* private: internal use only */ + + void (*reset)(struct dmub_srv *dmub); + + void (*reset_release)(struct dmub_srv *dmub); + + void (*backdoor_load)(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + + void (*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); + + void (*setup_mailbox)(struct dmub_srv *dmub, + const struct dmub_region *inbox1); + + uint32_t (*get_inbox1_rptr)(struct dmub_srv *dmub); + + void (*set_inbox1_wptr)(struct dmub_srv *dmub, uint32_t wptr_offset); + + bool (*is_supported)(struct dmub_srv *dmub); + + bool (*is_hw_init)(struct dmub_srv *dmub); + + bool (*is_phy_init)(struct dmub_srv *dmub); + + bool (*is_auto_load_done)(struct dmub_srv *dmub); +}; + +/** + * struct dmub_srv_create_params - params for dmub service creation + * @base_funcs: driver supplied base routines + * @hw_funcs: optional overrides for hw funcs + * @user_ctx: context data for callback funcs + * @asic: driver supplied asic + * @is_virtual: false for hw support only + */ +struct dmub_srv_create_params { + struct dmub_srv_base_funcs funcs; + struct dmub_srv_hw_funcs *hw_funcs; + void *user_ctx; + enum dmub_asic asic; + bool is_virtual; +}; + +/* + * struct dmub_srv_hw_params - params for dmub hardware initialization + * @fb: framebuffer info for each region + * @fb_base: base of the framebuffer aperture + * @fb_offset: offset of the framebuffer aperture + * @psp_version: psp version to pass for DMCU init + * @load_inst_const: true if DMUB should load inst const fw + */ +struct dmub_srv_hw_params { + struct dmub_fb *fb[DMUB_WINDOW_TOTAL]; + uint64_t fb_base; + uint64_t fb_offset; + uint32_t psp_version; + bool load_inst_const; +}; + +/** + * struct dmub_srv - software state for dmcub + * @asic: dmub asic identifier + * @user_ctx: user provided context for the dmub_srv + * @is_virtual: false if hardware support only + * @fw_state: dmub firmware state pointer + */ +struct dmub_srv { + enum dmub_asic asic; + void *user_ctx; + bool is_virtual; + volatile const struct dmub_fw_state *fw_state; + + /* private: internal use only */ + struct dmub_srv_base_funcs funcs; + struct dmub_srv_hw_funcs hw_funcs; + struct dmub_rb inbox1_rb; + + bool sw_init; + bool hw_init; + + uint64_t fb_base; + uint64_t fb_offset; + uint32_t psp_version; +}; + +/** + * dmub_srv_create() - creates the DMUB service. + * @dmub: the dmub service + * @params: creation parameters for the service + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_create(struct dmub_srv *dmub, + const struct dmub_srv_create_params *params); + +/** + * dmub_srv_destroy() - destroys the DMUB service. + * @dmub: the dmub service + */ +void dmub_srv_destroy(struct dmub_srv *dmub); + +/** + * dmub_srv_calc_region_info() - retreives region info from the dmub service + * @dmub: the dmub service + * @params: parameters used to calculate region locations + * @info_out: the output region info from dmub + * + * Calculates the base and top address for all relevant dmub regions + * using the parameters given (if any). + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status +dmub_srv_calc_region_info(struct dmub_srv *dmub, + const struct dmub_srv_region_params *params, + struct dmub_srv_region_info *out); + +/** + * dmub_srv_calc_region_info() - retreives fb info from the dmub service + * @dmub: the dmub service + * @params: parameters used to calculate fb locations + * @info_out: the output fb info from dmub + * + * Calculates the base and top address for all relevant dmub regions + * using the parameters given (if any). + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, + const struct dmub_srv_fb_params *params, + struct dmub_srv_fb_info *out); + +/** + * dmub_srv_has_hw_support() - returns hw support state for dmcub + * @dmub: the dmub service + * @is_supported: hw support state + * + * Queries the hardware for DMCUB support and returns the result. + * + * Can be called before dmub_srv_hw_init(). + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub, + bool *is_supported); + +/** + * dmub_srv_is_hw_init() - returns hardware init state + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init); + +/** + * dmub_srv_hw_init() - initializes the underlying DMUB hardware + * @dmub: the dmub service + * @params: params for hardware initialization + * + * Resets the DMUB hardware and performs backdoor loading of the + * required cache regions based on the input framebuffer regions. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_NO_CTX - dmcub context not initialized + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, + const struct dmub_srv_hw_params *params); + +/** + * dmub_srv_cmd_queue() - queues a command to the DMUB + * @dmub: the dmub service + * @cmd: the command to queue + * + * Queues a command to the DMUB service but does not begin execution + * immediately. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_QUEUE_FULL - no remaining room in queue + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub, + const struct dmub_cmd_header *cmd); + +/** + * dmub_srv_cmd_execute() - Executes a queued sequence to the dmub + * @dmub: the dmub service + * + * Begins execution of queued commands on the dmub. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub); + +/** + * dmub_srv_cmd_submit() - submits a command to the DMUB immediately + * @dmub: the dmub service + * @cmd: the command to submit + * @timeout_us: the maximum number of microseconds to wait + * + * Submits a command to the DMUB with an optional timeout. + * If timeout_us is given then the service will attempt to + * resubmit for the given number of microseconds. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - wait for submit timed out + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_cmd_submit(struct dmub_srv *dmub, + const struct dmub_cmd_header *cmd, + uint32_t timeout_us); + +/** + * dmub_srv_wait_for_auto_load() - Waits for firmware auto load to complete + * @dmub: the dmub service + * @timeout_us: the maximum number of microseconds to wait + * + * Waits until firmware has been autoloaded by the DMCUB. The maximum + * wait time is given in microseconds to prevent spinning forever. + * + * On ASICs without firmware autoload support this function will return + * immediately. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - wait for phy init timed out + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub, + uint32_t timeout_us); + +/** + * dmub_srv_wait_for_phy_init() - Waits for DMUB PHY init to complete + * @dmub: the dmub service + * @timeout_us: the maximum number of microseconds to wait + * + * Waits until the PHY has been initialized by the DMUB. The maximum + * wait time is given in microseconds to prevent spinning forever. + * + * On ASICs without PHY init support this function will return + * immediately. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - wait for phy init timed out + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub, + uint32_t timeout_us); + +/** + * dmub_srv_wait_for_idle() - Waits for the DMUB to be idle + * @dmub: the dmub service + * @timeout_us: the maximum number of microseconds to wait + * + * Waits until the DMUB buffer is empty and all commands have + * finished processing. The maximum wait time is given in + * microseconds to prevent spinning forever. + * + * Return: + * DMUB_STATUS_OK - success + * DMUB_STATUS_TIMEOUT - wait for buffer to flush timed out + * DMUB_STATUS_INVALID - unspecified error + */ +enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub, + uint32_t timeout_us); + +#if defined(__cplusplus) +} +#endif + +#endif /* _DMUB_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h new file mode 100644 index 000000000000..6b3ee42db350 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_trace_buffer.h @@ -0,0 +1,69 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#ifndef _DMUB_TRACE_BUFFER_H_ +#define _DMUB_TRACE_BUFFER_H_ + +#include "dmub_types.h" + +#define LOAD_DMCU_FW 1 +#define LOAD_PHY_FW 2 + + +enum dmucb_trace_code { + DMCUB__UNKNOWN, + DMCUB__MAIN_BEGIN, + DMCUB__PHY_INIT_BEGIN, + DMCUB__PHY_FW_SRAM_LOAD_BEGIN, + DMCUB__PHY_FW_SRAM_LOAD_END, + DMCUB__PHY_INIT_POLL_DONE, + DMCUB__PHY_INIT_END, + DMCUB__DMCU_ERAM_LOAD_BEGIN, + DMCUB__DMCU_ERAM_LOAD_END, + DMCUB__DMCU_ISR_LOAD_BEGIN, + DMCUB__DMCU_ISR_LOAD_END, + DMCUB__MAIN_IDLE, + DMCUB__PERF_TRACE, + DMCUB__PG_DONE, +}; + +struct dmcub_trace_buf_entry { + enum dmucb_trace_code trace_code; + uint32_t tick_count; + uint32_t param0; + uint32_t param1; +}; + +#define TRACE_BUF_SIZE (1024) //1 kB +#define PERF_TRACE_MAX_ENTRY ((TRACE_BUF_SIZE - 8)/sizeof(struct dmcub_trace_buf_entry)) + + +struct dmcub_trace_buf { + uint32_t entry_count; + uint32_t clk_freq; + struct dmcub_trace_buf_entry entries[PERF_TRACE_MAX_ENTRY]; +}; + + +#endif /* _DMUB_TRACE_BUFFER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h new file mode 100644 index 000000000000..41d524b0db2f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_types.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_TYPES_H_ +#define _DMUB_TYPES_H_ + +/* Basic type definitions. */ +#include <asm/byteorder.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/delay.h> +#include <stdarg.h> + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef dmub_memcpy +#define dmub_memcpy(dest, source, bytes) memcpy((dest), (source), (bytes)) +#endif + +#ifndef dmub_memset +#define dmub_memset(dest, val, bytes) memset((dest), (val), (bytes)) +#endif + +#ifndef dmub_udelay +#define dmub_udelay(microseconds) udelay(microseconds) +#endif + +union dmub_addr { + struct { + uint32_t low_part; + uint32_t high_part; + } u; + uint64_t quad_part; +}; + +#if defined(__cplusplus) +} +#endif + +#endif /* _DMUB_TYPES_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/Makefile b/drivers/gpu/drm/amd/display/dmub/src/Makefile new file mode 100644 index 000000000000..e08dfeea24b0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/Makefile @@ -0,0 +1,27 @@ +# +# Copyright 2019 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +DMUB = dmub_srv.o dmub_reg.o dmub_dcn20.o dmub_dcn21.o + +AMD_DAL_DMUB = $(addprefix $(AMDDALPATH)/dmub/src/,$(DMUB)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DMUB) diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c new file mode 100644 index 000000000000..951ea7053c7e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c @@ -0,0 +1,152 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "../inc/dmub_srv.h" +#include "dmub_reg.h" + +#include "dcn/dcn_2_0_0_offset.h" +#include "dcn/dcn_2_0_0_sh_mask.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" + +#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg +#define CTX dmub + +void dmub_dcn20_reset(struct dmub_srv *dmub) +{ + REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 1); + REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); +} + +void dmub_dcn20_reset_release(struct dmub_srv *dmub) +{ + REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF); + REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1); + REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 0); +} + +void dmub_dcn20_backdoor_load(struct dmub_srv *dmub, struct dmub_window *cw0, + struct dmub_window *cw1) +{ + REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); + REG_UPDATE_2(DMCUB_MEM_CNTL, DMCUB_MEM_READ_SPACE, 0x4, + DMCUB_MEM_WRITE_SPACE, 0x4); + + REG_WRITE(DMCUB_REGION3_CW0_OFFSET, cw0->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, cw0->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); + + REG_WRITE(DMCUB_REGION3_CW1_OFFSET, cw1->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, cw1->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_dcn20_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) +{ + REG_WRITE(DMCUB_REGION3_CW2_OFFSET, cw2->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW2_OFFSET_HIGH, cw2->offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW2_BASE_ADDRESS, cw2->region.base); + REG_SET_2(DMCUB_REGION3_CW2_TOP_ADDRESS, 0, + DMCUB_REGION3_CW2_TOP_ADDRESS, cw2->region.top, + DMCUB_REGION3_CW2_ENABLE, 1); + + REG_WRITE(DMCUB_REGION3_CW3_OFFSET, cw3->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, cw3->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); + + /* TODO: Move this to CW4. */ + + REG_WRITE(DMCUB_REGION4_OFFSET, cw4->offset.u.low_part); + REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, cw4->offset.u.high_part); + REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0, DMCUB_REGION4_TOP_ADDRESS, + cw4->region.top - cw4->region.base - 1, DMCUB_REGION4_ENABLE, + 1); + + REG_WRITE(DMCUB_REGION3_CW5_OFFSET, cw5->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, cw5->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_REGION3_CW6_OFFSET, cw6->offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, cw6->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); +} + +void dmub_dcn20_setup_mailbox(struct dmub_srv *dmub, + const struct dmub_region *inbox1) +{ + /* TODO: Use CW4 instead of region 4. */ + + REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, 0x80000000); + REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base); + REG_WRITE(DMCUB_INBOX1_RPTR, 0); + REG_WRITE(DMCUB_INBOX1_WPTR, 0); +} + +uint32_t dmub_dcn20_get_inbox1_rptr(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_INBOX1_RPTR); +} + +void dmub_dcn20_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset) +{ + REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset); +} + +bool dmub_dcn20_is_hw_init(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_REGION3_CW2_BASE_ADDRESS) != 0; +} + +bool dmub_dcn20_is_supported(struct dmub_srv *dmub) +{ + uint32_t supported = 0; + + REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported); + + return supported; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h new file mode 100644 index 000000000000..e70a57573467 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h @@ -0,0 +1,63 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_DCN20_H_ +#define _DMUB_DCN20_H_ + +#include "../inc/dmub_types.h" + +struct dmub_srv; + +/* Hardware functions. */ + +void dmub_dcn20_init(struct dmub_srv *dmub); + +void dmub_dcn20_reset(struct dmub_srv *dmub); + +void dmub_dcn20_reset_release(struct dmub_srv *dmub); + +void dmub_dcn20_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + +void dmub_dcn20_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); + +void dmub_dcn20_setup_mailbox(struct dmub_srv *dmub, + const struct dmub_region *inbox1); + +uint32_t dmub_dcn20_get_inbox1_rptr(struct dmub_srv *dmub); + +void dmub_dcn20_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset); + +bool dmub_dcn20_is_hw_init(struct dmub_srv *dmub); + +bool dmub_dcn20_is_supported(struct dmub_srv *dmub); + +#endif /* _DMUB_DCN20_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c new file mode 100644 index 000000000000..9cea7a2d8dbf --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c @@ -0,0 +1,141 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "../inc/dmub_srv.h" +#include "dmub_reg.h" + +#include "dcn/dcn_2_1_0_offset.h" +#include "dcn/dcn_2_1_0_sh_mask.h" +#include "renoir_ip_offset.h" + +#define BASE_INNER(seg) DMU_BASE__INST0_SEG##seg +#define CTX dmub + +static inline void dmub_dcn21_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_dcn21_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1) +{ + union dmub_addr offset; + uint64_t fb_base = dmub->fb_base, fb_offset = dmub->fb_offset; + + REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1); + REG_UPDATE_2(DMCUB_MEM_CNTL, DMCUB_MEM_READ_SPACE, 0x3, + DMCUB_MEM_WRITE_SPACE, 0x3); + + dmub_dcn21_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_dcn21_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_dcn21_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) +{ + union dmub_addr offset; + uint64_t fb_base = dmub->fb_base, fb_offset = dmub->fb_offset; + + dmub_dcn21_translate_addr(&cw2->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION3_CW2_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION3_CW2_OFFSET_HIGH, offset.u.high_part); + REG_WRITE(DMCUB_REGION3_CW2_BASE_ADDRESS, cw2->region.base); + REG_SET_2(DMCUB_REGION3_CW2_TOP_ADDRESS, 0, + DMCUB_REGION3_CW2_TOP_ADDRESS, cw2->region.top, + DMCUB_REGION3_CW2_ENABLE, 1); + + dmub_dcn21_translate_addr(&cw3->offset, fb_base, fb_offset, &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); + + /* TODO: Move this to CW4. */ + dmub_dcn21_translate_addr(&cw4->offset, fb_base, fb_offset, &offset); + + REG_WRITE(DMCUB_REGION4_OFFSET, offset.u.low_part); + REG_WRITE(DMCUB_REGION4_OFFSET_HIGH, offset.u.high_part); + REG_SET_2(DMCUB_REGION4_TOP_ADDRESS, 0, DMCUB_REGION4_TOP_ADDRESS, + cw4->region.top - cw4->region.base - 1, DMCUB_REGION4_ENABLE, + 1); + + dmub_dcn21_translate_addr(&cw5->offset, fb_base, fb_offset, &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); + + dmub_dcn21_translate_addr(&cw6->offset, fb_base, fb_offset, &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); +} + +bool dmub_dcn21_is_auto_load_done(struct dmub_srv *dmub) +{ + return (REG_READ(DMCUB_SCRATCH0) == 3); +} + +bool dmub_dcn21_is_phy_init(struct dmub_srv *dmub) +{ + return REG_READ(DMCUB_SCRATCH10) == 0; +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h new file mode 100644 index 000000000000..f7a93a5dcfa5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_DCN21_H_ +#define _DMUB_DCN21_H_ + +#include "dmub_dcn20.h" + +/* Hardware functions. */ + +void dmub_dcn21_backdoor_load(struct dmub_srv *dmub, + const struct dmub_window *cw0, + const struct dmub_window *cw1); + +void dmub_dcn21_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); + +bool dmub_dcn21_is_auto_load_done(struct dmub_srv *dmub); + +bool dmub_dcn21_is_phy_init(struct dmub_srv *dmub); + +#endif /* _DMUB_DCN21_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c new file mode 100644 index 000000000000..4094eca212f0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.c @@ -0,0 +1,109 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dmub_reg.h" +#include "../inc/dmub_srv.h" + +struct dmub_reg_value_masks { + uint32_t value; + uint32_t mask; +}; + +static inline void +set_reg_field_value_masks(struct dmub_reg_value_masks *field_value_mask, + uint32_t value, uint32_t mask, uint8_t shift) +{ + field_value_mask->value = + (field_value_mask->value & ~mask) | (mask & (value << shift)); + field_value_mask->mask = field_value_mask->mask | mask; +} + +static void set_reg_field_values(struct dmub_reg_value_masks *field_value_mask, + uint32_t addr, int n, uint8_t shift1, + uint32_t mask1, uint32_t field_value1, + va_list ap) +{ + uint32_t shift, mask, field_value; + int i = 1; + + /* gather all bits value/mask getting updated in this register */ + set_reg_field_value_masks(field_value_mask, field_value1, mask1, + shift1); + + while (i < n) { + shift = va_arg(ap, uint32_t); + mask = va_arg(ap, uint32_t); + field_value = va_arg(ap, uint32_t); + + set_reg_field_value_masks(field_value_mask, field_value, mask, + shift); + i++; + } +} + +static inline uint32_t get_reg_field_value_ex(uint32_t reg_value, uint32_t mask, + uint8_t shift) +{ + return (mask & reg_value) >> shift; +} + +void dmub_reg_update(struct dmub_srv *srv, uint32_t addr, int n, uint8_t shift1, + uint32_t mask1, uint32_t field_value1, ...) +{ + struct dmub_reg_value_masks field_value_mask = { 0 }; + uint32_t reg_val; + va_list ap; + + va_start(ap, field_value1); + set_reg_field_values(&field_value_mask, addr, n, shift1, mask1, + field_value1, ap); + va_end(ap); + + reg_val = srv->funcs.reg_read(srv->user_ctx, addr); + reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; + srv->funcs.reg_write(srv->user_ctx, addr, reg_val); +} + +void dmub_reg_set(struct dmub_srv *srv, uint32_t addr, uint32_t reg_val, int n, + uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...) +{ + struct dmub_reg_value_masks field_value_mask = { 0 }; + va_list ap; + + va_start(ap, field_value1); + set_reg_field_values(&field_value_mask, addr, n, shift1, mask1, + field_value1, ap); + va_end(ap); + + reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; + srv->funcs.reg_write(srv->user_ctx, addr, reg_val); +} + +void dmub_reg_get(struct dmub_srv *srv, uint32_t addr, uint8_t shift, + uint32_t mask, uint32_t *field_value) +{ + uint32_t reg_val = srv->funcs.reg_read(srv->user_ctx, addr); + *field_value = get_reg_field_value_ex(reg_val, mask, shift); +} diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h new file mode 100644 index 000000000000..bac4ee8f745f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h @@ -0,0 +1,120 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DMUB_REG_H_ +#define _DMUB_REG_H_ + +#include "../inc/dmub_types.h" + +struct dmub_srv; + +/* Register offset and field lookup. */ + +#define BASE(seg) BASE_INNER(seg) + +#define REG_OFFSET(base_index, addr) (BASE(base_index) + addr) + +#define REG(reg_name) REG_OFFSET(mm ## reg_name ## _BASE_IDX, mm ## reg_name) + +#define FD(reg_field) reg_field ## __SHIFT, reg_field ## _MASK + +#define FN(reg_name, field) FD(reg_name##__##field) + +/* Register reads and writes. */ + +#define REG_READ(reg) ((CTX)->funcs.reg_read((CTX)->user_ctx, REG(reg))) + +#define REG_WRITE(reg, val) \ + ((CTX)->funcs.reg_write((CTX)->user_ctx, REG(reg), (val))) + +/* Register field setting. */ + +#define REG_SET_N(reg_name, n, initial_val, ...) \ + dmub_reg_set(CTX, REG(reg_name), initial_val, n, __VA_ARGS__) + +#define REG_SET(reg_name, initial_val, field, val) \ + REG_SET_N(reg_name, 1, initial_val, \ + FN(reg_name, field), val) + +#define REG_SET_2(reg, init_value, f1, v1, f2, v2) \ + REG_SET_N(reg, 2, init_value, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2) + +#define REG_SET_3(reg, init_value, f1, v1, f2, v2, f3, v3) \ + REG_SET_N(reg, 3, init_value, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2, \ + FN(reg, f3), v3) + +#define REG_SET_4(reg, init_value, f1, v1, f2, v2, f3, v3, f4, v4) \ + REG_SET_N(reg, 4, init_value, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2, \ + FN(reg, f3), v3, \ + FN(reg, f4), v4) + +/* Register field updating. */ + +#define REG_UPDATE_N(reg_name, n, ...)\ + dmub_reg_update(CTX, REG(reg_name), n, __VA_ARGS__) + +#define REG_UPDATE(reg_name, field, val) \ + REG_UPDATE_N(reg_name, 1, \ + FN(reg_name, field), val) + +#define REG_UPDATE_2(reg, f1, v1, f2, v2) \ + REG_UPDATE_N(reg, 2,\ + FN(reg, f1), v1,\ + FN(reg, f2), v2) + +#define REG_UPDATE_3(reg, f1, v1, f2, v2, f3, v3) \ + REG_UPDATE_N(reg, 3, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2, \ + FN(reg, f3), v3) + +#define REG_UPDATE_4(reg, f1, v1, f2, v2, f3, v3, f4, v4) \ + REG_UPDATE_N(reg, 4, \ + FN(reg, f1), v1, \ + FN(reg, f2), v2, \ + FN(reg, f3), v3, \ + 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) + +void dmub_reg_set(struct dmub_srv *srv, uint32_t addr, uint32_t reg_val, int n, + uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...); + +void dmub_reg_update(struct dmub_srv *srv, uint32_t addr, int n, uint8_t shift1, + uint32_t mask1, uint32_t field_value1, ...); + +void dmub_reg_get(struct dmub_srv *srv, uint32_t addr, uint8_t shift, + uint32_t mask, uint32_t *field_value); + +#endif /* _DMUB_REG_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c new file mode 100644 index 000000000000..5f39166d3c08 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -0,0 +1,453 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "../inc/dmub_srv.h" +#include "dmub_dcn20.h" +#include "dmub_dcn21.h" +#include "dmub_trace_buffer.h" +#include "os_types.h" +/* + * Note: the DMUB service is standalone. No additional headers should be + * added below or above this line unless they reside within the DMUB + * folder. + */ + +/* Alignment for framebuffer memory. */ +#define DMUB_FB_ALIGNMENT (1024 * 1024) + +/* Stack size. */ +#define DMUB_STACK_SIZE (128 * 1024) + +/* Context size. */ +#define DMUB_CONTEXT_SIZE (512 * 1024) + +/* Mailbox size */ +#define DMUB_MAILBOX_SIZE (DMUB_RB_SIZE) + + +/* Number of windows in use. */ +#define DMUB_NUM_WINDOWS (DMUB_WINDOW_6_FW_STATE + 1) +/* Base addresses. */ + +#define DMUB_CW0_BASE (0x60000000) +#define DMUB_CW1_BASE (0x61000000) +#define DMUB_CW3_BASE (0x63000000) +#define DMUB_CW5_BASE (0x65000000) +#define DMUB_CW6_BASE (0x66000000) + +static inline uint32_t dmub_align(uint32_t val, uint32_t factor) +{ + return (val + factor - 1) / factor * factor; +} + +static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic) +{ + struct dmub_srv_hw_funcs *funcs = &dmub->hw_funcs; + + switch (asic) { + case DMUB_ASIC_DCN20: + case DMUB_ASIC_DCN21: + funcs->reset = dmub_dcn20_reset; + funcs->reset_release = dmub_dcn20_reset_release; + funcs->backdoor_load = dmub_dcn20_backdoor_load; + funcs->setup_windows = dmub_dcn20_setup_windows; + funcs->setup_mailbox = dmub_dcn20_setup_mailbox; + funcs->get_inbox1_rptr = dmub_dcn20_get_inbox1_rptr; + funcs->set_inbox1_wptr = dmub_dcn20_set_inbox1_wptr; + funcs->is_supported = dmub_dcn20_is_supported; + funcs->is_hw_init = dmub_dcn20_is_hw_init; + + if (asic == DMUB_ASIC_DCN21) { + funcs->backdoor_load = dmub_dcn21_backdoor_load; + funcs->setup_windows = dmub_dcn21_setup_windows; + funcs->is_auto_load_done = dmub_dcn21_is_auto_load_done; + funcs->is_phy_init = dmub_dcn21_is_phy_init; + } + break; + + default: + return false; + } + + return true; +} + +enum dmub_status dmub_srv_create(struct dmub_srv *dmub, + const struct dmub_srv_create_params *params) +{ + enum dmub_status status = DMUB_STATUS_OK; + + dmub_memset(dmub, 0, sizeof(*dmub)); + + dmub->funcs = params->funcs; + dmub->user_ctx = params->user_ctx; + dmub->asic = params->asic; + dmub->is_virtual = params->is_virtual; + + /* Setup asic dependent hardware funcs. */ + if (!dmub_srv_hw_setup(dmub, params->asic)) { + status = DMUB_STATUS_INVALID; + goto cleanup; + } + + /* Override (some) hardware funcs based on user params. */ + if (params->hw_funcs) { + if (params->hw_funcs->get_inbox1_rptr) + dmub->hw_funcs.get_inbox1_rptr = + params->hw_funcs->get_inbox1_rptr; + + if (params->hw_funcs->set_inbox1_wptr) + dmub->hw_funcs.set_inbox1_wptr = + params->hw_funcs->set_inbox1_wptr; + + if (params->hw_funcs->is_supported) + dmub->hw_funcs.is_supported = + params->hw_funcs->is_supported; + } + + /* Sanity checks for required hw func pointers. */ + if (!dmub->hw_funcs.get_inbox1_rptr || + !dmub->hw_funcs.set_inbox1_wptr) { + status = DMUB_STATUS_INVALID; + goto cleanup; + } + +cleanup: + if (status == DMUB_STATUS_OK) + dmub->sw_init = true; + else + dmub_srv_destroy(dmub); + + return status; +} + +void dmub_srv_destroy(struct dmub_srv *dmub) +{ + dmub_memset(dmub, 0, sizeof(*dmub)); +} + +enum dmub_status +dmub_srv_calc_region_info(struct dmub_srv *dmub, + const struct dmub_srv_region_params *params, + struct dmub_srv_region_info *out) +{ + struct dmub_region *inst = &out->regions[DMUB_WINDOW_0_INST_CONST]; + struct dmub_region *stack = &out->regions[DMUB_WINDOW_1_STACK]; + struct dmub_region *data = &out->regions[DMUB_WINDOW_2_BSS_DATA]; + struct dmub_region *bios = &out->regions[DMUB_WINDOW_3_VBIOS]; + struct dmub_region *mail = &out->regions[DMUB_WINDOW_4_MAILBOX]; + struct dmub_region *trace_buff = &out->regions[DMUB_WINDOW_5_TRACEBUFF]; + struct dmub_region *fw_state = &out->regions[DMUB_WINDOW_6_FW_STATE]; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + memset(out, 0, sizeof(*out)); + + out->num_regions = DMUB_NUM_WINDOWS; + + inst->base = 0x0; + inst->top = inst->base + params->inst_const_size; + + data->base = dmub_align(inst->top, 256); + data->top = data->base + params->bss_data_size; + + stack->base = dmub_align(data->top, 256); + stack->top = stack->base + DMUB_STACK_SIZE + DMUB_CONTEXT_SIZE; + + bios->base = dmub_align(stack->top, 256); + bios->top = bios->base + params->vbios_size; + + mail->base = dmub_align(bios->top, 256); + mail->top = mail->base + DMUB_MAILBOX_SIZE; + + trace_buff->base = dmub_align(mail->top, 256); + trace_buff->top = trace_buff->base + TRACE_BUF_SIZE; + + fw_state->base = dmub_align(trace_buff->top, 256); + + /* Align firmware state to size of cache line. */ + fw_state->top = + fw_state->base + dmub_align(sizeof(struct dmub_fw_state), 64); + + out->fb_size = dmub_align(fw_state->top, 4096); + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_calc_fb_info(struct dmub_srv *dmub, + const struct dmub_srv_fb_params *params, + struct dmub_srv_fb_info *out) +{ + uint8_t *cpu_base; + uint64_t gpu_base; + uint32_t i; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + memset(out, 0, sizeof(*out)); + + if (params->region_info->num_regions != DMUB_NUM_WINDOWS) + return DMUB_STATUS_INVALID; + + cpu_base = (uint8_t *)params->cpu_addr; + gpu_base = params->gpu_addr; + + for (i = 0; i < DMUB_NUM_WINDOWS; ++i) { + const struct dmub_region *reg = + ¶ms->region_info->regions[i]; + + out->fb[i].cpu_addr = cpu_base + reg->base; + out->fb[i].gpu_addr = gpu_base + reg->base; + out->fb[i].size = reg->top - reg->base; + } + + out->num_fb = DMUB_NUM_WINDOWS; + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_has_hw_support(struct dmub_srv *dmub, + bool *is_supported) +{ + *is_supported = false; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + if (dmub->hw_funcs.is_supported) + *is_supported = dmub->hw_funcs.is_supported(dmub); + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_is_hw_init(struct dmub_srv *dmub, bool *is_hw_init) +{ + *is_hw_init = false; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + if (dmub->hw_funcs.is_hw_init) + *is_hw_init = dmub->hw_funcs.is_hw_init(dmub); + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, + const struct dmub_srv_hw_params *params) +{ + struct dmub_fb *inst_fb = params->fb[DMUB_WINDOW_0_INST_CONST]; + struct dmub_fb *stack_fb = params->fb[DMUB_WINDOW_1_STACK]; + struct dmub_fb *data_fb = params->fb[DMUB_WINDOW_2_BSS_DATA]; + struct dmub_fb *bios_fb = params->fb[DMUB_WINDOW_3_VBIOS]; + struct dmub_fb *mail_fb = params->fb[DMUB_WINDOW_4_MAILBOX]; + struct dmub_fb *tracebuff_fb = params->fb[DMUB_WINDOW_5_TRACEBUFF]; + struct dmub_fb *fw_state_fb = params->fb[DMUB_WINDOW_6_FW_STATE]; + + struct dmub_rb_init_params rb_params; + struct dmub_window cw0, cw1, cw2, cw3, cw4, cw5, cw6; + struct dmub_region inbox1; + + if (!dmub->sw_init) + return DMUB_STATUS_INVALID; + + dmub->fb_base = params->fb_base; + dmub->fb_offset = params->fb_offset; + dmub->psp_version = params->psp_version; + + if (inst_fb && data_fb) { + cw0.offset.quad_part = inst_fb->gpu_addr; + cw0.region.base = DMUB_CW0_BASE; + cw0.region.top = cw0.region.base + inst_fb->size - 1; + + cw1.offset.quad_part = stack_fb->gpu_addr; + cw1.region.base = DMUB_CW1_BASE; + cw1.region.top = cw1.region.base + stack_fb->size - 1; + + if (params->load_inst_const && dmub->hw_funcs.backdoor_load) + dmub->hw_funcs.backdoor_load(dmub, &cw0, &cw1); + } + + if (dmub->hw_funcs.reset) + dmub->hw_funcs.reset(dmub); + + if (inst_fb && data_fb && bios_fb && mail_fb && tracebuff_fb && + fw_state_fb) { + cw2.offset.quad_part = data_fb->gpu_addr; + cw2.region.base = DMUB_CW0_BASE + inst_fb->size; + cw2.region.top = cw2.region.base + data_fb->size; + + cw3.offset.quad_part = bios_fb->gpu_addr; + cw3.region.base = DMUB_CW3_BASE; + cw3.region.top = cw3.region.base + bios_fb->size; + + cw4.offset.quad_part = mail_fb->gpu_addr; + cw4.region.base = cw3.region.top + 1; + cw4.region.top = cw4.region.base + mail_fb->size; + + inbox1.base = cw4.region.base; + inbox1.top = cw4.region.top; + + cw5.offset.quad_part = tracebuff_fb->gpu_addr; + cw5.region.base = DMUB_CW5_BASE; + cw5.region.top = cw5.region.base + tracebuff_fb->size; + + cw6.offset.quad_part = fw_state_fb->gpu_addr; + cw6.region.base = DMUB_CW6_BASE; + cw6.region.top = cw6.region.base + fw_state_fb->size; + + dmub->fw_state = fw_state_fb->cpu_addr; + + if (dmub->hw_funcs.setup_windows) + dmub->hw_funcs.setup_windows(dmub, &cw2, &cw3, &cw4, + &cw5, &cw6); + + if (dmub->hw_funcs.setup_mailbox) + dmub->hw_funcs.setup_mailbox(dmub, &inbox1); + } + + if (mail_fb) { + dmub_memset(&rb_params, 0, sizeof(rb_params)); + rb_params.ctx = dmub; + rb_params.base_address = mail_fb->cpu_addr; + rb_params.capacity = DMUB_RB_SIZE; + + dmub_rb_init(&dmub->inbox1_rb, &rb_params); + } + + if (dmub->hw_funcs.reset_release) + dmub->hw_funcs.reset_release(dmub); + + dmub->hw_init = true; + + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub, + const struct dmub_cmd_header *cmd) +{ + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + if (dmub_rb_push_front(&dmub->inbox1_rb, cmd)) + return DMUB_STATUS_OK; + + return DMUB_STATUS_QUEUE_FULL; +} + +enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub) +{ + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt); + return DMUB_STATUS_OK; +} + +enum dmub_status dmub_srv_cmd_submit(struct dmub_srv *dmub, + const struct dmub_cmd_header *cmd, + uint32_t timeout_us) +{ + uint32_t i = 0; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + for (i = 0; i <= timeout_us; ++i) { + dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub); + if (dmub_rb_push_front(&dmub->inbox1_rb, cmd)) { + dmub->hw_funcs.set_inbox1_wptr(dmub, + dmub->inbox1_rb.wrpt); + return DMUB_STATUS_OK; + } + + udelay(1); + } + + return DMUB_STATUS_TIMEOUT; +} + +enum dmub_status dmub_srv_wait_for_auto_load(struct dmub_srv *dmub, + uint32_t timeout_us) +{ + uint32_t i; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + if (!dmub->hw_funcs.is_auto_load_done) + return DMUB_STATUS_OK; + + for (i = 0; i <= timeout_us; i += 100) { + if (dmub->hw_funcs.is_auto_load_done(dmub)) + return DMUB_STATUS_OK; + + udelay(100); + } + + return DMUB_STATUS_TIMEOUT; +} + +enum dmub_status dmub_srv_wait_for_phy_init(struct dmub_srv *dmub, + uint32_t timeout_us) +{ + uint32_t i = 0; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + if (!dmub->hw_funcs.is_phy_init) + return DMUB_STATUS_OK; + + for (i = 0; i <= timeout_us; i += 10) { + if (dmub->hw_funcs.is_phy_init(dmub)) + return DMUB_STATUS_OK; + + udelay(10); + } + + return DMUB_STATUS_TIMEOUT; +} + +enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub, + uint32_t timeout_us) +{ + uint32_t i; + + if (!dmub->hw_init) + return DMUB_STATUS_INVALID; + + for (i = 0; i <= timeout_us; ++i) { + dmub->inbox1_rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub); + if (dmub_rb_empty(&dmub->inbox1_rb)) + return DMUB_STATUS_OK; + + udelay(1); + } + + return DMUB_STATUS_TIMEOUT; +} |