blob: da0b4feacbcf0bb7d90d76cf9b739b46fe55aaed [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>
Simon Glass90526e92020-05-10 11:39:56 -06008#include <asm/cache.h>
Stephen Warren88077282013-01-29 16:37:36 +00009#include <asm/io.h>
Matthias Brugger8e3361c2019-11-19 16:01:03 +010010#include <asm/arch/base.h>
Stephen Warren88077282013-01-29 16:37:36 +000011#include <asm/arch/mbox.h>
Stephen Warren122426d2015-04-06 20:28:39 -060012#include <phys2bus.h>
Stephen Warren88077282013-01-29 16:37:36 +000013
Stephen Warren004c1052014-01-13 19:50:12 -070014#define TIMEOUT 1000 /* ms */
Stephen Warren88077282013-01-29 16:37:36 +000015
16int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
17{
18 struct bcm2835_mbox_regs *regs =
19 (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
20 ulong endtime = get_timer(0) + TIMEOUT;
21 u32 val;
22
23 debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
24
25 if (send & BCM2835_CHAN_MASK) {
26 printf("mbox: Illegal mbox data 0x%08x\n", send);
27 return -1;
28 }
29
30 /* Drain any stale responses */
31
32 for (;;) {
Fabian Vogt49822442019-07-16 13:09:47 +020033 val = readl(&regs->mail0_status);
Stephen Warren88077282013-01-29 16:37:36 +000034 if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
35 break;
36 if (get_timer(0) >= endtime) {
37 printf("mbox: Timeout draining stale responses\n");
38 return -1;
39 }
40 val = readl(&regs->read);
41 }
42
43 /* Wait for space to send */
44
45 for (;;) {
Fabian Vogt49822442019-07-16 13:09:47 +020046 val = readl(&regs->mail1_status);
Stephen Warren88077282013-01-29 16:37:36 +000047 if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
48 break;
49 if (get_timer(0) >= endtime) {
50 printf("mbox: Timeout waiting for send space\n");
51 return -1;
52 }
53 }
54
55 /* Send the request */
56
57 val = BCM2835_MBOX_PACK(chan, send);
58 debug("mbox: TX raw: 0x%08x\n", val);
59 writel(val, &regs->write);
60
61 /* Wait for the response */
62
63 for (;;) {
Fabian Vogt49822442019-07-16 13:09:47 +020064 val = readl(&regs->mail0_status);
Stephen Warren88077282013-01-29 16:37:36 +000065 if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
66 break;
67 if (get_timer(0) >= endtime) {
68 printf("mbox: Timeout waiting for response\n");
69 return -1;
70 }
71 }
72
73 /* Read the response */
74
75 val = readl(&regs->read);
76 debug("mbox: RX raw: 0x%08x\n", val);
77
78 /* Validate the response */
79
80 if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
81 printf("mbox: Response channel mismatch\n");
82 return -1;
83 }
84
85 *recv = BCM2835_MBOX_UNPACK_DATA(val);
86
87 return 0;
88}
89
90#ifdef DEBUG
91void dump_buf(struct bcm2835_mbox_hdr *buffer)
92{
93 u32 *p;
94 u32 words;
95 int i;
96
97 p = (u32 *)buffer;
98 words = buffer->buf_size / 4;
99 for (i = 0; i < words; i++)
100 printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
101}
102#endif
103
104int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
105{
106 int ret;
107 u32 rbuffer;
108 struct bcm2835_mbox_tag_hdr *tag;
109 int tag_index;
110
111#ifdef DEBUG
112 printf("mbox: TX buffer\n");
113 dump_buf(buffer);
114#endif
115
Alexander Stein43425572015-07-24 09:22:13 +0200116 flush_dcache_range((unsigned long)buffer,
117 (unsigned long)((void *)buffer +
118 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
119
Stephen Warren2b513152016-03-16 21:40:57 -0600120 ret = bcm2835_mbox_call_raw(chan,
121 phys_to_bus((unsigned long)buffer),
122 &rbuffer);
Stephen Warren88077282013-01-29 16:37:36 +0000123 if (ret)
124 return ret;
Alexander Stein43425572015-07-24 09:22:13 +0200125
126 invalidate_dcache_range((unsigned long)buffer,
127 (unsigned long)((void *)buffer +
128 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
129
Stephen Warren2b513152016-03-16 21:40:57 -0600130 if (rbuffer != phys_to_bus((unsigned long)buffer)) {
Stephen Warren88077282013-01-29 16:37:36 +0000131 printf("mbox: Response buffer mismatch\n");
132 return -1;
133 }
134
135#ifdef DEBUG
136 printf("mbox: RX buffer\n");
137 dump_buf(buffer);
138#endif
139
140 /* Validate overall response status */
141
142 if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
143 printf("mbox: Header response code invalid\n");
144 return -1;
145 }
146
147 /* Validate each tag's response status */
148
149 tag = (void *)(buffer + 1);
150 tag_index = 0;
151 while (tag->tag) {
152 if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
153 printf("mbox: Tag %d missing val_len response bit\n",
154 tag_index);
155 return -1;
156 }
157 /*
158 * Clear the reponse bit so clients can just look right at the
159 * length field without extra processing
160 */
161 tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
162 tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
163 tag_index++;
164 }
165
166 return 0;
167}