Merge tag 'efi-2020-07-rc6' of https://gitlab.denx.de/u-boot/custodians/u-boot-efi
[oweals/u-boot.git] / arch / arm / mach-bcm283x / mbox.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2012 Stephen Warren
4  */
5
6 #include <common.h>
7 #include <cpu_func.h>
8 #include <log.h>
9 #include <asm/cache.h>
10 #include <asm/io.h>
11 #include <asm/arch/base.h>
12 #include <asm/arch/mbox.h>
13 #include <phys2bus.h>
14
15 #define TIMEOUT 1000 /* ms */
16
17 int 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 (;;) {
34                 val = readl(&regs->mail0_status);
35                 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 (;;) {
47                 val = readl(&regs->mail1_status);
48                 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 (;;) {
65                 val = readl(&regs->mail0_status);
66                 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
92 void 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
105 int 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
117         flush_dcache_range((unsigned long)buffer,
118                            (unsigned long)((void *)buffer +
119                            roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
120
121         ret = bcm2835_mbox_call_raw(chan,
122                                     phys_to_bus((unsigned long)buffer),
123                                     &rbuffer);
124         if (ret)
125                 return ret;
126
127         invalidate_dcache_range((unsigned long)buffer,
128                                 (unsigned long)((void *)buffer +
129                                 roundup(buffer->buf_size, ARCH_DMA_MINALIGN)));
130
131         if (rbuffer != phys_to_bus((unsigned long)buffer)) {
132                 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 }