Skip to content

Commit 3d2e408

Browse files
committed
Add IPM (Inter-Processor-Mailbox) driver to cores/arduino
This allows the mailbox to be used for Serial (instead of polling shared memory). The CurieMailbox library, in the codk-m-corelibs branch, will not require any API changes, but will now just be a thin wrapper around the methods in mailbox.cpp
1 parent c58480c commit 3d2e408

File tree

7 files changed

+210
-171
lines changed

7 files changed

+210
-171
lines changed

Diff for: cores/arduino/mailbox.cpp

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#include <string.h>
2+
#include "interrupt.h"
3+
#include "scss_registers.h"
4+
#include "mailbox.h"
5+
6+
#define CHANNEL_STS_MASK 0x1
7+
#define CHANNEL_INT_MASK 0x2
8+
#define CTRL_WORD_MASK 0x7FFFFFFF
9+
#define CHALL_STATUS_MASK 0xFFFF
10+
#define CHANNEL_STS_BITS (CHANNEL_STS_MASK | CHANNEL_INT_MASK)
11+
12+
/* Mailbox channel status register */
13+
#define IO_REG_MAILBOX_CHALL_STS (SCSS_REGISTER_BASE + 0xAC0)
14+
15+
typedef struct mbox_channel mbox_channel_t;
16+
typedef struct mbox_intmask mbox_intmask_t;
17+
18+
/* Represents the registers for a single mailbox channel */
19+
struct mbox_channel {
20+
uint32_t ctrl;
21+
uint32_t data[CHANNEL_DATA_WORDS];
22+
uint32_t sts;
23+
};
24+
25+
/* Mailbox interrupt mask; right now we only care about the
26+
* second byte, for SS mailbox interrupts (one bit per mailbox channel) */
27+
struct mbox_intmask {
28+
uint8_t lmt_intmask;
29+
uint8_t ss_intmask;
30+
uint8_t lmt_halt;
31+
uint8_t ss_halt;
32+
};
33+
34+
static volatile mbox_intmask_t *intmask;
35+
static volatile mbox_channel_t *mbox;
36+
static void (*callbacks[NUM_MAILBOX_CHANNELS])(CurieMailboxMsg);
37+
38+
void mailbox_register (int channel, void(*callback)(CurieMailboxMsg))
39+
{
40+
if (channel >= 0 && channel < NUM_MAILBOX_CHANNELS) {
41+
callbacks[channel] = callback;
42+
}
43+
}
44+
45+
void mailbox_unregister (int channel)
46+
{
47+
if (channel >= 0 && channel < NUM_MAILBOX_CHANNELS) {
48+
callbacks[channel] = 0;
49+
}
50+
}
51+
52+
void mailbox_disable_receive (int channel)
53+
{
54+
intmask->ss_intmask |= 1 << channel;
55+
}
56+
57+
void mailbox_enable_receive (int channel)
58+
{
59+
intmask->ss_intmask &= ~(1 << channel);
60+
}
61+
62+
static void do_callback (int channel, CurieMailboxMsg& msg)
63+
{
64+
void (*cb)(CurieMailboxMsg) = callbacks[channel];
65+
if (cb) {
66+
cb(msg);
67+
}
68+
}
69+
70+
static void mailbox_read (int channel, CurieMailboxMsg& msg)
71+
{
72+
unsigned int i;
73+
74+
/* Copy channel data into CurieMailboxMsg object */
75+
msg.id = mbox[channel].ctrl & CTRL_WORD_MASK;
76+
msg.channel = channel;
77+
78+
for (i = 0; i < CHANNEL_DATA_WORDS; ++i) {
79+
msg.data[i] = mbox[channel].data[i];
80+
}
81+
82+
/* Clear channel status & interrupt flags */
83+
mbox[channel].sts |= CHANNEL_STS_BITS;
84+
}
85+
86+
void mailbox_write (CurieMailboxMsg& msg)
87+
{
88+
int i;
89+
uint32_t key;
90+
91+
/* Can't write if channel status flag is set */
92+
while ((mbox[msg.channel].sts & CHANNEL_STS_MASK));
93+
key = interrupt_lock();
94+
95+
/* Poplate channel payload */
96+
mbox[msg.channel].ctrl |= (msg.id & CTRL_WORD_MASK);
97+
for (i = 0; i < CHANNEL_DATA_WORDS; ++i) {
98+
mbox[msg.channel].data[i] = msg.data[i];
99+
}
100+
101+
/* Trigger interupt to host */
102+
mbox[msg.channel].ctrl |= ~(CTRL_WORD_MASK);
103+
104+
/* Wait for HW to set the channel status bit */
105+
while (!(mbox[msg.channel].sts & CHANNEL_STS_MASK));
106+
107+
/* Wait for destination processor to clear channel status bit */
108+
while ((mbox[msg.channel].sts & CHANNEL_STS_MASK));
109+
interrupt_unlock(key);
110+
}
111+
112+
static uint16_t get_chall_sts (void)
113+
{
114+
return MMIO_REG_VAL(IO_REG_MAILBOX_CHALL_STS) & CHALL_STATUS_MASK;
115+
}
116+
117+
static void mailbox_isr (void)
118+
{
119+
int i;
120+
uint32_t sts;
121+
CurieMailboxMsg msg;
122+
123+
sts = get_chall_sts();
124+
/* Get channel number */
125+
for (i = 0; i < NUM_MAILBOX_CHANNELS; ++i) {
126+
if (sts & (1 << (i * 2 + 1))) {
127+
break;
128+
}
129+
}
130+
131+
mailbox_read(i, msg);
132+
do_callback(i, msg);
133+
}
134+
135+
static void mailbox_hardware_init (void)
136+
{
137+
int i;
138+
139+
for (i = 0; i < NUM_MAILBOX_CHANNELS; ++i) {
140+
mbox[i].sts &= ~(CHANNEL_STS_BITS);
141+
}
142+
}
143+
144+
static void mailbox_interrupts_init (bool master)
145+
{
146+
interrupt_disable(SOC_MBOX_INTERRUPT);
147+
148+
/* Mask SS mailbox interrupts for all channels;
149+
* Unmasking is done by enableReceive */
150+
intmask->ss_intmask = 0xFF;
151+
152+
if (master) mailbox_hardware_init();
153+
interrupt_connect(SOC_MBOX_INTERRUPT, mailbox_isr);
154+
interrupt_enable(SOC_MBOX_INTERRUPT);
155+
}
156+
157+
void mailbox_init (bool master)
158+
{
159+
intmask = (mbox_intmask_t *)IO_REG_MAILBOX_INT_MASK;
160+
mbox = (mbox_channel_t *)IO_REG_MAILBOX_BASE;
161+
memset(callbacks, 0, sizeof(callbacks));
162+
mailbox_interrupts_init(master);
163+
}

