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