1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  PCI IDE disk driver			File: dev_ide_frodo.c
5    *
6    *  This is a simple driver for IDE hard disks that are connected
7    *  ServerWorks "Frodo" Serial ATA controllers
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#include "lib_physio.h"
59
60
61#define BCM_BYTESWAP32(value)                       \
62       ((((uint32_t)(value) & 0xFF000000) >> 24) |  \
63        (((uint32_t)(value) & 0x00FF0000) >> 8)  |  \
64        (((uint32_t)(value) & 0x0000FF00) << 8)  |  \
65        (((uint32_t)(value) & 0x000000FF) << 24))
66
67#define BCM_BYTESWAP16(value)                       \
68       ((((uint16_t)(value) & 0xFF00) >> 8)  |      \
69        (((uint16_t)(value) & 0x00FF) << 8))
70
71
72#if   defined(ENDIAN_BIG)
73#define BCM_LE32_TO_HOST(x)     BCM_BYTESWAP32(x)
74#define BCM_HOST_TO_LE32(x)     BCM_BYTESWAP32(x)
75#define BCM_LE16_TO_HOST(x)     BCM_BYTESWAP16(x)
76#define BCM_HOST_TO_LE16(x)     BCM_BYTESWAP16(x)
77#else
78#define BCM_LE32_TO_HOST(x)     (x)
79#define BCM_HOST_TO_LE32(x)     (x)
80#define BCM_LE16_TO_HOST(x)     (x)
81#define BCM_HOST_TO_LE16(x)     (x)
82#endif
83
84#define BCM_REG_RD32_LE( p_reg32 )       BCM_LE32_TO_HOST(phys_read32( ((physaddr_t) p_reg32)))
85#define BCM_REG_WR32_LE( p_reg32, val )  phys_write32(((physaddr_t)p_reg32), BCM_HOST_TO_LE32( val ) )
86#define BCM_REG_RD16_LE( p_reg16 )       BCM_LE16_TO_HOST( phys_read16( ((physaddr_t)p_reg16 )))
87#define BCM_REG_WR16_LE( p_reg16, val )  phys_write16(((physaddr_t)p_reg16), BCM_HOST_TO_LE16( val ) )
88#define BCM_REG_RD8( p_reg8 )            phys_read8(  ((physaddr_t)p_reg8))
89#define BCM_REG_WR8(p_reg8, val)         phys_write8( ((physaddr_t)p_reg8), val)
90
91//#include "sb1250_defs.h"
92#include "sbmips.h"
93
94
95#define FRODO_TESTCTRLREG               0x10f0
96#define FRODO_MDIOCTRLREG               0x8c
97#define FRODO_PLLCTRLREG                0x84
98#define FRODO_SCR2REG                   0x48
99
100#define FRODO_TEST_CTRL_VALUE           0x40000000
101#define FRODO_SCR2_RESET_PHY       0x00000001
102#define FRODO_SCR2_CLEAR           0x00000000
103
104/* assume all Frodo deives have 4 ports for now... */
105#define FRODO_NUM_PORTS(dev, class)     4
106
107/*  *********************************************************************
108    *  Macros
109    ********************************************************************* */
110
111#if ENDIAN_BIG
112//#define _BYTESWAP_ 	/* don't byteswap these disks */
113#endif
114
115#define OUTB(x,y) outb(x,y)
116#define OUTW(x,y) outw(x,y)
117#define INB(x) inb(x)
118#define INW(x) inw(x)
119
120/*  *********************************************************************
121    *  Forward declarations
122    ********************************************************************* */
123
124extern void _wbflush(void);
125
126static void idedrv_probe(cfe_driver_t *drv,
127			      unsigned long probe_a, unsigned long probe_b,
128			      void *probe_ptr);
129
130/*  *********************************************************************
131    *  Device Dispatch
132    ********************************************************************* */
133
134static cfe_devdisp_t idedrv_dispatch = {
135    NULL,
136    NULL,
137    NULL,
138    NULL,
139    NULL,
140    NULL,
141    NULL,
142    NULL
143};
144
145const cfe_driver_t frododrv = {
146    "FRODO SATA disk",
147    "sata",
148    CFE_DEV_DISK,
149    &idedrv_dispatch,
150    idedrv_probe
151};
152
153
154/*  *********************************************************************
155    *  Supported PCI devices
156    ********************************************************************* */
157
158#define DEVID(vid,pid) (((pid)<<16)|(vid))
159
160static uint32_t pciidedrv_devlist[] = {
161    DEVID(0x1166,0x0212),		/* SW */
162    DEVID(0x1166,0x0213),		/* SW */
163    DEVID(0x1166,0x0241),		/* SW */
164    DEVID(0x1166,0x0242),		/* SW */
165    DEVID(0x1166,0x024a),		/* SW */
166    0xFFFFFFFF
167};
168
169
170/*  *********************************************************************
171    *  Port I/O routines
172    *
173    *  These routines are called back from the common code to do
174    *  I/O cycles to the IDE disk.  We provide routines for
175    *  reading and writing bytes, words, and strings of words.
176    ********************************************************************* */
177
178static uint8_t idedrv_inb(idecommon_dispatch_t *disp,uint32_t reg)
179{
180    return BCM_REG_RD8((reg*4)+disp->baseaddr);
181}
182
183static uint16_t idedrv_inw(idecommon_dispatch_t *disp,uint32_t reg)
184{
185    return  BCM_REG_RD16_LE((reg*4)+disp->baseaddr);
186}
187
188static void idedrv_ins(idecommon_dispatch_t *disp,uint32_t reg,hsaddr_t buf,int len)
189{
190    uint16_t data;
191
192    while (len > 0) {
193        data = BCM_REG_RD16_LE((reg*4)+disp->baseaddr);
194
195#ifdef _BYTESWAP_
196	hs_write8(buf,(data >> 8) & 0xFF);
197	buf++;
198	hs_write8(buf,(data & 0xFF));
199	buf++;
200#else
201	hs_write8(buf,(data & 0xFF));
202	buf++;
203	hs_write8(buf,(data >> 8) & 0xFF);
204	buf++;
205#endif
206    /* xprintf("FRODO: %04X:%04X:%02X%02X\n", (int) len, (int) data, (int) *((uint8_t *) (int)buf-2), (int) *((uint8_t *) (int)buf-1)); */
207
208	len--;
209	len--;
210	}
211
212}
213
214static void idedrv_outb(idecommon_dispatch_t *disp,uint32_t reg,uint8_t val)
215{
216    BCM_REG_WR8((reg*4)+disp->baseaddr,val);
217}
218
219static void idedrv_outw(idecommon_dispatch_t *disp,uint32_t reg,uint16_t val)
220{
221    BCM_REG_WR16_LE((reg*4)+disp->baseaddr,val);
222}
223
224static void idedrv_outs(idecommon_dispatch_t *disp,uint32_t reg,hsaddr_t buf,int len)
225{
226    uint16_t data;
227
228    while (len > 0) {
229#ifdef _BYTESWAP_
230	data = (uint16_t) hs_read8(buf+1) + ((uint16_t) hs_read8(buf+0) << 8);
231#else
232	data = (uint16_t) hs_read8(buf+0) + ((uint16_t) hs_read8(buf+1) << 8);
233#endif
234
235	BCM_REG_WR16_LE((reg*4)+disp->baseaddr,data);
236
237	buf++;
238	buf++;
239	len--;
240	len--;
241	}
242}
243
244
245/*  *********************************************************************
246    *  pciidedrv_find(devid,list)
247    *
248    *  Find a particular product ID on the list.  Return >= 0 if
249    *  the ID is valid.
250    *
251    *  Input parameters:
252    *  	   devid - product and device ID we have
253    *  	   list - list of product and device IDs we're looking for
254    *
255    *  Return value:
256    *  	   index into table, or -1 if not found
257    ********************************************************************* */
258static int pciidedrv_find(uint32_t devid,uint32_t *list)
259{
260    int idx = 0;
261
262    while (list[idx] != 0xFFFFFFFF) {
263
264	if (list[idx] == devid) return idx;
265
266	idx++;
267	}
268
269    return -1;
270}
271
272
273/*  *********************************************************************
274    *  idedrv_probe(drv,probe_a,probe_b,probe_ptr)
275    *
276    *  Our probe routine.  Attach an IDE device to the firmware.
277    *
278    *  Input parameters:
279    *  	   drv - driver structure
280    *  	   probe_a - physical address of IDE registers
281    *  	   probe_b - unit number
282    *  	   probe_ptr - not used
283    *
284    *  Return value:
285    *  	   nothing
286    ********************************************************************* */
287
288static void idedrv_probe(cfe_driver_t *drv,
289			      unsigned long probe_a, unsigned long probe_b,
290			      void *probe_ptr)
291{
292    idecommon_t *softc;
293    idecommon_dispatch_t *disp;
294    char descr[80];
295    char unitstr[50];
296    pcitag_t tag;
297    int index;
298    uint32_t devid,classid;
299    uint32_t reg;
300    int res;
301    int unit;
302    cfe_driver_t *realdrv;
303    int attached = 0;
304
305    /*
306     * probe_a is unused
307     * probe_b is unused
308     * probe_ptr is unused.
309     */
310
311    index = 0;
312
313    for (;;)
314    {
315        if (pci_find_class(PCI_CLASS_MASS_STORAGE,index,&tag) != 0) break;
316        index++;
317
318        devid = pci_conf_read(tag,PCI_ID_REG);
319        classid = pci_conf_read(tag,PCI_CLASS_REG);
320
321        /*
322         * This driver will only accept certain device IDs.
323         */
324        if (pciidedrv_find(devid,pciidedrv_devlist) < 0) {
325            continue;
326	    }
327
328        /*
329         * Mapping register #5 is the MMIO BAR.
330         */
331
332        reg = pci_conf_read(tag,PCI_MAPREG(5));
333
334        reg &= ~PCI_MAPREG_TYPE_MASK;
335
336
337        /*
338         * Make sure BAR is valid, HT1000 has second device instance without MM bar
339         */
340        if (reg == 0)
341        {
342            continue;
343	    }
344
345
346
347        /* Create CFE device instance for each port */
348        for (unit = 0; unit < FRODO_NUM_PORTS(devid, classid); unit++)
349        {
350            /* unit = (int) probe_b; */
351
352            softc = (idecommon_t *) KMALLOC(sizeof(idecommon_t),0);
353            disp = (idecommon_dispatch_t *) KMALLOC(sizeof(idecommon_dispatch_t),0);
354
355            if (!softc || !disp) {
356                if (softc) KFREE(softc);
357                if (disp) KFREE(disp);
358                return;		/* out of memory, stop here */
359            }
360
361            softc->idecommon_addr = reg + (unit * 0x100);
362            disp->ref = softc;
363            disp->baseaddr = softc->idecommon_addr;
364            softc->idecommon_deferprobe = 0;
365            softc->idecommon_dispatch = disp;
366            softc->idecommon_unit = 0;
367
368            disp->outb = idedrv_outb;
369            disp->outw = idedrv_outw;
370            disp->outs = idedrv_outs;
371
372            disp->inb = idedrv_inb;
373            disp->inw = idedrv_inw;
374            disp->ins = idedrv_ins;
375
376            {
377                cfe_usleep( 10000 );
378
379                uint32_t port_select, ncqrdval, ncqfixval, mdioctrl;
380                // Enable MDIO Space
381                BCM_REG_WR32_LE( reg + FRODO_TESTCTRLREG, FRODO_TEST_CTRL_VALUE | 0x00000001);
382                cfe_usleep( 10000 );
383
384                port_select = (((1 << unit) << 16) | (0x2007));
385                BCM_REG_WR32_LE( reg + FRODO_MDIOCTRLREG, port_select);
386                cfe_usleep( 10000 );
387
388                ncqrdval = 0x0000400d;
389                BCM_REG_WR32_LE( reg + FRODO_MDIOCTRLREG, ncqrdval );
390                cfe_usleep( 10000 );
391
392                ncqfixval = BCM_REG_RD32_LE( reg + FRODO_MDIOCTRLREG );
393                ncqfixval = (ncqfixval & 0xFFFF0000);
394                ncqfixval = (ncqfixval | 0x0004200d);
395                BCM_REG_WR32_LE( reg + FRODO_MDIOCTRLREG, ncqfixval);
396                cfe_usleep( 10000 );
397
398                // Disable MDIO Access
399                mdioctrl =  BCM_REG_RD32_LE( reg + FRODO_TESTCTRLREG );
400                mdioctrl &= (~FRODO_TEST_CTRL_VALUE);
401                BCM_REG_WR32_LE( reg + FRODO_TESTCTRLREG, mdioctrl);
402
403                BCM_REG_WR32_LE( disp->baseaddr + FRODO_SCR2REG, FRODO_SCR2_RESET_PHY);
404                cfe_usleep( 10000 );
405                BCM_REG_WR32_LE( disp->baseaddr + FRODO_SCR2REG, FRODO_SCR2_CLEAR);
406                cfe_usleep( 10000 );
407            }
408
409            /*
410             * If we're autoprobing, do it now.  Loop back if we have
411             * trouble finding the device.
412             *
413             * If not autoprobing, assume the device is there and set the
414             * common routines to double check later.
415             */
416
417            if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_AUTO) {
418                res = idecommon_devprobe(softc,1);
419                if (res < 0) {
420                    KFREE(softc);
421                    KFREE(disp);
422                    continue;
423                }
424            }
425            else {
426                idecommon_init(softc,IDE_PROBE_GET_TYPE(probe_b,unit));
427                softc->idecommon_deferprobe = 1;
428            }
429
430            xsprintf(descr,"%s unit %d at %04X",drv->drv_description,
431                     softc->idecommon_unit,softc->idecommon_addr);
432            xsprintf(unitstr,"%d",unit);
433
434            realdrv = (cfe_driver_t *) &frododrv;
435
436            idecommon_attach(&idedrv_dispatch);
437            cfe_attach(realdrv,softc,unitstr,descr);
438            attached++;
439        }
440    }
441
442    xprintf("FRODO: %d controllers found\n",attached);
443}
444
445
446