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