1 /* 2 * Copyright 2019 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "dc.h" 27 #include "dc_dmub_srv.h" 28 #include "../dmub/dmub_srv.h" 29 #include "dm_helpers.h" 30 31 #define CTX dc_dmub_srv->ctx 32 #define DC_LOGGER CTX->logger 33 34 static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc, 35 struct dmub_srv *dmub) 36 { 37 dc_srv->dmub = dmub; 38 dc_srv->ctx = dc->ctx; 39 } 40 41 struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub) 42 { 43 struct dc_dmub_srv *dc_srv = 44 kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL); 45 46 if (dc_srv == NULL) { 47 BREAK_TO_DEBUGGER(); 48 return NULL; 49 } 50 51 dc_dmub_srv_construct(dc_srv, dc, dmub); 52 53 return dc_srv; 54 } 55 56 void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv) 57 { 58 if (*dmub_srv) { 59 kfree(*dmub_srv); 60 *dmub_srv = NULL; 61 } 62 } 63 64 void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, 65 union dmub_rb_cmd *cmd) 66 { 67 struct dmub_srv *dmub = dc_dmub_srv->dmub; 68 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 69 enum dmub_status status; 70 71 status = dmub_srv_cmd_queue(dmub, cmd); 72 if (status == DMUB_STATUS_OK) 73 return; 74 75 if (status != DMUB_STATUS_QUEUE_FULL) 76 goto error; 77 78 /* Execute and wait for queue to become empty again. */ 79 dc_dmub_srv_cmd_execute(dc_dmub_srv); 80 dc_dmub_srv_wait_idle(dc_dmub_srv); 81 82 /* Requeue the command. */ 83 status = dmub_srv_cmd_queue(dmub, cmd); 84 if (status == DMUB_STATUS_OK) 85 return; 86 87 error: 88 DC_ERROR("Error queuing DMUB command: status=%d\n", status); 89 } 90 91 void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv) 92 { 93 struct dmub_srv *dmub = dc_dmub_srv->dmub; 94 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 95 enum dmub_status status; 96 97 status = dmub_srv_cmd_execute(dmub); 98 if (status != DMUB_STATUS_OK) 99 DC_ERROR("Error starting DMUB execution: status=%d\n", status); 100 } 101 102 void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) 103 { 104 struct dmub_srv *dmub = dc_dmub_srv->dmub; 105 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 106 enum dmub_status status; 107 108 status = dmub_srv_wait_for_idle(dmub, 100000); 109 if (status != DMUB_STATUS_OK) 110 DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); 111 } 112 113 void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dmub_srv, 114 union dmub_inbox0_data_register data) 115 { 116 struct dmub_srv *dmub = dmub_srv->dmub; 117 if (dmub->hw_funcs.send_inbox0_cmd) 118 dmub->hw_funcs.send_inbox0_cmd(dmub, data); 119 // TODO: Add wait command -- poll register for ACK 120 } 121 122 bool dc_dmub_srv_cmd_with_reply_data(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd) 123 { 124 struct dmub_srv *dmub; 125 enum dmub_status status; 126 127 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 128 return false; 129 130 dmub = dc_dmub_srv->dmub; 131 132 status = dmub_srv_cmd_with_reply_data(dmub, cmd); 133 if (status != DMUB_STATUS_OK) { 134 DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); 135 return false; 136 } 137 138 return true; 139 } 140 141 void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv) 142 { 143 struct dmub_srv *dmub = dc_dmub_srv->dmub; 144 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 145 enum dmub_status status; 146 147 for (;;) { 148 /* Wait up to a second for PHY init. */ 149 status = dmub_srv_wait_for_phy_init(dmub, 1000000); 150 if (status == DMUB_STATUS_OK) 151 /* Initialization OK */ 152 break; 153 154 DC_ERROR("DMCUB PHY init failed: status=%d\n", status); 155 ASSERT(0); 156 157 if (status != DMUB_STATUS_TIMEOUT) 158 /* 159 * Server likely initialized or we don't have 160 * DMCUB HW support - this won't end. 161 */ 162 break; 163 164 /* Continue spinning so we don't hang the ASIC. */ 165 } 166 } 167 168 bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv, 169 unsigned int stream_mask) 170 { 171 struct dmub_srv *dmub; 172 const uint32_t timeout = 30; 173 174 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 175 return false; 176 177 dmub = dc_dmub_srv->dmub; 178 179 return dmub_srv_send_gpint_command( 180 dmub, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK, 181 stream_mask, timeout) == DMUB_STATUS_OK; 182 } 183 #if defined(CONFIG_DRM_AMD_DC_DCN3_1) 184 bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv) 185 { 186 struct dmub_srv *dmub; 187 struct dc_context *dc_ctx; 188 union dmub_fw_boot_status boot_status; 189 enum dmub_status status; 190 191 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 192 return false; 193 194 dmub = dc_dmub_srv->dmub; 195 dc_ctx = dc_dmub_srv->ctx; 196 197 status = dmub_srv_get_fw_boot_status(dmub, &boot_status); 198 if (status != DMUB_STATUS_OK) { 199 DC_ERROR("Error querying DMUB boot status: error=%d\n", status); 200 return false; 201 } 202 203 return boot_status.bits.restore_required; 204 } 205 #endif 206 207 bool dc_dmub_srv_get_dmub_outbox0_msg(const struct dc *dc, struct dmcub_trace_buf_entry *entry) 208 { 209 struct dmub_srv *dmub = dc->ctx->dmub_srv->dmub; 210 return dmub_srv_get_outbox0_msg(dmub, entry); 211 } 212 213 void dc_dmub_trace_event_control(struct dc *dc, bool enable) 214 { 215 dm_helpers_dmub_outbox_interrupt_control(dc->ctx, enable); 216 } 217