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