1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2012 Stephen Warren 4 */ 5 6 #include <common.h> 7 #include <asm/io.h> 8 #include <asm/arch/mbox.h> 9 #include <phys2bus.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(®s->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(®s->read); 38 } 39 40 /* Wait for space to send */ 41 42 for (;;) { 43 val = readl(®s->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, ®s->write); 57 58 /* Wait for the response */ 59 60 for (;;) { 61 val = readl(®s->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(®s->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 flush_dcache_range((unsigned long)buffer, 114 (unsigned long)((void *)buffer + 115 roundup(buffer->buf_size, ARCH_DMA_MINALIGN))); 116 117 ret = bcm2835_mbox_call_raw(chan, 118 phys_to_bus((unsigned long)buffer), 119 &rbuffer); 120 if (ret) 121 return ret; 122 123 invalidate_dcache_range((unsigned long)buffer, 124 (unsigned long)((void *)buffer + 125 roundup(buffer->buf_size, ARCH_DMA_MINALIGN))); 126 127 if (rbuffer != phys_to_bus((unsigned long)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 } 165