blob: aa12932bab2191dab70c4fbcda9abab47c37633a [file] [log] [blame]
Haojian Zhuang1b5c2252017-06-01 15:20:46 +08001/*
2 * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#include <assert.h>
7#include <debug.h>
8#include <errno.h>
9#include <hi3660_mailbox.h>
10#include <mailbox.h>
11#include <mmio.h>
12#include <string.h>
13
14typedef struct hi3660_chan {
15 unsigned char src;
16 unsigned char dst;
17 unsigned char used;
18} hi3660_chan_t;
19
20static hi3660_chan_t chan_map[MBX_MAX_CHANNELS];
21
22static void hi3660_mbox_check_state(int chan, unsigned int state)
23{
24 unsigned int data;
25
26 data = mmio_read_32(MBX_MODE(chan));
27 assert((data & (MBX_MODE_AUTO_ANSWER | MBX_MODE_AUTO_LINK)) == 0);
28
29 data &= MBX_MODE_STATE_STATUS_MASK;
30 assert(data == state);
31 (void)state;
32}
33
34static int hi3660_mbox_send(int chan, void *message, int len)
35{
36 int i;
37 unsigned int *buf;
38 unsigned int data;
39
40 assert((chan >= 0) && (chan < MBX_MAX_CHANNELS) &&
41 (message != NULL) && (len <= MBX_MAX_DATA_LEN));
42 assert((chan_map[chan].used != 0) &&
43 (chan_map[chan].src != 0) &&
44 (chan_map[chan].dst != 0));
45
46 buf = (unsigned int *)message;
47 len = ((len + 3) >> 2); /* convert to word count */
48 for (i = 0; i < len; i++)
49 mmio_write_32(MBX_DATA0(chan) + (i << 2), *(buf + i));
50 /* send out */
51 mmio_write_32(MBX_SEND(chan), chan_map[chan].src);
52
53 do {
54 data = mmio_read_32(MBX_ICLR(chan));
55 } while ((data & chan_map[chan].src) == 0);
56 /* ack */
57 mmio_write_32(MBX_ICLR(chan), chan_map[chan].src);
58 return 0;
59}
60
61static int hi3660_mbox_recv(int chan, void *message, int *len)
62{
63 unsigned int *buf, data;
64 int i;
65
66 assert((chan >= 0) && (chan < MBX_MAX_CHANNELS) &&
67 (message != NULL) && (len != NULL));
68 assert((chan_map[chan].used != 0) &&
69 (chan_map[chan].src != 0) &&
70 (chan_map[chan].dst != 0));
71 /* wait IPC event */
72 do {
73 data = mmio_read_32(MBX_MODE(chan));
74 } while ((data & MBX_MODE_STATE_STATUS_MASK) != MBX_MODE_STATE_DEST);
75 /* wait to clear interrupt */
76 do {
77 data = mmio_read_32(MBX_ICLR(chan));
78 } while (data == 0);
79 do {
80 mmio_write_32(MBX_ICLR(chan), chan_map[chan].dst);
81 data = mmio_read_32(MBX_ICLR(chan));
82 } while (data);
83
84 /* read data from IPC */
85 buf = (unsigned int *)message;
86 for (i = 0; i < MBX_MAX_DATA_LEN; i += 4)
87 *(buf + (i >> 2)) = mmio_read_32(MBX_DATA0(chan) + i);
88 *len = MBX_MAX_DATA_LEN;
89 /* ack */
90 mmio_write_32(MBX_SEND(chan), chan_map[chan].dst);
91 return 0;
92}
93
94static int hi3660_mbox_request(int chan, int direction)
95{
96 unsigned int data;
97 unsigned int src, dst;
98
99 assert((chan >= 0) && (chan < MBX_MAX_CHANNELS));
100
101 if (direction == MAILBOX_DIR_TX) {
102 src = CPU_A53;
103 dst = CPU_LPM3;
104 } else if (direction == MAILBOX_DIR_RX) {
105 src = CPU_LPM3;
106 dst = CPU_A53;
107 } else
108 assert(0);
109 mmio_write_32(MBX_SOURCE(chan), src);
110 data = mmio_read_32(MBX_SOURCE(chan));
111 assert(data == src);
112
113 /* mask all interrupts */
114 mmio_write_32(MBX_IMASK(chan), CPU_MASK);
115 /* unmask interrupt */
116 mmio_write_32(MBX_IMASK(chan), ~(src | dst));
117
118 /* set destination */
119 mmio_write_32(MBX_DCLEAR(chan), (~dst) & CPU_MASK);
120 mmio_write_32(MBX_DSET(chan), dst);
121 data = mmio_read_32(MBX_DSTATUS(chan));
122 assert((data & dst) != 0);
123
124 /* clear auto link & auto answer */
125 data = mmio_read_32(MBX_MODE(chan));
126 data &= ~(MBX_MODE_AUTO_ANSWER | MBX_MODE_AUTO_LINK);
127 mmio_write_32(MBX_MODE(chan), data);
128
129 hi3660_mbox_check_state(chan, MBX_MODE_STATE_SOURCE);
130 chan_map[chan].used = 1;
131 chan_map[chan].src = src;
132 chan_map[chan].dst = dst;
133 return 0;
134}
135
136static void hi3660_mbox_free(int chan)
137{
138 assert((chan >= 0) && (chan < MBX_MAX_CHANNELS));
139}
140
141static mbox_ops_t hi3660_mbox_ops = {
142 .send = hi3660_mbox_send,
143 .recv = hi3660_mbox_recv,
144 .request = hi3660_mbox_request,
145 .free = hi3660_mbox_free,
146};
147
148int hi3660_mbox_init(mbox_params_t *params)
149{
150 int result;
151 unsigned int data;
152
153 assert(params != NULL);
154 result = mbox_init(&hi3660_mbox_ops, params);
155 assert(result == 0);
156 memset(&chan_map, 0, sizeof(chan_map));
157
158 /* unlock mailbox */
159 data = mmio_read_32(IPC_LOCK);
160 while (data == MBX_IPC_LOCKED) {
161 mmio_write_32(IPC_LOCK, MBX_IPC_UNLOCK_MAGIC);
162 data = mmio_read_32(IPC_LOCK);
163 }
164 (void)result;
165 return 0;
166}