blob: 17855506427159715d02b815d3136ffbf62a2a1d [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stephen Warren88077282013-01-29 16:37:36 +00002/*
3 * (C) Copyright 2012 Stephen Warren
Stephen Warren88077282013-01-29 16:37:36 +00004 */
5
6#include <common.h>
Simon Glass1eb69ae2019-11-14 12:57:39 -07007#include <cpu_func.h>
Stephen Warren88077282013-01-29 16:37:36 +00008#include <asm/io.h>
Matthias Brugger8e3361c2019-11-19 16:01:03 +01009#include <asm/arch/base.h>
Stephen Warren88077282013-01-29 16:37:36 +000010#include <asm/arch/mbox.h>
Stephen Warren122426d2015-04-06 20:28:39 -060011#include <phys2bus.h>
Stephen Warren88077282013-01-29 16:37:36 +000012
Stephen Warren004c1052014-01-13 19:50:12 -070013#define TIMEOUT 1000 /* ms */
Stephen Warren88077282013-01-29 16:37:36 +000014
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 /* Drain any stale responses */
30
31 for (;;) {
Fabian Vogt49822442019-07-16 13:09:47 +020032 val = readl(&regs->mail0_status);
Stephen Warren88077282013-01-29 16:37:36 +000033 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(&regs->read);
40 }
41
42 /* Wait for space to send */
43
44 for (;;) {
Fabian Vogt49822442019-07-16 13:09:47 +020045 val = readl(&regs->mail1_status);
Stephen Warren88077282013-01-29 16:37:36 +000046 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 /* Send the request */
55
56 val = BCM2835_MBOX_PACK(chan, send);
57 debug("mbox: TX raw: 0x%08x\n", val);
58 writel(val, &regs->write);
59
60 /* Wait for the response */
61
62 for (;;) {
Fabian Vogt49822442019-07-16 13:09:47 +020063 val = readl(&regs->mail0_status);
Stephen Warren88077282013-01-29 16:37:36 +000064 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 /* Read the response */
73
74 val = readl(&regs->read);
75 debug("mbox: RX raw: 0x%08x\n", val);
76
77 /* Validate the response */
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
Alexander Stein4342557f2015-07-24 09:22:13 +0200115 flush_dcache_range((unsigned long)buffer,
116 (unsigned long)((void *)buffer +
117 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
118
Stephen Warren2b513152016-03-16 21:40:57 -0600119 ret = bcm2835_mbox_call_raw(chan,
120 phys_to_bus((unsigned long)buffer),
121 &rbuffer);
Stephen Warren88077282013-01-29 16:37:36 +0000122 if (ret)
123 return ret;
Alexander Stein4342557f2015-07-24 09:22:13 +0200124
125 invalidate_dcache_range((unsigned long)buffer,
126 (unsigned long)((void *)buffer +
127 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
128
Stephen Warren2b513152016-03-16 21:40:57 -0600129 if (rbuffer != phys_to_bus((unsigned long)buffer)) {
Stephen Warren88077282013-01-29 16:37:36 +0000130 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 /* Validate overall response status */
140
141 if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
142 printf("mbox: Header response code invalid\n");
143 return -1;
144 }
145
146 /* Validate each tag's response status */
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 * Clear the reponse bit so clients can just look right at the
158 * length field without extra processing
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}