uboot/arch/arm/mach-bcm283x/mbox.c
<<
>>
Prefs
   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
  13int 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(&regs->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(&regs->read);
  38        }
  39
  40        /* Wait for space to send */
  41
  42        for (;;) {
  43                val = readl(&regs->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, &regs->write);
  57
  58        /* Wait for the response */
  59
  60        for (;;) {
  61                val = readl(&regs->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(&regs->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
  88void 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
 101int 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