1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  BCM1250 (BCM1250 as PCI device) driver	   File: dev_bcm1250.c
5    *
6    *********************************************************************
7    *
8    *  Copyright 2000,2001,2002,2003
9    *  Broadcom Corporation. All rights reserved.
10    *
11    *  This software is furnished under license and may be used and
12    *  copied only in accordance with the following terms and
13    *  conditions.  Subject to these conditions, you may download,
14    *  copy, install, use, modify and distribute modified or unmodified
15    *  copies of this software in source and/or binary form.  No title
16    *  or ownership is transferred hereby.
17    *
18    *  1) Any source code used, modified or distributed must reproduce
19    *     and retain this copyright notice and list of conditions
20    *     as they appear in the source file.
21    *
22    *  2) No right is granted to use any trade name, trademark, or
23    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
24    *     name may not be used to endorse or promote products derived
25    *     from this software without the prior written permission of
26    *     Broadcom Corporation.
27    *
28    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
29    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
30    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
31    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
32    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
33    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
34    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
36    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
37    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
38    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
39    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
40    *     THE POSSIBILITY OF SUCH DAMAGE.
41    ********************************************************************* */
42
43
44
45#include "cfe.h"
46#include "lib_physio.h"
47
48#include "pcivar.h"
49#include "pcireg.h"
50
51/* Note that PTR_TO_PHYS only works with 32-bit addresses */
52#define PTR_TO_PHYS(x) (PHYSADDR((uint32_t)(uintptr_t)(x)))
53
54
55static void bcm1250_probe(cfe_driver_t *drv,
56			  unsigned long probe_a, unsigned long probe_b,
57			  void *probe_ptr);
58
59static int bcm1250_open(cfe_devctx_t *ctx);
60static int bcm1250_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
61static int bcm1250_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
62static int bcm1250_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
63static int bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
64static int bcm1250_close(cfe_devctx_t *ctx);
65
66const static cfe_devdisp_t bcm1250_dispatch = {
67    bcm1250_open,
68    bcm1250_read,
69    bcm1250_inpstat,
70    bcm1250_write,
71    bcm1250_ioctl,
72    bcm1250_close,
73    NULL,
74    NULL
75};
76
77const cfe_driver_t bcm1250drv = {
78    "BCM1250",
79    "widget",
80    CFE_DEV_OTHER,
81    &bcm1250_dispatch,
82    bcm1250_probe
83};
84
85
86typedef struct bcm1250_s {
87    physaddr_t mailbox;
88    physaddr_t mem_base;
89    uint8_t    irq;              /* interrupt mapping */
90    pcitag_t   tag;              /* tag for  configuration register */
91
92    int        downloaded;       /* code has already been downloaded. */
93} bcm1250_t;
94
95
96/*
97 * BCM1250_PROBE
98 *   probe_a, probe_b and probe_ptr all unused
99 */
100
101static void
102bcm1250_probe(cfe_driver_t *drv,
103	      unsigned long probe_a, unsigned long probe_b,
104	      void *probe_ptr)
105{
106    int  index;
107
108    index = 0;
109    for (;;) {
110	pcitag_t tag;
111
112	if (pci_find_device(0x166d, 0x0001, index, &tag) != 0)
113	   break;
114
115	if (tag != 0x00000000) {   /* don't configure ourselves */
116	    bcm1250_t *softc;
117	    char descr[80];
118	    phys_addr_t pa;
119
120	    softc = (bcm1250_t *) KMALLOC(sizeof(bcm1250_t), 0);
121	    if (softc == NULL) {
122	        xprintf("BCM1250: No memory to complete probe\n");
123		break;
124	    }
125
126	    softc->tag = tag;
127
128	    pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BYTES, &pa);
129	    xsprintf(descr, "%s at 0x%X", drv->drv_description, (uint32_t)pa);
130	    softc->mem_base = pa;
131
132	    /* Map the CPU0 mailbox registers of the device 1250.
133               Note that our BAR2 space maps to its "alias" mailbox
134               registers.  Set bit 3 for mbox_set; clear bit 3 for
135               reading.  Address bits 15-4 are don't cares. */
136	    pci_map_mem(tag, PCI_MAPREG(2), PCI_MATCH_BYTES, &pa);
137	    softc->mailbox = pa;
138
139	    softc->downloaded = 0;
140
141	    cfe_attach(drv, softc, NULL, descr);
142	}
143	index++;
144    }
145}
146
147
148#include "elf.h"
149
150static int
151elf_header (const uint8_t *hdr)
152{
153    return (hdr[EI_MAG0] == ELFMAG0 &&
154	    hdr[EI_MAG1] == ELFMAG1 &&
155	    hdr[EI_MAG2] == ELFMAG2 &&
156	    hdr[EI_MAG3] == ELFMAG3);
157}
158
159
160#include "cfe_timer.h"
161
162typedef struct {
163    uint32_t addr;          /* source address, in device's PCI space */
164    uint32_t len;           /* length of this chunk */
165} chunk_desc;
166
167
168#define MBOX_SET_BIT  0x8
169
170extern void download_start(void), download_end(void);
171
172static int
173bcm1250_open(cfe_devctx_t *ctx)
174{
175    bcm1250_t *softc = ctx->dev_softc;
176    physaddr_t cmd_p = softc->mailbox + 4;
177
178    if (softc->downloaded) {
179	xprintf("bcm1250_open: Warning: Device previously downloaded\n");
180	softc->downloaded = 0;
181	}
182
183    if (phys_read32(cmd_p) != 0) {
184	xprintf("bcm1250_open: Device not in initial state\n");
185	return -1;
186	}
187
188    return 0;
189}
190
191static int
192bcm1250_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
193{
194    return -1;
195}
196
197static int
198bcm1250_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
199{
200    return -1;
201}
202
203static int
204bcm1250_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
205{
206    bcm1250_t *softc = ctx->dev_softc;
207    physaddr_t arg_p = softc->mailbox + 0;
208    physaddr_t cmd_p = softc->mailbox + 4;
209    chunk_desc code;
210    uint32_t cmd;
211    int64_t timer;
212    int res;
213
214    /* Note: This code assumes that PTR_TO_PHYS gives a PCI memory space
215       address that is accessible via our BAR4 or BAR5 */
216
217    /* XXX: This driver will not work with a 64-bit pointer */
218
219    code.addr = PTR_TO_PHYS(HSADDR2PTR(buffer->buf_ptr));
220    code.len  = buffer->buf_length;
221
222    cmd = 0x1;      /* load */
223    if (!elf_header((uint8_t *) HSADDR2PTR(buffer->buf_ptr))) {
224	/* No recognizable elf seal, so assume compressed. */
225	cmd |= 0x2;
226	}
227
228    phys_write32(arg_p | MBOX_SET_BIT, PTR_TO_PHYS(&code));
229    phys_write32(cmd_p | MBOX_SET_BIT, cmd);     /* load */
230
231    /* Wait for handshake */
232
233    res = CFE_ERR_TIMEOUT;
234    TIMER_SET(timer, 5*CFE_HZ);
235    while (!TIMER_EXPIRED(timer)) {
236        if ((phys_read32(cmd_p) & 0x3) == 0) {
237	    softc->downloaded = 1;
238	    buffer->buf_retlen = 0;    /* XXX check this */
239	    /* Note that the result code need not be translated only
240               because we are assuming a CFE in the device that is
241               compatible with us. */
242	    res = (int)phys_read32(arg_p);
243	    break;
244	    }
245	POLL();
246	}
247
248    return res;
249}
250
251static int
252bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
253{
254    return -1;
255}
256
257static int
258bcm1250_close(cfe_devctx_t *ctx)
259{
260    return 0;
261}
262