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