Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2020 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "../dmub_srv.h"
0027 #include "dmub_reg.h"
0028 #include "dmub_dcn31.h"
0029 
0030 #include "yellow_carp_offset.h"
0031 #include "dcn/dcn_3_1_2_offset.h"
0032 #include "dcn/dcn_3_1_2_sh_mask.h"
0033 
0034 #define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg
0035 #define CTX dmub
0036 #define REGS dmub->regs_dcn31
0037 #define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name)
0038 
0039 const struct dmub_srv_dcn31_regs dmub_srv_dcn31_regs = {
0040 #define DMUB_SR(reg) REG_OFFSET_EXP(reg),
0041     {
0042         DMUB_DCN31_REGS()
0043         DMCUB_INTERNAL_REGS()
0044     },
0045 #undef DMUB_SR
0046 
0047 #define DMUB_SF(reg, field) FD_MASK(reg, field),
0048     { DMUB_DCN31_FIELDS() },
0049 #undef DMUB_SF
0050 
0051 #define DMUB_SF(reg, field) FD_SHIFT(reg, field),
0052     { DMUB_DCN31_FIELDS() },
0053 #undef DMUB_SF
0054 };
0055 
0056 static void dmub_dcn31_get_fb_base_offset(struct dmub_srv *dmub,
0057                       uint64_t *fb_base,
0058                       uint64_t *fb_offset)
0059 {
0060     uint32_t tmp;
0061 
0062     if (dmub->fb_base || dmub->fb_offset) {
0063         *fb_base = dmub->fb_base;
0064         *fb_offset = dmub->fb_offset;
0065         return;
0066     }
0067 
0068     REG_GET(DCN_VM_FB_LOCATION_BASE, FB_BASE, &tmp);
0069     *fb_base = (uint64_t)tmp << 24;
0070 
0071     REG_GET(DCN_VM_FB_OFFSET, FB_OFFSET, &tmp);
0072     *fb_offset = (uint64_t)tmp << 24;
0073 }
0074 
0075 static inline void dmub_dcn31_translate_addr(const union dmub_addr *addr_in,
0076                          uint64_t fb_base,
0077                          uint64_t fb_offset,
0078                          union dmub_addr *addr_out)
0079 {
0080     addr_out->quad_part = addr_in->quad_part - fb_base + fb_offset;
0081 }
0082 
0083 void dmub_dcn31_reset(struct dmub_srv *dmub)
0084 {
0085     union dmub_gpint_data_register cmd;
0086     const uint32_t timeout = 100;
0087     uint32_t in_reset, scratch, i, pwait_mode;
0088 
0089     REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
0090 
0091     if (in_reset == 0) {
0092         cmd.bits.status = 1;
0093         cmd.bits.command_code = DMUB_GPINT__STOP_FW;
0094         cmd.bits.param = 0;
0095 
0096         dmub->hw_funcs.set_gpint(dmub, cmd);
0097 
0098         /**
0099          * Timeout covers both the ACK and the wait
0100          * for remaining work to finish.
0101          */
0102 
0103         for (i = 0; i < timeout; ++i) {
0104             if (dmub->hw_funcs.is_gpint_acked(dmub, cmd))
0105                 break;
0106 
0107             udelay(1);
0108         }
0109 
0110         for (i = 0; i < timeout; ++i) {
0111             scratch = dmub->hw_funcs.get_gpint_response(dmub);
0112             if (scratch == DMUB_GPINT__STOP_FW_RESPONSE)
0113                 break;
0114 
0115             udelay(1);
0116         }
0117 
0118         for (i = 0; i < timeout; ++i) {
0119             REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &pwait_mode);
0120             if (pwait_mode & (1 << 0))
0121                 break;
0122 
0123             udelay(1);
0124         }
0125         /* Force reset in case we timed out, DMCUB is likely hung. */
0126     }
0127 
0128     REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 1);
0129     REG_UPDATE(DMCUB_CNTL, DMCUB_ENABLE, 0);
0130     REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 1);
0131     REG_WRITE(DMCUB_INBOX1_RPTR, 0);
0132     REG_WRITE(DMCUB_INBOX1_WPTR, 0);
0133     REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
0134     REG_WRITE(DMCUB_OUTBOX1_WPTR, 0);
0135     REG_WRITE(DMCUB_OUTBOX0_RPTR, 0);
0136     REG_WRITE(DMCUB_OUTBOX0_WPTR, 0);
0137     REG_WRITE(DMCUB_SCRATCH0, 0);
0138 
0139     /* Clear the GPINT command manually so we don't send anything during boot. */
0140     cmd.all = 0;
0141     dmub->hw_funcs.set_gpint(dmub, cmd);
0142 }
0143 
0144 void dmub_dcn31_reset_release(struct dmub_srv *dmub)
0145 {
0146     REG_UPDATE(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET, 0);
0147     REG_WRITE(DMCUB_SCRATCH15, dmub->psp_version & 0x001100FF);
0148     REG_UPDATE_2(DMCUB_CNTL, DMCUB_ENABLE, 1, DMCUB_TRACEPORT_EN, 1);
0149     REG_UPDATE(DMCUB_CNTL2, DMCUB_SOFT_RESET, 0);
0150 }
0151 
0152 void dmub_dcn31_backdoor_load(struct dmub_srv *dmub,
0153                   const struct dmub_window *cw0,
0154                   const struct dmub_window *cw1)
0155 {
0156     union dmub_addr offset;
0157     uint64_t fb_base, fb_offset;
0158 
0159     dmub_dcn31_get_fb_base_offset(dmub, &fb_base, &fb_offset);
0160 
0161     REG_UPDATE(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 1);
0162 
0163     dmub_dcn31_translate_addr(&cw0->offset, fb_base, fb_offset, &offset);
0164 
0165     REG_WRITE(DMCUB_REGION3_CW0_OFFSET, offset.u.low_part);
0166     REG_WRITE(DMCUB_REGION3_CW0_OFFSET_HIGH, offset.u.high_part);
0167     REG_WRITE(DMCUB_REGION3_CW0_BASE_ADDRESS, cw0->region.base);
0168     REG_SET_2(DMCUB_REGION3_CW0_TOP_ADDRESS, 0,
0169           DMCUB_REGION3_CW0_TOP_ADDRESS, cw0->region.top,
0170           DMCUB_REGION3_CW0_ENABLE, 1);
0171 
0172     dmub_dcn31_translate_addr(&cw1->offset, fb_base, fb_offset, &offset);
0173 
0174     REG_WRITE(DMCUB_REGION3_CW1_OFFSET, offset.u.low_part);
0175     REG_WRITE(DMCUB_REGION3_CW1_OFFSET_HIGH, offset.u.high_part);
0176     REG_WRITE(DMCUB_REGION3_CW1_BASE_ADDRESS, cw1->region.base);
0177     REG_SET_2(DMCUB_REGION3_CW1_TOP_ADDRESS, 0,
0178           DMCUB_REGION3_CW1_TOP_ADDRESS, cw1->region.top,
0179           DMCUB_REGION3_CW1_ENABLE, 1);
0180 
0181     REG_UPDATE_2(DMCUB_SEC_CNTL, DMCUB_SEC_RESET, 0, DMCUB_MEM_UNIT_ID,
0182              0x20);
0183 }
0184 
0185 void dmub_dcn31_setup_windows(struct dmub_srv *dmub,
0186                   const struct dmub_window *cw2,
0187                   const struct dmub_window *cw3,
0188                   const struct dmub_window *cw4,
0189                   const struct dmub_window *cw5,
0190                   const struct dmub_window *cw6)
0191 {
0192     union dmub_addr offset;
0193 
0194     offset = cw3->offset;
0195 
0196     REG_WRITE(DMCUB_REGION3_CW3_OFFSET, offset.u.low_part);
0197     REG_WRITE(DMCUB_REGION3_CW3_OFFSET_HIGH, offset.u.high_part);
0198     REG_WRITE(DMCUB_REGION3_CW3_BASE_ADDRESS, cw3->region.base);
0199     REG_SET_2(DMCUB_REGION3_CW3_TOP_ADDRESS, 0,
0200           DMCUB_REGION3_CW3_TOP_ADDRESS, cw3->region.top,
0201           DMCUB_REGION3_CW3_ENABLE, 1);
0202 
0203     offset = cw4->offset;
0204 
0205     REG_WRITE(DMCUB_REGION3_CW4_OFFSET, offset.u.low_part);
0206     REG_WRITE(DMCUB_REGION3_CW4_OFFSET_HIGH, offset.u.high_part);
0207     REG_WRITE(DMCUB_REGION3_CW4_BASE_ADDRESS, cw4->region.base);
0208     REG_SET_2(DMCUB_REGION3_CW4_TOP_ADDRESS, 0,
0209           DMCUB_REGION3_CW4_TOP_ADDRESS, cw4->region.top,
0210           DMCUB_REGION3_CW4_ENABLE, 1);
0211 
0212     offset = cw5->offset;
0213 
0214     REG_WRITE(DMCUB_REGION3_CW5_OFFSET, offset.u.low_part);
0215     REG_WRITE(DMCUB_REGION3_CW5_OFFSET_HIGH, offset.u.high_part);
0216     REG_WRITE(DMCUB_REGION3_CW5_BASE_ADDRESS, cw5->region.base);
0217     REG_SET_2(DMCUB_REGION3_CW5_TOP_ADDRESS, 0,
0218           DMCUB_REGION3_CW5_TOP_ADDRESS, cw5->region.top,
0219           DMCUB_REGION3_CW5_ENABLE, 1);
0220 
0221     REG_WRITE(DMCUB_REGION5_OFFSET, offset.u.low_part);
0222     REG_WRITE(DMCUB_REGION5_OFFSET_HIGH, offset.u.high_part);
0223     REG_SET_2(DMCUB_REGION5_TOP_ADDRESS, 0,
0224           DMCUB_REGION5_TOP_ADDRESS,
0225           cw5->region.top - cw5->region.base - 1,
0226           DMCUB_REGION5_ENABLE, 1);
0227 
0228     offset = cw6->offset;
0229 
0230     REG_WRITE(DMCUB_REGION3_CW6_OFFSET, offset.u.low_part);
0231     REG_WRITE(DMCUB_REGION3_CW6_OFFSET_HIGH, offset.u.high_part);
0232     REG_WRITE(DMCUB_REGION3_CW6_BASE_ADDRESS, cw6->region.base);
0233     REG_SET_2(DMCUB_REGION3_CW6_TOP_ADDRESS, 0,
0234           DMCUB_REGION3_CW6_TOP_ADDRESS, cw6->region.top,
0235           DMCUB_REGION3_CW6_ENABLE, 1);
0236 }
0237 
0238 void dmub_dcn31_setup_mailbox(struct dmub_srv *dmub,
0239                   const struct dmub_region *inbox1)
0240 {
0241     REG_WRITE(DMCUB_INBOX1_BASE_ADDRESS, inbox1->base);
0242     REG_WRITE(DMCUB_INBOX1_SIZE, inbox1->top - inbox1->base);
0243 }
0244 
0245 uint32_t dmub_dcn31_get_inbox1_rptr(struct dmub_srv *dmub)
0246 {
0247     return REG_READ(DMCUB_INBOX1_RPTR);
0248 }
0249 
0250 void dmub_dcn31_set_inbox1_wptr(struct dmub_srv *dmub, uint32_t wptr_offset)
0251 {
0252     REG_WRITE(DMCUB_INBOX1_WPTR, wptr_offset);
0253 }
0254 
0255 void dmub_dcn31_setup_out_mailbox(struct dmub_srv *dmub,
0256                   const struct dmub_region *outbox1)
0257 {
0258     REG_WRITE(DMCUB_OUTBOX1_BASE_ADDRESS, outbox1->base);
0259     REG_WRITE(DMCUB_OUTBOX1_SIZE, outbox1->top - outbox1->base);
0260 }
0261 
0262 uint32_t dmub_dcn31_get_outbox1_wptr(struct dmub_srv *dmub)
0263 {
0264     /**
0265      * outbox1 wptr register is accessed without locks (dal & dc)
0266      * and to be called only by dmub_srv_stat_get_notification()
0267      */
0268     return REG_READ(DMCUB_OUTBOX1_WPTR);
0269 }
0270 
0271 void dmub_dcn31_set_outbox1_rptr(struct dmub_srv *dmub, uint32_t rptr_offset)
0272 {
0273     /**
0274      * outbox1 rptr register is accessed without locks (dal & dc)
0275      * and to be called only by dmub_srv_stat_get_notification()
0276      */
0277     REG_WRITE(DMCUB_OUTBOX1_RPTR, rptr_offset);
0278 }
0279 
0280 bool dmub_dcn31_is_hw_init(struct dmub_srv *dmub)
0281 {
0282     union dmub_fw_boot_status status;
0283     uint32_t is_enable;
0284 
0285     status.all = REG_READ(DMCUB_SCRATCH0);
0286     REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_enable);
0287 
0288     return is_enable != 0 && status.bits.dal_fw;
0289 }
0290 
0291 bool dmub_dcn31_is_supported(struct dmub_srv *dmub)
0292 {
0293     uint32_t supported = 0;
0294 
0295     REG_GET(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE, &supported);
0296 
0297     return supported;
0298 }
0299 
0300 void dmub_dcn31_set_gpint(struct dmub_srv *dmub,
0301               union dmub_gpint_data_register reg)
0302 {
0303     REG_WRITE(DMCUB_GPINT_DATAIN1, reg.all);
0304 }
0305 
0306 bool dmub_dcn31_is_gpint_acked(struct dmub_srv *dmub,
0307                    union dmub_gpint_data_register reg)
0308 {
0309     union dmub_gpint_data_register test;
0310 
0311     reg.bits.status = 0;
0312     test.all = REG_READ(DMCUB_GPINT_DATAIN1);
0313 
0314     return test.all == reg.all;
0315 }
0316 
0317 uint32_t dmub_dcn31_get_gpint_response(struct dmub_srv *dmub)
0318 {
0319     return REG_READ(DMCUB_SCRATCH7);
0320 }
0321 
0322 uint32_t dmub_dcn31_get_gpint_dataout(struct dmub_srv *dmub)
0323 {
0324     uint32_t dataout = REG_READ(DMCUB_GPINT_DATAOUT);
0325 
0326     REG_UPDATE(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN, 0);
0327 
0328     REG_WRITE(DMCUB_GPINT_DATAOUT, 0);
0329     REG_UPDATE(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK, 1);
0330     REG_UPDATE(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK, 0);
0331 
0332     REG_UPDATE(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN, 1);
0333 
0334     return dataout;
0335 }
0336 
0337 union dmub_fw_boot_status dmub_dcn31_get_fw_boot_status(struct dmub_srv *dmub)
0338 {
0339     union dmub_fw_boot_status status;
0340 
0341     status.all = REG_READ(DMCUB_SCRATCH0);
0342     return status;
0343 }
0344 
0345 void dmub_dcn31_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmub_srv_hw_params *params)
0346 {
0347     union dmub_fw_boot_options boot_options = {0};
0348 
0349     boot_options.bits.z10_disable = params->disable_z10;
0350     boot_options.bits.dpia_supported = params->dpia_supported;
0351     boot_options.bits.enable_dpia = params->disable_dpia ? 0 : 1;
0352     boot_options.bits.usb4_cm_version = params->usb4_cm_version;
0353     boot_options.bits.power_optimization = params->power_optimization;
0354 
0355     boot_options.bits.sel_mux_phy_c_d_phy_f_g = (dmub->asic == DMUB_ASIC_DCN31B) ? 1 : 0;
0356 
0357     REG_WRITE(DMCUB_SCRATCH14, boot_options.all);
0358 }
0359 
0360 void dmub_dcn31_skip_dmub_panel_power_sequence(struct dmub_srv *dmub, bool skip)
0361 {
0362     union dmub_fw_boot_options boot_options;
0363     boot_options.all = REG_READ(DMCUB_SCRATCH14);
0364     boot_options.bits.skip_phy_init_panel_sequence = skip;
0365     REG_WRITE(DMCUB_SCRATCH14, boot_options.all);
0366 }
0367 
0368 void dmub_dcn31_setup_outbox0(struct dmub_srv *dmub,
0369                   const struct dmub_region *outbox0)
0370 {
0371     REG_WRITE(DMCUB_OUTBOX0_BASE_ADDRESS, outbox0->base);
0372 
0373     REG_WRITE(DMCUB_OUTBOX0_SIZE, outbox0->top - outbox0->base);
0374 }
0375 
0376 uint32_t dmub_dcn31_get_outbox0_wptr(struct dmub_srv *dmub)
0377 {
0378     return REG_READ(DMCUB_OUTBOX0_WPTR);
0379 }
0380 
0381 void dmub_dcn31_set_outbox0_rptr(struct dmub_srv *dmub, uint32_t rptr_offset)
0382 {
0383     REG_WRITE(DMCUB_OUTBOX0_RPTR, rptr_offset);
0384 }
0385 
0386 uint32_t dmub_dcn31_get_current_time(struct dmub_srv *dmub)
0387 {
0388     return REG_READ(DMCUB_TIMER_CURRENT);
0389 }
0390 
0391 void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnostic_data *diag_data)
0392 {
0393     uint32_t is_dmub_enabled, is_soft_reset, is_sec_reset;
0394     uint32_t is_traceport_enabled, is_cw0_enabled, is_cw6_enabled;
0395 
0396     if (!dmub || !diag_data)
0397         return;
0398 
0399     memset(diag_data, 0, sizeof(*diag_data));
0400 
0401     diag_data->dmcub_version = dmub->fw_version;
0402 
0403     diag_data->scratch[0] = REG_READ(DMCUB_SCRATCH0);
0404     diag_data->scratch[1] = REG_READ(DMCUB_SCRATCH1);
0405     diag_data->scratch[2] = REG_READ(DMCUB_SCRATCH2);
0406     diag_data->scratch[3] = REG_READ(DMCUB_SCRATCH3);
0407     diag_data->scratch[4] = REG_READ(DMCUB_SCRATCH4);
0408     diag_data->scratch[5] = REG_READ(DMCUB_SCRATCH5);
0409     diag_data->scratch[6] = REG_READ(DMCUB_SCRATCH6);
0410     diag_data->scratch[7] = REG_READ(DMCUB_SCRATCH7);
0411     diag_data->scratch[8] = REG_READ(DMCUB_SCRATCH8);
0412     diag_data->scratch[9] = REG_READ(DMCUB_SCRATCH9);
0413     diag_data->scratch[10] = REG_READ(DMCUB_SCRATCH10);
0414     diag_data->scratch[11] = REG_READ(DMCUB_SCRATCH11);
0415     diag_data->scratch[12] = REG_READ(DMCUB_SCRATCH12);
0416     diag_data->scratch[13] = REG_READ(DMCUB_SCRATCH13);
0417     diag_data->scratch[14] = REG_READ(DMCUB_SCRATCH14);
0418     diag_data->scratch[15] = REG_READ(DMCUB_SCRATCH15);
0419 
0420     diag_data->undefined_address_fault_addr = REG_READ(DMCUB_UNDEFINED_ADDRESS_FAULT_ADDR);
0421     diag_data->inst_fetch_fault_addr = REG_READ(DMCUB_INST_FETCH_FAULT_ADDR);
0422     diag_data->data_write_fault_addr = REG_READ(DMCUB_DATA_WRITE_FAULT_ADDR);
0423 
0424     diag_data->inbox1_rptr = REG_READ(DMCUB_INBOX1_RPTR);
0425     diag_data->inbox1_wptr = REG_READ(DMCUB_INBOX1_WPTR);
0426     diag_data->inbox1_size = REG_READ(DMCUB_INBOX1_SIZE);
0427 
0428     diag_data->inbox0_rptr = REG_READ(DMCUB_INBOX0_RPTR);
0429     diag_data->inbox0_wptr = REG_READ(DMCUB_INBOX0_WPTR);
0430     diag_data->inbox0_size = REG_READ(DMCUB_INBOX0_SIZE);
0431 
0432     REG_GET(DMCUB_CNTL, DMCUB_ENABLE, &is_dmub_enabled);
0433     diag_data->is_dmcub_enabled = is_dmub_enabled;
0434 
0435     REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &is_soft_reset);
0436     diag_data->is_dmcub_soft_reset = is_soft_reset;
0437 
0438     REG_GET(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS, &is_sec_reset);
0439     diag_data->is_dmcub_secure_reset = is_sec_reset;
0440 
0441     REG_GET(DMCUB_CNTL, DMCUB_TRACEPORT_EN, &is_traceport_enabled);
0442     diag_data->is_traceport_en  = is_traceport_enabled;
0443 
0444     REG_GET(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE, &is_cw0_enabled);
0445     diag_data->is_cw0_enabled = is_cw0_enabled;
0446 
0447     REG_GET(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE, &is_cw6_enabled);
0448     diag_data->is_cw6_enabled = is_cw6_enabled;
0449 }
0450 
0451 bool dmub_dcn31_should_detect(struct dmub_srv *dmub)
0452 {
0453     uint32_t fw_boot_status = REG_READ(DMCUB_SCRATCH0);
0454     bool should_detect = (fw_boot_status & DMUB_FW_BOOT_STATUS_BIT_DETECTION_REQUIRED) != 0;
0455     return should_detect;
0456 }
0457