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