Some VIA SATA controllers provide access to non-standard SATA registers via

PCI config space. Use them to implement hot-plug and link speed reporting.
Tested on ASRock PV530 board with VX900 chipset.
This commit is contained in:
Alexander Motin 2010-11-18 08:03:40 +00:00
parent 144df3a28f
commit ee597c8246
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=215449

View File

@ -63,6 +63,12 @@ static int ata_via_new_setmode(device_t dev, int target, int mode);
static int ata_via_sata_ch_attach(device_t dev);
static int ata_via_sata_getrev(device_t dev, int target);
static int ata_via_sata_setmode(device_t dev, int target, int mode);
static void ata_via_sata_reset(device_t dev);
static int ata_via_sata_scr_read(device_t dev, int port, int reg,
u_int32_t *result);
static int ata_via_sata_scr_write(device_t dev, int port, int reg,
u_int32_t value);
static int ata_via_sata_status(device_t dev);
/* misc defines */
#define VIA33 0
@ -153,11 +159,12 @@ ata_via_chipinit(device_t dev)
if (ata_ahci_chipinit(dev) != ENXIO)
return (0);
}
/* 2 SATA without SATA registers on first channel + 1 PATA on second */
/* 2 SATA with "SATA registers" at PCI config space + PATA on secondary */
if (ctlr->chip->cfg2 & VIASATA) {
ctlr->ch_attach = ata_via_sata_ch_attach;
ctlr->setmode = ata_via_sata_setmode;
ctlr->getrev = ata_via_sata_getrev;
ctlr->reset = ata_via_sata_reset;
return 0;
}
/* Legacy SATA/SATA+PATA with SATA registers in BAR(5). */
@ -405,18 +412,30 @@ ata_via_sata_ch_attach(device_t dev)
if (ata_pci_ch_attach(dev))
return ENXIO;
if (ch->unit == 0)
if (ch->unit == 0) {
ch->hw.status = ata_via_sata_status;
ch->hw.pm_read = ata_via_sata_scr_read;
ch->hw.pm_write = ata_via_sata_scr_write;
ch->flags |= ATA_PERIODIC_POLL;
ch->flags |= ATA_SATA;
ata_sata_scr_write(ch, 0, ATA_SERROR, 0xffffffff);
ata_sata_scr_write(ch, 1, ATA_SERROR, 0xffffffff);
}
return (0);
}
static int
ata_via_sata_getrev(device_t dev, int target)
{
device_t parent = device_get_parent(dev);
struct ata_channel *ch = device_get_softc(dev);
if (ch->unit == 0)
return (1);
if (ch->unit == 0) {
if (pci_read_config(parent, 0xa0 + target, 1) & 0x10)
return (2);
else
return (1);
}
return (0);
}
@ -430,5 +449,110 @@ ata_via_sata_setmode(device_t dev, int target, int mode)
return (ata_via_old_setmode(dev, target, mode));
}
static void
ata_via_sata_reset(device_t dev)
{
struct ata_channel *ch = device_get_softc(dev);
int devs;
if (ch->unit == 0) {
devs = ata_sata_phy_reset(dev, 0, 0);
DELAY(10000);
devs += ata_sata_phy_reset(dev, 1, 0);
} else
devs = 1;
if (devs)
ata_generic_reset(dev);
}
static int
ata_via_sata_scr_read(device_t dev, int port, int reg, u_int32_t *result)
{
struct ata_channel *ch;
device_t parent;
uint32_t val;
parent = device_get_parent(dev);
ch = device_get_softc(dev);
port = (port == 1) ? 1 : 0;
switch (reg) {
case ATA_SSTATUS:
val = pci_read_config(parent, 0xa0 + port, 1);
*result = val & 0x03;
if (*result != ATA_SS_DET_NO_DEVICE) {
if (val & 0x04)
*result |= ATA_SS_IPM_PARTIAL;
else if (val & 0x08)
*result |= ATA_SS_IPM_SLUMBER;
else
*result |= ATA_SS_IPM_ACTIVE;
if (val & 0x10)
*result |= ATA_SS_SPD_GEN2;
else
*result |= ATA_SS_SPD_GEN1;
}
break;
case ATA_SERROR:
*result = pci_read_config(parent, 0xa8 + port * 4, 4);
break;
case ATA_SCONTROL:
val = pci_read_config(parent, 0xa4 + port, 1);
*result = 0;
if (val & 0x01)
*result |= ATA_SC_DET_RESET;
if (val & 0x02)
*result |= ATA_SC_DET_DISABLE;
if (val & 0x04)
*result |= ATA_SC_IPM_DIS_PARTIAL;
if (val & 0x08)
*result |= ATA_SC_IPM_DIS_SLUMBER;
break;
default:
return (EINVAL);
}
return (0);
}
static int
ata_via_sata_scr_write(device_t dev, int port, int reg, u_int32_t value)
{
struct ata_channel *ch;
device_t parent;
uint32_t val;
parent = device_get_parent(dev);
ch = device_get_softc(dev);
port = (port == 1) ? 1 : 0;
switch (reg) {
case ATA_SERROR:
pci_write_config(parent, 0xa8 + port * 4, value, 4);
break;
case ATA_SCONTROL:
val = 0;
if (value & ATA_SC_DET_RESET)
val |= 0x01;
if (value & ATA_SC_DET_DISABLE)
val |= 0x02;
if (value & ATA_SC_IPM_DIS_PARTIAL)
val |= 0x04;
if (value & ATA_SC_IPM_DIS_SLUMBER)
val |= 0x08;
pci_write_config(parent, 0xa4 + port, val, 1);
break;
default:
return (EINVAL);
}
return (0);
}
static int
ata_via_sata_status(device_t dev)
{
ata_sata_phy_check_events(dev, 0);
ata_sata_phy_check_events(dev, 1);
return (ata_pci_status(dev));
}
ATA_DECLARE_DRIVER(ata_via);
MODULE_DEPEND(ata_via, ata_ahci, 1, 1, 1);