blob: fd65e3387ffabda80ad036949f2c2bed596c984d [file] [log] [blame]
Stephen Warren91ea2882013-01-29 16:37:36 +00001/*
2 * (C) Copyright 2012 Stephen Warren
3 *
4 * See file CREDITS for list of people who contributed to this
5 * project.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <common.h>
19#include <asm/io.h>
20#include <asm/arch/mbox.h>
21
22#define TIMEOUT (100 * 1000) /* 100mS in uS */
23
24int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
25{
26 struct bcm2835_mbox_regs *regs =
27 (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
28 ulong endtime = get_timer(0) + TIMEOUT;
29 u32 val;
30
31 debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
32
33 if (send & BCM2835_CHAN_MASK) {
34 printf("mbox: Illegal mbox data 0x%08x\n", send);
35 return -1;
36 }
37
38 /* Drain any stale responses */
39
40 for (;;) {
41 val = readl(&regs->status);
42 if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
43 break;
44 if (get_timer(0) >= endtime) {
45 printf("mbox: Timeout draining stale responses\n");
46 return -1;
47 }
48 val = readl(&regs->read);
49 }
50
51 /* Wait for space to send */
52
53 for (;;) {
54 val = readl(&regs->status);
55 if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
56 break;
57 if (get_timer(0) >= endtime) {
58 printf("mbox: Timeout waiting for send space\n");
59 return -1;
60 }
61 }
62
63 /* Send the request */
64
65 val = BCM2835_MBOX_PACK(chan, send);
66 debug("mbox: TX raw: 0x%08x\n", val);
67 writel(val, &regs->write);
68
69 /* Wait for the response */
70
71 for (;;) {
72 val = readl(&regs->status);
73 if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
74 break;
75 if (get_timer(0) >= endtime) {
76 printf("mbox: Timeout waiting for response\n");
77 return -1;
78 }
79 }
80
81 /* Read the response */
82
83 val = readl(&regs->read);
84 debug("mbox: RX raw: 0x%08x\n", val);
85
86 /* Validate the response */
87
88 if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
89 printf("mbox: Response channel mismatch\n");
90 return -1;
91 }
92
93 *recv = BCM2835_MBOX_UNPACK_DATA(val);
94
95 return 0;
96}
97
98#ifdef DEBUG
99void dump_buf(struct bcm2835_mbox_hdr *buffer)
100{
101 u32 *p;
102 u32 words;
103 int i;
104
105 p = (u32 *)buffer;
106 words = buffer->buf_size / 4;
107 for (i = 0; i < words; i++)
108 printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
109}
110#endif
111
112int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
113{
114 int ret;
115 u32 rbuffer;
116 struct bcm2835_mbox_tag_hdr *tag;
117 int tag_index;
118
119#ifdef DEBUG
120 printf("mbox: TX buffer\n");
121 dump_buf(buffer);
122#endif
123
124 ret = bcm2835_mbox_call_raw(chan, (u32)buffer, &rbuffer);
125 if (ret)
126 return ret;
127 if (rbuffer != (u32)buffer) {
128 printf("mbox: Response buffer mismatch\n");
129 return -1;
130 }
131
132#ifdef DEBUG
133 printf("mbox: RX buffer\n");
134 dump_buf(buffer);
135#endif
136
137 /* Validate overall response status */
138
139 if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
140 printf("mbox: Header response code invalid\n");
141 return -1;
142 }
143
144 /* Validate each tag's response status */
145
146 tag = (void *)(buffer + 1);
147 tag_index = 0;
148 while (tag->tag) {
149 if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
150 printf("mbox: Tag %d missing val_len response bit\n",
151 tag_index);
152 return -1;
153 }
154 /*
155 * Clear the reponse bit so clients can just look right at the
156 * length field without extra processing
157 */
158 tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
159 tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
160 tag_index++;
161 }
162
163 return 0;
164}