Index: sys/dev/amdsbwd/amd_chipset.h =================================================================== --- sys/dev/amdsbwd/amd_chipset.h (nonexistent) +++ sys/dev/amdsbwd/amd_chipset.h (working copy) @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2016 Andriy Gapon + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * The following registers, bits and magic values are defined in Register + * Reference Guide documents for SB600, SB7x0, SB8x0, SB9x0 southbridges and + * various versions of Fusion Controller Hubs (FCHs). FCHs integrated into + * CPUs are documented in BIOS and Kernel Development Guide documents for + * the corresponding processor families. + * + * At present there are three classes of supported chipsets: + * - SB600 and S7x0 southbridges where the SMBus controller device has + * a PCI Device ID of 0x43851002 and a revision less than 0x40 + * - SB8x0, SB9x0 southbridges and FCHs where the SMBus controller device has + * a PCI Device ID of 0x43851002 and a revision greater than or equal to 0x40 + * or the controller has an ID of 0x780b1022 and a revision less than 0x41 + * - FCHs where the SMBus controller device has a PCI Device ID of 0x780b1022 + * and a revision greater than or equal to 0x41 + * The register definitions are compatible within the classes and may be + * incompatible accross them. + * So far there is no public documentation for "KERNCZ" FCH where the SMBus + * controller has a PCI ID of 0x790b1022. Based on some code in Linux it is + * assumed that revisions less than 0x49 are compatible with the SB8x0 class + * and revisions greater than or equal to 0x49 are compatible with the class + * of FCHs with 0x41+ revisions. + */ + +/* + * IO registers for accessing the PMIO space. */ +#define AMDSB_PMIO_INDEX 0xcd6 +#define AMDSB_PMIO_DATA (PMIO_INDEX + 1) +#define AMDSB_PMIO_WIDTH 2 + +/* Registers in the Watchdog IO space. */ +#define AMDSB_WD_CTRL 0x00 +#define AMDSB_WD_RUN 0x01 +#define AMDSB_WD_FIRED 0x02 +#define AMDSB_WD_SHUTDOWN 0x04 +#define AMDSB_WD_DISABLE 0x08 +#define AMDSB_WD_RESERVED 0x70 +#define AMDSB_WD_RELOAD 0x80 +#define AMDSB_WD_COUNT 0x04 +#define AMDSB_WD_COUNT_MASK 0xffff +#define AMDSB_WDIO_REG_WIDTH 4 + +/* SB7x0 and compatible registers in the PMIO space. */ +#define AMDSB_PM_RESET_STATUS0 0x44 +#define AMDSB_PM_RESET_STATUS1 0x45 +#define AMDSB_WD_RST_STS 0x02 +#define AMDSB_PM_WDT_CTRL 0x69 +#define AMDSB_WDT_DISABLE 0x01 +#define AMDSB_WDT_RES_MASK (0x02 | 0x04) +#define AMDSB_WDT_RES_32US 0x00 +#define AMDSB_WDT_RES_10MS 0x02 +#define AMDSB_WDT_RES_100MS 0x04 +#define AMDSB_WDT_RES_1S 0x06 +#define AMDSB_PM_WDT_BASE_LSB 0x6c +#define AMDSB_PM_WDT_BASE_MSB 0x6f + +/* SB8x0 and compatible registers in the PMIO space. */ +#define AMDSB8_PM_SMBUS_EN 0x2c +#define AMDSB8_SMBUS_EN 0x01 +#define AMDSB8_SMBUS_ADDR_MASK 0xffe0u +#define AMDSB8_PM_WDT_EN 0x48 +#define AMDSB8_WDT_DEC_EN 0x01 +#define AMDSB8_WDT_DISABLE 0x02 +#define AMDSB8_PM_WDT_CTRL 0x4c +#define AMDSB8_WDT_32KHZ 0x00 +#define AMDSB8_WDT_1HZ 0x03 +#define AMDSB8_WDT_RES_MASK 0x03 +#define AMDSB8_PM_RESET_STATUS0 0xc0 +#define AMDSB8_PM_RESET_STATUS1 0xc1 +#define AMDSB8_WD_RST_STS 0x20 + +/* Newer FCH registers in the PMIO space. */ +#define AMDFCH41_PM_DECODE_EN0 0x00 +#define AMDFCH41_SMBUS_EN 0x10 +#define AMDFCH41_WDT_EN 0x80 +#define AMDFCH41_PM_DECODE_EN1 0x01 +#define AMDFCH41_PM_DECODE_EN3 0x03 +#define AMDFCH41_WDT_RES_MASK 0x03 +#define AMDFCH41_WDT_RES_32US 0x00 +#define AMDFCH41_WDT_RES_10MS 0x01 +#define AMDFCH41_WDT_RES_100MS 0x02 +#define AMDFCH41_WDT_RES_1S 0x03 +#define AMDFCH41_WDT_EN_MASK 0x0c +#define AMDFCH41_WDT_ENABLE 0x00 +#define AMDFCH41_PM_ISA_CTRL 0x04 +#define AMDFCH41_MMIO_EN 0x02 + +/* Fixed MMIO addresses for accessing Watchdog and SMBus registers. */ +#define AMDFCH41_WDT_FIXED_ADDR 0xfeb00000u +#define AMDFCH41_MMIO_ADDR 0xfed80000u +#define AMDFCH41_MMIO_SMBUS_OFF 0x0a00 +#define AMDFCH41_MMIO_WDT_OFF 0x0b00 + +/* PCI Device IDs and revisions. */ +#define AMDSB_SMBUS_DEVID 0x43851002 +#define AMDSB8_SMBUS_REVID 0x40 +#define AMDFCH_SMBUS_DEVID 0x780b1022 +#define AMDFCH41_SMBUS_REVID 0x41 +#define AMDCZ_SMBUS_DEVID 0x790b1022 +#define AMDCZ49_SMBUS_REVID 0x49 + Property changes on: sys/dev/amdsbwd/amd_chipset.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: sys/dev/amdsbwd/amdsbwd.c =================================================================== --- sys/dev/amdsbwd/amdsbwd.c (revision 305937) +++ sys/dev/amdsbwd/amdsbwd.c (working copy) @@ -59,38 +59,13 @@ #include #include +#include #include -/* SB7xx RRG 2.3.3.1.1. */ -#define AMDSB_PMIO_INDEX 0xcd6 -#define AMDSB_PMIO_DATA (PMIO_INDEX + 1) -#define AMDSB_PMIO_WIDTH 2 -/* SB7xx RRG 2.3.3.2. */ -#define AMDSB_PM_RESET_STATUS0 0x44 -#define AMDSB_PM_RESET_STATUS1 0x45 -#define AMDSB_WD_RST_STS 0x02 -/* SB7xx RRG 2.3.3.2, RPR 2.36. */ -#define AMDSB_PM_WDT_CTRL 0x69 -#define AMDSB_WDT_DISABLE 0x01 -#define AMDSB_WDT_RES_MASK (0x02 | 0x04) -#define AMDSB_WDT_RES_32US 0x00 -#define AMDSB_WDT_RES_10MS 0x02 -#define AMDSB_WDT_RES_100MS 0x04 -#define AMDSB_WDT_RES_1S 0x06 -#define AMDSB_PM_WDT_BASE_LSB 0x6c -#define AMDSB_PM_WDT_BASE_MSB 0x6f -/* SB8xx RRG 2.3.3. */ -#define AMDSB8_PM_WDT_EN 0x48 -#define AMDSB8_WDT_DEC_EN 0x01 -#define AMDSB8_WDT_DISABLE 0x02 -#define AMDSB8_PM_WDT_CTRL 0x4c -#define AMDSB8_WDT_32KHZ 0x00 -#define AMDSB8_WDT_1HZ 0x03 -#define AMDSB8_WDT_RES_MASK 0x03 -#define AMDSB8_PM_RESET_STATUS0 0xC0 -#define AMDSB8_PM_RESET_STATUS1 0xC1 -#define AMDSB8_WD_RST_STS 0x20 -/* SB7xx RRG 2.3.4, WDRT. */ +/* + * Registers in the Watchdog IO space. + * See SB7xx RRG 2.3.4, WDRT. + */ #define AMDSB_WD_CTRL 0x00 #define AMDSB_WD_RUN 0x01 #define AMDSB_WD_FIRED 0x02 @@ -101,28 +76,6 @@ #define AMDSB_WD_COUNT 0x04 #define AMDSB_WD_COUNT_MASK 0xffff #define AMDSB_WDIO_REG_WIDTH 4 -/* WDRT */ -#define MAXCOUNT_MIN_VALUE 511 -/* SB7xx RRG 2.3.1.1, SB600 RRG 2.3.1.1, SB8xx RRG 2.3.1. */ -#define AMDSB_SMBUS_DEVID 0x43851002 -#define AMDSB8_SMBUS_REVID 0x40 -#define AMDHUDSON_SMBUS_DEVID 0x780b1022 -#define AMDKERNCZ_SMBUS_DEVID 0x790b1022 -/* BKDG Family 16h Models 30h - 3Fh */ -#define AMDFCH16H3XH_PM_WDT_EN 0x00 -#define AMDFCH_WDT_DEC_EN 0x80 -#define AMDFCH16H3XH_PM_WDT_CTRL 0x03 -#define AMDFCH_WDT_RES_MASK 0x03 -#define AMDFCH_WDT_RES_32US 0x00 -#define AMDFCH_WDT_RES_10MS 0x01 -#define AMDFCH_WDT_RES_100MS 0x02 -#define AMDFCH_WDT_RES_1S 0x03 -#define AMDFCH_WDT_ENABLE_MASK 0x0c -#define AMDFCH_WDT_ENABLE 0x00 -#define AMDFCH16H3XH_PM_MMIO_CTRL 0x04 -#define AMDFCH_WDT_MMIO_EN 0x02 -#define AMDFCH16H3XH_WDT_ADDR1 0xfed80b00u -#define AMDFCH16H3XH_WDT_ADDR2 0xfeb00000u #define amdsbwd_verbose_printf(dev, ...) \ do { \ @@ -297,8 +250,8 @@ if (smb_dev == NULL) return; if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID && - pci_get_devid(smb_dev) != AMDHUDSON_SMBUS_DEVID && - pci_get_devid(smb_dev) != AMDKERNCZ_SMBUS_DEVID) + pci_get_devid(smb_dev) != AMDFCH_SMBUS_DEVID && + pci_get_devid(smb_dev) != AMDCZ_SMBUS_DEVID) return; child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "amdsbwd", -1); @@ -397,30 +350,30 @@ } static void -amdsbwd_probe_fch_16h_3xh(device_t dev, struct resource *pmres, uint32_t *addr) +amdsbwd_probe_fch41(device_t dev, struct resource *pmres, uint32_t *addr) { uint8_t val; - val = pmio_read(pmres, AMDFCH16H3XH_PM_MMIO_CTRL); - if ((val & AMDFCH_WDT_MMIO_EN) != 0) { + val = pmio_read(pmres, AMDFCH41_PM_ISA_CTRL); + if ((val & AMDFCH41_MMIO_EN) != 0) { /* Fixed offset for the watchdog within ACPI MMIO range. */ amdsbwd_verbose_printf(dev, "ACPI MMIO range is enabled\n"); - *addr = AMDFCH16H3XH_WDT_ADDR1; + *addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_WDT_OFF; } else { /* * Enable decoding of watchdog MMIO address. */ - val = pmio_read(pmres, AMDFCH16H3XH_PM_WDT_EN); - val |= AMDFCH_WDT_DEC_EN; - pmio_write(pmres, AMDFCH16H3XH_PM_WDT_EN, val); + val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0); + val |= AMDFCH41_WDT_EN; + pmio_write(pmres, AMDFCH41_PM_DECODE_EN0, val); #ifdef AMDSBWD_DEBUG - val = pmio_read(pmres, AMDFCH16H3XH_PM_WDT_EN); - device_printf(dev, "AMDFCH16H3XH_PM_WDT_EN value = %#04x\n", + val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0); + device_printf(dev, "AMDFCH41_PM_DECODE_EN0 value = %#04x\n", val); #endif /* Special fixed MMIO range for the watchdog. */ - *addr = AMDFCH16H3XH_WDT_ADDR2; + *addr = AMDFCH41_WDT_FIXED_ADDR; } /* @@ -427,18 +380,18 @@ * Set watchdog timer tick to 1s and * enable the watchdog device (in stopped state). */ - val = pmio_read(pmres, AMDFCH16H3XH_PM_WDT_CTRL); - val &= ~AMDFCH_WDT_RES_MASK; - val |= AMDFCH_WDT_RES_1S; - val &= ~AMDFCH_WDT_ENABLE_MASK; - val |= AMDFCH_WDT_ENABLE; - pmio_write(pmres, AMDFCH16H3XH_PM_WDT_CTRL, val); + val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3); + val &= ~AMDFCH41_WDT_RES_MASK; + val |= AMDFCH41_WDT_RES_1S; + val &= ~AMDFCH41_WDT_EN_MASK; + val |= AMDFCH41_WDT_ENABLE; + pmio_write(pmres, AMDFCH41_PM_DECODE_EN3, val); #ifdef AMDSBWD_DEBUG - val = pmio_read(pmres, AMDFCH16H3XH_PM_WDT_CTRL); - amdsbwd_verbose_printf(dev, "AMDFCH16H3XH_PM_WDT_CTRL value = %#04x\n", + val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3); + amdsbwd_verbose_printf(dev, "AMDFCH41_PM_DECODE_EN3 value = %#04x\n", val); #endif - device_set_desc(dev, "AMD FCH Rev 42h+ Watchdog Timer"); + device_set_desc(dev, "AMD FCH Rev 41h+ Watchdog Timer"); } static int @@ -476,11 +429,12 @@ revid = pci_get_revid(smb_dev); if (devid == AMDSB_SMBUS_DEVID && revid < AMDSB8_SMBUS_REVID) amdsbwd_probe_sb7xx(dev, res, &addr); - else if (devid == AMDSB_SMBUS_DEVID || devid == AMDKERNCZ_SMBUS_DEVID || - (devid == AMDHUDSON_SMBUS_DEVID && revid < 0x42)) + else if (devid == AMDSB_SMBUS_DEVID || + (devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) || + (devid == AMDCZ_SMBUS_DEVID && revid < AMDCZ49_SMBUS_REVID)) amdsbwd_probe_sb8xx(dev, res, &addr); else - amdsbwd_probe_fch_16h_3xh(dev, res, &addr); + amdsbwd_probe_fch41(dev, res, &addr); bus_release_resource(dev, SYS_RES_IOPORT, rid, res); bus_delete_resource(dev, SYS_RES_IOPORT, rid); Index: sys/dev/intpm/intpm.c =================================================================== --- sys/dev/intpm/intpm.c (revision 305937) +++ sys/dev/intpm/intpm.c (working copy) @@ -43,6 +43,7 @@ #include #include #include +#include #include "opt_intpm.h" @@ -103,12 +104,11 @@ case 0x43721002: device_set_desc(dev, "ATI IXP400 SMBus Controller"); break; - case 0x43851002: + case AMDSB_SMBUS_DEVID: device_set_desc(dev, "AMD SB600/7xx/8xx/9xx SMBus Controller"); break; - case 0x780b1022: /* AMD FCH */ - if (pci_get_revid(dev) < 0x40) - return (ENXIO); + case AMDFCH_SMBUS_DEVID: /* AMD FCH */ + case AMDCZ_SMBUS_DEVID: /* AMD Carizzo FCH */ device_set_desc(dev, "AMD FCH SMBus Controller"); break; default: @@ -119,7 +119,7 @@ } static uint8_t -sb8xx_pmio_read(struct resource *res, uint8_t reg) +amd_pmio_read(struct resource *res, uint8_t reg) { bus_write_1(res, 0, reg); /* Index */ return (bus_read_1(res, 1)); /* Data */ @@ -128,27 +128,18 @@ static int sb8xx_attach(device_t dev) { - static const int AMDSB_PMIO_INDEX = 0xcd6; - static const int AMDSB_PMIO_WIDTH = 2; - static const int AMDSB8_SMBUS_ADDR = 0x2c; - static const int AMDSB8_SMBUS_EN = 0x01; - static const int AMDSB8_SMBUS_ADDR_MASK = ~0x1fu; static const int AMDSB_SMBIO_WIDTH = 0x14; - static const int AMDSB_SMBUS_CFG = 0x10; - static const int AMDSB_SMBUS_IRQ = 0x01; - static const int AMDSB_SMBUS_REV_MASK = ~0x0fu; - static const int AMDSB_SMBUS_REV_SHIFT = 4; - static const int AMDSB_IO_RID = 0; - struct intsmb_softc *sc; struct resource *res; + uint32_t devid; + uint8_t revid; uint16_t addr; - uint8_t cfg; int rid; int rc; + bool enabled; sc = device_get_softc(dev); - rid = AMDSB_IO_RID; + rid = 0; rc = bus_set_resource(dev, SYS_RES_IOPORT, rid, AMDSB_PMIO_INDEX, AMDSB_PMIO_WIDTH); if (rc != 0) { @@ -156,26 +147,38 @@ return (ENXIO); } res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, - RF_ACTIVE | RF_SHAREABLE); + RF_ACTIVE); if (res == NULL) { device_printf(dev, "bus_alloc_resource for PM IO failed\n"); return (ENXIO); } - addr = sb8xx_pmio_read(res, AMDSB8_SMBUS_ADDR + 1); - addr <<= 8; - addr |= sb8xx_pmio_read(res, AMDSB8_SMBUS_ADDR); + devid = pci_get_devid(dev); + revid = pci_get_revid(dev); + if (devid == AMDSB_SMBUS_DEVID || + (devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) || + (devid == AMDCZ_SMBUS_DEVID && revid < AMDCZ49_SMBUS_REVID)) { + addr = amd_pmio_read(res, AMDSB8_PM_SMBUS_EN + 1); + addr <<= 8; + addr |= amd_pmio_read(res, AMDSB8_PM_SMBUS_EN); + enabled = (addr & AMDSB8_SMBUS_EN) != 0; + addr &= AMDSB8_SMBUS_ADDR_MASK; + } else { + addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN0); + enabled = (addr & AMDFCH41_SMBUS_EN) != 0; + addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN1); + addr <<= 8; + } bus_release_resource(dev, SYS_RES_IOPORT, rid, res); bus_delete_resource(dev, SYS_RES_IOPORT, rid); - if ((addr & AMDSB8_SMBUS_EN) == 0) { - device_printf(dev, "SB8xx SMBus not enabled\n"); + if (!enabled) { + device_printf(dev, "SB8xx/SB9xx/FCH SMBus not enabled\n"); return (ENXIO); } - addr &= AMDSB8_SMBUS_ADDR_MASK; - sc->io_rid = AMDSB_IO_RID; + sc->io_rid = 0; rc = bus_set_resource(dev, SYS_RES_IOPORT, sc->io_rid, addr, AMDSB_SMBIO_WIDTH); if (rc != 0) { @@ -187,15 +190,8 @@ return (ENXIO); } sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid, - RF_ACTIVE | RF_SHAREABLE); - cfg = bus_read_1(sc->io_res, AMDSB_SMBUS_CFG); - + RF_ACTIVE); sc->poll = 1; - device_printf(dev, "intr %s disabled ", - (cfg & AMDSB_SMBUS_IRQ) != 0 ? "IRQ" : "SMI"); - printf("revision %d\n", - (cfg & AMDSB_SMBUS_REV_MASK) >> AMDSB_SMBUS_REV_SHIFT); - return (0); } @@ -237,11 +233,12 @@ sc->cfg_irq9 = 1; break; #endif - case 0x43851002: - if (pci_get_revid(dev) >= 0x40) + case AMDSB_SMBUS_DEVID: + if (pci_get_revid(dev) >= AMDSB8_SMBUS_REVID) sc->sb8xx = 1; break; - case 0x780b1022: + case AMDFCH_SMBUS_DEVID: + case AMDCZ_SMBUS_DEVID: sc->sb8xx = 1; break; }