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#include "sbmips.h"
45
46#ifndef _SB_MAKE64
47#define _SB_MAKE64(x) ((uint64_t)(x))
48#endif
49#ifndef _SB_MAKEMASK1
50#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n))
51#endif
52
53#include "lib_types.h"
54#include "lib_physio.h"
55#include "lib_malloc.h"
56#include "lib_printf.h"
57
58#include "cfe_iocb.h"
59#include "cfe_error.h"
60#include "cfe_device.h"
61
62#include "pcivar.h"
63#include "pcireg.h"
64
65#include "bsp_config.h"
66
67/* Note that PTR_TO_PHYS only works with 32-bit addresses */
68#define PTR_TO_PHYS(x) (K0_TO_PHYS((uint32_t)(uintptr_t)(x)))
69
70
71static void bcm1250_probe(cfe_driver_t *drv,
72			  unsigned long probe_a, unsigned long probe_b,
73			  void *probe_ptr);
74
75static int bcm1250_open(cfe_devctx_t *ctx);
76static int bcm1250_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
77static int bcm1250_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
78static int bcm1250_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
79static int bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
80static int bcm1250_close(cfe_devctx_t *ctx);
81
82const static cfe_devdisp_t bcm1250_dispatch = {
83    bcm1250_open,
84    bcm1250_read,
85    bcm1250_inpstat,
86    bcm1250_write,
87    bcm1250_ioctl,
88    bcm1250_close,
89    NULL,
90    NULL
91};
92
93const cfe_driver_t bcm1250drv = {
94    "BCM1250",
95    "widget",
96    CFE_DEV_OTHER,
97    &bcm1250_dispatch,
98    bcm1250_probe
99};
100
101
102typedef struct bcm1250_s {
103    physaddr_t mailbox;
104    physaddr_t mem_base;
105    uint8_t    irq;              /* interrupt mapping */
106    pcitag_t   tag;              /* tag for  configuration register */
107
108    int        downloaded;       /* code has already been downloaded. */
109} bcm1250_t;
110
111
112/*
113 * BCM1250_PROBE
114 *   probe_a, probe_b and probe_ptr all unused
115 */
116
117static void
118bcm1250_probe(cfe_driver_t *drv,
119	      unsigned long probe_a, unsigned long probe_b,
120	      void *probe_ptr)
121{
122    int  index;
123
124    index = 0;
125    for (;;) {
126	pcitag_t tag;
127
128	if (pci_find_device(0x166d, 0x0001, index, &tag) != 0)
129	   break;
130
131	if (tag != 0x00000000) {   /* don't configure ourselves */
132	    bcm1250_t *softc;
133	    char descr[80];
134	    phys_addr_t pa;
135
136	    softc = (bcm1250_t *) KMALLOC(sizeof(bcm1250_t), 0);
137	    if (softc == NULL) {
138	        xprintf("BCM1250: No memory to complete probe\n");
139		break;
140	    }
141
142	    softc->tag = tag;
143
144	    pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BYTES, &pa);
145	    xsprintf(descr, "%s at 0x%X", drv->drv_description, (uint32_t)pa);
146	    softc->mem_base = pa;
147
148	    /* Map the CPU0 mailbox registers of the device 1250.
149               Note that our BAR2 space maps to its "alias" mailbox
150               registers.  Set bit 3 for mbox_set; clear bit 3 for
151               reading.  Address bits 15-4 are don't cares. */
152	    pci_map_mem(tag, PCI_MAPREG(2), PCI_MATCH_BYTES, &pa);
153	    softc->mailbox = pa;
154
155	    softc->downloaded = 0;
156
157	    cfe_attach(drv, softc, NULL, descr);
158	}
159	index++;
160    }
161}
162
163
164#include "elf.h"
165
166static int
167elf_header (const uint8_t *hdr)
168{
169    return (hdr[EI_MAG0] == ELFMAG0 &&
170	    hdr[EI_MAG1] == ELFMAG1 &&
171	    hdr[EI_MAG2] == ELFMAG2 &&
172	    hdr[EI_MAG3] == ELFMAG3);
173}
174
175
176#include "cfe_timer.h"
177
178typedef struct {
179    uint32_t addr;          /* source address, in device's PCI space */
180    uint32_t len;           /* length of this chunk */
181} chunk_desc;
182
183
184#define MBOX_SET_BIT  0x8
185
186extern void download_start(void), download_end(void);
187
188static int
189bcm1250_open(cfe_devctx_t *ctx)
190{
191    bcm1250_t *softc = ctx->dev_softc;
192    physaddr_t cmd_p = softc->mailbox + 4;
193
194    if (softc->downloaded) {
195	xprintf("bcm1250_open: Warning: Device previously downloaded\n");
196	softc->downloaded = 0;
197	}
198
199    if (phys_read32(cmd_p) != 0) {
200	xprintf("bcm1250_open: Device not in initial state\n");
201	return -1;
202	}
203
204    return 0;
205}
206
207static int
208bcm1250_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
209{
210    return -1;
211}
212
213static int
214bcm1250_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
215{
216    return -1;
217}
218
219static int
220bcm1250_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
221{
222    bcm1250_t *softc = ctx->dev_softc;
223    physaddr_t arg_p = softc->mailbox + 0;
224    physaddr_t cmd_p = softc->mailbox + 4;
225    chunk_desc code;
226    uint32_t cmd;
227    int64_t timer;
228    int res;
229
230    /* Note: This code assumes that PTR_TO_PHYS gives a PCI memory space
231       address that is accessible via our BAR4 or BAR5 */
232
233    code.addr = PTR_TO_PHYS((uint8_t *)buffer->buf_ptr);
234    code.len  = buffer->buf_length;
235
236    cmd = 0x1;      /* load */
237    if (!elf_header((uint8_t *)buffer->buf_ptr)) {
238	/* No recognizable elf seal, so assume compressed. */
239	cmd |= 0x2;
240	}
241
242    phys_write32(arg_p | MBOX_SET_BIT, PTR_TO_PHYS(&code));
243    phys_write32(cmd_p | MBOX_SET_BIT, cmd);     /* load */
244
245    /* Wait for handshake */
246
247    res = CFE_ERR_TIMEOUT;
248    TIMER_SET(timer, 5*CFE_HZ);
249    while (!TIMER_EXPIRED(timer)) {
250        if ((phys_read32(cmd_p) & 0x3) == 0) {
251	    softc->downloaded = 1;
252	    buffer->buf_retlen = 0;
253	    /* Note that the result code need not be translated only
254               because we are assuming a CFE in the device that is
255               compatible with us. */
256	    res = (int)phys_read32(arg_p);
257	    break;
258	    }
259	POLL();
260	}
261
262    return res;
263}
264
265static int
266bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
267{
268    return -1;
269}
270
271static int
272bcm1250_close(cfe_devctx_t *ctx)
273{
274    return 0;
275}
276