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