blob: c7cbfa72ffcce0998cc082ce58b94a82d5963b02 [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
Simon Glass63334482019-11-14 12:57:39 -07006#include <cpu_func.h>
Simon Glass0f2af882020-05-10 11:40:05 -06007#include <log.h>
Tom Rinidec7ea02024-05-20 13:35:03 -06008#include <time.h>
Simon Glass274e0b02020-05-10 11:39:56 -06009#include <asm/cache.h>
Stephen Warren91ea2882013-01-29 16:37:36 +000010#include <asm/io.h>
Matthias Brugger2c68dee2019-11-19 16:01:03 +010011#include <asm/arch/base.h>
Stephen Warren91ea2882013-01-29 16:37:36 +000012#include <asm/arch/mbox.h>
Stephen Warrenb44229c2015-04-06 20:28:39 -060013#include <phys2bus.h>
Stephen Warren91ea2882013-01-29 16:37:36 +000014
Stephen Warrenc2b50ff2014-01-13 19:50:12 -070015#define TIMEOUT 1000 /* ms */
Stephen Warren91ea2882013-01-29 16:37:36 +000016
17int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
18{
19 struct bcm2835_mbox_regs *regs =
20 (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
21 ulong endtime = get_timer(0) + TIMEOUT;
22 u32 val;
23
24 debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
25
26 if (send & BCM2835_CHAN_MASK) {
27 printf("mbox: Illegal mbox data 0x%08x\n", send);
28 return -1;
29 }
30
31 /* Drain any stale responses */
32
33 for (;;) {
Fabian Vogtbcf941f2019-07-16 13:09:47 +020034 val = readl(&regs->mail0_status);
Stephen Warren91ea2882013-01-29 16:37:36 +000035 if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
36 break;
37 if (get_timer(0) >= endtime) {
38 printf("mbox: Timeout draining stale responses\n");
39 return -1;
40 }
41 val = readl(&regs->read);
42 }
43
44 /* Wait for space to send */
45
46 for (;;) {
Fabian Vogtbcf941f2019-07-16 13:09:47 +020047 val = readl(&regs->mail1_status);
Stephen Warren91ea2882013-01-29 16:37:36 +000048 if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
49 break;
50 if (get_timer(0) >= endtime) {
51 printf("mbox: Timeout waiting for send space\n");
52 return -1;
53 }
54 }
55
56 /* Send the request */
57
58 val = BCM2835_MBOX_PACK(chan, send);
59 debug("mbox: TX raw: 0x%08x\n", val);
60 writel(val, &regs->write);
61
62 /* Wait for the response */
63
64 for (;;) {
Fabian Vogtbcf941f2019-07-16 13:09:47 +020065 val = readl(&regs->mail0_status);
Stephen Warren91ea2882013-01-29 16:37:36 +000066 if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
67 break;
68 if (get_timer(0) >= endtime) {
69 printf("mbox: Timeout waiting for response\n");
70 return -1;
71 }
72 }
73
74 /* Read the response */
75
76 val = readl(&regs->read);
77 debug("mbox: RX raw: 0x%08x\n", val);
78
79 /* Validate the response */
80
81 if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
82 printf("mbox: Response channel mismatch\n");
83 return -1;
84 }
85
86 *recv = BCM2835_MBOX_UNPACK_DATA(val);
87
88 return 0;
89}
90
91#ifdef DEBUG
92void dump_buf(struct bcm2835_mbox_hdr *buffer)
93{
94 u32 *p;
95 u32 words;
96 int i;
97
98 p = (u32 *)buffer;
99 words = buffer->buf_size / 4;
100 for (i = 0; i < words; i++)
101 printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
102}
103#endif
104
105int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
106{
107 int ret;
108 u32 rbuffer;
109 struct bcm2835_mbox_tag_hdr *tag;
110 int tag_index;
111
112#ifdef DEBUG
113 printf("mbox: TX buffer\n");
114 dump_buf(buffer);
115#endif
116
Alexander Steinfbeb89d2015-07-24 09:22:13 +0200117 flush_dcache_range((unsigned long)buffer,
118 (unsigned long)((void *)buffer +
119 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
120
Stephen Warrenfc0f7bc2016-03-16 21:40:57 -0600121 ret = bcm2835_mbox_call_raw(chan,
122 phys_to_bus((unsigned long)buffer),
123 &rbuffer);
Stephen Warren91ea2882013-01-29 16:37:36 +0000124 if (ret)
125 return ret;
Alexander Steinfbeb89d2015-07-24 09:22:13 +0200126
127 invalidate_dcache_range((unsigned long)buffer,
128 (unsigned long)((void *)buffer +
129 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
130
Stephen Warrenfc0f7bc2016-03-16 21:40:57 -0600131 if (rbuffer != phys_to_bus((unsigned long)buffer)) {
Stephen Warren91ea2882013-01-29 16:37:36 +0000132 printf("mbox: Response buffer mismatch\n");
133 return -1;
134 }
135
136#ifdef DEBUG
137 printf("mbox: RX buffer\n");
138 dump_buf(buffer);
139#endif
140
141 /* Validate overall response status */
142
143 if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
144 printf("mbox: Header response code invalid\n");
145 return -1;
146 }
147
148 /* Validate each tag's response status */
149
150 tag = (void *)(buffer + 1);
151 tag_index = 0;
152 while (tag->tag) {
153 if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
154 printf("mbox: Tag %d missing val_len response bit\n",
155 tag_index);
156 return -1;
157 }
158 /*
159 * Clear the reponse bit so clients can just look right at the
160 * length field without extra processing
161 */
162 tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
163 tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
164 tag_index++;
165 }
166
167 return 0;
168}