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