155 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * (C) Copyright 2012 Stephen Warren
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier:	GPL-2.0+
 | 
						|
 */
 | 
						|
 | 
						|
#include <common.h>
 | 
						|
#include <asm/io.h>
 | 
						|
#include <asm/arch/mbox.h>
 | 
						|
#include <phys2bus.h>
 | 
						|
 | 
						|
#define TIMEOUT 1000 /* ms */
 | 
						|
 | 
						|
int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv)
 | 
						|
{
 | 
						|
	struct bcm2835_mbox_regs *regs =
 | 
						|
		(struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR;
 | 
						|
	ulong endtime = get_timer(0) + TIMEOUT;
 | 
						|
	u32 val;
 | 
						|
 | 
						|
	debug("time: %lu timeout: %lu\n", get_timer(0), endtime);
 | 
						|
 | 
						|
	if (send & BCM2835_CHAN_MASK) {
 | 
						|
		printf("mbox: Illegal mbox data 0x%08x\n", send);
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Drain any stale responses */
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		val = readl(®s->status);
 | 
						|
		if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
 | 
						|
			break;
 | 
						|
		if (get_timer(0) >= endtime) {
 | 
						|
			printf("mbox: Timeout draining stale responses\n");
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
		val = readl(®s->read);
 | 
						|
	}
 | 
						|
 | 
						|
	/* Wait for space to send */
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		val = readl(®s->status);
 | 
						|
		if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
 | 
						|
			break;
 | 
						|
		if (get_timer(0) >= endtime) {
 | 
						|
			printf("mbox: Timeout waiting for send space\n");
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Send the request */
 | 
						|
 | 
						|
	val = BCM2835_MBOX_PACK(chan, send);
 | 
						|
	debug("mbox: TX raw: 0x%08x\n", val);
 | 
						|
	writel(val, ®s->write);
 | 
						|
 | 
						|
	/* Wait for the response */
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		val = readl(®s->status);
 | 
						|
		if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
 | 
						|
			break;
 | 
						|
		if (get_timer(0) >= endtime) {
 | 
						|
			printf("mbox: Timeout waiting for response\n");
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Read the response */
 | 
						|
 | 
						|
	val = readl(®s->read);
 | 
						|
	debug("mbox: RX raw: 0x%08x\n", val);
 | 
						|
 | 
						|
	/* Validate the response */
 | 
						|
 | 
						|
	if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) {
 | 
						|
		printf("mbox: Response channel mismatch\n");
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	*recv = BCM2835_MBOX_UNPACK_DATA(val);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
void dump_buf(struct bcm2835_mbox_hdr *buffer)
 | 
						|
{
 | 
						|
	u32 *p;
 | 
						|
	u32 words;
 | 
						|
	int i;
 | 
						|
 | 
						|
	p = (u32 *)buffer;
 | 
						|
	words = buffer->buf_size / 4;
 | 
						|
	for (i = 0; i < words; i++)
 | 
						|
		printf("    0x%04x: 0x%08x\n", i * 4, p[i]);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
	u32 rbuffer;
 | 
						|
	struct bcm2835_mbox_tag_hdr *tag;
 | 
						|
	int tag_index;
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
	printf("mbox: TX buffer\n");
 | 
						|
	dump_buf(buffer);
 | 
						|
#endif
 | 
						|
 | 
						|
	ret = bcm2835_mbox_call_raw(chan, phys_to_bus((u32)buffer), &rbuffer);
 | 
						|
	if (ret)
 | 
						|
		return ret;
 | 
						|
	if (rbuffer != phys_to_bus((u32)buffer)) {
 | 
						|
		printf("mbox: Response buffer mismatch\n");
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
	printf("mbox: RX buffer\n");
 | 
						|
	dump_buf(buffer);
 | 
						|
#endif
 | 
						|
 | 
						|
	/* Validate overall response status */
 | 
						|
 | 
						|
	if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) {
 | 
						|
		printf("mbox: Header response code invalid\n");
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Validate each tag's response status */
 | 
						|
 | 
						|
	tag = (void *)(buffer + 1);
 | 
						|
	tag_index = 0;
 | 
						|
	while (tag->tag) {
 | 
						|
		if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) {
 | 
						|
			printf("mbox: Tag %d missing val_len response bit\n",
 | 
						|
				tag_index);
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
		/*
 | 
						|
		 * Clear the reponse bit so clients can just look right at the
 | 
						|
		 * length field without extra processing
 | 
						|
		 */
 | 
						|
		tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE;
 | 
						|
		tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size);
 | 
						|
		tag_index++;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |