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