1189702Ssam/*- 2189702Ssam * Copyright (c) 1998 - 2008 S��ren Schmidt <sos@FreeBSD.org> 3189702Ssam * All rights reserved. 4189702Ssam * 5189702Ssam * Redistribution and use in source and binary forms, with or without 6189702Ssam * modification, are permitted provided that the following conditions 7189702Ssam * are met: 8189702Ssam * 1. Redistributions of source code must retain the above copyright 9189702Ssam * notice, this list of conditions and the following disclaimer, 10189702Ssam * without modification, immediately at the beginning of the file. 11189702Ssam * 2. Redistributions in binary form must reproduce the above copyright 12189702Ssam * notice, this list of conditions and the following disclaimer in the 13189702Ssam * documentation and/or other materials provided with the distribution. 14189702Ssam * 15189702Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16189702Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17189702Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18189702Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19189702Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20189702Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21189702Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22189702Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23189702Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24189702Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25189702Ssam */ 26189702Ssam 27189702Ssam#include <sys/cdefs.h> 28189702Ssam__FBSDID("$FreeBSD$"); 29189702Ssam 30189702Ssam#include <sys/param.h> 31189702Ssam#include <sys/module.h> 32189702Ssam#include <sys/systm.h> 33189702Ssam#include <sys/kernel.h> 34189702Ssam#include <sys/ata.h> 35189702Ssam#include <sys/bus.h> 36189702Ssam#include <sys/endian.h> 37189702Ssam#include <sys/malloc.h> 38189702Ssam#include <sys/lock.h> 39189702Ssam#include <sys/mutex.h> 40217680Sadrian#include <sys/sema.h> 41217680Sadrian#include <sys/taskqueue.h> 42189702Ssam#include <vm/uma.h> 43189702Ssam#include <machine/stdarg.h> 44189702Ssam#include <machine/resource.h> 45189702Ssam#include <machine/bus.h> 46189702Ssam#include <sys/rman.h> 47189702Ssam#include <dev/pci/pcivar.h> 48189702Ssam#include <dev/pci/pcireg.h> 49189702Ssam#include <dev/ata/ata-all.h> 50189702Ssam#include <dev/ata/ata-pci.h> 51189702Ssam#include <ata_if.h> 52189702Ssam 53189702Ssam/* local prototypes */ 54189702Ssamstatic int ata_cmd_ch_attach(device_t dev); 55189702Ssamstatic int ata_cmd_status(device_t dev); 56189702Ssamstatic int ata_cmd_setmode(device_t dev, int target, int mode); 57189702Ssamstatic int ata_sii_ch_attach(device_t dev); 58189702Ssamstatic int ata_sii_ch_detach(device_t dev); 59189702Ssamstatic int ata_sii_status(device_t dev); 60189702Ssamstatic void ata_sii_reset(device_t dev); 61189702Ssamstatic int ata_sii_setmode(device_t dev, int target, int mode); 62189702Ssam 63189702Ssam/* misc defines */ 64189702Ssam#define SII_MEMIO 1 65189702Ssam#define SII_INTR 0x01 66189702Ssam#define SII_SETCLK 0x02 67189702Ssam#define SII_BUG 0x04 68189702Ssam#define SII_4CH 0x08 69189702Ssam 70189702Ssam/* 71189702Ssam * Silicon Image Inc. (SiI) (former CMD) chipset support functions 72244962Sadrian */ 73189702Ssamstatic int 74189702Ssamata_sii_probe(device_t dev) 75189702Ssam{ 76189702Ssam struct ata_pci_controller *ctlr = device_get_softc(dev); 77189702Ssam static const struct ata_chip_id ids[] = 78189702Ssam {{ ATA_SII3114, 0x00, SII_MEMIO, SII_4CH, ATA_SA150, "3114" }, 79189702Ssam { ATA_SII3512, 0x02, SII_MEMIO, 0, ATA_SA150, "3512" }, 80189702Ssam { ATA_SII3112, 0x02, SII_MEMIO, 0, ATA_SA150, "3112" }, 81189702Ssam { ATA_SII3112_1, 0x02, SII_MEMIO, 0, ATA_SA150, "3112" }, 82189702Ssam { ATA_SII3512, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3512" }, 83189702Ssam { ATA_SII3112, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3112" }, 84189702Ssam { ATA_SII3112_1, 0x00, SII_MEMIO, SII_BUG, ATA_SA150, "3112" }, 85189702Ssam { ATA_SII0680, 0x00, SII_MEMIO, SII_SETCLK, ATA_UDMA6, "680" }, 86189702Ssam { ATA_CMD649, 0x00, 0, SII_INTR, ATA_UDMA5, "(CMD) 649" }, 87189702Ssam { ATA_CMD648, 0x00, 0, SII_INTR, ATA_UDMA4, "(CMD) 648" }, 88189702Ssam { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "(CMD) 646U2" }, 89189702Ssam { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "(CMD) 646" }, 90189702Ssam { 0, 0, 0, 0, 0, 0}}; 91189702Ssam 92189702Ssam if (pci_get_vendor(dev) != ATA_SILICON_IMAGE_ID) 93189702Ssam return ENXIO; 94189702Ssam 95189702Ssam if (!(ctlr->chip = ata_match_chip(dev, ids))) 96189702Ssam return ENXIO; 97189702Ssam 98189702Ssam ata_set_desc(dev); 99189702Ssam ctlr->chipinit = ata_sii_chipinit; 100189702Ssam return (BUS_PROBE_LOW_PRIORITY); 101189702Ssam} 102189702Ssam 103189702Ssamint 104189702Ssamata_sii_chipinit(device_t dev) 105189702Ssam{ 106189702Ssam struct ata_pci_controller *ctlr = device_get_softc(dev); 107189702Ssam 108189702Ssam if (ata_setup_interrupt(dev, ata_generic_intr)) 109189702Ssam return ENXIO; 110189702Ssam 111189702Ssam switch (ctlr->chip->cfg1) { 112189702Ssam case SII_MEMIO: 113189702Ssam ctlr->r_type2 = SYS_RES_MEMORY; 114189702Ssam ctlr->r_rid2 = PCIR_BAR(5); 115189702Ssam if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, 116189702Ssam &ctlr->r_rid2, RF_ACTIVE))){ 117189702Ssam if (ctlr->chip->chipid != ATA_SII0680 || 118189702Ssam (pci_read_config(dev, 0x8a, 1) & 1)) 119189702Ssam return ENXIO; 120189702Ssam } 121189702Ssam 122189702Ssam if (ctlr->chip->cfg2 & SII_SETCLK) { 123189702Ssam if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10) 124189702Ssam pci_write_config(dev, 0x8a, 125189702Ssam (pci_read_config(dev, 0x8a, 1) & 0xcf)|0x10,1); 126189702Ssam if ((pci_read_config(dev, 0x8a, 1) & 0x30) != 0x10) 127189702Ssam device_printf(dev, "%s could not set ATA133 clock\n", 128189702Ssam ctlr->chip->text); 129189702Ssam } 130202161Sgavin 131189702Ssam /* if we have 4 channels enable the second set */ 132189702Ssam if (ctlr->chip->cfg2 & SII_4CH) { 133202161Sgavin ATA_OUTL(ctlr->r_res2, 0x0200, 0x00000002); 134189702Ssam ctlr->channels = 4; 135189702Ssam } 136202161Sgavin 137189702Ssam /* dont block interrupts from any channel */ 138189702Ssam pci_write_config(dev, 0x48, 139189702Ssam (pci_read_config(dev, 0x48, 4) & ~0x03c00000), 4); 140189702Ssam 141189702Ssam /* enable PCI interrupt as BIOS might not */ 142189702Ssam pci_write_config(dev, 0x8a, (pci_read_config(dev, 0x8a, 1) & 0x3f), 1); 143189702Ssam 144189702Ssam if (ctlr->r_res2) { 145189702Ssam ctlr->ch_attach = ata_sii_ch_attach; 146189702Ssam ctlr->ch_detach = ata_sii_ch_detach; 147189702Ssam } 148189702Ssam 149189702Ssam if (ctlr->chip->max_dma >= ATA_SA150) { 150189702Ssam ctlr->reset = ata_sii_reset; 151189702Ssam ctlr->setmode = ata_sata_setmode; 152189702Ssam ctlr->getrev = ata_sata_getrev; 153189702Ssam } 154189702Ssam else 155189702Ssam ctlr->setmode = ata_sii_setmode; 156189702Ssam break; 157189702Ssam 158189702Ssam default: 159189702Ssam if ((pci_read_config(dev, 0x51, 1) & 0x08) != 0x08) { 160189702Ssam device_printf(dev, "HW has secondary channel disabled\n"); 161189702Ssam ctlr->channels = 1; 162189702Ssam } 163189702Ssam 164189702Ssam /* enable interrupt as BIOS might not */ 165189702Ssam pci_write_config(dev, 0x71, 0x01, 1); 166189702Ssam 167189702Ssam ctlr->ch_attach = ata_cmd_ch_attach; 168189702Ssam ctlr->ch_detach = ata_pci_ch_detach; 169189702Ssam ctlr->setmode = ata_cmd_setmode; 170189702Ssam break; 171189702Ssam } 172189702Ssam return 0; 173189702Ssam} 174189702Ssam 175189702Ssamstatic int 176189702Ssamata_cmd_ch_attach(device_t dev) 177189702Ssam{ 178189702Ssam struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 179189702Ssam struct ata_channel *ch = device_get_softc(dev); 180189702Ssam 181189702Ssam /* setup the usual register normal pci style */ 182189702Ssam if (ata_pci_ch_attach(dev)) 183189702Ssam return ENXIO; 184189702Ssam 185189702Ssam if (ctlr->chip->cfg2 & SII_INTR) 186189702Ssam ch->hw.status = ata_cmd_status; 187189702Ssam 188189702Ssam ch->flags |= ATA_NO_ATAPI_DMA; 189189702Ssam 190189702Ssam return 0; 191189702Ssam} 192189702Ssam 193189702Ssamstatic int 194189702Ssamata_cmd_status(device_t dev) 195244962Sadrian{ 196189702Ssam struct ata_channel *ch = device_get_softc(dev); 197189702Ssam u_int8_t reg71; 198189702Ssam 199189702Ssam if (((reg71 = pci_read_config(device_get_parent(dev), 0x71, 1)) & 200189702Ssam (ch->unit ? 0x08 : 0x04))) { 201189702Ssam pci_write_config(device_get_parent(dev), 0x71, 202189702Ssam reg71 & ~(ch->unit ? 0x04 : 0x08), 1); 203189702Ssam return ata_pci_status(dev); 204189702Ssam } 205189702Ssam return 0; 206189702Ssam} 207189702Ssam 208189702Ssamstatic int 209189702Ssamata_cmd_setmode(device_t dev, int target, int mode) 210189702Ssam{ 211189702Ssam device_t parent = device_get_parent(dev); 212189702Ssam struct ata_pci_controller *ctlr = device_get_softc(parent); 213189702Ssam struct ata_channel *ch = device_get_softc(dev); 214189702Ssam int devno = (ch->unit << 1) + target; 215189702Ssam int treg = 0x54 + ((devno < 3) ? (devno << 1) : 7); 216189702Ssam int ureg = ch->unit ? 0x7b : 0x73; 217189702Ssam int piomode; 218189702Ssam static const uint8_t piotimings[] = 219189702Ssam { 0xa9, 0x57, 0x44, 0x32, 0x3f, 0x87, 0x32, 0x3f }; 220189702Ssam static const uint8_t udmatimings[][2] = 221189702Ssam { { 0x31, 0xc2 }, { 0x21, 0x82 }, { 0x11, 0x42 }, 222189702Ssam { 0x25, 0x8a }, { 0x15, 0x4a }, { 0x05, 0x0a } }; 223189702Ssam 224189702Ssam mode = min(mode, ctlr->chip->max_dma); 225189702Ssam if (mode >= ATA_UDMA0) { 226189702Ssam u_int8_t umode = pci_read_config(parent, ureg, 1); 227189702Ssam 228189702Ssam umode &= ~(target == 0 ? 0x35 : 0xca); 229189702Ssam umode |= udmatimings[mode & ATA_MODE_MASK][target]; 230189702Ssam pci_write_config(parent, ureg, umode, 1); 231189702Ssam piomode = ATA_PIO4; 232189702Ssam } else { 233189702Ssam pci_write_config(parent, ureg, 234189702Ssam pci_read_config(parent, ureg, 1) & 235189702Ssam ~(target == 0 ? 0x35 : 0xca), 1); 236189702Ssam piomode = mode; 237189702Ssam } 238189702Ssam pci_write_config(parent, treg, piotimings[ata_mode2idx(piomode)], 1); 239189702Ssam return (mode); 240189702Ssam} 241189702Ssam 242189702Ssamstatic int 243189702Ssamata_sii_ch_attach(device_t dev) 244189702Ssam{ 245189702Ssam struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 246189702Ssam struct ata_channel *ch = device_get_softc(dev); 247189702Ssam int unit01 = (ch->unit & 1), unit10 = (ch->unit & 2); 248189702Ssam int i; 249189702Ssam 250189702Ssam for (i = ATA_DATA; i <= ATA_COMMAND; i++) { 251189702Ssam ch->r_io[i].res = ctlr->r_res2; 252189702Ssam ch->r_io[i].offset = 0x80 + i + (unit01 << 6) + (unit10 << 8); 253189702Ssam } 254189702Ssam ch->r_io[ATA_CONTROL].res = ctlr->r_res2; 255189702Ssam ch->r_io[ATA_CONTROL].offset = 0x8a + (unit01 << 6) + (unit10 << 8); 256189702Ssam ch->r_io[ATA_IDX_ADDR].res = ctlr->r_res2; 257189702Ssam ata_default_registers(dev); 258189702Ssam 259189702Ssam ch->r_io[ATA_BMCMD_PORT].res = ctlr->r_res2; 260189702Ssam ch->r_io[ATA_BMCMD_PORT].offset = 0x00 + (unit01 << 3) + (unit10 << 8); 261189702Ssam ch->r_io[ATA_BMSTAT_PORT].res = ctlr->r_res2; 262189702Ssam ch->r_io[ATA_BMSTAT_PORT].offset = 0x02 + (unit01 << 3) + (unit10 << 8); 263189702Ssam ch->r_io[ATA_BMDTP_PORT].res = ctlr->r_res2; 264189702Ssam ch->r_io[ATA_BMDTP_PORT].offset = 0x04 + (unit01 << 3) + (unit10 << 8); 265189702Ssam 266189702Ssam if (ctlr->chip->max_dma >= ATA_SA150) { 267189702Ssam ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; 268189702Ssam ch->r_io[ATA_SSTATUS].offset = 0x104 + (unit01 << 7) + (unit10 << 8); 269189702Ssam ch->r_io[ATA_SERROR].res = ctlr->r_res2; 270189702Ssam ch->r_io[ATA_SERROR].offset = 0x108 + (unit01 << 7) + (unit10 << 8); 271189702Ssam ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; 272189702Ssam ch->r_io[ATA_SCONTROL].offset = 0x100 + (unit01 << 7) + (unit10 << 8); 273189702Ssam ch->flags |= ATA_NO_SLAVE; 274189702Ssam ch->flags |= ATA_SATA; 275189702Ssam ch->flags |= ATA_KNOWN_PRESENCE; 276189702Ssam 277189702Ssam /* enable PHY state change interrupt */ 278189702Ssam ATA_OUTL(ctlr->r_res2, 0x148 + (unit01 << 7) + (unit10 << 8),(1 << 16)); 279189702Ssam } 280189702Ssam 281189702Ssam if (ctlr->chip->cfg2 & SII_BUG) { 282189702Ssam /* work around errata in early chips */ 283189702Ssam ch->dma.boundary = 8192; 284189702Ssam ch->dma.segsize = 15 * DEV_BSIZE; 285189702Ssam } 286189702Ssam 287189702Ssam ata_pci_hw(dev); 288189702Ssam ch->hw.status = ata_sii_status; 289189702Ssam if (ctlr->chip->cfg2 & SII_SETCLK) 290189702Ssam ch->flags |= ATA_CHECKS_CABLE; 291189702Ssam 292189702Ssam ata_pci_dmainit(dev); 293189702Ssam 294189702Ssam return 0; 295189702Ssam} 296189702Ssam 297189702Ssamstatic int 298189702Ssamata_sii_ch_detach(device_t dev) 299189702Ssam{ 300189702Ssam 301189702Ssam ata_pci_dmafini(dev); 302189702Ssam return (0); 303189702Ssam} 304189702Ssam 305189702Ssamstatic int 306244962Sadrianata_sii_status(device_t dev) 307244962Sadrian{ 308189702Ssam struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 309189702Ssam struct ata_channel *ch = device_get_softc(dev); 310189702Ssam int offset0 = ((ch->unit & 1) << 3) + ((ch->unit & 2) << 8); 311189702Ssam int offset1 = ((ch->unit & 1) << 6) + ((ch->unit & 2) << 8); 312189702Ssam 313189702Ssam /* do we have any PHY events ? */ 314189702Ssam if (ctlr->chip->max_dma >= ATA_SA150 && 315189702Ssam (ATA_INL(ctlr->r_res2, 0x10 + offset0) & 0x00000010)) 316189702Ssam ata_sata_phy_check_events(dev, -1); 317189702Ssam 318189702Ssam if (ATA_INL(ctlr->r_res2, 0xa0 + offset1) & 0x00000800) 319189702Ssam return ata_pci_status(dev); 320189702Ssam else 321189702Ssam return 0; 322189702Ssam} 323189702Ssam 324189702Ssamstatic void 325189702Ssamata_sii_reset(device_t dev) 326189702Ssam{ 327189702Ssam struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); 328189702Ssam struct ata_channel *ch = device_get_softc(dev); 329189702Ssam int offset = ((ch->unit & 1) << 7) + ((ch->unit & 2) << 8); 330189702Ssam uint32_t val; 331189702Ssam 332189702Ssam /* Apply R_ERR on DMA activate FIS errata workaround. */ 333189702Ssam val = ATA_INL(ctlr->r_res2, 0x14c + offset); 334189702Ssam if ((val & 0x3) == 0x1) 335189702Ssam ATA_OUTL(ctlr->r_res2, 0x14c + offset, val & ~0x3); 336189702Ssam 337189702Ssam if (ata_sata_phy_reset(dev, -1, 1)) 338189702Ssam ata_generic_reset(dev); 339189702Ssam else 340189702Ssam ch->devices = 0; 341189702Ssam} 342189702Ssam 343189702Ssamstatic int 344189702Ssamata_sii_setmode(device_t dev, int target, int mode) 345189702Ssam{ 346189702Ssam device_t parent = device_get_parent(dev); 347189702Ssam struct ata_pci_controller *ctlr = device_get_softc(parent); 348189702Ssam struct ata_channel *ch = device_get_softc(dev); 349189702Ssam int rego = (ch->unit << 4) + (target << 1); 350189702Ssam int mreg = ch->unit ? 0x84 : 0x80; 351189702Ssam int mask = 0x03 << (target << 2); 352189702Ssam int mval = pci_read_config(parent, mreg, 1) & ~mask; 353189702Ssam int piomode; 354189702Ssam u_int8_t preg = 0xa4 + rego; 355189702Ssam u_int8_t dreg = 0xa8 + rego; 356189702Ssam u_int8_t ureg = 0xac + rego; 357189702Ssam static const uint16_t piotimings[] = 358189702Ssam { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 }; 359189702Ssam static const uint16_t dmatimings[] = { 0x2208, 0x10c2, 0x10c1 }; 360189702Ssam static const uint8_t udmatimings[] = 361189702Ssam { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 }; 362189702Ssam 363189702Ssam mode = min(mode, ctlr->chip->max_dma); 364189702Ssam 365189702Ssam if (ctlr->chip->cfg2 & SII_SETCLK) { 366189702Ssam if (ata_dma_check_80pin && mode > ATA_UDMA2 && 367189702Ssam (pci_read_config(parent, 0x79, 1) & 368189702Ssam (ch->unit ? 0x02 : 0x01))) { 369189702Ssam ata_print_cable(dev, "controller"); 370189702Ssam mode = ATA_UDMA2; 371189702Ssam } 372189702Ssam } 373189702Ssam if (mode >= ATA_UDMA0) { 374189702Ssam pci_write_config(parent, mreg, 375189702Ssam mval | (0x03 << (target << 2)), 1); 376189702Ssam pci_write_config(parent, ureg, 377189702Ssam (pci_read_config(parent, ureg, 1) & ~0x3f) | 378189702Ssam udmatimings[mode & ATA_MODE_MASK], 1); 379233887Sadrian piomode = ATA_PIO4; 380189702Ssam } else if (mode >= ATA_WDMA0) { 381189702Ssam pci_write_config(parent, mreg, 382189702Ssam mval | (0x02 << (target << 2)), 1); 383189702Ssam pci_write_config(parent, dreg, dmatimings[mode & ATA_MODE_MASK], 2); 384189702Ssam piomode = (mode == ATA_WDMA0) ? ATA_PIO0 : 385189702Ssam (mode == ATA_WDMA1) ? ATA_PIO3 : ATA_PIO4; 386189702Ssam } else { 387189702Ssam pci_write_config(parent, mreg, 388189702Ssam mval | (0x01 << (target << 2)), 1); 389189702Ssam piomode = mode; 390189702Ssam } 391189702Ssam pci_write_config(parent, preg, piotimings[ata_mode2idx(piomode)], 2); 392189702Ssam return (mode); 393189702Ssam} 394189702Ssam 395189702SsamATA_DECLARE_DRIVER(ata_sii); 396189702Ssam