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