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