summaryrefslogtreecommitdiff
path: root/include/linux/soc/mediatek/mtk-cmdq.h
blob: d4a8e34505e6bdea98e38f76558ee8e9c260daa3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2018 MediaTek Inc.
 *
 */

#ifndef __MTK_CMDQ_H__
#define __MTK_CMDQ_H__

#include <linux/mailbox_client.h>
#include <linux/mailbox/mtk-cmdq-mailbox.h>
#include <linux/timer.h>

#define CMDQ_ADDR_HIGH(addr)	((u32)(((addr) >> 16) & GENMASK(31, 0)))
#define CMDQ_ADDR_LOW(addr)	((u16)(addr) | BIT(1))

/*
 * Every cmdq thread has its own SPRs (Specific Purpose Registers),
 * so there are 4 * N (threads) SPRs in GCE that shares the same indexes below.
 */
#define CMDQ_THR_SPR_IDX0	(0)
#define CMDQ_THR_SPR_IDX1	(1)
#define CMDQ_THR_SPR_IDX2	(2)
#define CMDQ_THR_SPR_IDX3	(3)

struct cmdq_pkt;

struct cmdq_client_reg {
	u8 subsys;
	u16 offset;
	u16 size;
};

struct cmdq_client {
	struct mbox_client client;
	struct mbox_chan *chan;
};

#if IS_ENABLED(CONFIG_MTK_CMDQ)

/**
 * cmdq_dev_get_client_reg() - parse cmdq client reg from the device
 *			       node of CMDQ client
 * @dev:	device of CMDQ mailbox client
 * @client_reg: CMDQ client reg pointer
 * @idx:	the index of desired reg
 *
 * Return: 0 for success; else the error code is returned
 *
 * Help CMDQ client parsing the cmdq client reg
 * from the device node of CMDQ client.
 */
int cmdq_dev_get_client_reg(struct device *dev,
			    struct cmdq_client_reg *client_reg, int idx);

/**
 * cmdq_mbox_create() - create CMDQ mailbox client and channel
 * @dev:	device of CMDQ mailbox client
 * @index:	index of CMDQ mailbox channel
 *
 * Return: CMDQ mailbox client pointer
 */
struct cmdq_client *cmdq_mbox_create(struct device *dev, int index);

/**
 * cmdq_mbox_destroy() - destroy CMDQ mailbox client and channel
 * @client:	the CMDQ mailbox client
 */
void cmdq_mbox_destroy(struct cmdq_client *client);

/**
 * cmdq_pkt_create() - create a CMDQ packet
 * @client:	the CMDQ mailbox client
 * @pkt:	the CMDQ packet
 * @size:	required CMDQ buffer size
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size);

/**
 * cmdq_pkt_destroy() - destroy the CMDQ packet
 * @client:	the CMDQ mailbox client
 * @pkt:	the CMDQ packet
 */
void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt);

/**
 * cmdq_pkt_write() - append write command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @subsys:	the CMDQ sub system code
 * @offset:	register offset from CMDQ sub system
 * @value:	the specified target register value
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value);

/**
 * cmdq_pkt_write_mask() - append write command with mask to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @subsys:	the CMDQ sub system code
 * @offset:	register offset from CMDQ sub system
 * @value:	the specified target register value
 * @mask:	the specified target register mask
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
			u16 offset, u32 value, u32 mask);

/*
 * cmdq_pkt_read_s() - append read_s command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @high_addr_reg_idx:	internal register ID which contains high address of pa
 * @addr_low:	low address of pa
 * @reg_idx:	the CMDQ internal register ID to cache read data
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low,
		    u16 reg_idx);

/**
 * cmdq_pkt_write_s() - append write_s command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @high_addr_reg_idx:	internal register ID which contains high address of pa
 * @addr_low:	low address of pa
 * @src_reg_idx:	the CMDQ internal register ID which cache source value
 *
 * Return: 0 for success; else the error code is returned
 *
 * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH()
 * to get high address and call cmdq_pkt_assign() to assign value into internal
 * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when
 * call to this function.
 */
int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
		     u16 addr_low, u16 src_reg_idx);

/**
 * cmdq_pkt_write_s_mask() - append write_s with mask command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @high_addr_reg_idx:	internal register ID which contains high address of pa
 * @addr_low:	low address of pa
 * @src_reg_idx:	the CMDQ internal register ID which cache source value
 * @mask:	the specified target address mask, use U32_MAX if no need
 *
 * Return: 0 for success; else the error code is returned
 *
 * Support write value to physical address without subsys. Use CMDQ_ADDR_HIGH()
 * to get high address and call cmdq_pkt_assign() to assign value into internal
 * reg. Also use CMDQ_ADDR_LOW() to get low address for addr_low parameter when
 * call to this function.
 */
