summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/dev/dev_bcm1250.c
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/dev/dev_bcm1250.c')
-rw-r--r--cfe/cfe/dev/dev_bcm1250.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/cfe/cfe/dev/dev_bcm1250.c b/cfe/cfe/dev/dev_bcm1250.c
new file mode 100644
index 0000000..8343a46
--- /dev/null
+++ b/cfe/cfe/dev/dev_bcm1250.c
@@ -0,0 +1,275 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * BCM1250 (BCM1250 as PCI device) driver File: dev_bcm1250.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "sbmips.h"
+
+#ifndef _SB_MAKE64
+#define _SB_MAKE64(x) ((uint64_t)(x))
+#endif
+#ifndef _SB_MAKEMASK1
+#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n))
+#endif
+
+#include "lib_types.h"
+#include "lib_hssubr.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_iocb.h"
+#include "cfe_error.h"
+#include "cfe_device.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+#include "bsp_config.h"
+
+/* Note that PHYSADDR only works with 32-bit addresses */
+#define PHYSADDR(x) (K0_TO_PHYS((uint32_t)(uintptr_t)(x)))
+
+
+static void bcm1250_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+static int bcm1250_open(cfe_devctx_t *ctx);
+static int bcm1250_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm1250_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int bcm1250_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm1250_close(cfe_devctx_t *ctx);
+
+const static cfe_devdisp_t bcm1250_dispatch = {
+ bcm1250_open,
+ bcm1250_read,
+ bcm1250_inpstat,
+ bcm1250_write,
+ bcm1250_ioctl,
+ bcm1250_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t bcm1250drv = {
+ "BCM1250",
+ "widget",
+ CFE_DEV_OTHER,
+ &bcm1250_dispatch,
+ bcm1250_probe
+};
+
+
+typedef struct bcm1250_s {
+ uint64_t mailbox;
+ uint64_t mem_base;
+ uint8_t irq; /* interrupt mapping */
+ pcitag_t tag; /* tag for configuration register */
+
+ int downloaded; /* code has already been downloaded. */
+} bcm1250_t;
+
+
+/*
+ * BCM1250_PROBE
+ * probe_a, probe_b and probe_ptr all unused
+ */
+
+static void
+bcm1250_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ int index;
+
+ index = 0;
+ for (;;) {
+ pcitag_t tag;
+
+ if (pci_find_device(0x166d, 0x0001, index, &tag) != 0)
+ break;
+
+ if (tag != 0x00000000) { /* don't configure ourselves */
+ bcm1250_t *softc;
+ char descr[80];
+ phys_addr_t pa;
+
+ softc = (bcm1250_t *) KMALLOC(sizeof(bcm1250_t), 0);
+ if (softc == NULL) {
+ xprintf("BCM1250: No memory to complete probe\n");
+ break;
+ }
+
+ softc->tag = tag;
+
+ pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BYTES, &pa);
+ xsprintf(descr, "%s at 0x%X", drv->drv_description, (uint32_t)pa);
+ softc->mem_base = PHYS_TO_XKSEG_UNCACHED(pa);
+
+ /* Map the CPU0 mailbox registers of the device 1250.
+ Note that our BAR2 space maps to its "alias" mailbox
+ registers. Set bit 3 for mbox_set; clear bit 3 for
+ reading. Address bits 15-4 are don't cares. */
+ pci_map_mem(tag, PCI_MAPREG(2), PCI_MATCH_BYTES, &pa);
+ softc->mailbox = PHYS_TO_XKSEG_UNCACHED(pa);
+
+ softc->downloaded = 0;
+
+ cfe_attach(drv, softc, NULL, descr);
+ }
+ index++;
+ }
+}
+
+
+#include "elf.h"
+
+static int
+elf_header (const uint8_t *hdr)
+{
+ return (hdr[EI_MAG0] == ELFMAG0 &&
+ hdr[EI_MAG1] == ELFMAG1 &&
+ hdr[EI_MAG2] == ELFMAG2 &&
+ hdr[EI_MAG3] == ELFMAG3);
+}
+
+
+#include "cfe_timer.h"
+
+typedef struct {
+ uint32_t addr; /* source address, in device's PCI space */
+ uint32_t len; /* length of this chunk */
+} chunk_desc;
+
+
+#define MBOX_SET_BIT 0x8
+
+extern void download_start(void), download_end(void);
+
+static int
+bcm1250_open(cfe_devctx_t *ctx)
+{
+ bcm1250_t *softc = ctx->dev_softc;
+ uint64_t cmd_p = softc->mailbox + 4;
+
+ if (softc->downloaded) {
+ xprintf("bcm1250_open: Warning: Device previously downloaded\n");
+ softc->downloaded = 0;
+ }
+
+ if (hs_read32(cmd_p) != 0) {
+ xprintf("bcm1250_open: Device not in initial state\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+bcm1250_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+static int
+bcm1250_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ return -1;
+}
+
+static int
+bcm1250_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ bcm1250_t *softc = ctx->dev_softc;
+ uint64_t arg_p = softc->mailbox + 0;
+ uint64_t cmd_p = softc->mailbox + 4;
+ chunk_desc code;
+ uint32_t cmd;
+ int64_t timer;
+ int res;
+
+ /* Note: This code assumes that PHYSADDR gives a PCI memory space
+ address that is accessible via our BAR4 or BAR5 */
+
+ code.addr = PHYSADDR((uint8_t *)buffer->buf_ptr);
+ code.len = buffer->buf_length;
+
+ cmd = 0x1; /* load */
+ if (!elf_header((uint8_t *)buffer->buf_ptr)) {
+ /* No recognizable elf seal, so assume compressed. */
+ cmd |= 0x2;
+ }
+
+ hs_write32(arg_p | MBOX_SET_BIT, PHYSADDR(&code));
+ hs_write32(cmd_p | MBOX_SET_BIT, cmd); /* load */
+
+ /* Wait for handshake */
+
+ res = CFE_ERR_TIMEOUT;
+ TIMER_SET(timer, 5*CFE_HZ);
+ while (!TIMER_EXPIRED(timer)) {
+ if ((hs_read32(cmd_p) & 0x3) == 0) {
+ softc->downloaded = 1;
+ buffer->buf_retlen = 0; /* XXX check this */
+ /* Note that the result code need not be translated only
+ because we are assuming a CFE in the device that is
+ compatible with us. */
+ res = (int)hs_read32(arg_p);
+ break;
+ }
+ POLL();
+ }
+
+ return res;
+}
+
+static int
+bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+static int
+bcm1250_close(cfe_devctx_t *ctx)
+{
+ return 0;
+}