1ddf6bd48SMasahiro Yamada /*
2ddf6bd48SMasahiro Yamada * (C) Copyright 2012 Stephen Warren
3ddf6bd48SMasahiro Yamada *
4ddf6bd48SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+
5ddf6bd48SMasahiro Yamada */
6ddf6bd48SMasahiro Yamada
7ddf6bd48SMasahiro Yamada #include <common.h>
8ddf6bd48SMasahiro Yamada #include <asm/io.h>
9ddf6bd48SMasahiro Yamada #include <asm/arch/mbox.h>
10122426d4SStephen Warren #include <phys2bus.h>
11ddf6bd48SMasahiro Yamada
12ddf6bd48SMasahiro Yamada #define TIMEOUT 1000 /* ms */
13ddf6bd48SMasahiro Yamada
bcm2835_mbox_call_raw(u32 chan,u32 send,u32 * recv)14ddf6bd48SMasahiro Yamada int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
15ddf6bd48SMasahiro Yamada {
16ddf6bd48SMasahiro Yamada struct bcm2835_mbox_regs *regs =
17ddf6bd48SMasahiro Yamada (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
18ddf6bd48SMasahiro Yamada ulong endtime = get_timer(0) + TIMEOUT;
19ddf6bd48SMasahiro Yamada u32 val;
20ddf6bd48SMasahiro Yamada
21ddf6bd48SMasahiro Yamada debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
22ddf6bd48SMasahiro Yamada
23ddf6bd48SMasahiro Yamada if (send & BCM2835_CHAN_MASK) {
24ddf6bd48SMasahiro Yamada printf("mbox: Illegal mbox data 0x%08x\n", send);
25ddf6bd48SMasahiro Yamada return -1;
26ddf6bd48SMasahiro Yamada }
27ddf6bd48SMasahiro Yamada
28ddf6bd48SMasahiro Yamada /* Drain any stale responses */
29ddf6bd48SMasahiro Yamada
30ddf6bd48SMasahiro Yamada for (;;) {
31ddf6bd48SMasahiro Yamada val = readl(®s->status);
32ddf6bd48SMasahiro Yamada if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
33ddf6bd48SMasahiro Yamada break;
34ddf6bd48SMasahiro Yamada if (get_timer(0) >= endtime) {
35ddf6bd48SMasahiro Yamada printf("mbox: Timeout draining stale responses\n");
36ddf6bd48SMasahiro Yamada return -1;
37ddf6bd48SMasahiro Yamada }
38ddf6bd48SMasahiro Yamada val = readl(®s->read);
39ddf6bd48SMasahiro Yamada }
40ddf6bd48SMasahiro Yamada
41ddf6bd48SMasahiro Yamada /* Wait for space to send */
42ddf6bd48SMasahiro Yamada
43ddf6bd48SMasahiro Yamada for (;;) {
44ddf6bd48SMasahiro Yamada val = readl(®s->status);
45ddf6bd48SMasahiro Yamada if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
46ddf6bd48SMasahiro Yamada break;
47ddf6bd48SMasahiro Yamada if (get_timer(0) >= endtime) {
48ddf6bd48SMasahiro Yamada printf("mbox: Timeout waiting for send space\n");
49ddf6bd48SMasahiro Yamada return -1;
50ddf6bd48SMasahiro Yamada }
51ddf6bd48SMasahiro Yamada }
52ddf6bd48SMasahiro Yamada
53ddf6bd48SMasahiro Yamada /* Send the request */
54ddf6bd48SMasahiro Yamada
55ddf6bd48SMasahiro Yamada val = BCM2835_MBOX_PACK(chan, send);
56ddf6bd48SMasahiro Yamada debug("mbox: TX raw: 0x%08x\n", val);
57ddf6bd48SMasahiro Yamada writel(val, ®s->write);
58ddf6bd48SMasahiro Yamada
59ddf6bd48SMasahiro Yamada /* Wait for the response */
60ddf6bd48SMasahiro Yamada
61ddf6bd48SMasahiro Yamada for (;;) {
62ddf6bd48SMasahiro Yamada val = readl(®s->status);
63ddf6bd48SMasahiro Yamada if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
64ddf6bd48SMasahiro Yamada break;
65ddf6bd48SMasahiro Yamada if (get_timer(0) >= endtime) {
66ddf6bd48SMasahiro Yamada printf("mbox: Timeout waiting for response\n");
67ddf6bd48SMasahiro Yamada return -1;
68ddf6bd48SMasahiro Yamada }
69ddf6bd48SMasahiro Yamada }
70ddf6bd48SMasahiro Yamada
71ddf6bd48SMasahiro Yamada /* Read the response */
72ddf6bd48SMasahiro Yamada
73ddf6bd48SMasahiro Yamada val = readl(®s->read);
74ddf6bd48SMasahiro Yamada debug("mbox: RX raw: 0x%08x\n", val);
75ddf6bd48SMasahiro Yamada
76ddf6bd48SMasahiro Yamada /* Validate the response */
77ddf6bd48SMasahiro Yamada
78ddf6bd48SMasahiro Yamada if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
79ddf6bd48SMasahiro Yamada printf("mbox: Response channel mismatch\n");
80ddf6bd48SMasahiro Yamada return -1;
81ddf6bd48SMasahiro Yamada }
82ddf6bd48SMasahiro Yamada
83ddf6bd48SMasahiro Yamada *recv = BCM2835_MBOX_UNPACK_DATA(val);
84ddf6bd48SMasahiro Yamada
85ddf6bd48SMasahiro Yamada return 0;
86ddf6bd48SMasahiro Yamada }
87ddf6bd48SMasahiro Yamada
88ddf6bd48SMasahiro Yamada #ifdef DEBUG
dump_buf(struct bcm2835_mbox_hdr * buffer)89ddf6bd48SMasahiro Yamada void dump_buf(struct bcm2835_mbox_hdr *buffer)
90ddf6bd48SMasahiro Yamada {
91ddf6bd48SMasahiro Yamada u32 *p;
92ddf6bd48SMasahiro Yamada u32 words;
93ddf6bd48SMasahiro Yamada int i;
94ddf6bd48SMasahiro Yamada
95ddf6bd48SMasahiro Yamada p = (u32 *)buffer;
96ddf6bd48SMasahiro Yamada words = buffer->buf_size / 4;
97ddf6bd48SMasahiro Yamada for (i = 0; i < words; i++)
98ddf6bd48SMasahiro Yamada printf(" 0x%04x: 0x%08x\n", i * 4, p[i]);
99ddf6bd48SMasahiro Yamada }
100ddf6bd48SMasahiro Yamada #endif
101ddf6bd48SMasahiro Yamada
bcm2835_mbox_call_prop(u32 chan,struct bcm2835_mbox_hdr * buffer)102ddf6bd48SMasahiro Yamada int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
103ddf6bd48SMasahiro Yamada {
104ddf6bd48SMasahiro Yamada int ret;
105ddf6bd48SMasahiro Yamada u32 rbuffer;
106ddf6bd48SMasahiro Yamada struct bcm2835_mbox_tag_hdr *tag;
107ddf6bd48SMasahiro Yamada int tag_index;
108ddf6bd48SMasahiro Yamada
109ddf6bd48SMasahiro Yamada #ifdef DEBUG
110ddf6bd48SMasahiro Yamada printf("mbox: TX buffer\n");
111ddf6bd48SMasahiro Yamada dump_buf(buffer);
112ddf6bd48SMasahiro Yamada #endif
113ddf6bd48SMasahiro Yamada
1144342557fSAlexander Stein flush_dcache_range((unsigned long)buffer,
1154342557fSAlexander Stein (unsigned long)((void *)buffer +
1164342557fSAlexander Stein roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
1174342557fSAlexander Stein
118*2b513158SStephen Warren ret = bcm2835_mbox_call_raw(chan,
119*2b513158SStephen Warren phys_to_bus((unsigned long)buffer),
120*2b513158SStephen Warren &rbuffer);
121ddf6bd48SMasahiro Yamada if (ret)
122ddf6bd48SMasahiro Yamada return ret;
1234342557fSAlexander Stein
1244342557fSAlexander Stein invalidate_dcache_range((unsigned long)buffer,
1254342557fSAlexander Stein (unsigned long)((void *)buffer +
1264342557fSAlexander Stein roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
1274342557fSAlexander Stein
128*2b513158SStephen Warren if (rbuffer != phys_to_bus((unsigned long)buffer)) {
129ddf6bd48SMasahiro Yamada printf("mbox: Response buffer mismatch\n");
130ddf6bd48SMasahiro Yamada return -1;
131ddf6bd48SMasahiro Yamada }
132ddf6bd48SMasahiro Yamada
133ddf6bd48SMasahiro Yamada #ifdef DEBUG
134ddf6bd48SMasahiro Yamada printf("mbox: RX buffer\n");
135ddf6bd48SMasahiro Yamada dump_buf(buffer);
136ddf6bd48SMasahiro Yamada #endif
137ddf6bd48SMasahiro Yamada
138ddf6bd48SMasahiro Yamada /* Validate overall response status */
139ddf6bd48SMasahiro Yamada
140ddf6bd48SMasahiro Yamada if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
141ddf6bd48SMasahiro Yamada printf("mbox: Header response code invalid\n");
142ddf6bd48SMasahiro Yamada return -1;
143ddf6bd48SMasahiro Yamada }
144ddf6bd48SMasahiro Yamada
145ddf6bd48SMasahiro Yamada /* Validate each tag's response status */
146ddf6bd48SMasahiro Yamada
147ddf6bd48SMasahiro Yamada tag = (void *)(buffer + 1);
148ddf6bd48SMasahiro Yamada tag_index = 0;
149ddf6bd48SMasahiro Yamada while (tag->tag) {
150ddf6bd48SMasahiro Yamada if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
151ddf6bd48SMasahiro Yamada printf("mbox: Tag %d missing val_len response bit\n",
152ddf6bd48SMasahiro Yamada tag_index);
153ddf6bd48SMasahiro Yamada return -1;
154ddf6bd48SMasahiro Yamada }
155ddf6bd48SMasahiro Yamada /*
156ddf6bd48SMasahiro Yamada * Clear the reponse bit so clients can just look right at the
157ddf6bd48SMasahiro Yamada * length field without extra processing
158ddf6bd48SMasahiro Yamada */
159ddf6bd48SMasahiro Yamada tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
160ddf6bd48SMasahiro Yamada tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
161ddf6bd48SMasahiro Yamada tag_index++;
162ddf6bd48SMasahiro Yamada }
163ddf6bd48SMasahiro Yamada
164ddf6bd48SMasahiro Yamada return 0;
165ddf6bd48SMasahiro Yamada }
166