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