Merge branch 'u-boot-imx/master' 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  * See file CREDITS for list of people who contributed to this
5  * project.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  */
17
18 #include <common.h>
19 #include <asm/io.h>
20 #include <asm/arch/mbox.h>
21
22 #define TIMEOUT (100 * 1000) /* 100mS in uS */
23
24 int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
25 {
26         struct bcm2835_mbox_regs *regs =
27                 (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
28         ulong endtime = get_timer(0) + TIMEOUT;
29         u32 val;
30
31         debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
32
33         if (send & BCM2835_CHAN_MASK) {
34                 printf("mbox: Illegal mbox data 0x%08x\n", send);
35                 return -1;
36         }
37
38         /* Drain any stale responses */
39
40         for (;;) {
41                 val = readl(&regs->status);
42                 if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
43                         break;
44                 if (get_timer(0) >= endtime) {
45                         printf("mbox: Timeout draining stale responses\n");
46                         return -1;
47                 }
48                 val = readl(&regs->read);
49         }
50
51         /* Wait for space to send */
52
53         for (;;) {
54                 val = readl(&regs->status);
55                 if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
56                         break;
57                 if (get_timer(0) >= endtime) {
58                         printf("mbox: Timeout waiting for send space\n");
59                         return -1;
60                 }
61         }
62
63         /* Send the request */
64
65         val = BCM2835_MBOX_PACK(chan, send);
66         debug("mbox: TX raw: 0x%08x\n", val);
67         writel(val, &regs->write);
68
69         /* Wait for the response */
70
71         for (;;) {
72                 val = readl(&regs->status);
73                 if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
74                         break;
75                 if (get_timer(0) >= endtime) {
76                         printf("mbox: Timeout waiting for response\n");
77                         return -1;
78                 }
79         }
80
81         /* Read the response */
82
83         val = readl(&regs->read);
84         debug("mbox: RX raw: 0x%08x\n", val);
85
86         /* Validate the response */
87
88         if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
89                 printf("mbox: Response channel mismatch\n");
90                 return -1;
91         }
92
93         *recv = BCM2835_MBOX_UNPACK_DATA(val);
94
95         return 0;
96 }
97
98 #ifdef DEBUG
99 void dump_buf(struct bcm2835_mbox_hdr *buffer)
100 {
101         u32 *p;
102         u32 words;
103         int i;
104
105         p = (u32 *)buffer;
106         words = buffer->buf_size / 4;
107         for (i = 0; i < words; i++)
108                 printf("    0x%04x: 0x%08x\n", i * 4, p[i]);
109 }
110 #endif
111
112 int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
113 {
114         int ret;
115         u32 rbuffer;
116         struct bcm2835_mbox_tag_hdr *tag;
117         int tag_index;
118
119 #ifdef DEBUG
120         printf("mbox: TX buffer\n");
121         dump_buf(buffer);
122 #endif
123
124         ret = bcm2835_mbox_call_raw(chan, (u32)buffer, &rbuffer);
125         if (ret)
126                 return ret;
127         if (rbuffer != (u32)buffer) {
128                 printf("mbox: Response buffer mismatch\n");
129                 return -1;
130         }
131
132 #ifdef DEBUG
133         printf("mbox: RX buffer\n");
134         dump_buf(buffer);
135 #endif
136
137         /* Validate overall response status */
138
139         if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
140                 printf("mbox: Header response code invalid\n");
141                 return -1;
142         }
143
144         /* Validate each tag's response status */
145
146         tag = (void *)(buffer + 1);
147         tag_index = 0;
148         while (tag->tag) {
149                 if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
150                         printf("mbox: Tag %d missing val_len response bit\n",
151                                 tag_index);
152                         return -1;
153                 }
154                 /*
155                  * Clear the reponse bit so clients can just look right at the
156                  * length field without extra processing
157                  */
158                 tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
159                 tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
160                 tag_index++;
161         }
162
163         return 0;
164 }