Date: Tue, 23 Sep 2014 06:31:15 +0000 (UTC) From: Rui Paulo <rpaulo@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r272017 - in head/sys: conf dev/alpm dev/amdpm dev/intpm dev/viapm modules/i2c/controllers/alpm modules/i2c/controllers/amdpm modules/i2c/controllers/intpm modules/i2c/controllers/viapm... Message-ID: <201409230631.s8N6VFlM085108@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rpaulo Date: Tue Sep 23 06:31:15 2014 New Revision: 272017 URL: http://svnweb.freebsd.org/changeset/base/272017 Log: Move all the power management (SMBus) drivers to their own directory, away from sys/pci. Added: head/sys/dev/alpm/ head/sys/dev/alpm/alpm.c - copied unchanged from r272014, head/sys/pci/alpm.c head/sys/dev/amdpm/ head/sys/dev/amdpm/amdpm.c - copied unchanged from r272014, head/sys/pci/amdpm.c head/sys/dev/intpm/ head/sys/dev/intpm/intpm.c - copied, changed from r272014, head/sys/pci/intpm.c head/sys/dev/intpm/intpmreg.h - copied unchanged from r272014, head/sys/pci/intpmreg.h head/sys/dev/viapm/ head/sys/dev/viapm/viapm.c - copied unchanged from r272014, head/sys/pci/viapm.c Deleted: head/sys/pci/alpm.c head/sys/pci/amdpm.c head/sys/pci/intpm.c head/sys/pci/intpmreg.h head/sys/pci/viapm.c Modified: head/sys/conf/files head/sys/modules/i2c/controllers/alpm/Makefile head/sys/modules/i2c/controllers/amdpm/Makefile head/sys/modules/i2c/controllers/intpm/Makefile head/sys/modules/i2c/controllers/viapm/Makefile Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Tue Sep 23 05:54:18 2014 (r272016) +++ head/sys/conf/files Tue Sep 23 06:31:15 2014 (r272017) @@ -646,6 +646,7 @@ dev/aic7xxx/aic7xxx_pci.c optional ahc p dev/aic7xxx/aic7xxx_reg_print.c optional ahc ahc_reg_pretty_print dev/alc/if_alc.c optional alc pci dev/ale/if_ale.c optional ale pci +dev/alpm/alpm.c optional alpm pci dev/altera/avgen/altera_avgen.c optional altera_avgen dev/altera/avgen/altera_avgen_fdt.c optional altera_avgen fdt dev/altera/avgen/altera_avgen_nexus.c optional altera_avgen @@ -654,6 +655,7 @@ dev/altera/sdcard/altera_sdcard_disk.c o dev/altera/sdcard/altera_sdcard_io.c optional altera_sdcard dev/altera/sdcard/altera_sdcard_fdt.c optional altera_sdcard fdt dev/altera/sdcard/altera_sdcard_nexus.c optional altera_sdcard +dev/amdpm/amdpm.c optional amdpm pci | nfpm pci dev/amdsmb/amdsmb.c optional amdsmb pci dev/amr/amr.c optional amr dev/amr/amr_cam.c optional amrp amr @@ -1484,6 +1486,7 @@ dev/iicbus/s35390a.c optional s35390a dev/iir/iir.c optional iir dev/iir/iir_ctrl.c optional iir dev/iir/iir_pci.c optional iir pci +dev/intpm/intpm.c optional intpm pci # XXX Work around clang warning, until maintainer approves fix. dev/ips/ips.c optional ips \ compile-with "${NORMAL_C} ${NO_WSOMETIMES_UNINITIALIZED}" @@ -2584,7 +2587,7 @@ dev/utopia/idtphy.c optional utopia dev/utopia/suni.c optional utopia dev/utopia/utopia.c optional utopia dev/vge/if_vge.c optional vge - +dev/viapm/viapm.c optional viapm pci dev/vkbd/vkbd.c optional vkbd dev/vr/if_vr.c optional vr pci dev/vt/colors/vt_termcolors.c optional vt @@ -3868,10 +3871,6 @@ opencrypto/cryptodeflate.c optional cryp opencrypto/rmd160.c optional crypto | ipsec opencrypto/skipjack.c optional crypto opencrypto/xform.c optional crypto -pci/alpm.c optional alpm pci -pci/amdpm.c optional amdpm pci | nfpm pci -pci/intpm.c optional intpm pci -pci/viapm.c optional viapm pci rpc/auth_none.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd rpc/auth_unix.c optional krpc | nfslockd | nfsclient | nfscl | nfsd rpc/authunix_prot.c optional krpc | nfslockd | nfsclient | nfsserver | nfscl | nfsd Copied: head/sys/dev/alpm/alpm.c (from r272014, head/sys/pci/alpm.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/alpm/alpm.c Tue Sep 23 06:31:15 2014 (r272017, copy of r272014, head/sys/pci/alpm.c) @@ -0,0 +1,663 @@ +/*- + * Copyright (c) 1998, 1999, 2001 Nicolas Souchu + * 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. + */ + +/* + * Power Management support for the Acer M15x3 chipsets + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/systm.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> + +#include <dev/smbus/smbconf.h> +#include "smbus_if.h" + +#define ALPM_DEBUG(x) if (alpm_debug) (x) + +#ifdef DEBUG +static int alpm_debug = 1; +#else +static int alpm_debug = 0; +#endif + +#define ACER_M1543_PMU_ID 0x710110b9 + +/* + * I/O registers offsets - the base address is programmed via the + * SMBBA PCI configuration register + */ +#define SMBSTS 0x0 /* SMBus host/slave status register */ +#define SMBCMD 0x1 /* SMBus host/slave command register */ +#define SMBSTART 0x2 /* start to generate programmed cycle */ +#define SMBHADDR 0x3 /* host address register */ +#define SMBHDATA 0x4 /* data A register for host controller */ +#define SMBHDATB 0x5 /* data B register for host controller */ +#define SMBHBLOCK 0x6 /* block register for host controller */ +#define SMBHCMD 0x7 /* command register for host controller */ + +/* SMBHADDR mask. */ +#define LSB 0x1 /* XXX: Better name: Read/Write? */ + +/* SMBSTS masks */ +#define TERMINATE 0x80 +#define BUS_COLLI 0x40 +#define DEVICE_ERR 0x20 +#define SMI_I_STS 0x10 +#define HST_BSY 0x08 +#define IDL_STS 0x04 +#define HSTSLV_STS 0x02 +#define HSTSLV_BSY 0x01 + +/* SMBCMD masks */ +#define SMB_BLK_CLR 0x80 +#define T_OUT_CMD 0x08 +#define ABORT_HOST 0x04 + +/* SMBus commands */ +#define SMBQUICK 0x00 +#define SMBSRBYTE 0x10 /* send/receive byte */ +#define SMBWRBYTE 0x20 /* write/read byte */ +#define SMBWRWORD 0x30 /* write/read word */ +#define SMBWRBLOCK 0x40 /* write/read block */ + +/* PCI configuration registers and masks + */ +#define COM 0x4 +#define COM_ENABLE_IO 0x1 + +#define SMBBA PCIR_BAR(1) + +#define ATPC 0x5b +#define ATPC_SMBCTRL 0x04 /* XX linux has this as 0x6 */ + +#define SMBHSI 0xe0 +#define SMBHSI_SLAVE 0x2 +#define SMBHSI_HOST 0x1 + +#define SMBHCBC 0xe2 +#define SMBHCBC_CLOCK 0x70 + +#define SMBCLOCK_149K 0x0 +#define SMBCLOCK_74K 0x20 +#define SMBCLOCK_37K 0x40 +#define SMBCLOCK_223K 0x80 +#define SMBCLOCK_111K 0xa0 +#define SMBCLOCK_55K 0xc0 + +struct alpm_softc { + int base; + struct resource *res; + bus_space_tag_t smbst; + bus_space_handle_t smbsh; + device_t smbus; + struct mtx lock; +}; + +#define ALPM_LOCK(alpm) mtx_lock(&(alpm)->lock) +#define ALPM_UNLOCK(alpm) mtx_unlock(&(alpm)->lock) +#define ALPM_LOCK_ASSERT(alpm) mtx_assert(&(alpm)->lock, MA_OWNED) + +#define ALPM_SMBINB(alpm,register) \ + (bus_space_read_1(alpm->smbst, alpm->smbsh, register)) +#define ALPM_SMBOUTB(alpm,register,value) \ + (bus_space_write_1(alpm->smbst, alpm->smbsh, register, value)) + +static int alpm_detach(device_t dev); + +static int +alpm_probe(device_t dev) +{ + + if (pci_get_devid(dev) == ACER_M1543_PMU_ID) { + device_set_desc(dev, "AcerLabs M15x3 Power Management Unit"); + + return (BUS_PROBE_DEFAULT); + } + + return (ENXIO); +} + +static int +alpm_attach(device_t dev) +{ + int rid; + u_int32_t l; + struct alpm_softc *alpm; + + alpm = device_get_softc(dev); + + /* Unlock SMBIO base register access */ + l = pci_read_config(dev, ATPC, 1); + pci_write_config(dev, ATPC, l & ~ATPC_SMBCTRL, 1); + + /* + * XX linux sets clock to 74k, should we? + l = pci_read_config(dev, SMBHCBC, 1); + l &= 0x1f; + l |= SMBCLOCK_74K; + pci_write_config(dev, SMBHCBC, l, 1); + */ + + if (bootverbose || alpm_debug) { + l = pci_read_config(dev, SMBHSI, 1); + device_printf(dev, "%s/%s", + (l & SMBHSI_HOST) ? "host":"nohost", + (l & SMBHSI_SLAVE) ? "slave":"noslave"); + + l = pci_read_config(dev, SMBHCBC, 1); + switch (l & SMBHCBC_CLOCK) { + case SMBCLOCK_149K: + printf(" 149K"); + break; + case SMBCLOCK_74K: + printf(" 74K"); + break; + case SMBCLOCK_37K: + printf(" 37K"); + break; + case SMBCLOCK_223K: + printf(" 223K"); + break; + case SMBCLOCK_111K: + printf(" 111K"); + break; + case SMBCLOCK_55K: + printf(" 55K"); + break; + default: + printf("unkown"); + break; + } + printf("\n"); + } + + rid = SMBBA; + alpm->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, + RF_ACTIVE); + + if (alpm->res == NULL) { + device_printf(dev,"Could not allocate Bus space\n"); + return (ENXIO); + } + alpm->smbst = rman_get_bustag(alpm->res); + alpm->smbsh = rman_get_bushandle(alpm->res); + mtx_init(&alpm->lock, device_get_nameunit(dev), "alpm", MTX_DEF); + + /* attach the smbus */ + alpm->smbus = device_add_child(dev, "smbus", -1); + if (alpm->smbus == NULL) { + alpm_detach(dev); + return (EINVAL); + } + bus_generic_attach(dev); + + return (0); +} + +static int +alpm_detach(device_t dev) +{ + struct alpm_softc *alpm = device_get_softc(dev); + + if (alpm->smbus) { + device_delete_child(dev, alpm->smbus); + alpm->smbus = NULL; + } + mtx_destroy(&alpm->lock); + + if (alpm->res) + bus_release_resource(dev, SYS_RES_IOPORT, SMBBA, alpm->res); + + return (0); +} + +static int +alpm_callback(device_t dev, int index, void *data) +{ + int error = 0; + + switch (index) { + case SMB_REQUEST_BUS: + case SMB_RELEASE_BUS: + /* ok, bus allocation accepted */ + break; + default: + error = EINVAL; + } + + return (error); +} + +static int +alpm_clear(struct alpm_softc *sc) +{ + ALPM_SMBOUTB(sc, SMBSTS, 0xff); + DELAY(10); + + return (0); +} + +#if 0 +static int +alpm_abort(struct alpm_softc *sc) +{ + ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST); + + return (0); +} +#endif + +static int +alpm_idle(struct alpm_softc *sc) +{ + u_char sts; + + sts = ALPM_SMBINB(sc, SMBSTS); + + ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts)); + + return (sts & IDL_STS); +} + +/* + * Poll the SMBus controller + */ +static int +alpm_wait(struct alpm_softc *sc) +{ + int count = 10000; + u_char sts = 0; + int error; + + /* wait for command to complete and SMBus controller is idle */ + while (count--) { + DELAY(10); + sts = ALPM_SMBINB(sc, SMBSTS); + if (sts & SMI_I_STS) + break; + } + + ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts)); + + error = SMB_ENOERR; + + if (!count) + error |= SMB_ETIMEOUT; + + if (sts & TERMINATE) + error |= SMB_EABORT; + + if (sts & BUS_COLLI) + error |= SMB_ENOACK; + + if (sts & DEVICE_ERR) + error |= SMB_EBUSERR; + + if (error != SMB_ENOERR) + alpm_clear(sc); + + return (error); +} + +static int +alpm_quick(device_t dev, u_char slave, int how) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + int error; + + ALPM_LOCK(sc); + alpm_clear(sc); + if (!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (EBUSY); + } + + switch (how) { + case SMB_QWRITE: + ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave)); + ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); + break; + case SMB_QREAD: + ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave)); + ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); + break; + default: + panic("%s: unknown QUICK command (%x)!", __func__, + how); + } + ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + error = alpm_wait(sc); + + ALPM_DEBUG(printf(", error=0x%x\n", error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static int +alpm_sendb(device_t dev, u_char slave, char byte) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + int error; + + ALPM_LOCK(sc); + alpm_clear(sc); + if (!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (SMB_EBUSY); + } + + ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); + ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); + ALPM_SMBOUTB(sc, SMBHDATA, byte); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + error = alpm_wait(sc); + + ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static int +alpm_recvb(device_t dev, u_char slave, char *byte) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + int error; + + ALPM_LOCK(sc); + alpm_clear(sc); + if (!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (SMB_EBUSY); + } + + ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); + ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + if ((error = alpm_wait(sc)) == SMB_ENOERR) + *byte = ALPM_SMBINB(sc, SMBHDATA); + + ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static int +alpm_writeb(device_t dev, u_char slave, char cmd, char byte) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + int error; + + ALPM_LOCK(sc); + alpm_clear(sc); + if (!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (SMB_EBUSY); + } + + ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); + ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); + ALPM_SMBOUTB(sc, SMBHDATA, byte); + ALPM_SMBOUTB(sc, SMBHCMD, cmd); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + error = alpm_wait(sc); + + ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static int +alpm_readb(device_t dev, u_char slave, char cmd, char *byte) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + int error; + + ALPM_LOCK(sc); + alpm_clear(sc); + if (!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (SMB_EBUSY); + } + + ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); + ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); + ALPM_SMBOUTB(sc, SMBHCMD, cmd); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + if ((error = alpm_wait(sc)) == SMB_ENOERR) + *byte = ALPM_SMBINB(sc, SMBHDATA); + + ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static int +alpm_writew(device_t dev, u_char slave, char cmd, short word) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + int error; + + ALPM_LOCK(sc); + alpm_clear(sc); + if (!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (SMB_EBUSY); + } + + ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); + ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); + ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff); + ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8); + ALPM_SMBOUTB(sc, SMBHCMD, cmd); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + error = alpm_wait(sc); + + ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static int +alpm_readw(device_t dev, u_char slave, char cmd, short *word) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + int error; + u_char high, low; + + ALPM_LOCK(sc); + alpm_clear(sc); + if (!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (SMB_EBUSY); + } + + ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); + ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); + ALPM_SMBOUTB(sc, SMBHCMD, cmd); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + if ((error = alpm_wait(sc)) == SMB_ENOERR) { + low = ALPM_SMBINB(sc, SMBHDATA); + high = ALPM_SMBINB(sc, SMBHDATB); + + *word = ((high & 0xff) << 8) | (low & 0xff); + } + + ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static int +alpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + u_char i; + int error; + + if (count < 1 || count > 32) + return (SMB_EINVAL); + + ALPM_LOCK(sc); + alpm_clear(sc); + if(!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (SMB_EBUSY); + } + + ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); + + /* set the cmd and reset the + * 32-byte long internal buffer */ + ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); + + ALPM_SMBOUTB(sc, SMBHDATA, count); + + /* fill the 32-byte internal buffer */ + for (i = 0; i < count; i++) { + ALPM_SMBOUTB(sc, SMBHBLOCK, buf[i]); + DELAY(2); + } + ALPM_SMBOUTB(sc, SMBHCMD, cmd); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + error = alpm_wait(sc); + + ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static int +alpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) +{ + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); + u_char data, len, i; + int error; + + if (*count < 1 || *count > 32) + return (SMB_EINVAL); + + ALPM_LOCK(sc); + alpm_clear(sc); + if (!alpm_idle(sc)) { + ALPM_UNLOCK(sc); + return (SMB_EBUSY); + } + + ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); + + /* set the cmd and reset the + * 32-byte long internal buffer */ + ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); + + ALPM_SMBOUTB(sc, SMBHCMD, cmd); + ALPM_SMBOUTB(sc, SMBSTART, 0xff); + + if ((error = alpm_wait(sc)) != SMB_ENOERR) + goto error; + + len = ALPM_SMBINB(sc, SMBHDATA); + + /* read the 32-byte internal buffer */ + for (i = 0; i < len; i++) { + data = ALPM_SMBINB(sc, SMBHBLOCK); + if (i < *count) + buf[i] = data; + DELAY(2); + } + *count = len; + +error: + ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); + ALPM_UNLOCK(sc); + + return (error); +} + +static devclass_t alpm_devclass; + +static device_method_t alpm_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, alpm_probe), + DEVMETHOD(device_attach, alpm_attach), + DEVMETHOD(device_detach, alpm_detach), + + /* smbus interface */ + DEVMETHOD(smbus_callback, alpm_callback), + DEVMETHOD(smbus_quick, alpm_quick), + DEVMETHOD(smbus_sendb, alpm_sendb), + DEVMETHOD(smbus_recvb, alpm_recvb), + DEVMETHOD(smbus_writeb, alpm_writeb), + DEVMETHOD(smbus_readb, alpm_readb), + DEVMETHOD(smbus_writew, alpm_writew), + DEVMETHOD(smbus_readw, alpm_readw), + DEVMETHOD(smbus_bwrite, alpm_bwrite), + DEVMETHOD(smbus_bread, alpm_bread), + + { 0, 0 } +}; + +static driver_t alpm_driver = { + "alpm", + alpm_methods, + sizeof(struct alpm_softc) +}; + +DRIVER_MODULE(alpm, pci, alpm_driver, alpm_devclass, 0, 0); +DRIVER_MODULE(smbus, alpm, smbus_driver, smbus_devclass, 0, 0); +MODULE_DEPEND(alpm, pci, 1, 1, 1); +MODULE_DEPEND(alpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); +MODULE_VERSION(alpm, 1); Copied: head/sys/dev/amdpm/amdpm.c (from r272014, head/sys/pci/amdpm.c) ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/amdpm/amdpm.c Tue Sep 23 06:31:15 2014 (r272017, copy of r272014, head/sys/pci/amdpm.c) @@ -0,0 +1,668 @@ +/*- + * Copyright (c) 2000 Matthew C. Forman + * + * Based (heavily) on alpm.c which is: + * + * Copyright (c) 1998, 1999 Nicolas Souchu + * 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. + */ + +/* + * Power management function/SMBus function support for the AMD 756 chip. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/systm.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/rman.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> + +#include <dev/smbus/smbconf.h> +#include "smbus_if.h" + +#define AMDPM_DEBUG(x) if (amdpm_debug) (x) + +#ifdef DEBUG +static int amdpm_debug = 1; +#else +static int amdpm_debug = 0; +#endif + +#define AMDPM_VENDORID_AMD 0x1022 +#define AMDPM_DEVICEID_AMD756PM 0x740b +#define AMDPM_DEVICEID_AMD766PM 0x7413 +#define AMDPM_DEVICEID_AMD768PM 0x7443 +#define AMDPM_DEVICEID_AMD8111PM 0x746B + +/* nVidia nForce chipset */ +#define AMDPM_VENDORID_NVIDIA 0x10de +#define AMDPM_DEVICEID_NF_SMB 0x01b4 + +/* PCI Configuration space registers */ +#define AMDPCI_PMBASE 0x58 +#define NFPCI_PMBASE 0x14 + +#define AMDPCI_GEN_CONFIG_PM 0x41 +#define AMDPCI_PMIOEN (1<<7) + +#define AMDPCI_SCIINT_CONFIG_PM 0x42 +#define AMDPCI_SCISEL_IRQ11 11 + +#define AMDPCI_REVID 0x08 + +/* + * I/O registers. + * Base address programmed via AMDPCI_PMBASE. + */ + +#define AMDSMB_GLOBAL_STATUS (0x00) +#define AMDSMB_GS_TO_STS (1<<5) +#define AMDSMB_GS_HCYC_STS (1<<4) +#define AMDSMB_GS_HST_STS (1<<3) +#define AMDSMB_GS_PRERR_STS (1<<2) +#define AMDSMB_GS_COL_STS (1<<1) +#define AMDSMB_GS_ABRT_STS (1<<0) +#define AMDSMB_GS_CLEAR_STS (AMDSMB_GS_TO_STS|AMDSMB_GS_HCYC_STS|AMDSMB_GS_PRERR_STS|AMDSMB_GS_COL_STS|AMDSMB_GS_ABRT_STS) + +#define AMDSMB_GLOBAL_ENABLE (0x02) +#define AMDSMB_GE_ABORT (1<<5) +#define AMDSMB_GE_HCYC_EN (1<<4) +#define AMDSMB_GE_HOST_STC (1<<3) +#define AMDSMB_GE_CYC_QUICK 0 +#define AMDSMB_GE_CYC_BYTE 1 +#define AMDSMB_GE_CYC_BDATA 2 +#define AMDSMB_GE_CYC_WDATA 3 +#define AMDSMB_GE_CYC_PROCCALL 4 +#define AMDSMB_GE_CYC_BLOCK 5 + +#define LSB 0x1 /* XXX: Better name: Read/Write? */ + +#define AMDSMB_HSTADDR (0x04) +#define AMDSMB_HSTDATA (0x06) +#define AMDSMB_HSTCMD (0x08) +#define AMDSMB_HSTDFIFO (0x09) +#define AMDSMB_HSLVDATA (0x0A) +#define AMDSMB_HSLVDA (0x0C) +#define AMDSMB_HSLVDDR (0x0E) +#define AMDSMB_SNPADDR (0x0F) + +struct amdpm_softc { + int base; + int rid; + struct resource *res; + device_t smbus; + struct mtx lock; +}; + +#define AMDPM_LOCK(amdpm) mtx_lock(&(amdpm)->lock) +#define AMDPM_UNLOCK(amdpm) mtx_unlock(&(amdpm)->lock) +#define AMDPM_LOCK_ASSERT(amdpm) mtx_assert(&(amdpm)->lock, MA_OWNED) + +#define AMDPM_SMBINB(amdpm,register) \ + (bus_read_1(amdpm->res, register)) +#define AMDPM_SMBOUTB(amdpm,register,value) \ + (bus_write_1(amdpm->res, register, value)) +#define AMDPM_SMBINW(amdpm,register) \ + (bus_read_2(amdpm->res, register)) +#define AMDPM_SMBOUTW(amdpm,register,value) \ + (bus_write_2(amdpm->res, register, value)) + +static int amdpm_detach(device_t dev); + +static int +amdpm_probe(device_t dev) +{ + u_long base; + u_int16_t vid; + u_int16_t did; + + vid = pci_get_vendor(dev); + did = pci_get_device(dev); + if ((vid == AMDPM_VENDORID_AMD) && + ((did == AMDPM_DEVICEID_AMD756PM) || + (did == AMDPM_DEVICEID_AMD766PM) || + (did == AMDPM_DEVICEID_AMD768PM) || + (did == AMDPM_DEVICEID_AMD8111PM))) { + device_set_desc(dev, "AMD 756/766/768/8111 Power Management Controller"); + + /* + * We have to do this, since the BIOS won't give us the + * resource info (not mine, anyway). + */ + base = pci_read_config(dev, AMDPCI_PMBASE, 4); + base &= 0xff00; + bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, + base+0xe0, 32); + return (BUS_PROBE_DEFAULT); + } + + if ((vid == AMDPM_VENDORID_NVIDIA) && + (did == AMDPM_DEVICEID_NF_SMB)) { + device_set_desc(dev, "nForce SMBus Controller"); + + /* + * We have to do this, since the BIOS won't give us the + * resource info (not mine, anyway). + */ + base = pci_read_config(dev, NFPCI_PMBASE, 4); + base &= 0xff00; + bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE, + base, 32); + + return (BUS_PROBE_DEFAULT); + } + + return ENXIO; +} + +static int +amdpm_attach(device_t dev) +{ + struct amdpm_softc *amdpm_sc = device_get_softc(dev); + u_char val_b; + + /* Enable I/O block access */ + val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1); + pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1); + + /* Allocate I/O space */ + if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD) + amdpm_sc->rid = AMDPCI_PMBASE; + else + amdpm_sc->rid = NFPCI_PMBASE; + amdpm_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, + &amdpm_sc->rid, RF_ACTIVE); + + if (amdpm_sc->res == NULL) { + device_printf(dev, "could not map i/o space\n"); + return (ENXIO); + } + + mtx_init(&amdpm_sc->lock, device_get_nameunit(dev), "amdpm", MTX_DEF); + + /* Allocate a new smbus device */ + amdpm_sc->smbus = device_add_child(dev, "smbus", -1); + if (!amdpm_sc->smbus) { + amdpm_detach(dev); + return (EINVAL); + } + + bus_generic_attach(dev); + + return (0); +} + +static int +amdpm_detach(device_t dev) +{ + struct amdpm_softc *amdpm_sc = device_get_softc(dev); + + if (amdpm_sc->smbus) { + device_delete_child(dev, amdpm_sc->smbus); + amdpm_sc->smbus = NULL; + } + + mtx_destroy(&amdpm_sc->lock); + if (amdpm_sc->res) + bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid, + amdpm_sc->res); + + return (0); +} + +static int +amdpm_callback(device_t dev, int index, void *data) +{ + int error = 0; + + switch (index) { + case SMB_REQUEST_BUS: + case SMB_RELEASE_BUS: + break; + default: + error = EINVAL; + } + + return (error); +} + +static int +amdpm_clear(struct amdpm_softc *sc) +{ + + AMDPM_LOCK_ASSERT(sc); + AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS); + DELAY(10); + + return (0); +} + +#if 0 +static int +amdpm_abort(struct amdpm_softc *sc) +{ + u_short l; + + l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); + AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT); + + return (0); +} +#endif + *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201409230631.s8N6VFlM085108>