1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  PCI IDE disk driver			File: dev_ide_pci.c
5    *
6    *  This is a simple driver for IDE hard disks that are connected
7    *  to PCI IDE controllers, such as a Promise UltraXX.
8    *
9    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
16    *  This software is furnished under license and may be used and
17    *  copied only in accordance with the following terms and
18    *  conditions.  Subject to these conditions, you may download,
19    *  copy, install, use, modify and distribute modified or unmodified
20    *  copies of this software in source and/or binary form.  No title
21    *  or ownership is transferred hereby.
22    *
23    *  1) Any source code used, modified or distributed must reproduce
24    *     and retain this copyright notice and list of conditions
25    *     as they appear in the source file.
26    *
27    *  2) No right is granted to use any trade name, trademark, or
28    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
29    *     name may not be used to endorse or promote products derived
30    *     from this software without the prior written permission of
31    *     Broadcom Corporation.
32    *
33    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45    *     THE POSSIBILITY OF SUCH DAMAGE.
46    ********************************************************************* */
47
48
49#include "lib_types.h"
50#include "lib_malloc.h"
51#include "lib_printf.h"
52#include "lib_string.h"
53#include "cfe_timer.h"
54#include "cfe_iocb.h"
55#include "cfe_device.h"
56#include "cfe_ioctl.h"
57
58#include "dev_ide_common.h"
59
60#include "dev_ide.h"
61
62#include "pcivar.h"
63#include "pcireg.h"
64
65/*  *********************************************************************
66    *  Macros
67    ********************************************************************* */
68
69#define _BYTESWAP_ 	/* don't byteswap these disks */
70
71#define OUTB(x,y) outb(x,y)
72#define OUTW(x,y) outw(x,y)
73#define INB(x) inb(x)
74#define INW(x) inw(x)
75
76/*  *********************************************************************
77    *  Forward declarations
78    ********************************************************************* */
79
80extern void _wbflush(void);
81
82static void idedrv_probe(cfe_driver_t *drv,
83			      unsigned long probe_a, unsigned long probe_b,
84			      void *probe_ptr);
85
86/*  *********************************************************************
87    *  Device Dispatch
88    ********************************************************************* */
89
90static cfe_devdisp_t idedrv_dispatch = {
91    NULL,
92    NULL,
93    NULL,
94    NULL,
95    NULL,
96    NULL,
97    NULL,
98    NULL
99};
100
101const cfe_driver_t pciidedrv = {
102    "PCI IDE disk",
103    "ide",
104    CFE_DEV_DISK,
105    &idedrv_dispatch,
106    idedrv_probe
107};
108
109const cfe_driver_t pciatapidrv = {
110    "PCI ATAPI device",
111    "atapi",
112    CFE_DEV_DISK,
113    &idedrv_dispatch,
114    idedrv_probe
115};
116
117/*  *********************************************************************
118    *  Supported PCI devices
119    ********************************************************************* */
120
121#define DEVID(vid,pid) (((pid)<<16)|(vid))
122
123static uint32_t pciidedrv_devlist[] = {
124    DEVID(0x105a,0x4d33),		/* Promise Ultra33 */
125    DEVID(0x1095,0x0649),		/* CMD PCI0649 */
126    DEVID(0x1095,0x0648),               /* CMD PCI0648 */
127    0xFFFFFFFF
128};
129
130
131/*  *********************************************************************
132    *  Port I/O routines
133    *
134    *  These routines are called back from the common code to do
135    *  I/O cycles to the IDE disk.  We provide routines for
136    *  reading and writing bytes, words, and strings of words.
137    ********************************************************************* */
138
139static uint8_t idedrv_inb(idecommon_dispatch_t *disp,uint32_t reg)
140{
141    return INB(reg+disp->baseaddr);
142}
143
144static uint16_t idedrv_inw(idecommon_dispatch_t *disp,uint32_t reg)
145{
146    return INW(reg+disp->baseaddr);
147}
148
149static void idedrv_ins(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len)
150{
151    uint16_t data;
152
153    while (len > 0) {
154	data = INW(reg+disp->baseaddr);
155
156#ifdef _BYTESWAP_
157	*buf++ = (data >> 8) & 0xFF;
158	*buf++ = (data & 0xFF);
159#else
160	*buf++ = (data & 0xFF);
161	*buf++ = (data >> 8) & 0xFF;
162#endif
163	len--;
164	len--;
165	}
166
167}
168
169static void idedrv_outb(idecommon_dispatch_t *disp,uint32_t reg,uint8_t val)
170{
171    OUTB(reg+disp->baseaddr,val);
172}
173
174static void idedrv_outw(idecommon_dispatch_t *disp,uint32_t reg,uint16_t val)
175{
176    OUTW(reg+disp->baseaddr,val);
177}
178
179static void idedrv_outs(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len)
180{
181    uint16_t data;
182
183    while (len > 0) {
184#ifdef _BYTESWAP_
185	data = (uint16_t) buf[1] + ((uint16_t) buf[0] << 8);
186#else
187	data = (uint16_t) buf[0] + ((uint16_t) buf[1] << 8);
188#endif
189
190	OUTW(reg+disp->baseaddr,data);
191
192	buf++;
193	buf++;
194	len--;
195	len--;
196	}
197}
198
199
200/*  *********************************************************************
201    *  pciidedrv_find(devid,list)
202    *
203    *  Find a particular product ID on the list.  Return >= 0 if
204    *  the ID is valid.
205    *
206    *  Input parameters:
207    *  	   devid - product and device ID we have
208    *  	   list - list of product and device IDs we're looking for
209    *
210    *  Return value:
211    *  	   index into table, or -1 if not found
212    ********************************************************************* */
213static int pciidedrv_find(uint32_t devid,uint32_t *list)
214{
215    int idx = 0;
216
217    while (list[idx] != 0xFFFFFFFF) {
218	if (list[idx] == devid) return idx;
219	idx++;
220	}
221
222    return -1;
223}
224
225
226/*  *********************************************************************
227    *  idedrv_probe(drv,probe_a,probe_b,probe_ptr)
228    *
229    *  Our probe routine.  Attach an IDE device to the firmware.
230    *
231    *  Input parameters:
232    *  	   drv - driver structure
233    *  	   probe_a - physical address of IDE registers
234    *  	   probe_b - unit number
235    *  	   probe_ptr - not used
236    *
237    *  Return value:
238    *  	   nothing
239    ********************************************************************* */
240
241static void idedrv_probe(cfe_driver_t *drv,
242			      unsigned long probe_a, unsigned long probe_b,
243			      void *probe_ptr)
244{
245    idecommon_t *softc;
246    idecommon_dispatch_t *disp;
247    char descr[80];
248    char unitstr[50];
249    pcitag_t tag;
250    int index;
251    uint32_t devid;
252    uint32_t reg;
253    int res;
254    int unit;
255    cfe_driver_t *realdrv;
256    int attached = 0;
257
258    /*
259     * probe_a is unused
260     * probe_b is unused
261     * probe_ptr is unused.
262     */
263
264    index = 0;
265
266    for (;;) {
267	if (pci_find_class(PCI_CLASS_MASS_STORAGE,index,&tag) != 0) break;
268	index++;
269	devid = pci_conf_read(tag,PCI_ID_REG);
270
271	if (pciidedrv_find(devid,pciidedrv_devlist) < 0) {
272	    continue;
273	    }
274
275
276	reg = pci_conf_read(tag,PCI_MAPREG(0));
277
278	if (PCI_MAPREG_TYPE(reg) != PCI_MAPREG_TYPE_IO) {
279	    xprintf("Skipping this IDE device, we don't do memory mapped IDE yet\n");
280	    continue;
281	    }
282
283	reg &= ~PCI_MAPREG_TYPE_MASK;
284
285	for (unit = 0; unit < 2; unit++) {
286
287	    /*
288	     * If we've deliberately disabled probing of this
289	     * device, then skip it.
290	     */
291
292	    if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_NOPROBE) {
293		continue;
294		}
295
296	    softc = (idecommon_t *) KMALLOC(sizeof(idecommon_t),0);
297	    disp = (idecommon_dispatch_t *) KMALLOC(sizeof(idecommon_dispatch_t),0);
298
299	    if (!softc || !disp) {
300		if (softc) KFREE(softc);
301		if (disp) KFREE(disp);
302		return;		/* out of memory, stop here */
303		}
304
305
306	    softc->idecommon_addr = reg;
307	    disp->ref = softc;
308	    disp->baseaddr = softc->idecommon_addr;
309	    softc->idecommon_deferprobe = 0;
310	    softc->idecommon_dispatch = disp;
311	    softc->idecommon_unit = unit;
312
313	    disp->outb = idedrv_outb;
314	    disp->outw = idedrv_outw;
315	    disp->outs = idedrv_outs;
316
317	    disp->inb = idedrv_inb;
318	    disp->inw = idedrv_inw;
319	    disp->ins = idedrv_ins;
320
321	    /*
322	     * If we're autoprobing, do it now.  Loop back if we have
323	     * trouble finding the device.
324	     *
325	     * If not autoprobing, assume the device is there and set the
326	     * common routines to double check later.
327	     */
328
329	    if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_AUTO) {
330		res = idecommon_devprobe(softc,1);
331		if (res < 0) {
332		    KFREE(softc);
333		    KFREE(disp);
334		    continue;
335		    }
336		}
337	    else {
338		idecommon_init(softc,IDE_PROBE_GET_TYPE(probe_b,unit));
339		softc->idecommon_deferprobe = 1;
340		}
341
342	    xsprintf(descr,"%s unit %d at I/O %04X",drv->drv_description,
343		     softc->idecommon_unit,softc->idecommon_addr);
344	    xsprintf(unitstr,"%d",unit);
345
346	    realdrv = (cfe_driver_t *) (softc->idecommon_atapi ? &pciatapidrv : &pciidedrv);
347
348	    idecommon_attach(&idedrv_dispatch);
349	    cfe_attach(realdrv,softc,unitstr,descr);
350	    attached++;
351	    }
352
353	}
354
355    xprintf("PCIIDE: %d controllers found\n",attached);
356}
357
358
359