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