1 /* 2 * Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <bpmp_ipc.h> 9 #include <common/debug.h> 10 #include <drivers/delay_timer.h> 11 #include <errno.h> 12 #include <lib/mmio.h> 13 #include <lib/utils_def.h> 14 #include <stdbool.h> 15 #include <string.h> 16 #include <tegra_def.h> 17 18 #include "intf.h" 19 #include "ivc.h" 20 21 /** 22 * Holds IVC channel data 23 */ 24 struct ccplex_bpmp_channel_data { 25 /* Buffer for incoming data */ 26 struct frame_data *ib; 27 28 /* Buffer for outgoing data */ 29 struct frame_data *ob; 30 }; 31 32 static struct ccplex_bpmp_channel_data s_channel; 33 static struct ivc ivc_ccplex_bpmp_channel; 34 35 /* 36 * Helper functions to access the HSP doorbell registers 37 */ 38 static inline uint32_t hsp_db_read(uint32_t reg) 39 { 40 return mmio_read_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg)); 41 } 42 43 static inline void hsp_db_write(uint32_t reg, uint32_t val) 44 { 45 mmio_write_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg), val); 46 } 47 48 /******************************************************************************* 49 * IVC wrappers for CCPLEX <-> BPMP communication. 50 ******************************************************************************/ 51 52 static void tegra_bpmp_ring_bpmp_doorbell(void); 53 54 /* 55 * Get the next frame where data can be written. 56 */ 57 static struct frame_data *tegra_bpmp_get_next_out_frame(void) 58 { 59 struct frame_data *frame; 60 const struct ivc *ch = &ivc_ccplex_bpmp_channel; 61 62 frame = (struct frame_data *)tegra_ivc_write_get_next_frame(ch); 63 if (frame == NULL) { 64 ERROR("%s: Error in getting next frame, exiting\n", __func__); 65 } else { 66 s_channel.ob = frame; 67 } 68 69 return frame; 70 } 71 72 static void tegra_bpmp_signal_slave(void) 73 { 74 (void)tegra_ivc_write_advance(&ivc_ccplex_bpmp_channel); 75 tegra_bpmp_ring_bpmp_doorbell(); 76 } 77 78 static int32_t tegra_bpmp_free_master(void) 79 { 80 return tegra_ivc_read_advance(&ivc_ccplex_bpmp_channel); 81 } 82 83 static bool tegra_bpmp_slave_acked(void) 84 { 85 struct frame_data *frame; 86 bool ret = true; 87 88 frame = (struct frame_data *)tegra_ivc_read_get_next_frame(&ivc_ccplex_bpmp_channel); 89 if (frame == NULL) { 90 ret = false; 91 } else { 92 s_channel.ib = frame; 93 } 94 95 return ret; 96 } 97 98 static struct frame_data *tegra_bpmp_get_cur_in_frame(void) 99 { 100 return s_channel.ib; 101 } 102 103 /* 104 * Enables BPMP to ring CCPlex doorbell 105 */ 106 static void tegra_bpmp_enable_ccplex_doorbell(void) 107 { 108 uint32_t reg; 109 110 reg = hsp_db_read(HSP_DBELL_1_ENABLE); 111 reg |= HSP_MASTER_BPMP_BIT; 112 hsp_db_write(HSP_DBELL_1_ENABLE, reg); 113 } 114 115 /* 116 * CCPlex rings the BPMP doorbell 117 */ 118 static void tegra_bpmp_ring_bpmp_doorbell(void) 119 { 120 /* 121 * Any writes to this register has the same effect, 122 * uses master ID of the write transaction and set 123 * corresponding flag. 124 */ 125 hsp_db_write(HSP_DBELL_3_TRIGGER, HSP_MASTER_CCPLEX_BIT); 126 } 127 128 /* 129 * Returns true if CCPLex can ring BPMP doorbell, otherwise false. 130 * This also signals that BPMP is up and ready. 131 */ 132 static bool tegra_bpmp_can_ccplex_ring_doorbell(void) 133 { 134 uint32_t reg; 135 136 /* check if ccplex can communicate with bpmp */ 137 reg = hsp_db_read(HSP_DBELL_3_ENABLE); 138 139 return ((reg & HSP_MASTER_CCPLEX_BIT) != 0U); 140 } 141 142 static int32_t tegra_bpmp_wait_for_slave_ack(void) 143 { 144 uint32_t timeout = TIMEOUT_RESPONSE_FROM_BPMP_US; 145 146 while (!tegra_bpmp_slave_acked() && (timeout != 0U)) { 147 udelay(1); 148 timeout--; 149 }; 150 151 return ((timeout == 0U) ? -ETIMEDOUT : 0); 152 } 153 154 /* 155 * Notification from the ivc layer 156 */ 157 static void tegra_bpmp_ivc_notify(const struct ivc *ivc) 158 { 159 (void)(ivc); 160 161 tegra_bpmp_ring_bpmp_doorbell(); 162 } 163 164 /* 165 * Atomic send/receive API, which means it waits until slave acks 166 */ 167 static int32_t tegra_bpmp_ipc_send_req_atomic(uint32_t mrq, void *p_out, 168 uint32_t size_out, void *p_in, uint32_t size_in) 169 { 170 struct frame_data *frame = tegra_bpmp_get_next_out_frame(); 171 const struct frame_data *f_in = NULL; 172 int32_t ret = 0; 173 void *p_fdata; 174 175 if ((p_out == NULL) || (size_out > IVC_DATA_SZ_BYTES) || 176 (frame == NULL)) { 177 ERROR("%s: invalid parameters, exiting\n", __func__); 178 return -EINVAL; 179 } 180 181 /* prepare the command frame */ 182 frame->mrq = mrq; 183 frame->flags = FLAG_DO_ACK; 184 p_fdata = frame->data; 185 (void)memcpy(p_fdata, p_out, (size_t)size_out); 186 187 /* signal the slave */ 188 tegra_bpmp_signal_slave(); 189 190 /* wait for slave to ack */ 191 ret = tegra_bpmp_wait_for_slave_ack(); 192 if (ret < 0) { 193 ERROR("%s: wait for slave failed (%d)\n", __func__, ret); 194 return ret; 195 } 196 197 /* retrieve the response frame */ 198 if ((size_in <= IVC_DATA_SZ_BYTES) && (p_in != NULL)) { 199 200 f_in = tegra_bpmp_get_cur_in_frame(); 201 if (f_in != NULL) { 202 ERROR("Failed to get next input frame!\n"); 203 } else { 204 (void)memcpy(p_in, p_fdata, (size_t)size_in); 205 } 206 } 207 208 ret = tegra_bpmp_free_master(); 209 if (ret < 0) { 210 ERROR("%s: free master failed (%d)\n", __func__, ret); 211 } 212 213 return ret; 214 } 215 216 /* 217 * Initializes the BPMP<--->CCPlex communication path. 218 */ 219 int32_t tegra_bpmp_ipc_init(void) 220 { 221 size_t msg_size; 222 uint32_t frame_size, timeout; 223 int32_t error = 0; 224 225 /* allow bpmp to ring CCPLEX's doorbell */ 226 tegra_bpmp_enable_ccplex_doorbell(); 227 228 /* wait for BPMP to actually ring the doorbell */ 229 timeout = TIMEOUT_RESPONSE_FROM_BPMP_US; 230 while ((timeout != 0U) && !tegra_bpmp_can_ccplex_ring_doorbell()) { 231 udelay(1); /* bpmp turn-around time */ 232 timeout--; 233 } 234 235 if (timeout == 0U) { 236 ERROR("%s: BPMP firmware is not ready\n", __func__); 237 return -ENOTSUP; 238 } 239 240 INFO("%s: BPMP handshake completed\n", __func__); 241 242 msg_size = tegra_ivc_align(IVC_CMD_SZ_BYTES); 243 frame_size = (uint32_t)tegra_ivc_total_queue_size(msg_size); 244 if (frame_size > TEGRA_BPMP_IPC_CH_MAP_SIZE) { 245 ERROR("%s: carveout size is not sufficient\n", __func__); 246 return -EINVAL; 247 } 248 249 error = tegra_ivc_init(&ivc_ccplex_bpmp_channel, 250 (uint32_t)TEGRA_BPMP_IPC_RX_PHYS_BASE, 251 (uint32_t)TEGRA_BPMP_IPC_TX_PHYS_BASE, 252 1U, frame_size, tegra_bpmp_ivc_notify); 253 if (error != 0) { 254 255 ERROR("%s: IVC init failed (%d)\n", __func__, error); 256 257 } else { 258 259 /* reset channel */ 260 tegra_ivc_channel_reset(&ivc_ccplex_bpmp_channel); 261 262 /* wait for notification from BPMP */ 263 while (tegra_ivc_channel_notified(&ivc_ccplex_bpmp_channel) != 0) { 264 /* 265 * Interrupt BPMP with doorbell each time after 266 * tegra_ivc_channel_notified() returns non zero 267 * value. 268 */ 269 tegra_bpmp_ring_bpmp_doorbell(); 270 } 271 272 INFO("%s: All communication channels initialized\n", __func__); 273 } 274 275 return error; 276 } 277 278 /* Handler to reset a hardware module */ 279 int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id) 280 { 281 int32_t ret; 282 struct mrq_reset_request req = { 283 .cmd = (uint32_t)CMD_RESET_MODULE, 284 .reset_id = rst_id 285 }; 286 287 /* only GPCDMA/XUSB_PADCTL resets are supported */ 288 assert((rst_id == TEGRA_RESET_ID_XUSB_PADCTL) || 289 (rst_id == TEGRA_RESET_ID_GPCDMA)); 290 291 ret = tegra_bpmp_ipc_send_req_atomic(MRQ_RESET, &req, 292 (uint32_t)sizeof(req), NULL, 0); 293 if (ret != 0) { 294 ERROR("%s: failed for module %d with error %d\n", __func__, 295 rst_id, ret); 296 } 297 298 return ret; 299 } 300 301 int tegra_bpmp_ipc_enable_clock(uint32_t clk_id) 302 { 303 int ret; 304 struct mrq_clk_request req; 305 306 /* only SE clocks are supported */ 307 if (clk_id != TEGRA_CLK_SE) { 308 return -ENOTSUP; 309 } 310 311 /* prepare the MRQ_CLK command */ 312 req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_ENABLE, clk_id); 313 314 ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, (uint32_t)sizeof(req), 315 NULL, 0); 316 if (ret != 0) { 317 ERROR("%s: failed for module %d with error %d\n", __func__, 318 clk_id, ret); 319 } 320 321 return ret; 322 } 323 324 int tegra_bpmp_ipc_disable_clock(uint32_t clk_id) 325 { 326 int ret; 327 struct mrq_clk_request req; 328 329 /* only SE clocks are supported */ 330 if (clk_id != TEGRA_CLK_SE) { 331 return -ENOTSUP; 332 } 333 334 /* prepare the MRQ_CLK command */ 335 req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_DISABLE, clk_id); 336 337 ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, (uint32_t)sizeof(req), 338 NULL, 0); 339 if (ret != 0) { 340 ERROR("%s: failed for module %d with error %d\n", __func__, 341 clk_id, ret); 342 } 343 344 return ret; 345 } 346