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