Diff for: cores/arduino/mailbox.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef _MAILBOX_H_
2+
#define _MAILBOX_H_
3+
4+
#define NUM_MAILBOX_CHANNELS 8
5+
#define CHANNEL_DATA_WORDS 4
6+
7+
class CurieMailboxMsg {
8+
public:
9+
uint32_t data[CHANNEL_DATA_WORDS];
10+
uint32_t id;
11+
int channel = 0;
12+
};
13+
14+
void mailbox_init (bool master);
15+
void mailbox_register (int channel, void(*callback)(CurieMailboxMsg));
16+
void mailbox_unregister (int channel);
17+
void mailbox_enable_receive (int channel);
18+
void mailbox_disable_receive (int channel);
19+
void mailbox_write(CurieMailboxMsg& msg);
20+
21+
#endif

Diff for: libraries/CurieMailbox/README.txt

+6-20
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,13 @@ can fill. Here's how you might populate a CurieMailboxMsg;
3434
API reference:
3535

3636

37-
void CurieMailbox::begin (bool master)
37+
void CurieMailbox::begin ()
3838

39-
Enable interrupts for the mailbox, and optionally initialise the
40-
mailbox hardware.
39+
Enable interrupts for the mailbox, and set up the mailbox hardware for use
4140

4241
Params:
4342

44-
bool master: flag indicating whether mailbox hardware should be initialised.
45-
The first processor to access the mailbox should do this; if in doubt, set
46-
to false (default is false, no initialisation).
47-
48-
49-
50-
void CurieMailbox::begin (void)
51-
52-
Enable interrupts for the mailbox, and do not initialise the hardware.
53-
54-
Params:
55-
56-
None.
57-
43+
None
5844

5945

6046
void CurieMailbox::enableReceive (unsigned int channel)
@@ -77,9 +63,9 @@ void CurieMailbox::disableReceive (unsigned int channel)
7763

7864
Params:
7965

80-
int channel: integer value (0-7) representing the channel to be enabled.
81-
If the passed value does not represent a valid channel, then the highest
82-
channel will be used instead.
66+
int channel: integer value between 0 and CurieMailbox.numChannels,
67+
representing the channel to be enabled. If the passed value does not
68+
represent a valid channel, then the highest channel will be used instead.
8369

8470

8571
int CurieMailbox::available (void)

0 commit comments

Comments
 (0)