1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (c) 2018 MediaTek Inc. 4 * 5 */ 6 7 #ifndef __MTK_CMDQ_H__ 8 #define __MTK_CMDQ_H__ 9 10 #include <linux/mailbox_client.h> 11 #include <linux/mailbox/mtk-cmdq-mailbox.h> 12 #include <linux/timer.h> 13 14 #define CMDQ_ADDR_HIGH(addr) ((u32)(((addr) >> 16) & GENMASK(31, 0))) 15 #define CMDQ_ADDR_LOW(addr) ((u16)(addr) | BIT(1)) 16 17 /* 18 * Every cmdq thread has its own SPRs (Specific Purpose Registers), 19 * so there are 4 * N (threads) SPRs in GCE that shares the same indexes below. 20 */ 21 #define CMDQ_THR_SPR_IDX0 (0) 22 #define CMDQ_THR_SPR_IDX1 (1) 23 #define CMDQ_THR_SPR_IDX2 (2) 24 #define CMDQ_THR_SPR_IDX3 (3) 25 26 struct cmdq_pkt; 27 28 struct cmdq_client_reg { 29 u8 subsys; 30 u16 offset; 31 u16 size; 32 }; 33 34 struct cmdq_client { 35 struct mbox_client client; 36 struct mbox_chan *chan; 37 }; 38 39 #if IS_ENABLED(CONFIG_MTK_CMDQ) 40 41 /** 42 * cmdq_dev_get_client_reg() - parse cmdq client reg from the device 43 * node of CMDQ client 44 * @dev: device of CMDQ mailbox client 45 * @client_reg: CMDQ client reg pointer 46 * @idx: the index of desired reg 47 * 48 * Return: 0 for success; else the error code is returned 49 * 50 * Help CMDQ client parsing the cmdq client reg 51 * from the device node of CMDQ client. 52 */ 53 int cmdq_dev_get_client_reg(struct device *dev, 54 struct cmdq_client_reg *client_reg, int idx); 55 56 /** 57 * cmdq_mbox_create() - create CMDQ mailbox client and channel 58 * @dev: device of CMDQ mailbox client 59 * @index: index of CMDQ mailbox channel 60 * 61 * Return: CMDQ mailbox client pointer 62 */ 63 struct cmdq_client *cmdq_mbox_create(struct device *dev, int index); 64 65 /** 66 * cmdq_mbox_destroy() - destroy CMDQ mailbox client and channel 67 * @client: the CMDQ mailbox client 68 */ 69 void cmdq_mbox_destroy(struct cmdq_client *client); 70 71 /** 72 * cmdq_pkt_create() - create a CMDQ packet 73 * @client: the CMDQ mailbox client 74 * @pkt: the CMDQ packet 75 * @size: required CMDQ buffer size 76 * 77 * Return: 0 for success; else the error code is returned 78 */ 79 int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size); 80 81 /** 82 * cmdq_pkt_destroy() - destroy the CMDQ packet 83 * @client: the CMDQ mailbox client 84 * @pkt: the CMDQ packet 85 */ 86 void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt); 87 88 /** 89 * cmdq_pkt_write() - append write command to the CMDQ packet 90 * @pkt: the CMDQ packet 91 * @subsys: the CMDQ sub system code 92 * @offset: register offset from CMDQ sub system 93 * @value: the specified target register value 94 * 95 * Return: 0 for success; else the error code is returned 96 */ 97 int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value); 98 99 /** 100 * cmdq_pkt_write_mask() - append write command with mask to the CMDQ packet 101 * @pkt: the CMDQ packet 102 * @subsys: the CMDQ sub system code 103 * @offset: register offset from CMDQ sub system 104 * @value: the specified target register value 105 * @mask: the specified target register mask 106 * 107 * Return: 0 for success; else the error code is returned 108 */ 109 int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, 110 u16 offset, u32 value, u32 mask); 111 112 /* 113 * cmdq_pkt_read_s() - append read_s command to the CMDQ packet 114 * @pkt: the CMDQ packet 115 * @high_addr_reg_idx: internal register ID which contains high address of pa 116 * @addr_low: low address of pa 117 * @reg_idx: the CMDQ internal register ID to cache read data 118 * 119 * Return: 0 for success; else the error code is returned 120 */ 121 int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low, 122 u16 reg_idx); 123 124 /** 125 * cmdq_pkt_write_s() - append write_s command to the CMDQ packet 126 * @pkt: the CMDQ packet 127 * @high_addr_reg_idx: internal register ID which contains high address of pa 128 * @addr_low: low address of pa 129 * @src_reg_idx: the CMDQ internal register ID which cache source value 130 * 131 * Return: 0 for success; else the error code is returned 132 * 133 * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH() 134 * to get high address and call cmdq_pkt_assign() to assign value into internal 135 * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when 136 * call to this function. 137 */ 138 int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 139 u16 addr_low, u16 src_reg_idx); 140 141 /** 142 * cmdq_pkt_write_s_mask() - append write_s with mask command to the CMDQ packet 143 * @pkt: the CMDQ packet 144 * @high_addr_reg_idx: internal register ID which contains high address of pa 145 * @addr_low: low address of pa 146 * @src_reg_idx: the CMDQ internal register ID which cache source value 147 * @mask: the specified target address mask, use U32_MAX if no need 148 * 149 * Return: 0 for success; else the error code is returned 150 * 151 * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH() 152 * to get high address and call cmdq_pkt_assign() to assign value into internal 153 * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when 154 * call to this function. 155 */ 156 int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 157 u16 addr_low, u16 src_reg_idx, u32 mask); 158 159 /** 160 * cmdq_pkt_write_s_value() - append write_s command to the CMDQ packet which 161 * write value to a physical address 162 * @pkt: the CMDQ packet 163 * @high_addr_reg_idx: internal register ID which contains high address of pa 164 * @addr_low: low address of pa 165 * @value: the specified target value 166 * 167 * Return: 0 for success; else the error code is returned 168 */ 169 int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, 170 u16 addr_low, u32 value); 171 172 /** 173 * cmdq_pkt_write_s_mask_value() - append write_s command with mask to the CMDQ 174 * packet which write value to a physical 175 * address 176 * @pkt: the CMDQ packet 177 * @high_addr_reg_idx: internal register ID which contains high address of pa 178 * @addr_low: low address of pa 179 * @value: the specified target value 180 * @mask: the specified target mask 181 * 182 * Return: 0 for success; else the error code is returned 183 */ 184 int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, 185 u16 addr_low, u32 value, u32 mask); 186 187 /** 188 * cmdq_pkt_mem_move() - append memory move command to the CMDQ packet 189 * @pkt: the CMDQ packet 190 * @src_addr: source address 191 * @dst_addr: destination address 192 * 193 * Appends a CMDQ command to copy the value found in `src_addr` to `dst_addr`. 194 * 195 * Return: 0 for success; else the error code is returned 196 */ 197 int cmdq_pkt_mem_move(struct cmdq_pkt *pkt, dma_addr_t src_addr, dma_addr_t dst_addr); 198 199 /** 200 * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet 201 * @pkt: the CMDQ packet 202 * @event: the desired event type to wait 203 * @clear: clear event or not after event arrive 204 * 205 * Return: 0 for success; else the error code is returned 206 */ 207 int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear); 208 209 /** 210 * cmdq_pkt_acquire_event() - append acquire event command to the CMDQ packet 211 * @pkt: the CMDQ packet 212 * @event: the desired event to be acquired 213 * 214 * User can use cmdq_pkt_acquire_event() as `mutex_lock` and cmdq_pkt_clear_event() 215 * as `mutex_unlock` to protect some `critical section` instructions between them. 216 * cmdq_pkt_acquire_event() would wait for event to be cleared. 217 * After event is cleared by cmdq_pkt_clear_event in other GCE threads, 218 * cmdq_pkt_acquire_event() would set event and keep executing next instruction. 219 * 220 * Return: 0 for success; else the error code is returned 221 */ 222 int cmdq_pkt_acquire_event(struct cmdq_pkt *pkt, u16 event); 223 224 /** 225 * cmdq_pkt_clear_event() - append clear event command to the CMDQ packet 226 * @pkt: the CMDQ packet 227 * @event: the desired event to be cleared 228 * 229 * Return: 0 for success; else the error code is returned 230 */ 231 int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event); 232 233 /** 234 * cmdq_pkt_set_event() - append set event command to the CMDQ packet 235 * @pkt: the CMDQ packet 236 * @event: the desired event to be set 237 * 238 * Return: 0 for success; else the error code is returned 239 */ 240 int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event); 241 242 /** 243 * cmdq_pkt_poll() - Append polling command to the CMDQ packet, ask GCE to 244 * execute an instruction that wait for a specified 245 * hardware register to check for the value w/o mask. 246 * All GCE hardware threads will be blocked by this 247 * instruction. 248 * @pkt: the CMDQ packet 249 * @subsys: the CMDQ sub system code 250 * @offset: register offset from CMDQ sub system 251 * @value: the specified target register value 252 * 253 * Return: 0 for success; else the error code is returned 254 */ 255 int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, 256 u16 offset, u32 value); 257 258 /** 259 * cmdq_pkt_poll_mask() - Append polling command to the CMDQ packet, ask GCE to 260 * execute an instruction that wait for a specified 261 * hardware register to check for the value w/ mask. 262 * All GCE hardware threads will be blocked by this 263 * instruction. 264 * @pkt: the CMDQ packet 265 * @subsys: the CMDQ sub system code 266 * @offset: register offset from CMDQ sub system 267 * @value: the specified target register value 268 * @mask: the specified target register mask 269 * 270 * Return: 0 for success; else the error code is returned 271 */ 272 int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, 273 u16 offset, u32 value, u32 mask); 274 275 /** 276 * cmdq_pkt_assign() - Append logic assign command to the CMDQ packet, ask GCE 277 * to execute an instruction that set a constant value into 278 * internal register and use as value, mask or address in 279 * read/write instruction. 280 * @pkt: the CMDQ packet 281 * @reg_idx: the CMDQ internal register ID 282 * @value: the specified value 283 * 284 * Return: 0 for success; else the error code is returned 285 */ 286 int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value); 287 288 /** 289 * cmdq_pkt_poll_addr() - Append blocking POLL command to CMDQ packet 290 * @pkt: the CMDQ packet 291 * @addr: the hardware register address 292 * @value: the specified target register value 293 * @mask: the specified target register mask 294 * 295 * Appends a polling (POLL) command to the CMDQ packet and asks the GCE 296 * to execute an instruction that checks for the specified `value` (with 297 * or without `mask`) to appear in the specified hardware register `addr`. 298 * All GCE threads will be blocked by this instruction. 299 * 300 * Return: 0 for success or negative error code 301 */ 302 int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask); 303 304 /** 305 * cmdq_pkt_jump_abs() - Append jump command to the CMDQ packet, ask GCE 306 * to execute an instruction that change current thread 307 * PC to a absolute physical address which should 308 * contains more instruction. 309 * @pkt: the CMDQ packet 310 * @addr: absolute physical address of target instruction buffer 311 * @shift_pa: shift bits of physical address in CMDQ instruction. This value 312 * is got by cmdq_get_shift_pa(). 313 * 314 * Return: 0 for success; else the error code is returned 315 */ 316 int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa); 317 318 /* This wrapper has to be removed after all users migrated to jump_abs */ 319 static inline int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa) 320 { 321 return cmdq_pkt_jump_abs(pkt, addr, shift_pa); 322 } 323 324 /** 325 * cmdq_pkt_jump_rel() - Append jump command to the CMDQ packet, ask GCE 326 * to execute an instruction that change current thread 327 * PC to a physical address with relative offset. The 328 * target address should contains more instruction. 329 * @pkt: the CMDQ packet 330 * @offset: relative offset of target instruction buffer from current PC. 331 * @shift_pa: shift bits of physical address in CMDQ instruction. This value 332 * is got by cmdq_get_shift_pa(). 333 * 334 * Return: 0 for success; else the error code is returned 335 */ 336 int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa); 337 338 /** 339 * cmdq_pkt_eoc() - Append EOC and ask GCE to generate an IRQ at end of execution 340 * @pkt: The CMDQ packet 341 * 342 * Appends an End Of Code (EOC) command to the CMDQ packet and asks the GCE 343 * to generate an interrupt at the end of the execution of all commands in 344 * the pipeline. 345 * The EOC command is usually appended to the end of the pipeline to notify 346 * that all commands are done. 347 * 348 * Return: 0 for success or negative error number 349 */ 350 int cmdq_pkt_eoc(struct cmdq_pkt *pkt); 351 352 /** 353 * cmdq_pkt_finalize() - Append EOC and jump command to pkt. 354 * @pkt: the CMDQ packet 355 * 356 * Return: 0 for success; else the error code is returned 357 */ 358 int cmdq_pkt_finalize(struct cmdq_pkt *pkt); 359 360 #else /* IS_ENABLED(CONFIG_MTK_CMDQ) */ 361 362 static inline int cmdq_dev_get_client_reg(struct device *dev, 363 struct cmdq_client_reg *client_reg, int idx) 364 { 365 return -ENODEV; 366 } 367 368 static inline struct cmdq_client *cmdq_mbox_create(struct device *dev, int index) 369 { 370 return ERR_PTR(-EINVAL); 371 } 372 373 static inline void cmdq_mbox_destroy(struct cmdq_client *client) { } 374 375 static inline int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size) 376 { 377 return -EINVAL; 378 } 379 380 static inline void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt) { } 381 382 static inline int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) 383 { 384 return -ENOENT; 385 } 386 387 static inline int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, 388 u16 offset, u32 value, u32 mask) 389 { 390 return -ENOENT; 391 } 392 393 static inline int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 394 u16 addr_low, u16 reg_idx) 395 { 396 return -ENOENT; 397 } 398 399 static inline int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 400 u16 addr_low, u16 src_reg_idx) 401 { 402 return -ENOENT; 403 } 404 405 static inline int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 406 u16 addr_low, u16 src_reg_idx, u32 mask) 407 { 408 return -ENOENT; 409 } 410 411 static inline int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, 412 u16 addr_low, u32 value) 413 { 414 return -ENOENT; 415 } 416 417 static inline int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, 418 u16 addr_low, u32 value, u32 mask) 419 { 420 return -ENOENT; 421 } 422 423 static inline int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear) 424 { 425 return -EINVAL; 426 } 427 428 static inline int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event) 429 { 430 return -EINVAL; 431 } 432 433 static inline int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event) 434 { 435 return -EINVAL; 436 } 437 438 static inline int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, 439 u16 offset, u32 value) 440 { 441 return -EINVAL; 442 } 443 444 static inline int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, 445 u16 offset, u32 value, u32 mask) 446 { 447 return -EINVAL; 448 } 449 450 static inline int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value) 451 { 452 return -EINVAL; 453 } 454 455 static inline int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask) 456 { 457 return -EINVAL; 458 } 459 460 static inline int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa) 461 { 462 return -EINVAL; 463 } 464 465 static inline int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa) 466 { 467 return -EINVAL; 468 } 469 470 static inline int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa) 471 { 472 return -EINVAL; 473 } 474 475 static inline int cmdq_pkt_eoc(struct cmdq_pkt *pkt) 476 { 477 return -EINVAL; 478 } 479 480 static inline int cmdq_pkt_finalize(struct cmdq_pkt *pkt) 481 { 482 return -EINVAL; 483 } 484 485 #endif /* IS_ENABLED(CONFIG_MTK_CMDQ) */ 486 487 #endif /* __MTK_CMDQ_H__ */ 488