123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- /*
- * (C) Copyright 2012 Stephen Warren
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <common.h>
- #include <asm/io.h>
- #include <asm/arch/mbox.h>
- #define TIMEOUT (100 * 1000) /* 100mS in uS */
- 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, (u32)buffer, &rbuffer);
- if (ret)
- return ret;
- if (rbuffer != (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;
- }
|