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
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 "cfe.h"
50
51#include "dev_ide_common.h"
52
53#include "dev_ide.h"
54
55#include "pcivar.h"
56#include "pcireg.h"
57
58/*  *********************************************************************
59    *  Macros
60    ********************************************************************* */
61
62#if ENDIAN_BIG
63#define _BYTESWAP_ 	/* don't byteswap these disks */
64#endif
65
66#define OUTB(x,y) outb(x,y)
67#define OUTW(x,y) outw(x,y)
68#define INB(x) inb(x)
69#define INW(x) inw(x)
70
71/*  *********************************************************************
72    *  Forward declarations
73    ********************************************************************* */
74
75extern void _wbflush(void);
76
77static void idedrv_probe(cfe_driver_t *drv,
78			      unsigned long probe_a, unsigned long probe_b,
79			      void *probe_ptr);
80
81/*  *********************************************************************
82    *  Device Dispatch
83    ********************************************************************* */
84
85static cfe_devdisp_t idedrv_dispatch = {
86    NULL,
87    NULL,
88    NULL,
89    NULL,
90    NULL,
91    NULL,
92    NULL,
93    NULL
94};
95
96const cfe_driver_t pciidedrv = {
97    "PCI IDE disk",
98    "ide",
99    CFE_DEV_DISK,
100    &idedrv_dispatch,
101    idedrv_probe
102};
103
104const cfe_driver_t pciatapidrv = {
105    "PCI ATAPI device",
106    "atapi",
107    CFE_DEV_DISK,
108    &idedrv_dispatch,
109    idedrv_probe
110};
111
112/*  *********************************************************************
113    *  Supported PCI devices
114    ********************************************************************* */
115
116#define DEVID(vid,pid) (((pid)<<16)|(vid))
117
118static uint32_t pciidedrv_devlist[] = {
119//    DEVID(0x105a,0x4d33),		/* Promise Ultra33 */
120//    DEVID(0x1095,0x0649),		/* CMD PCI0649 */
121//    DEVID(0x1095,0x0648),               /* CMD PCI0648 */
122//    DEVID(0x1166,0x0212),		/* SW */
123//    DEVID(0x1166,0x0213),		/* SW */
124//    DEVID(0x1166,0x0241),		/* SW */
125//    DEVID(0x1166,0x0242),		/* SW */
126    DEVID(0x1095,0x0680),
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,hsaddr_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	hs_write8(buf,(data >> 8) & 0xFF);
158	buf++;
159	hs_write8(buf,(data & 0xFF));
160	buf++;
161#else
162	hs_write8(buf,(data & 0xFF));
163	buf++;
164	hs_write8(buf,(data >> 8) & 0xFF);
165	buf++;
166#endif
167	len--;
168	len--;
169	}
170
171}
172
173static void idedrv_outb(idecommon_dispatch_t *disp,uint32_t reg,uint8_t val)
174{
175    OUTB(reg+disp->baseaddr,val);
176}
177
178static void idedrv_outw(idecommon_dispatch_t *disp,uint32_t reg,uint16_t val)
179{
180    OUTW(reg+disp->baseaddr,val);
181}
182
183static void idedrv_outs(idecommon_dispatch_t *disp,uint32_t reg,hsaddr_t buf,int len)
184{
185    uint16_t data;
186
187    while (len > 0) {
188#ifdef _BYTESWAP_
189	data = (uint16_t) hs_read8(buf+1) + ((uint16_t) hs_read8(buf+0) << 8);
190#else
191	data = (uint16_t) hs_read8(buf+0) + ((uint16_t) hs_read8(buf+1) << 8);
192#endif
193
194	OUTW(reg+disp->baseaddr,data);
195
196	buf++;
197	buf++;
198	len--;
199	len--;
200	}
201}
202
203
204/*  *********************************************************************
205    *  pciidedrv_find(devid,list)
206    *
207    *  Find a particular product ID on the list.  Return >= 0 if
208    *  the ID is valid.
209    *
210    *  Input parameters:
211    *  	   devid - product and device ID we have
212    *  	   list - list of product and device IDs we're looking for
213    *
214    *  Return value:
215    *  	   index into table, or -1 if not found
216    ********************************************************************* */
217static int pciidedrv_find(uint32_t devid,uint32_t *list)
218{
219    int idx = 0;
220
221    while (list[idx] != 0xFFFFFFFF) {
222	if (list[idx] == devid) return idx;
223	idx++;
224	}
225
226    return -1;
227}
228
229
230/*  *********************************************************************
231    *  idedrv_probe(drv,probe_a,probe_b,probe_ptr)
232    *
233    *  Our probe routine.  Attach an IDE device to the firmware.
234    *
235    *  Input parameters:
236    *  	   drv - driver structure
237    *  	   probe_a - physical address of IDE registers
238    *  	   probe_b - unit number
239    *  	   probe_ptr - not used
240    *
241    *  Return value:
242    *  	   nothing
243    ********************************************************************* */
244
245static void idedrv_probe(cfe_driver_t *drv,
246			      unsigned long probe_a, unsigned long probe_b,
247			      void *probe_ptr)
248{
249    idecommon_t *softc;
250    idecommon_dispatch_t *disp;
251    char descr[80];
252    char unitstr[50];
253    pcitag_t tag;
254    int index;
255    uint32_t devid,classid;
256    uint32_t reg;
257    int res;
258    int unit;
259    cfe_driver_t *realdrv;
260    int attached = 0;
261
262    /*
263     * probe_a is unused
264     * probe_b is unused
265     * probe_ptr is unused.
266     */
267
268    index = 0;
269
270    for (;;) {
271	if (pci_find_class(PCI_CLASS_MASS_STORAGE,index,&tag) != 0) break;
272	index++;
273
274	devid = pci_conf_read(tag,PCI_ID_REG);
275	classid = pci_conf_read(tag,PCI_CLASS_REG);
276
277	/*
278	 * If it's not an IDE controller and it isn't on our exception list,
279	 * we can't use it.
280	 */
281	if ((PCI_SUBCLASS(classid) != PCI_SUBCLASS_MASS_STORAGE_IDE) &&
282	    (pciidedrv_find(devid,pciidedrv_devlist) < 0)) {
283	    continue;
284	    }
285
286
287	reg = pci_conf_read(tag,PCI_MAPREG(0));
288
289	if (PCI_MAPREG_TYPE(reg) != PCI_MAPREG_TYPE_IO) {
290	    xprintf("Skipping this IDE device, we don't do memory mapped IDE yet\n");
291	    continue;
292	    }
293
294	reg &= ~PCI_MAPREG_TYPE_MASK;
295
296	for (unit = 0; unit < 2; unit++) {
297
298	    /*
299	     * If we've deliberately disabled probing of this
300	     * device, then skip it.
301	     */
302
303	    if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_NOPROBE) {
304		continue;
305		}
306
307	    softc = (idecommon_t *) KMALLOC(sizeof(idecommon_t),0);
308	    disp = (idecommon_dispatch_t *) KMALLOC(sizeof(idecommon_dispatch_t),0);
309
310	    if (!softc || !disp) {
311		if (softc) KFREE(softc);
312		if (disp) KFREE(disp);
313		return;		/* out of memory, stop here */
314		}
315
316
317	    softc->idecommon_addr = reg;
318	    disp->ref = softc;
319	    disp->baseaddr = softc->idecommon_addr;
320	    softc->idecommon_deferprobe = 0;
321	    softc->idecommon_dispatch = disp;
322	    softc->idecommon_unit = unit;
323
324	    disp->outb = idedrv_outb;
325	    disp->outw = idedrv_outw;
326	    disp->outs = idedrv_outs;
327
328	    disp->inb = idedrv_inb;
329	    disp->inw = idedrv_inw;
330	    disp->ins = idedrv_ins;
331
332	    /*
333	     * If we're autoprobing, do it now.  Loop back if we have
334	     * trouble finding the device.
335	     *
336	     * If not autoprobing, assume the device is there and set the
337	     * common routines to double check later.
338	     */
339
340	    if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_AUTO) {
341		res = idecommon_devprobe(softc,1);
342		if (res < 0) {
343		    KFREE(softc);
344		    KFREE(disp);
345		    continue;
346		    }
347		}
348	    else {
349		idecommon_init(softc,IDE_PROBE_GET_TYPE(probe_b,unit));
350		softc->idecommon_deferprobe = 1;
351		}
352
353	    xsprintf(descr,"%s unit %d at I/O %04X",drv->drv_description,
354		     softc->idecommon_unit,softc->idecommon_addr);
355	    xsprintf(unitstr,"%d",unit);
356
357	    realdrv = (cfe_driver_t *) (softc->idecommon_atapi ? &pciatapidrv : &pciidedrv);
358
359	    idecommon_attach(&idedrv_dispatch);
360	    cfe_attach(realdrv,softc,unitstr,descr);
361	    attached++;
362	    }
363
364	}
365
366    xprintf("PCIIDE: %d controllers found\n",attached);
367}
368
369
370