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 #define CMDQ_SUBSYS_INVALID (U8_MAX) 27 28 struct cmdq_pkt; 29 30 enum cmdq_logic_op { 31 CMDQ_LOGIC_ASSIGN = 0, 32 CMDQ_LOGIC_ADD = 1, 33 CMDQ_LOGIC_SUBTRACT = 2, 34 CMDQ_LOGIC_MULTIPLY = 3, 35 CMDQ_LOGIC_XOR = 8, 36 CMDQ_LOGIC_NOT = 9, 37 CMDQ_LOGIC_OR = 10, 38 CMDQ_LOGIC_AND = 11, 39 CMDQ_LOGIC_LEFT_SHIFT = 12, 40 CMDQ_LOGIC_RIGHT_SHIFT = 13, 41 CMDQ_LOGIC_MAX, 42 }; 43 44 struct cmdq_operand { 45 /* register type */ 46 bool reg; 47 union { 48 /* index */ 49 u16 idx; 50 /* value */ 51 u16 value; 52 }; 53 }; 54 55 struct cmdq_client_reg { 56 u8 subsys; 57 phys_addr_t pa_base; 58 u16 offset; 59 u16 size; 60 61 /* 62 * Client only uses these functions for MMIO access, 63 * so doesn't need to handle the mminfra_offset. 64 * The mminfra_offset is used for DRAM access and 65 * is handled internally by CMDQ APIs. 66 */ 67 int (*pkt_write)(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base, 68 u16 offset, u32 value); 69 int (*pkt_write_mask)(struct cmdq_pkt *pkt, u8 subsys, u32 pa_base, 70 u16 offset, u32 value, u32 mask); 71 }; 72 73 struct cmdq_client { 74 struct mbox_client client; 75 struct mbox_chan *chan; 76 }; 77 78 #if IS_ENABLED(CONFIG_MTK_CMDQ) 79 80 /** 81 * cmdq_dev_get_client_reg() - parse cmdq client reg from the device 82 * node of CMDQ client 83 * @dev: device of CMDQ mailbox client 84 * @client_reg: CMDQ client reg pointer 85 * @idx: the index of desired reg 86 * 87 * Return: 0 for success; else the error code is returned 88 * 89 * Help CMDQ client parsing the cmdq client reg 90 * from the device node of CMDQ client. 91 */ 92 int cmdq_dev_get_client_reg(struct device *dev, 93 struct cmdq_client_reg *client_reg, int idx); 94 95 /** 96 * cmdq_mbox_create() - create CMDQ mailbox client and channel 97 * @dev: device of CMDQ mailbox client 98 * @index: index of CMDQ mailbox channel 99 * 100 * Return: CMDQ mailbox client pointer 101 */ 102 struct cmdq_client *cmdq_mbox_create(struct device *dev, int index); 103 104 /** 105 * cmdq_mbox_destroy() - destroy CMDQ mailbox client and channel 106 * @client: the CMDQ mailbox client 107 */ 108 void cmdq_mbox_destroy(struct cmdq_client *client); 109 110 /** 111 * cmdq_pkt_create() - create a CMDQ packet 112 * @client: the CMDQ mailbox client 113 * @pkt: the CMDQ packet 114 * @size: required CMDQ buffer size 115 * 116 * Return: 0 for success; else the error code is returned 117 */ 118 int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size); 119 120 /** 121 * cmdq_pkt_destroy() - destroy the CMDQ packet 122 * @client: the CMDQ mailbox client 123 * @pkt: the CMDQ packet 124 */ 125 void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt); 126 127 /** 128 * cmdq_pkt_write() - append write command to the CMDQ packet 129 * @pkt: the CMDQ packet 130 * @subsys: the CMDQ sub system code 131 * @offset: register offset from CMDQ sub system 132 * @value: the specified target register value 133 * 134 * Return: 0 for success; else the error code is returned 135 */ 136 int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value); 137 138 /** 139 * cmdq_pkt_write_pa() - append write command to the CMDQ packet with pa_base 140 * @pkt: the CMDQ packet 141 * @subsys: unused parameter 142 * @pa_base: the physical address base of the hardware register 143 * @offset: register offset from CMDQ sub system 144 * @value: the specified target register value 145 * 146 * Return: 0 for success; else the error code is returned 147 */ 148 int cmdq_pkt_write_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, 149 u32 pa_base, u16 offset, u32 value); 150 151 /** 152 * cmdq_pkt_write_subsys() - append write command to the CMDQ packet with subsys 153 * @pkt: the CMDQ packet 154 * @subsys: the CMDQ sub system code 155 * @pa_base: unused parameter 156 * @offset: register offset from CMDQ sub system 157 * @value: the specified target register value 158 * 159 * Return: 0 for success; else the error code is returned 160 */ 161 int cmdq_pkt_write_subsys(struct cmdq_pkt *pkt, u8 subsys, 162 u32 pa_base /*unused*/, u16 offset, u32 value); 163 164 /** 165 * cmdq_pkt_write_mask() - append write command with mask to the CMDQ packet 166 * @pkt: the CMDQ packet 167 * @subsys: the CMDQ sub system code 168 * @offset: register offset from CMDQ sub system 169 * @value: the specified target register value 170 * @mask: the specified target register mask 171 * 172 * Return: 0 for success; else the error code is returned 173 */ 174 int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, 175 u16 offset, u32 value, u32 mask); 176 177 /** 178 * cmdq_pkt_write_mask_pa() - append write command with mask to the CMDQ packet with pa 179 * @pkt: the CMDQ packet 180 * @subsys: unused parameter 181 * @pa_base: the physical address base of the hardware register 182 * @offset: register offset from CMDQ sub system 183 * @value: the specified target register value 184 * @mask: the specified target register mask 185 * 186 * Return: 0 for success; else the error code is returned 187 */ 188 int cmdq_pkt_write_mask_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, 189 u32 pa_base, u16 offset, u32 value, u32 mask); 190 191 /** 192 * cmdq_pkt_write_mask_subsys() - append write command with mask to the CMDQ packet with subsys 193 * @pkt: the CMDQ packet 194 * @subsys: the CMDQ sub system code 195 * @pa_base: unused parameter 196 * @offset: register offset from CMDQ sub system 197 * @value: the specified target register value 198 * @mask: the specified target register mask 199 * 200 * Return: 0 for success; else the error code is returned 201 */ 202 int cmdq_pkt_write_mask_subsys(struct cmdq_pkt *pkt, u8 subsys, 203 u32 pa_base /*unused*/, u16 offset, u32 value, u32 mask); 204 205 /* 206 * cmdq_pkt_read_s() - append read_s command to the CMDQ packet 207 * @pkt: the CMDQ packet 208 * @high_addr_reg_idx: internal register ID which contains high address of pa 209 * @addr_low: low address of pa 210 * @reg_idx: the CMDQ internal register ID to cache read data 211 * 212 * Return: 0 for success; else the error code is returned 213 */ 214 int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low, 215 u16 reg_idx); 216 217 /** 218 * cmdq_pkt_write_s() - append write_s command to the CMDQ packet 219 * @pkt: the CMDQ packet 220 * @high_addr_reg_idx: internal register ID which contains high address of pa 221 * @addr_low: low address of pa 222 * @src_reg_idx: the CMDQ internal register ID which cache source value 223 * 224 * Return: 0 for success; else the error code is returned 225 * 226 * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH() 227 * to get high address and call cmdq_pkt_assign() to assign value into internal 228 * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when 229 * call to this function. 230 */ 231 int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 232 u16 addr_low, u16 src_reg_idx); 233 234 /** 235 * cmdq_pkt_write_s_mask() - append write_s with mask command to the CMDQ packet 236 * @pkt: the CMDQ packet 237 * @high_addr_reg_idx: internal register ID which contains high address of pa 238 * @addr_low: low address of pa 239 * @src_reg_idx: the CMDQ internal register ID which cache source value 240 * @mask: the specified target address mask, use U32_MAX if no need 241 * 242 * Return: 0 for success; else the error code is returned 243 * 244 * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH() 245 * to get high address and call cmdq_pkt_assign() to assign value into internal 246 * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when 247 * call to this function. 248 */ 249 int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 250 u16 addr_low, u16 src_reg_idx, u32 mask); 251 252 /** 253 * cmdq_pkt_write_s_value() - append write_s command to the CMDQ packet which 254 * write value to a physical address 255 * @pkt: the CMDQ packet 256 * @high_addr_reg_idx: internal register ID which contains high address of pa 257 * @addr_low: low address of pa 258 * @value: the specified target value 259 * 260 * Return: 0 for success; else the error code is returned 261 */ 262 int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, 263 u16 addr_low, u32 value); 264 265 /** 266 * cmdq_pkt_write_s_mask_value() - append write_s command with mask to the CMDQ 267 * packet which write value to a physical 268 * address 269 * @pkt: the CMDQ packet 270 * @high_addr_reg_idx: internal register ID which contains high address of pa 271 * @addr_low: low address of pa 272 * @value: the specified target value 273 * @mask: the specified target mask 274 * 275 * Return: 0 for success; else the error code is returned 276 */ 277 int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, 278 u16 addr_low, u32 value, u32 mask); 279 280 /** 281 * cmdq_pkt_mem_move() - append memory move command to the CMDQ packet 282 * @pkt: the CMDQ packet 283 * @src_addr: source address 284 * @dst_addr: destination address 285 * 286 * Appends a CMDQ command to copy the value found in `src_addr` to `dst_addr`. 287 * 288 * Return: 0 for success; else the error code is returned 289 */ 290 int cmdq_pkt_mem_move(struct cmdq_pkt *pkt, dma_addr_t src_addr, dma_addr_t dst_addr); 291 292 /** 293 * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet 294 * @pkt: the CMDQ packet 295 * @event: the desired event type to wait 296 * @clear: clear event or not after event arrive 297 * 298 * Return: 0 for success; else the error code is returned 299 */ 300 int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear); 301 302 /** 303 * cmdq_pkt_acquire_event() - append acquire event command to the CMDQ packet 304 * @pkt: the CMDQ packet 305 * @event: the desired event to be acquired 306 * 307 * User can use cmdq_pkt_acquire_event() as `mutex_lock` and cmdq_pkt_clear_event() 308 * as `mutex_unlock` to protect some `critical section` instructions between them. 309 * cmdq_pkt_acquire_event() would wait for event to be cleared. 310 * After event is cleared by cmdq_pkt_clear_event in other GCE threads, 311 * cmdq_pkt_acquire_event() would set event and keep executing next instruction. 312 * 313 * Return: 0 for success; else the error code is returned 314 */ 315 int cmdq_pkt_acquire_event(struct cmdq_pkt *pkt, u16 event); 316 317 /** 318 * cmdq_pkt_clear_event() - append clear event command to the CMDQ packet 319 * @pkt: the CMDQ packet 320 * @event: the desired event to be cleared 321 * 322 * Return: 0 for success; else the error code is returned 323 */ 324 int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event); 325 326 /** 327 * cmdq_pkt_set_event() - append set event command to the CMDQ packet 328 * @pkt: the CMDQ packet 329 * @event: the desired event to be set 330 * 331 * Return: 0 for success; else the error code is returned 332 */ 333 int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event); 334 335 /** 336 * cmdq_pkt_poll() - Append polling command to the CMDQ packet, ask GCE to 337 * execute an instruction that wait for a specified 338 * hardware register to check for the value w/o mask. 339 * All GCE hardware threads will be blocked by this 340 * instruction. 341 * @pkt: the CMDQ packet 342 * @subsys: the CMDQ sub system code 343 * @offset: register offset from CMDQ sub system 344 * @value: the specified target register value 345 * 346 * Return: 0 for success; else the error code is returned 347 */ 348 int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, 349 u16 offset, u32 value); 350 351 /** 352 * cmdq_pkt_poll_mask() - Append polling command to the CMDQ packet, ask GCE to 353 * execute an instruction that wait for a specified 354 * hardware register to check for the value w/ mask. 355 * All GCE hardware threads will be blocked by this 356 * instruction. 357 * @pkt: the CMDQ packet 358 * @subsys: the CMDQ sub system code 359 * @offset: register offset from CMDQ sub system 360 * @value: the specified target register value 361 * @mask: the specified target register mask 362 * 363 * Return: 0 for success; else the error code is returned 364 */ 365 int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, 366 u16 offset, u32 value, u32 mask); 367 368 /** 369 * cmdq_pkt_logic_command() - Append logic command to the CMDQ packet, ask GCE to 370 * execute an instruction that store the result of logic operation 371 * with left and right operand into result_reg_idx. 372 * @pkt: the CMDQ packet 373 * @result_reg_idx: SPR index that store operation result of left_operand and right_operand 374 * @left_operand: left operand 375 * @s_op: the logic operator enum 376 * @right_operand: right operand 377 * 378 * Return: 0 for success; else the error code is returned 379 */ 380 int cmdq_pkt_logic_command(struct cmdq_pkt *pkt, u16 result_reg_idx, 381 struct cmdq_operand *left_operand, 382 enum cmdq_logic_op s_op, 383 struct cmdq_operand *right_operand); 384 385 /** 386 * cmdq_pkt_assign() - Append logic assign command to the CMDQ packet, ask GCE 387 * to execute an instruction that set a constant value into 388 * internal register and use as value, mask or address in 389 * read/write instruction. 390 * @pkt: the CMDQ packet 391 * @reg_idx: the CMDQ internal register ID 392 * @value: the specified value 393 * 394 * Return: 0 for success; else the error code is returned 395 */ 396 int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value); 397 398 /** 399 * cmdq_pkt_poll_addr() - Append blocking POLL command to CMDQ packet 400 * @pkt: the CMDQ packet 401 * @addr: the hardware register address 402 * @value: the specified target register value 403 * @mask: the specified target register mask 404 * 405 * Appends a polling (POLL) command to the CMDQ packet and asks the GCE 406 * to execute an instruction that checks for the specified `value` (with 407 * or without `mask`) to appear in the specified hardware register `addr`. 408 * All GCE threads will be blocked by this instruction. 409 * 410 * Return: 0 for success or negative error code 411 */ 412 int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask); 413 414 /** 415 * cmdq_pkt_jump_abs() - Append jump command to the CMDQ packet, ask GCE 416 * to execute an instruction that change current thread 417 * PC to a absolute physical address which should 418 * contains more instruction. 419 * @pkt: the CMDQ packet 420 * @addr: absolute physical address of target instruction buffer 421 * @shift_pa: shift bits of physical address in CMDQ instruction. This value 422 * is got by cmdq_get_shift_pa(). 423 * 424 * Return: 0 for success; else the error code is returned 425 */ 426 int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa); 427 428 /* This wrapper has to be removed after all users migrated to jump_abs */ 429 static inline int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa) 430 { 431 return cmdq_pkt_jump_abs(pkt, addr, shift_pa); 432 } 433 434 /** 435 * cmdq_pkt_jump_rel() - Append jump command to the CMDQ packet, ask GCE 436 * to execute an instruction that change current thread 437 * PC to a physical address with relative offset. The 438 * target address should contains more instruction. 439 * @pkt: the CMDQ packet 440 * @offset: relative offset of target instruction buffer from current PC. 441 * @shift_pa: shift bits of physical address in CMDQ instruction. This value 442 * is got by cmdq_get_shift_pa(). 443 * 444 * Return: 0 for success; else the error code is returned 445 */ 446 int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa); 447 448 /** 449 * cmdq_pkt_eoc() - Append EOC and ask GCE to generate an IRQ at end of execution 450 * @pkt: The CMDQ packet 451 * 452 * Appends an End Of Code (EOC) command to the CMDQ packet and asks the GCE 453 * to generate an interrupt at the end of the execution of all commands in 454 * the pipeline. 455 * The EOC command is usually appended to the end of the pipeline to notify 456 * that all commands are done. 457 * 458 * Return: 0 for success or negative error number 459 */ 460 int cmdq_pkt_eoc(struct cmdq_pkt *pkt); 461 462 #else /* IS_ENABLED(CONFIG_MTK_CMDQ) */ 463 464 static inline int cmdq_dev_get_client_reg(struct device *dev, 465 struct cmdq_client_reg *client_reg, int idx) 466 { 467 return -ENODEV; 468 } 469 470 static inline struct cmdq_client *cmdq_mbox_create(struct device *dev, int index) 471 { 472 return ERR_PTR(-EINVAL); 473 } 474 475 static inline void cmdq_mbox_destroy(struct cmdq_client *client) { } 476 477 static inline int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size) 478 { 479 return -EINVAL; 480 } 481 482 static inline void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt) { } 483 484 static inline int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value) 485 { 486 return -ENOENT; 487 } 488 489 static inline int cmdq_pkt_write_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, 490 u32 pa_base, u16 offset, u32 value) 491 { 492 return -ENOENT; 493 } 494 495 static inline int cmdq_pkt_write_subsys(struct cmdq_pkt *pkt, u8 subsys, 496 u32 pa_base /*unused*/, u16 offset, u32 value) 497 { 498 return -ENOENT; 499 } 500 501 static inline int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, 502 u16 offset, u32 value, u32 mask) 503 { 504 return -ENOENT; 505 } 506 507 static inline int cmdq_pkt_write_mask_pa(struct cmdq_pkt *pkt, u8 subsys /*unused*/, 508 u32 pa_base, u16 offset, u32 value, u32 mask) 509 { 510 return -ENOENT; 511 } 512 513 static inline int cmdq_pkt_write_mask_subsys(struct cmdq_pkt *pkt, u8 subsys, 514 u32 pa_base /*unused*/, u16 offset, 515 u32 value, u32 mask) 516 { 517 return -ENOENT; 518 } 519 520 static inline int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 521 u16 addr_low, u16 reg_idx) 522 { 523 return -ENOENT; 524 } 525 526 static inline int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 527 u16 addr_low, u16 src_reg_idx) 528 { 529 return -ENOENT; 530 } 531 532 static inline int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, 533 u16 addr_low, u16 src_reg_idx, u32 mask) 534 { 535 return -ENOENT; 536 } 537 538 static inline int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, 539 u16 addr_low, u32 value) 540 { 541 return -ENOENT; 542 } 543 544 static inline int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, 545 u16 addr_low, u32 value, u32 mask) 546 { 547 return -ENOENT; 548 } 549 550 static inline int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear) 551 { 552 return -EINVAL; 553 } 554 555 static inline int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event) 556 { 557 return -EINVAL; 558 } 559 560 static inline int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event) 561 { 562 return -EINVAL; 563 } 564 565 static inline int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, 566 u16 offset, u32 value) 567 { 568 return -EINVAL; 569 } 570 571 static inline int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, 572 u16 offset, u32 value, u32 mask) 573 { 574 return -EINVAL; 575 } 576 577 static inline int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value) 578 { 579 return -EINVAL; 580 } 581 582 static inline int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask) 583 { 584 return -EINVAL; 585 } 586 587 static inline int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa) 588 { 589 return -EINVAL; 590 } 591 592 static inline int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa) 593 { 594 return -EINVAL; 595 } 596 597 static inline int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa) 598 { 599 return -EINVAL; 600 } 601 602 static inline int cmdq_pkt_eoc(struct cmdq_pkt *pkt) 603 { 604 return -EINVAL; 605 } 606 607 #endif /* IS_ENABLED(CONFIG_MTK_CMDQ) */ 608 609 #endif /* __MTK_CMDQ_H__ */ 610