summaryrefslogtreecommitdiff
path: root/drivers/hisi/hifi_mailbox/ipcm/bsp_ipc.c
blob: 6f2f3378c098616bac72b96b04ec96e76517105a (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
/*
 *
 * Modifications made by Cadence Design Systems, Inc.  06/21/2017
 * Copyright (C) 2017 Cadence Design Systems, Inc.All rights reserved worldwide.
 *
 */

#include <linux/module.h>
#include <asm/io.h>
#include <asm/string.h>
#include <linux/semaphore.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
#include <linux/delay.h>

#include <linux/slab.h>
#include <linux/hisi/hisi_mailbox.h>
#include <linux/hisi/hisi_rproc.h>

#include "bsp_drv_ipc.h"

/*#define USE_HIFI_IPC*/
BSP_IPC_ENTRY stIpcIntTable[INTSRC_NUM];
static IPC_DEV_S g_stIpcDev = { 0 };

BSP_U32 g_CoreNum;

struct semaphore g_semIpcTask[INTSRC_NUM];
IPC_DEBUG_E g_stIpc_debug = { 0 };

/* base address of ipc registers */
void __iomem *ipc_base;
spinlock_t g_ipc_int_lock = __SPIN_LOCK_UNLOCKED("ipc");

#define USE_HISI_MAILBOX

/*************************************k3 ipc******************************************/
#define BIT_ENABLE(n)                           (1 << (n))
#define BYTE_REF(address) (*((unsigned char volatile *) (address)))
#define HALFWORD_REF(address) (*((unsigned short volatile *) (address)))
#define WORD_REF(address) (*((unsigned int volatile *) (address)))
#define WORD_PTR(address) (*((unsigned int volatile **) (address)))
#define BYTE(address)   volatile unsigned char __attribute__((section(".ARM.__at_"address)))
#define HALFWORD(address)   volatile unsigned short __attribute__((section(".ARM.__at_"address)))
#define WORD(address)   volatile unsigned int __attribute__((section(".ARM.__at_"address)))

#define K3_IPC_MODE_ACK                         (7)
#define K3_IPC_MODE_IDLE                        (4)
#define K3_IPC_MODE_AUTOACK                 (0)

/*************************************hifiϵͳipc******************************************/
#define K3_SYS_IPC_BASE_ADDR_S      (unsigned long)(0xe896a000)
#define K3_SYS_IPC_BASE_ADDR_NS    (unsigned long)(0xe896b000)
#define K3_SYS_IPC_REG_SIZE     (0xA00)

#define K3_IPC_LOCK(base)                          WORD_REF(base + 0xA00)
#define K3_IPC_SOURCE(base, box)           WORD_REF(base + ((box) * 64))
#define K3_IPC_DEST(base, box)             WORD_REF(base + ((box) * 64) + 0x04)
#define K3_IPC_DCLR(base, box)             WORD_REF(base + ((box) * 64) + 0x08)
#define K3_IPC_DSTATUS(base, box)          WORD_REF(base + ((box) * 64) + 0x0c)
#define K3_IPC_MODE(base, box)          WORD_REF(base + ((box) * 64) + 0x10)
#define K3_IPC_IMASK(base, box)        WORD_REF(base + ((box) * 64) + 0x14)
#define K3_IPC_ICLR(base, box)             WORD_REF(base + ((box) * 64) + 0x18)
#define K3_IPC_SEND(base, box)                WORD_REF(base + ((box) * 64) + 0x1c)
#define K3_IPC_DATA(base, box, num)       WORD_REF(base + ((box) * 64) + 0x20 + ((num) * 4))
#define K3_IPC_CPUIMST(base, core)         WORD_REF(base + 0x800 + ((core) * 8))
#define K3_IPC_CPUIRST(base, core)         WORD_REF(base + 0x804 + ((core) * 8))

#define K3_SYS_IPC_CORE_LIT                        (0)
#define K3_SYS_IPC_CORE_BIG                          (1)
#define K3_SYS_IPC_CORE_IOM3                      (2)
#define K3_SYS_IPC_CORE_LPM3                      (3)
#define K3_SYS_IPC_CORE_HIFI                        (4)

#define K3_HIFI_IPC_BASE_ADDR      (unsigned long)(0xE804C000)
#define K3_HIFI_IPC_REG_SIZE        (0x1000)

#define K3_ASP_CFG_CTRLDIS(base)                       WORD_REF(base + 0x04)
#define K3_ASP_CFG_GATE_EN(base)                       WORD_REF(base + 0x0c)

enum {
	K3_HIFI_IPC_CORE_AP_LPM3_IOM3 = 0,
	K3_HIFI_IPC_CORE_MODEM_A9 = 1,
	K3_HIFI_IPC_CORE_MODEM_BBE = 2,
	K3_HIFI_IPC_CORE_HIFI = 3,
	K3_HIFI_IPC_CORE_IOM3 = 5,
	K3_HIFI_IPC_CORE_AP = 6,
	K3_HIFI_IPC_CORE_LPM3 = 8,
};

typedef enum {
	K3_SEC_SYS_IPC = 0,
	K3_UNSEC_SYS_IPC,
	K3_HIFI_IPC,
} K3_IPC;

typedef struct {
	K3_IPC ipcMode;
	void __iomem *ipcBase;
	int mailBoxNum;
	int intNum;
	int sourceCore;
	int destCore;
} K3_IPC_CONFIG;

enum {
	K3_IPC_CORE_IS_SEND = 0,
	K3_IPC_CORE_IS_RECEIVE,
	K3_IPC_CORE_IS_UNKNOEN,
};

static K3_IPC_CONFIG k3IpcConfig[K3_IPC_CORE_IS_UNKNOEN] = {
	{
	 K3_UNSEC_SYS_IPC,
	 NULL,
	 18,
	 220,
	 K3_SYS_IPC_CORE_LIT,
	 K3_SYS_IPC_CORE_HIFI},

	{
	 K3_UNSEC_SYS_IPC,
	 NULL,
	 2,
	 227,
	 K3_SYS_IPC_CORE_HIFI,
	 K3_SYS_IPC_CORE_BIG}
};

static int DRV_k3IpcIntHandler_ipc(struct notifier_block *nb, unsigned long len,
				   void *msg);
struct hisi_mbox *hifi_tx_mbox;
struct notifier_block rx_nb;

#ifdef USE_HISI_MAILBOX
#define MAX_SEND_IPC_TRY    3

static int hisi_hifi_mbox_init(void)
{
	int ret = 0, rproc_id = 0;

	rx_nb.next = NULL;
	rx_nb.notifier_call = DRV_k3IpcIntHandler_ipc;
	rproc_id = HISI_RPROC_HIFI_MBX2;
	/* register the rx notify callback */
	ret = RPROC_MONITOR_REGISTER(rproc_id, &rx_nb);
	if (ret)
		pr_info("%s:RPROC_MONITOR_REGISTER failed", __func__);

	return ret;
}

/*
static void hisi_hifi_mbox_exit(void)
{
    if (hifi_mbox)
	hisi_mbox_put(&hifi_mbox);
}
*/
#else
static irqreturn_t DRV_k3IpcIntHandler_ack(int irq, void *dev_id)
{
	BSP_S32 retval = IRQ_HANDLED;
	BSP_U32 u32IntStat = 0;

	int myRole = K3_IPC_CORE_IS_SEND;
	BSP_U32 mailBoxNum = k3IpcConfig[myRole].mailBoxNum;
	BSP_U32 source = k3IpcConfig[myRole].sourceCore;
	void __iomem *ipcBase = k3IpcConfig[myRole].ipcBase;

	u32IntStat = K3_IPC_CPUIMST(ipcBase, source);

	if (u32IntStat & BIT_ENABLE(mailBoxNum)) {
		if (K3_IPC_MODE(ipcBase, mailBoxNum) &
		    BIT_ENABLE(K3_IPC_MODE_ACK)) {
			pr_info("func:%s: Receive ack int\n", __func__);

			K3_IPC_SOURCE(ipcBase, mailBoxNum) = BIT_ENABLE(source);
		}
		K3_IPC_DCLR(ipcBase, mailBoxNum) = BIT_ENABLE(mailBoxNum);
	}
	return (irqreturn_t)IRQ_RETVAL(retval);
}

#endif

irqreturn_t DRV_k3IpcIntHandler_Autoack(void)
{
	BSP_S32 retval = IRQ_HANDLED;
	BSP_U32 u32IntStat = 0;

	int myRole = K3_IPC_CORE_IS_RECEIVE;
	BSP_U32 mailBoxNum = k3IpcConfig[myRole].mailBoxNum;
	BSP_U32 source = k3IpcConfig[myRole].sourceCore;
	void __iomem *ipcBase = k3IpcConfig[myRole].ipcBase;

	u32IntStat = K3_IPC_CPUIMST(ipcBase, source);

	if (u32IntStat & BIT_ENABLE(mailBoxNum)) {
		if (K3_IPC_MODE(ipcBase, mailBoxNum) & BIT_ENABLE(K3_IPC_MODE_AUTOACK)) {
			K3_IPC_SOURCE(ipcBase, mailBoxNum) = BIT_ENABLE(source);
		}
		K3_IPC_DCLR(ipcBase, mailBoxNum) = BIT_ENABLE(mailBoxNum);
	}
	return (irqreturn_t)IRQ_RETVAL(retval);
}

BSP_S32 DRV_IPCIntInit(void)
{

	int myRole = 0;

	printk(KERN_ERR "DRV_IPCIntInit begin.\n");

	if (BSP_TRUE == g_stIpcDev.bInit) {
		return BSP_OK;
	}

	printk(KERN_ERR "DRV_IPCIntInit line = %d\n", __LINE__);

	g_CoreNum = IPC_CORE_ACPU;

	memset((void *)stIpcIntTable, 0x0,
	       (INTSRC_NUM * sizeof(BSP_IPC_ENTRY)));

	myRole = K3_IPC_CORE_IS_SEND;
	if (K3_UNSEC_SYS_IPC == k3IpcConfig[myRole].ipcMode) {
		k3IpcConfig[myRole].ipcBase =
		    ioremap(K3_SYS_IPC_BASE_ADDR_NS, K3_SYS_IPC_REG_SIZE);
		if (!k3IpcConfig[myRole].ipcBase) {
			printk(KERN_ERR
			       "line %d :k3 unsec sys ipc ioremap error.\n",
			       __LINE__);
			return -1;
		}
	} else if (K3_SEC_SYS_IPC == k3IpcConfig[myRole].ipcMode) {
		k3IpcConfig[myRole].ipcBase =
		    ioremap(K3_SYS_IPC_BASE_ADDR_S, K3_SYS_IPC_REG_SIZE);
		if (!k3IpcConfig[myRole].ipcBase) {
			printk(KERN_ERR
			       "line %d :k3 sec sys ipc ioremap error.\n",
			       __LINE__);
			return -1;
		}
	} else {
		k3IpcConfig[myRole].ipcBase =
		    ioremap(K3_HIFI_IPC_BASE_ADDR, K3_HIFI_IPC_REG_SIZE);
		if (!k3IpcConfig[myRole].ipcBase) {
			printk(KERN_ERR "line %d :k3 hifi ipc ioremap error.\n",
			       __LINE__);
			return -1;
		}
	}

	K3_IPC_LOCK(k3IpcConfig[myRole].ipcBase) = 0x1ACCE551;
	myRole = K3_IPC_CORE_IS_RECEIVE;
	if (K3_UNSEC_SYS_IPC == k3IpcConfig[myRole].ipcMode) {
		k3IpcConfig[myRole].ipcBase =
		    ioremap(K3_SYS_IPC_BASE_ADDR_NS, K3_SYS_IPC_REG_SIZE);
		if (!k3IpcConfig[myRole].ipcBase) {
			printk(KERN_ERR
			       "line %d :k3 unsec sys ipc ioremap error.\n",
			       __LINE__);
			return -1;
		}
	} else if (K3_SEC_SYS_IPC == k3IpcConfig[myRole].ipcMode) {
		k3IpcConfig[myRole].ipcBase =
		    ioremap(K3_SYS_IPC_BASE_ADDR_S, K3_SYS_IPC_REG_SIZE);
		if (!k3IpcConfig[myRole].ipcBase) {
			printk(KERN_ERR
			       "line %d :k3 sec sys ipc ioremap error.\n",
			       __LINE__);
			return -1;
		}
	} else {
		k3IpcConfig[myRole].ipcBase =
		    ioremap(K3_HIFI_IPC_BASE_ADDR, K3_HIFI_IPC_REG_SIZE);
		if (!k3IpcConfig[myRole].ipcBase) {
			printk(KERN_ERR "line %d :k3 hifi ipc ioremap error.\n",
			       __LINE__);
			return -1;
		}
	}
	K3_IPC_LOCK(k3IpcConfig[myRole].ipcBase) = 0x1ACCE551;
#ifdef USE_HISI_MAILBOX
	hisi_hifi_mbox_init();
#else
	ret = request_irq(k3IpcConfig[K3_IPC_CORE_IS_SEND].intNum,
			  DRV_k3IpcIntHandler_ack, 0, "k3IpcIntHandler_ack",
			  NULL);
	if (ret) {
		printk(KERN_ERR
		       "BSP_DRV_IPCIntInit: Unable to register ipc irq ret=%d.\n",
		       ret);
		return BSP_ERROR;
	}
	printk(KERN_ERR "BSP_DRV_IPCIntInit line = %d\n", __LINE__);
#endif

	g_stIpcDev.bInit = BSP_TRUE;

	printk(KERN_ERR "BSP_DRV_IPCIntInit end.\n");

	return BSP_OK;
}

BSP_S32 IPC_IntEnable(IPC_INT_LEV_E ulLvl)
{
	IPC_CHECK_PARA(ulLvl);

	return BSP_OK;
}

BSP_S32 IPC_IntDisable(IPC_INT_LEV_E ulLvl)
{
	IPC_CHECK_PARA(ulLvl);

	return BSP_OK;
}

BSP_S32 IPC_IntConnect(IPC_INT_LEV_E ulLvl, VOIDFUNCPTR routine,
		       BSP_U32 parameter)
{

	unsigned long flag = 0;

	IPC_CHECK_PARA(ulLvl);

	spin_lock_irqsave(&g_ipc_int_lock, flag);
	stIpcIntTable[ulLvl].routine = routine;
	stIpcIntTable[ulLvl].arg = parameter;
	spin_unlock_irqrestore(&g_ipc_int_lock, flag);

	return BSP_OK;
}

BSP_S32 IPC_IntDisonnect(IPC_INT_LEV_E ulLvl, VOIDFUNCPTR routine,
			 BSP_U32 parameter)
{
	unsigned long flag = 0;

	IPC_CHECK_PARA(ulLvl);

	spin_lock_irqsave(&g_ipc_int_lock, flag);
	stIpcIntTable[ulLvl].routine = NULL;
	stIpcIntTable[ulLvl].arg = 0;
	spin_unlock_irqrestore(&g_ipc_int_lock, flag);

	return BSP_OK;
}

static int DRV_k3IpcIntHandler_ipc(struct notifier_block *nb, unsigned long len,
				   void *msg)
{
	BSP_U32 newLevel = 0;
	mbox_msg_t *_msg = (mbox_msg_t *) msg;

	newLevel = _msg[0];

	if (newLevel < INTSRC_NUM) {
		g_stIpc_debug.u32IntHandleTimes[newLevel]++;

		if (NULL != stIpcIntTable[newLevel].routine) {
			stIpcIntTable[newLevel].routine(stIpcIntTable[newLevel].
							arg);
		}
	}

	return 0;
}

BSP_S32 IPC_IntSend(IPC_INT_CORE_E enDstCore, IPC_INT_LEV_E ulLvl)
{
	int myRole = K3_IPC_CORE_IS_SEND;
	BSP_U32 source = k3IpcConfig[myRole].sourceCore;

#ifdef USE_HISI_MAILBOX
	BSP_U32 ipcMsg[2];
	int ret = 0, rproc_id = 0;
#else
	BSP_U32 mailBoxNum = k3IpcConfig[myRole].mailBoxNum;
	BSP_U32 dest = k3IpcConfig[myRole].destCore;
	void __iomem *ipcBase = k3IpcConfig[myRole].ipcBase;
#endif

	IPC_CHECK_PARA(ulLvl);

	if (IPC_CORE_HiFi == enDstCore) {
#ifdef USE_HISI_MAILBOX
		ipcMsg[0] = (source << 24) | (ulLvl << 8);

		rproc_id = HISI_RPROC_HIFI_MBX18;
		ret = RPROC_ASYNC_SEND(rproc_id, (mbox_msg_t *) ipcMsg, 2);
		if (ret) {
			printk(" %s , line %d, send error\n", __func__,
			       __LINE__);
		}
#else
		while (0 ==
		       (K3_IPC_MODE(ipcBase, mailBoxNum) &
			BIT_ENABLE(K3_IPC_MODE_IDLE))) {
			printk("func:%s: mailbox is busy mode = 0x%x\n",
			       __func__, K3_IPC_MODE(ipcBase, mailBoxNum));
		}

		K3_IPC_SOURCE(ipcBase, mailBoxNum) = BIT_ENABLE(source);
		K3_IPC_DEST(ipcBase, mailBoxNum) = BIT_ENABLE(dest);

		K3_IPC_IMASK(ipcBase, mailBoxNum) =
		    ~(BIT_ENABLE(source) | BIT_ENABLE(dest));

		K3_IPC_MODE(ipcBase, mailBoxNum) =
		    BIT_ENABLE(K3_IPC_MODE_AUTOACK);

		K3_IPC_DATA(ipcBase, mailBoxNum, 0) = source;
		K3_IPC_DATA(ipcBase, mailBoxNum, 1) = ulLvl;

		K3_IPC_SEND(ipcBase, mailBoxNum) = BIT_ENABLE(source);

#endif
	} else {
		BSP_RegWr(BSP_IPC_CPU_RAW_INT(enDstCore), 1 << ulLvl);
	}

	g_stIpc_debug.u32RecvIntCore = enDstCore;
	g_stIpc_debug.u32IntSendTimes[ulLvl]++;

	return BSP_OK;
}

void BSP_IPC_SpinLock(unsigned int u32SignalNum)
{
	unsigned int u32HsCtrl;

	if (u32SignalNum >= INTSRC_NUM) {
		printk("BSP_IPC_SpinLock  Parameter error, line:%d\n",
		       __LINE__);
		return;
	}
	for (;;) {
		u32HsCtrl = BSP_RegRd(BSP_IPC_HS_CTRL(g_CoreNum, u32SignalNum));
		if (0 == u32HsCtrl) {
			break;
		}
	}
}

void BSP_IPC_SpinUnLock(unsigned int u32SignalNum)
{
	if (u32SignalNum >= INTSRC_NUM) {
		printk("BSP_IPC_SpinUnLock  Parameter error, line:%d\n",
		       __LINE__);
		return;
	}
	BSP_RegWr(BSP_IPC_HS_CTRL(g_CoreNum, u32SignalNum), 0);
}

EXPORT_SYMBOL(IPC_IntEnable);
EXPORT_SYMBOL(IPC_IntDisable);
EXPORT_SYMBOL(IPC_IntConnect);
EXPORT_SYMBOL(IPC_IntSend);