1
2
3
4
5
6#include <common.h>
7#include <cpu_func.h>
8#include <asm/io.h>
9#include <asm/arch/base.h>
10#include <asm/arch/mbox.h>
11#include <phys2bus.h>
12
13#define TIMEOUT 1000
14
15int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
16{
17 struct bcm2835_mbox_regs *regs =
18 (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
19 ulong endtime = get_timer(0) + TIMEOUT;
20 u32 val;
21
22 debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
23
24 if (send & BCM2835_CHAN_MASK) {
25 printf("mbox: Illegal mbox data 0x%08x\n", send);
26 return -1;
27 }
28
29
30
31 for (;;) {
32 val = readl(®s->mail0_status);
33 if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
34 break;
35 if (get_timer(0) >= endtime) {
36 printf("mbox: Timeout draining stale responses\n");
37 return -1;
38 }
39 val = readl(®s->read);
40 }
41
42
43
44 for (;;) {
45 val = readl(®s->mail1_status);
46 if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
47 break;
48 if (get_timer(0) >= endtime) {
49 printf("mbox: Timeout waiting for send space\n");
50 return -1;
51 }
52 }
53
54
55
56 val = BCM2835_MBOX_PACK(chan, send);
57 debug("mbox: TX raw: 0x%08x\n", val);
58 writel(val, ®s->write);
59
60
61
62 for (;;) {
63 val = readl(®s->mail0_status);
64 if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
65 break;
66 if (get_timer(0) >= endtime) {
67 printf("mbox: Timeout waiting for response\n");
68 return -1;
69 }
70 }
71
72
73
74 val = readl(®s->read);
75 debug("mbox: RX raw: 0x%08x\n", val);
76
77
78
79 if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
80 printf("mbox: Response channel mismatch\n");
81 return -1;
82 }
83
84 *recv = BCM2835_MBOX_UNPACK_DATA(val);
85
86 return 0;
87}
88
89#ifdef DEBUG
90void dump_buf(struct bcm2835_mbox_hdr *buffer)
91{
92 u32 *p;
93 u32 words;
94 int i;
95
96 p = (u32 *)buffer;
97 words = buffer->buf_size / 4;
98 for (i = 0; i < words; i++)
99 printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
100}
101#endif
102
103int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
104{
105 int ret;
106 u32 rbuffer;
107 struct bcm2835_mbox_tag_hdr *tag;
108 int tag_index;
109
110#ifdef DEBUG
111 printf("mbox: TX buffer\n");
112 dump_buf(buffer);
113#endif
114
115 flush_dcache_range((unsigned long)buffer,
116 (unsigned long)((void *)buffer +
117 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
118
119 ret = bcm2835_mbox_call_raw(chan,
120 phys_to_bus((unsigned long)buffer),
121 &rbuffer);
122 if (ret)
123 return ret;
124
125 invalidate_dcache_range((unsigned long)buffer,
126 (unsigned long)((void *)buffer +
127 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
128
129 if (rbuffer != phys_to_bus((unsigned long)buffer)) {
130 printf("mbox: Response buffer mismatch\n");
131 return -1;
132 }
133
134#ifdef DEBUG
135 printf("mbox: RX buffer\n");
136 dump_buf(buffer);
137#endif
138
139
140
141 if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
142 printf("mbox: Header response code invalid\n");
143 return -1;
144 }
145
146
147
148 tag = (void *)(buffer + 1);
149 tag_index = 0;
150 while (tag->tag) {
151 if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
152 printf("mbox: Tag %d missing val_len response bit\n",
153 tag_index);
154 return -1;
155 }
156
157
158
159
160 tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
161 tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
162 tag_index++;
163 }
164
165 return 0;
166}
167