blob: 1642ebd1031ff44aca88b453dccb637888aeff8c [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stephen Warren91ea2882013-01-29 16:37:36 +00002/*
3 * (C) Copyright 2012 Stephen Warren
Stephen Warren91ea2882013-01-29 16:37:36 +00004 */
5
6#include <common.h>
7#include <asm/io.h>
8#include <asm/arch/mbox.h>
Stephen Warrenb44229c2015-04-06 20:28:39 -06009#include <phys2bus.h>
Stephen Warren91ea2882013-01-29 16:37:36 +000010
Stephen Warrenc2b50ff2014-01-13 19:50:12 -070011#define TIMEOUT 1000 /* ms */
Stephen Warren91ea2882013-01-29 16:37:36 +000012
13int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
14{
15 struct bcm2835_mbox_regs *regs =
16 (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
17 ulong endtime = get_timer(0) + TIMEOUT;
18 u32 val;
19
20 debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
21
22 if (send & BCM2835_CHAN_MASK) {
23 printf("mbox: Illegal mbox data 0x%08x\n", send);
24 return -1;
25 }
26
27 /* Drain any stale responses */
28
29 for (;;) {
30 val = readl(&regs->status);
31 if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
32 break;
33 if (get_timer(0) >= endtime) {
34 printf("mbox: Timeout draining stale responses\n");
35 return -1;
36 }
37 val = readl(&regs->read);
38 }
39
40 /* Wait for space to send */
41
42 for (;;) {
43 val = readl(&regs->status);
44 if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
45 break;
46 if (get_timer(0) >= endtime) {
47 printf("mbox: Timeout waiting for send space\n");
48 return -1;
49 }
50 }
51
52 /* Send the request */
53
54 val = BCM2835_MBOX_PACK(chan, send);
55 debug("mbox: TX raw: 0x%08x\n", val);
56 writel(val, &regs->write);
57
58 /* Wait for the response */
59
60 for (;;) {
61 val = readl(&regs->status);
62 if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
63 break;
64 if (get_timer(0) >= endtime) {
65 printf("mbox: Timeout waiting for response\n");
66 return -1;
67 }
68 }
69
70 /* Read the response */
71
72 val = readl(&regs->read);
73 debug("mbox: RX raw: 0x%08x\n", val);
74
75 /* Validate the response */
76
77 if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
78 printf("mbox: Response channel mismatch\n");
79 return -1;
80 }
81
82 *recv = BCM2835_MBOX_UNPACK_DATA(val);
83
84 return 0;
85}
86
87#ifdef DEBUG
88void dump_buf(struct bcm2835_mbox_hdr *buffer)
89{
90 u32 *p;
91 u32 words;
92 int i;
93
94 p = (u32 *)buffer;
95 words = buffer->buf_size / 4;
96 for (i = 0; i < words; i++)
97 printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
98}
99#endif
100
101int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
102{
103 int ret;
104 u32 rbuffer;
105 struct bcm2835_mbox_tag_hdr *tag;
106 int tag_index;
107
108#ifdef DEBUG
109 printf("mbox: TX buffer\n");
110 dump_buf(buffer);
111#endif
112
Alexander Steinfbeb89d2015-07-24 09:22:13 +0200113 flush_dcache_range((unsigned long)buffer,
114 (unsigned long)((void *)buffer +
115 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
116
Stephen Warrenfc0f7bc2016-03-16 21:40:57 -0600117 ret = bcm2835_mbox_call_raw(chan,
118 phys_to_bus((unsigned long)buffer),
119 &rbuffer);
Stephen Warren91ea2882013-01-29 16:37:36 +0000120 if (ret)
121 return ret;
Alexander Steinfbeb89d2015-07-24 09:22:13 +0200122
123 invalidate_dcache_range((unsigned long)buffer,
124 (unsigned long)((void *)buffer +
125 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
126
Stephen Warrenfc0f7bc2016-03-16 21:40:57 -0600127 if (rbuffer != phys_to_bus((unsigned long)buffer)) {
Stephen Warren91ea2882013-01-29 16:37:36 +0000128 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}