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 30 #define CTX dc_dmub_srv->ctx 31 #define DC_LOGGER CTX->logger 32 33 static void dc_dmub_srv_construct(struct dc_dmub_srv *dc_srv, struct dc *dc, 34 struct dmub_srv *dmub) 35 { 36 dc_srv->dmub = dmub; 37 dc_srv->ctx = dc->ctx; 38 } 39 40 struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub) 41 { 42 struct dc_dmub_srv *dc_srv = 43 kzalloc(sizeof(struct dc_dmub_srv), GFP_KERNEL); 44 45 if (dc_srv == NULL) { 46 BREAK_TO_DEBUGGER(); 47 return NULL; 48 } 49 50 dc_dmub_srv_construct(dc_srv, dc, dmub); 51 52 return dc_srv; 53 } 54 55 void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv) 56 { 57 if (*dmub_srv) { 58 kfree(*dmub_srv); 59 *dmub_srv = NULL; 60 } 61 } 62 63 void dc_dmub_srv_cmd_queue(struct dc_dmub_srv *dc_dmub_srv, 64 union dmub_rb_cmd *cmd) 65 { 66 struct dmub_srv *dmub = dc_dmub_srv->dmub; 67 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 68 enum dmub_status status; 69 70 status = dmub_srv_cmd_queue(dmub, cmd); 71 if (status == DMUB_STATUS_OK) 72 return; 73 74 if (status != DMUB_STATUS_QUEUE_FULL) 75 goto error; 76 77 /* Execute and wait for queue to become empty again. */ 78 dc_dmub_srv_cmd_execute(dc_dmub_srv); 79 dc_dmub_srv_wait_idle(dc_dmub_srv); 80 81 /* Requeue the command. */ 82 status = dmub_srv_cmd_queue(dmub, cmd); 83 if (status == DMUB_STATUS_OK) 84 return; 85 86 error: 87 DC_ERROR("Error queuing DMUB command: status=%d\n", status); 88 } 89 90 void dc_dmub_srv_cmd_execute(struct dc_dmub_srv *dc_dmub_srv) 91 { 92 struct dmub_srv *dmub = dc_dmub_srv->dmub; 93 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 94 enum dmub_status status; 95 96 status = dmub_srv_cmd_execute(dmub); 97 if (status != DMUB_STATUS_OK) 98 DC_ERROR("Error starting DMUB execution: status=%d\n", status); 99 } 100 101 void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv) 102 { 103 struct dmub_srv *dmub = dc_dmub_srv->dmub; 104 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 105 enum dmub_status status; 106 107 status = dmub_srv_wait_for_idle(dmub, 100000); 108 if (status != DMUB_STATUS_OK) 109 DC_ERROR("Error waiting for DMUB idle: status=%d\n", status); 110 } 111 112 bool dc_dmub_srv_cmd_with_reply_data(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd) 113 { 114 struct dmub_srv *dmub; 115 enum dmub_status status; 116 117 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 118 return false; 119 120 dmub = dc_dmub_srv->dmub; 121 122 status = dmub_srv_cmd_with_reply_data(dmub, cmd); 123 if (status != DMUB_STATUS_OK) { 124 DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); 125 return false; 126 } 127 128 return true; 129 } 130 131 void dc_dmub_srv_wait_phy_init(struct dc_dmub_srv *dc_dmub_srv) 132 { 133 struct dmub_srv *dmub = dc_dmub_srv->dmub; 134 struct dc_context *dc_ctx = dc_dmub_srv->ctx; 135 enum dmub_status status; 136 137 for (;;) { 138 /* Wait up to a second for PHY init. */ 139 status = dmub_srv_wait_for_phy_init(dmub, 1000000); 140 if (status == DMUB_STATUS_OK) 141 /* Initialization OK */ 142 break; 143 144 DC_ERROR("DMCUB PHY init failed: status=%d\n", status); 145 ASSERT(0); 146 147 if (status != DMUB_STATUS_TIMEOUT) 148 /* 149 * Server likely initialized or we don't have 150 * DMCUB HW support - this won't end. 151 */ 152 break; 153 154 /* Continue spinning so we don't hang the ASIC. */ 155 } 156 } 157 158 bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv, 159 unsigned int stream_mask) 160 { 161 struct dmub_srv *dmub; 162 const uint32_t timeout = 30; 163 164 if (!dc_dmub_srv || !dc_dmub_srv->dmub) 165 return false; 166 167 dmub = dc_dmub_srv->dmub; 168 169 return dmub_srv_send_gpint_command( 170 dmub, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK, 171 stream_mask, timeout) == DMUB_STATUS_OK; 172 } 173