int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
			  u16 addr_low, u16 src_reg_idx, u32 mask);

/**
 * cmdq_pkt_write_s_value() - append write_s command to the CMDQ packet which
 *			      write value to a physical address
 * @pkt:	the CMDQ packet
 * @high_addr_reg_idx:	internal register ID which contains high address of pa
 * @addr_low:	low address of pa
 * @value:	the specified target value
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
			   u16 addr_low, u32 value);

/**
 * cmdq_pkt_write_s_mask_value() - append write_s command with mask to the CMDQ
 *				   packet which write value to a physical
 *				   address
 * @pkt:	the CMDQ packet
 * @high_addr_reg_idx:	internal register ID which contains high address of pa
 * @addr_low:	low address of pa
 * @value:	the specified target value
 * @mask:	the specified target mask
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
				u16 addr_low, u32 value, u32 mask);

/**
 * cmdq_pkt_mem_move() - append memory move command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @src_addr:	source address
 * @dst_addr:	destination address
 *
 * Appends a CMDQ command to copy the value found in `src_addr` to `dst_addr`.
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_mem_move(struct cmdq_pkt *pkt, dma_addr_t src_addr, dma_addr_t dst_addr);

/**
 * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @event:	the desired event type to wait
 * @clear:	clear event or not after event arrive
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear);

/**
 * cmdq_pkt_acquire_event() - append acquire event command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @event:	the desired event to be acquired
 *
 * User can use cmdq_pkt_acquire_event() as `mutex_lock` and cmdq_pkt_clear_event()
 * as `mutex_unlock` to protect some `critical section` instructions between them.
 * cmdq_pkt_acquire_event() would wait for event to be cleared.
 * After event is cleared by cmdq_pkt_clear_event in other GCE threads,
 * cmdq_pkt_acquire_event() would set event and keep executing next instruction.
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_acquire_event(struct cmdq_pkt *pkt, u16 event);

/**
 * cmdq_pkt_clear_event() - append clear event command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @event:	the desired event to be cleared
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event);

/**
 * cmdq_pkt_set_event() - append set event command to the CMDQ packet
 * @pkt:	the CMDQ packet
 * @event:	the desired event to be set
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event);

/**
 * cmdq_pkt_poll() - Append polling command to the CMDQ packet, ask GCE to
 *		     execute an instruction that wait for a specified
 *		     hardware register to check for the value w/o mask.
 *		     All GCE hardware threads will be blocked by this
 *		     instruction.
 * @pkt:	the CMDQ packet
 * @subsys:	the CMDQ sub system code
 * @offset:	register offset from CMDQ sub system
 * @value:	the specified target register value
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys,
		  u16 offset, u32 value);

/**
 * cmdq_pkt_poll_mask() - Append polling command to the CMDQ packet, ask GCE to
 *		          execute an instruction that wait for a specified
 *		          hardware register to check for the value w/ mask.
 *		          All GCE hardware threads will be blocked by this
 *		          instruction.
 * @pkt:	the CMDQ packet
 * @subsys:	the CMDQ sub system code
 * @offset:	register offset from CMDQ sub system
 * @value:	the specified target register value
 * @mask:	the specified target register mask
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys,
		       u16 offset, u32 value, u32 mask);

/**
 * cmdq_pkt_assign() - Append logic assign command to the CMDQ packet, ask GCE
 *		       to execute an instruction that set a constant value into
 *		       internal register and use as value, mask or address in
 *		       read/write instruction.
 * @pkt:	the CMDQ packet
 * @reg_idx:	the CMDQ internal register ID
 * @value:	the specified value
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value);

/**
 * cmdq_pkt_poll_addr() - Append blocking POLL command to CMDQ packet
 * @pkt:	the CMDQ packet
 * @addr:	the hardware register address
 * @value:	the specified target register value
 * @mask:	the specified target register mask
 *
 * Appends a polling (POLL) command to the CMDQ packet and asks the GCE
 * to execute an instruction that checks for the specified `value` (with
 * or without `mask`) to appear in the specified hardware register `addr`.
 * All GCE threads will be blocked by this instruction.
 *
 * Return: 0 for success or negative error code
 */
int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask);

