diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dmub/src')
-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 | 202 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h | 182 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c | 64 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.h | 41 | ||||
-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 | 124 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c | 505 |
8 files changed, 1254 insertions, 0 deletions
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..cd51c6138894 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.c @@ -0,0 +1,202 @@ +/* + * 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 "dmub_dcn20.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 +#define REGS dmub->regs + +/* Registers. */ + +const struct dmub_srv_common_regs dmub_srv_dcn20_regs = { +#define DMUB_SR(reg) REG_OFFSET(reg), + { DMUB_COMMON_REGS() }, +#undef DMUB_SR + +#define DMUB_SF(reg, field) FD_MASK(reg, field), + { DMUB_COMMON_FIELDS() }, +#undef DMUB_SF + +#define DMUB_SF(reg, field) FD_SHIFT(reg, field), + { DMUB_COMMON_FIELDS() }, +#undef DMUB_SF +}; + +/* Shared functions. */ + +static inline void dmub_dcn20_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_dcn20_reset(struct dmub_srv *dmub) +{ + REG_UPDATE(DMCUB_CNTL, DMCUB_SOFT_RESET, 1); + REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0); + REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1); +} + +void dmub_dcn20_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_CNTL, DMCUB_SOFT_RESET, 0); +} + +void dmub_dcn20_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_dcn20_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_dcn20_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_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) +{ + union dmub_addr offset; + uint64_t fb_base = dmub->fb_base, fb_offset = dmub->fb_offset; + + dmub_dcn20_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_dcn20_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_dcn20_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_dcn20_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_dcn20_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); +} + +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..53bfd4da69ad --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn20.h @@ -0,0 +1,182 @@ +/* + * 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; + +/* DCN20 register definitions. */ + +#define DMUB_COMMON_REGS() \ + DMUB_SR(DMCUB_CNTL) \ + DMUB_SR(DMCUB_MEM_CNTL) \ + DMUB_SR(DMCUB_SEC_CNTL) \ + DMUB_SR(DMCUB_INBOX1_BASE_ADDRESS) \ + DMUB_SR(DMCUB_INBOX1_SIZE) \ + DMUB_SR(DMCUB_INBOX1_RPTR) \ + DMUB_SR(DMCUB_INBOX1_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_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(CC_DC_PIPE_DIS) \ + DMUB_SR(MMHUBBUB_SOFT_RESET) + +#define DMUB_COMMON_FIELDS() \ + DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \ + DMUB_SF(DMCUB_CNTL, DMCUB_SOFT_RESET) \ + DMUB_SF(DMCUB_CNTL, DMCUB_TRACEPORT_EN) \ + DMUB_SF(DMCUB_MEM_CNTL, DMCUB_MEM_READ_SPACE) \ + DMUB_SF(DMCUB_MEM_CNTL, DMCUB_MEM_WRITE_SPACE) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \ + DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \ + 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(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE) \ + DMUB_SF(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET) + +struct dmub_srv_common_reg_offset { +#define DMUB_SR(reg) uint32_t reg; + DMUB_COMMON_REGS() +#undef DMUB_SR +}; + +struct dmub_srv_common_reg_shift { +#define DMUB_SF(reg, field) uint8_t reg##__##field; + DMUB_COMMON_FIELDS() +#undef DMUB_SF +}; + +struct dmub_srv_common_reg_mask { +#define DMUB_SF(reg, field) uint32_t reg##__##field; + DMUB_COMMON_FIELDS() +#undef DMUB_SF +}; + +struct dmub_srv_common_regs { + const struct dmub_srv_common_reg_offset offset; + const struct dmub_srv_common_reg_mask mask; + const struct dmub_srv_common_reg_shift shift; +}; + +extern const struct dmub_srv_common_regs dmub_srv_dcn20_regs; + +/* 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..5bed9fcd6b5c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.c @@ -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 + * + */ + +#include "../inc/dmub_srv.h" +#include "dmub_reg.h" +#include "dmub_dcn21.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 +#define REGS dmub->regs + +/* Registers. */ + +const struct dmub_srv_common_regs dmub_srv_dcn21_regs = { +#define DMUB_SR(reg) REG_OFFSET(reg), + { DMUB_COMMON_REGS() }, +#undef DMUB_SR + +#define DMUB_SF(reg, field) FD_MASK(reg, field), + { DMUB_COMMON_FIELDS() }, +#undef DMUB_SF + +#define DMUB_SF(reg, field) FD_SHIFT(reg, field), + { DMUB_COMMON_FIELDS() }, +#undef DMUB_SF +}; + +/* Shared functions. */ + +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..2bbea237137b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn21.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_DCN21_H_ +#define _DMUB_DCN21_H_ + +#include "dmub_dcn20.h" + +/* Registers. */ + +extern const struct dmub_srv_common_regs dmub_srv_dcn21_regs; + +/* Hardware functions. */ + +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..c1f4030929a4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_reg.h @@ -0,0 +1,124 @@ +/* + * 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(reg_name) (BASE(mm##reg_name##_BASE_IDX) + mm##reg_name) + +#define FD_SHIFT(reg_name, field) reg_name##__##field##__SHIFT + +#define FD_MASK(reg_name, field) reg_name##__##field##_MASK + +#define REG(reg) (REGS)->offset.reg + +#define FD(reg_field) (REGS)->shift.reg_field, (REGS)->mask.reg_field + +#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..dee676335d73 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -0,0 +1,505 @@ +/* + * 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_fw_meta.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) + +/* Default state size if meta is absent. */ +#define DMUB_FW_STATE_SIZE (1024) + +/* Default tracebuffer size if meta is absent. */ +#define DMUB_TRACE_BUFFER_SIZE (1024) + +/* 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 void dmub_flush_buffer_mem(const struct dmub_fb *fb) +{ + const uint8_t *base = (const uint8_t *)fb->cpu_addr; + uint8_t buf[64]; + uint32_t pos, end; + + /** + * Read 64-byte chunks since we don't want to store a + * large temporary buffer for this purpose. + */ + end = fb->size / sizeof(buf) * sizeof(buf); + + for (pos = 0; pos < end; pos += sizeof(buf)) + dmub_memcpy(buf, base + pos, sizeof(buf)); + + /* Read anything leftover into the buffer. */ + if (end < fb->size) + dmub_memcpy(buf, base + pos, fb->size - end); +} + +static const struct dmub_fw_meta_info * +dmub_get_fw_meta_info(const uint8_t *fw_bss_data, uint32_t fw_bss_data_size) +{ + const union dmub_fw_meta *meta; + + if (fw_bss_data == NULL) + return NULL; + + if (fw_bss_data_size < sizeof(union dmub_fw_meta) + DMUB_FW_META_OFFSET) + return NULL; + + meta = (const union dmub_fw_meta *)(fw_bss_data + fw_bss_data_size - + DMUB_FW_META_OFFSET - + sizeof(union dmub_fw_meta)); + + if (meta->info.magic_value != DMUB_FW_META_MAGIC) + return NULL; + + return &meta->info; +} + +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: + dmub->regs = &dmub_srv_dcn20_regs; + + 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) { + dmub->regs = &dmub_srv_dcn21_regs; + + 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]; + const struct dmub_fw_meta_info *fw_info; + uint32_t fw_state_size = DMUB_FW_STATE_SIZE; + uint32_t trace_buffer_size = DMUB_TRACE_BUFFER_SIZE; + + 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; + + /* + * All cache windows below should be aligned to the size + * of the DMCUB cache line, 64 bytes. + */ + + 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; + + fw_info = dmub_get_fw_meta_info(params->fw_bss_data, + params->bss_data_size); + + if (fw_info) { + fw_state_size = fw_info->fw_region_size; + trace_buffer_size = fw_info->trace_buffer_size; + } + + trace_buff->base = dmub_align(mail->top, 256); + trace_buff->top = trace_buff->base + dmub_align(trace_buffer_size, 64); + + fw_state->base = dmub_align(trace_buff->top, 256); + fw_state->top = fw_state->base + dmub_align(fw_state_size, 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; + + /** + * Read back all the instruction memory so we don't hang the + * DMCUB when backdoor loading if the write from x86 hasn't been + * flushed yet. This only occurs in backdoor loading. + */ + dmub_flush_buffer_mem(inst_fb); + + 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; + + /** + * Read back all the queued commands to ensure that they've + * been flushed to framebuffer memory. Otherwise DMCUB might + * read back stale, fully invalid or partially invalid data. + */ + dmub_rb_flush_pending(&dmub->inbox1_rb); + + dmub->hw_funcs.set_inbox1_wptr(dmub, dmub->inbox1_rb.wrpt); + return DMUB_STATUS_OK; +} + +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; +} |