/**
 * cmdq_pkt_jump_abs() - Append jump command to the CMDQ packet, ask GCE
 *			 to execute an instruction that change current thread
 *			 PC to a absolute physical address which should
 *			 contains more instruction.
 * @pkt:        the CMDQ packet
 * @addr:       absolute physical address of target instruction buffer
 * @shift_pa:	shift bits of physical address in CMDQ instruction. This value
 *		is got by cmdq_get_shift_pa().
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa);

/* This wrapper has to be removed after all users migrated to jump_abs */
static inline int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa)
{
	return cmdq_pkt_jump_abs(pkt, addr, shift_pa);
}

/**
 * cmdq_pkt_jump_rel() - Append jump command to the CMDQ packet, ask GCE
 *			 to execute an instruction that change current thread
 *			 PC to a physical address with relative offset. The
 *			 target address should contains more instruction.
 * @pkt:	the CMDQ packet
 * @offset:	relative offset of target instruction buffer from current PC.
 * @shift_pa:	shift bits of physical address in CMDQ instruction. This value
 *		is got by cmdq_get_shift_pa().
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa);

/**
 * cmdq_pkt_eoc() - Append EOC and ask GCE to generate an IRQ at end of execution
 * @pkt:	The CMDQ packet
 *
 * Appends an End Of Code (EOC) command to the CMDQ packet and asks the GCE
 * to generate an interrupt at the end of the execution of all commands in
 * the pipeline.
 * The EOC command is usually appended to the end of the pipeline to notify
 * that all commands are done.
 *
 * Return: 0 for success or negative error number
 */
int cmdq_pkt_eoc(struct cmdq_pkt *pkt);

/**
 * cmdq_pkt_finalize() - Append EOC and jump command to pkt.
 * @pkt:	the CMDQ packet
 *
 * Return: 0 for success; else the error code is returned
 */
int cmdq_pkt_finalize(struct cmdq_pkt *pkt);

#else /* IS_ENABLED(CONFIG_MTK_CMDQ) */

static inline int cmdq_dev_get_client_reg(struct device *dev,
					  struct cmdq_client_reg *client_reg, int idx)
{
	return -ENODEV;
}

static inline struct cmdq_client *cmdq_mbox_create(struct device *dev, int index)
{
	return ERR_PTR(-EINVAL);
}

static inline void cmdq_mbox_destroy(struct cmdq_client *client) { }

static inline int cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, size_t size)
{
	return -EINVAL;
}

static inline void cmdq_pkt_destroy(struct cmdq_client *client, struct cmdq_pkt *pkt) { }

static inline int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value)
{
	return -ENOENT;
}

static inline int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
				      u16 offset, u32 value, u32 mask)
{
	return -ENOENT;
}

static inline int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
				  u16 addr_low, u16 reg_idx)
{
	return -ENOENT;
}

static inline int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
				   u16 addr_low, u16 src_reg_idx)
{
	return -ENOENT;
}

static inline int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx,
					u16 addr_low, u16 src_reg_idx, u32 mask)
{
	return -ENOENT;
}

static inline int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
					 u16 addr_low, u32 value)
{
	return -ENOENT;
}

static inline int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx,
					      u16 addr_low, u32 value, u32 mask)
{
	return -ENOENT;
}

static inline int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear)
{
	return -EINVAL;
}

static inline int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event)
{
	return -EINVAL;
}

static inline int cmdq_pkt_set_event(struct cmdq_pkt *pkt, u16 event)
{
	return -EINVAL;
}

static inline int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys,
				u16 offset, u32 value)
{
	return -EINVAL;
}

static inline int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys,
				     u16 offset, u32 value, u32 mask)
{
	return -EINVAL;
}

static inline int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value)
{
	return -EINVAL;
}

static inline int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mask)
{
	return -EINVAL;
}

static inline int cmdq_pkt_jump_abs(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa)
{
	return -EINVAL;
}

static inline int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr, u8 shift_pa)
{
	return -EINVAL;
}

static inline int cmdq_pkt_jump_rel(struct cmdq_pkt *pkt, s32 offset, u8 shift_pa)
{
	return -EINVAL;
}

static inline int cmdq_pkt_eoc(struct cmdq_pkt *pkt)
{
	return -EINVAL;
}

static inline int cmdq_pkt_finalize(struct cmdq_pkt *pkt)
{
	return -EINVAL;
}

#endif /* IS_ENABLED(CONFIG_MTK_CMDQ) */

#endif	/* __MTK_CMDQ_H__ */