MFC r266474:
Add ismt(4) driver. ismt(4) supports the SMBus Message Transport controller found on Intel C2000 series (Avoton) and S1200 series (Briarwood) Atom SoCs. Relnotes: Yes
This commit is contained in:
parent
cf634dbeba
commit
984dd4e553
@ -208,6 +208,7 @@ MAN= aac.4 \
|
||||
ipw.4 \
|
||||
ipwfw.4 \
|
||||
isci.4 \
|
||||
ismt.4 \
|
||||
isp.4 \
|
||||
ispfw.4 \
|
||||
iwi.4 \
|
||||
|
59
share/man/man4/ismt.4
Normal file
59
share/man/man4/ismt.4
Normal file
@ -0,0 +1,59 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2014 Intel Corporation
|
||||
.\" 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,
|
||||
.\" without modification.
|
||||
.\" 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.
|
||||
.\" 3. Neither the name of Intel Corporation nor the names of its
|
||||
.\" contributors may be used to endorse or promote products derived from
|
||||
.\" this software without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
.\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
|
||||
.\"
|
||||
.\" ismt driver man page.
|
||||
.\"
|
||||
.\" Author: Jim Harris <jimharris@FreeBSD.org>
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 9, 2014
|
||||
.Dt ISMT 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ismt
|
||||
.Nd Intel SMBus Message Transport (SMBus 2.0) driver
|
||||
.Sh SYNOPSIS
|
||||
.Cd device pci
|
||||
.Cd device smbus
|
||||
.Cd device smb
|
||||
.Cd device ismt
|
||||
.Sh DESCRIPTION
|
||||
This driver provides access to the SMBus 2.0 controller device contained
|
||||
in the Intel Atom S1200 and C2000 CPUs.
|
||||
.Sh SEE ALSO
|
||||
.Xr smb 4 ,
|
||||
.Xr smbus 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
driver first appeared in
|
||||
.Fx 11.0 .
|
||||
.Sh AUTHORS
|
||||
.An Jim Harris Aq jimharris@FreeBSD.org
|
@ -2493,6 +2493,7 @@ device sdhci
|
||||
# amdsmb AMD 8111 SMBus 2.0 Controller
|
||||
# nfpm NVIDIA nForce Power Management Unit
|
||||
# nfsmb NVIDIA nForce2/3/4 MCP SMBus 2.0 Controller
|
||||
# ismt Intel SMBus 2.0 controller chips (on Atom S1200, C2000)
|
||||
#
|
||||
device smbus # Bus support, required for smb below.
|
||||
|
||||
@ -2504,6 +2505,7 @@ device amdpm
|
||||
device amdsmb
|
||||
device nfpm
|
||||
device nfsmb
|
||||
device ismt
|
||||
|
||||
device smb
|
||||
|
||||
|
@ -1523,6 +1523,7 @@ dev/iscsi_initiator/isc_cam.c optional iscsi_initiator scbus
|
||||
dev/iscsi_initiator/isc_soc.c optional iscsi_initiator scbus
|
||||
dev/iscsi_initiator/isc_sm.c optional iscsi_initiator scbus
|
||||
dev/iscsi_initiator/isc_subr.c optional iscsi_initiator scbus
|
||||
dev/ismt/ismt.c optional ismt
|
||||
dev/isp/isp.c optional isp
|
||||
dev/isp/isp_freebsd.c optional isp
|
||||
dev/isp/isp_library.c optional isp
|
||||
|
778
sys/dev/ismt/ismt.c
Normal file
778
sys/dev/ismt/ismt.c
Normal file
@ -0,0 +1,778 @@
|
||||
/*-
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
* 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.
|
||||
* 3. Neither the name of Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/priority.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/smbus/smbconf.h>
|
||||
|
||||
#include "smbus_if.h"
|
||||
|
||||
#define ISMT_DESC_ENTRIES 32
|
||||
|
||||
/* Hardware Descriptor Constants - Control Field */
|
||||
#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */
|
||||
#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */
|
||||
#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */
|
||||
#define ISMT_DESC_PEC 0x10 /* Packet Error Code */
|
||||
#define ISMT_DESC_I2C 0x20 /* I2C Enable */
|
||||
#define ISMT_DESC_INT 0x40 /* Interrupt */
|
||||
#define ISMT_DESC_SOE 0x80 /* Stop On Error */
|
||||
|
||||
/* Hardware Descriptor Constants - Status Field */
|
||||
#define ISMT_DESC_SCS 0x01 /* Success */
|
||||
#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */
|
||||
#define ISMT_DESC_NAK 0x08 /* NAK Received */
|
||||
#define ISMT_DESC_CRC 0x10 /* CRC Error */
|
||||
#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */
|
||||
#define ISMT_DESC_COL 0x40 /* Collisions */
|
||||
#define ISMT_DESC_LPR 0x80 /* Large Packet Received */
|
||||
|
||||
/* Macros */
|
||||
#define ISMT_DESC_ADDR_RW(addr, is_read) ((addr) | (is_read))
|
||||
|
||||
/* iSMT General Register address offsets (SMBBAR + <addr>) */
|
||||
#define ISMT_GR_GCTRL 0x000 /* General Control */
|
||||
#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */
|
||||
#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */
|
||||
#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */
|
||||
#define ISMT_GR_ERRSTS 0x018 /* Error Status */
|
||||
#define ISMT_GR_ERRINFO 0x01c /* Error Information */
|
||||
|
||||
/* iSMT Master Registers */
|
||||
#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */
|
||||
#define ISMT_MSTR_MCTRL 0x108 /* Master Control */
|
||||
#define ISMT_MSTR_MSTS 0x10c /* Master Status */
|
||||
#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */
|
||||
#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */
|
||||
|
||||
/* iSMT Miscellaneous Registers */
|
||||
#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */
|
||||
|
||||
/* General Control Register (GCTRL) bit definitions */
|
||||
#define ISMT_GCTRL_TRST 0x04 /* Target Reset */
|
||||
#define ISMT_GCTRL_KILL 0x08 /* Kill */
|
||||
#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */
|
||||
|
||||
/* Master Control Register (MCTRL) bit definitions */
|
||||
#define ISMT_MCTRL_SS 0x01 /* Start/Stop */
|
||||
#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */
|
||||
#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */
|
||||
|
||||
/* Master Status Register (MSTS) bit definitions */
|
||||
#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */
|
||||
#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */
|
||||
#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */
|
||||
#define ISMT_MSTS_IP 0x01 /* In Progress */
|
||||
|
||||
/* Master Descriptor Size (MDS) bit definitions */
|
||||
#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */
|
||||
|
||||
/* SMBus PHY Global Timing Register (SPGT) bit definitions */
|
||||
#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */
|
||||
#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */
|
||||
#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */
|
||||
#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */
|
||||
#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */
|
||||
|
||||
/* MSI Control Register (MSICTL) bit definitions */
|
||||
#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */
|
||||
|
||||
#define ISMT_MAX_BLOCK_SIZE 32 /* per SMBus spec */
|
||||
|
||||
//#define ISMT_DEBUG device_printf
|
||||
#ifndef ISMT_DEBUG
|
||||
#define ISMT_DEBUG(...)
|
||||
#endif
|
||||
|
||||
/* iSMT Hardware Descriptor */
|
||||
struct ismt_desc {
|
||||
uint8_t tgtaddr_rw; /* target address & r/w bit */
|
||||
uint8_t wr_len_cmd; /* write length in bytes or a command */
|
||||
uint8_t rd_len; /* read length */
|
||||
uint8_t control; /* control bits */
|
||||
uint8_t status; /* status bits */
|
||||
uint8_t retry; /* collision retry and retry count */
|
||||
uint8_t rxbytes; /* received bytes */
|
||||
uint8_t txbytes; /* transmitted bytes */
|
||||
uint32_t dptr_low; /* lower 32 bit of the data pointer */
|
||||
uint32_t dptr_high; /* upper 32 bit of the data pointer */
|
||||
} __packed;
|
||||
|
||||
#define DESC_SIZE (ISMT_DESC_ENTRIES * sizeof(struct ismt_desc))
|
||||
|
||||
#define DMA_BUFFER_SIZE 64
|
||||
|
||||
struct ismt_softc {
|
||||
device_t pcidev;
|
||||
device_t smbdev;
|
||||
|
||||
struct thread *bus_reserved;
|
||||
|
||||
int intr_rid;
|
||||
struct resource *intr_res;
|
||||
void *intr_handle;
|
||||
|
||||
bus_space_tag_t mmio_tag;
|
||||
bus_space_handle_t mmio_handle;
|
||||
int mmio_rid;
|
||||
struct resource *mmio_res;
|
||||
|
||||
uint8_t head;
|
||||
|
||||
struct ismt_desc *desc;
|
||||
bus_dma_tag_t desc_dma_tag;
|
||||
bus_dmamap_t desc_dma_map;
|
||||
uint64_t desc_bus_addr;
|
||||
|
||||
uint8_t *dma_buffer;
|
||||
bus_dma_tag_t dma_buffer_dma_tag;
|
||||
bus_dmamap_t dma_buffer_dma_map;
|
||||
uint64_t dma_buffer_bus_addr;
|
||||
|
||||
uint8_t using_msi;
|
||||
};
|
||||
|
||||
static void
|
||||
ismt_intr(void *arg)
|
||||
{
|
||||
struct ismt_softc *sc = arg;
|
||||
uint32_t val;
|
||||
|
||||
val = bus_read_4(sc->mmio_res, ISMT_MSTR_MSTS);
|
||||
ISMT_DEBUG(sc->pcidev, "%s MSTS=0x%x\n", __func__, val);
|
||||
|
||||
val |= (ISMT_MSTS_MIS | ISMT_MSTS_MEIS);
|
||||
bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, val);
|
||||
|
||||
wakeup(sc);
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_callback(device_t dev, int index, void *data)
|
||||
{
|
||||
struct ismt_softc *sc;
|
||||
int acquired, err;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
switch (index) {
|
||||
case SMB_REQUEST_BUS:
|
||||
acquired = atomic_cmpset_ptr(
|
||||
(uintptr_t *)&sc->bus_reserved,
|
||||
(uintptr_t)NULL, (uintptr_t)curthread);
|
||||
ISMT_DEBUG(dev, "SMB_REQUEST_BUS acquired=%d\n", acquired);
|
||||
if (acquired)
|
||||
err = 0;
|
||||
else
|
||||
err = EWOULDBLOCK;
|
||||
break;
|
||||
case SMB_RELEASE_BUS:
|
||||
KASSERT(sc->bus_reserved == curthread,
|
||||
("SMB_RELEASE_BUS called by wrong thread\n"));
|
||||
ISMT_DEBUG(dev, "SMB_RELEASE_BUS\n");
|
||||
atomic_store_rel_ptr((uintptr_t *)&sc->bus_reserved,
|
||||
(uintptr_t)NULL);
|
||||
err = 0;
|
||||
break;
|
||||
default:
|
||||
err = SMB_EABORT;
|
||||
break;
|
||||
}
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static struct ismt_desc *
|
||||
ismt_alloc_desc(struct ismt_softc *sc)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
|
||||
KASSERT(sc->bus_reserved == curthread,
|
||||
("curthread %p did not request bus (%p has reserved)\n",
|
||||
curthread, sc->bus_reserved));
|
||||
|
||||
desc = &sc->desc[sc->head++];
|
||||
if (sc->head == ISMT_DESC_ENTRIES)
|
||||
sc->head = 0;
|
||||
|
||||
memset(desc, 0, sizeof(*desc));
|
||||
|
||||
return (desc);
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_submit(struct ismt_softc *sc, struct ismt_desc *desc, uint8_t slave,
|
||||
uint8_t is_read)
|
||||
{
|
||||
uint32_t err, fmhp, val;
|
||||
|
||||
desc->control |= ISMT_DESC_FAIR;
|
||||
if (sc->using_msi)
|
||||
desc->control |= ISMT_DESC_INT;
|
||||
|
||||
desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(slave, is_read);
|
||||
desc->dptr_low = (sc->dma_buffer_bus_addr & 0xFFFFFFFFLL);
|
||||
desc->dptr_high = (sc->dma_buffer_bus_addr >> 32);
|
||||
|
||||
wmb();
|
||||
|
||||
fmhp = sc->head << 16;
|
||||
val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL);
|
||||
val &= ~ISMT_MCTRL_FMHP;
|
||||
val |= fmhp;
|
||||
bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val);
|
||||
|
||||
/* set the start bit */
|
||||
val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL);
|
||||
val |= ISMT_MCTRL_SS;
|
||||
bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val);
|
||||
|
||||
err = tsleep(sc, PWAIT, "ismt_wait", 5 * hz);
|
||||
|
||||
if (err != 0) {
|
||||
ISMT_DEBUG(sc->pcidev, "%s timeout\n", __func__);
|
||||
return (SMB_ETIMEOUT);
|
||||
}
|
||||
|
||||
ISMT_DEBUG(sc->pcidev, "%s status=0x%x\n", __func__, desc->status);
|
||||
|
||||
if (desc->status & ISMT_DESC_SCS)
|
||||
return (SMB_ENOERR);
|
||||
|
||||
if (desc->status & ISMT_DESC_NAK)
|
||||
return (SMB_ENOACK);
|
||||
|
||||
if (desc->status & ISMT_DESC_CRC)
|
||||
return (SMB_EBUSERR);
|
||||
|
||||
if (desc->status & ISMT_DESC_COL)
|
||||
return (SMB_ECOLLI);
|
||||
|
||||
if (desc->status & ISMT_DESC_LPR)
|
||||
return (SMB_EINVAL);
|
||||
|
||||
if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO))
|
||||
return (SMB_ETIMEOUT);
|
||||
|
||||
return (SMB_EBUSERR);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ismt_quick(device_t dev, u_char slave, int how)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
int is_read;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
if (how != SMB_QREAD && how != SMB_QWRITE) {
|
||||
return (SMB_ENOTSUPP);
|
||||
}
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
is_read = (how == SMB_QREAD ? 1 : 0);
|
||||
return (ismt_submit(sc, desc, slave, is_read));
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_sendb(device_t dev, u_char slave, char byte)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->control = ISMT_DESC_CWRL;
|
||||
desc->wr_len_cmd = byte;
|
||||
|
||||
return (ismt_submit(sc, desc, slave, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_recvb(device_t dev, u_char slave, char *byte)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
int err;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->rd_len = 1;
|
||||
|
||||
err = ismt_submit(sc, desc, slave, 1);
|
||||
|
||||
if (err != SMB_ENOERR)
|
||||
return (err);
|
||||
|
||||
*byte = sc->dma_buffer[0];
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_writeb(device_t dev, u_char slave, char cmd, char byte)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->wr_len_cmd = 2;
|
||||
sc->dma_buffer[0] = cmd;
|
||||
sc->dma_buffer[1] = byte;
|
||||
|
||||
return (ismt_submit(sc, desc, slave, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_writew(device_t dev, u_char slave, char cmd, short word)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->wr_len_cmd = 3;
|
||||
sc->dma_buffer[0] = cmd;
|
||||
sc->dma_buffer[1] = word & 0xFF;
|
||||
sc->dma_buffer[2] = word >> 8;
|
||||
|
||||
return (ismt_submit(sc, desc, slave, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_readb(device_t dev, u_char slave, char cmd, char *byte)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
int err;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->control = ISMT_DESC_CWRL;
|
||||
desc->wr_len_cmd = cmd;
|
||||
desc->rd_len = 1;
|
||||
|
||||
err = ismt_submit(sc, desc, slave, 1);
|
||||
|
||||
if (err != SMB_ENOERR)
|
||||
return (err);
|
||||
|
||||
*byte = sc->dma_buffer[0];
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_readw(device_t dev, u_char slave, char cmd, short *word)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
int err;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->control = ISMT_DESC_CWRL;
|
||||
desc->wr_len_cmd = cmd;
|
||||
desc->rd_len = 2;
|
||||
|
||||
err = ismt_submit(sc, desc, slave, 1);
|
||||
|
||||
if (err != SMB_ENOERR)
|
||||
return (err);
|
||||
|
||||
*word = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
int err;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->wr_len_cmd = 3;
|
||||
desc->rd_len = 2;
|
||||
sc->dma_buffer[0] = cmd;
|
||||
sc->dma_buffer[1] = sdata & 0xff;
|
||||
sc->dma_buffer[2] = sdata >> 8;
|
||||
|
||||
err = ismt_submit(sc, desc, slave, 0);
|
||||
|
||||
if (err != SMB_ENOERR)
|
||||
return (err);
|
||||
|
||||
*rdata = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
if (count == 0 || count > ISMT_MAX_BLOCK_SIZE)
|
||||
return (SMB_EINVAL);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->control = ISMT_DESC_I2C;
|
||||
desc->wr_len_cmd = count + 1;
|
||||
sc->dma_buffer[0] = cmd;
|
||||
memcpy(&sc->dma_buffer[1], buf, count);
|
||||
|
||||
return (ismt_submit(sc, desc, slave, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
|
||||
{
|
||||
struct ismt_desc *desc;
|
||||
struct ismt_softc *sc;
|
||||
int err;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
|
||||
if (*count == 0 || *count > ISMT_MAX_BLOCK_SIZE)
|
||||
return (SMB_EINVAL);
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
desc = ismt_alloc_desc(sc);
|
||||
desc->control = ISMT_DESC_I2C | ISMT_DESC_CWRL;
|
||||
desc->wr_len_cmd = cmd;
|
||||
desc->rd_len = *count;
|
||||
|
||||
err = ismt_submit(sc, desc, slave, 0);
|
||||
|
||||
if (err != SMB_ENOERR)
|
||||
return (err);
|
||||
|
||||
memcpy(buf, sc->dma_buffer, desc->rxbytes);
|
||||
*count = desc->rxbytes;
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_detach(device_t dev)
|
||||
{
|
||||
struct ismt_softc *sc;
|
||||
int error;
|
||||
|
||||
ISMT_DEBUG(dev, "%s\n", __func__);
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
error = bus_generic_detach(dev);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
device_delete_child(dev, sc->smbdev);
|
||||
|
||||
if (sc->intr_handle != NULL) {
|
||||
bus_teardown_intr(dev, sc->intr_res, sc->intr_handle);
|
||||
sc->intr_handle = NULL;
|
||||
}
|
||||
if (sc->intr_res != NULL) {
|
||||
bus_release_resource(dev,
|
||||
SYS_RES_IRQ, sc->intr_rid, sc->intr_res);
|
||||
sc->intr_res = NULL;
|
||||
}
|
||||
if (sc->using_msi == 1)
|
||||
pci_release_msi(dev);
|
||||
|
||||
if (sc->mmio_res != NULL) {
|
||||
bus_release_resource(dev,
|
||||
SYS_RES_MEMORY, sc->mmio_rid, sc->mmio_res);
|
||||
sc->mmio_res = NULL;
|
||||
}
|
||||
|
||||
bus_dmamap_unload(sc->desc_dma_tag, sc->desc_dma_map);
|
||||
bus_dmamap_unload(sc->dma_buffer_dma_tag, sc->dma_buffer_dma_map);
|
||||
|
||||
bus_dmamem_free(sc->desc_dma_tag, sc->desc,
|
||||
sc->desc_dma_map);
|
||||
bus_dmamem_free(sc->dma_buffer_dma_tag, sc->dma_buffer,
|
||||
sc->dma_buffer_dma_map);
|
||||
|
||||
bus_dma_tag_destroy(sc->desc_dma_tag);
|
||||
bus_dma_tag_destroy(sc->dma_buffer_dma_tag);
|
||||
|
||||
pci_disable_busmaster(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ismt_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
|
||||
{
|
||||
uint64_t *bus_addr = (uint64_t *)arg;
|
||||
|
||||
KASSERT(error == 0, ("%s: error=%d\n", __func__, error));
|
||||
KASSERT(nseg == 1, ("%s: nseg=%d\n", __func__, nseg));
|
||||
|
||||
*bus_addr = seg[0].ds_addr;
|
||||
}
|
||||
|
||||
static int
|
||||
ismt_attach(device_t dev)
|
||||
{
|
||||
struct ismt_softc *sc = device_get_softc(dev);
|
||||
int err, num_vectors, val;
|
||||
|
||||
sc->pcidev = dev;
|
||||
pci_enable_busmaster(dev);
|
||||
|
||||
if ((sc->smbdev = device_add_child(dev, "smbus", -1)) == NULL) {
|
||||
device_printf(dev, "no smbus child found\n");
|
||||
err = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sc->mmio_rid = PCIR_BAR(0);
|
||||
sc->mmio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
&sc->mmio_rid, RF_ACTIVE);
|
||||
if (sc->mmio_res == NULL) {
|
||||
device_printf(dev, "cannot allocate mmio region\n");
|
||||
err = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sc->mmio_tag = rman_get_bustag(sc->mmio_res);
|
||||
sc->mmio_handle = rman_get_bushandle(sc->mmio_res);
|
||||
|
||||
/* Attach "smbus" child */
|
||||
if ((err = bus_generic_attach(dev)) != 0) {
|
||||
device_printf(dev, "failed to attach child: %d\n", err);
|
||||
err = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE,
|
||||
BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
DESC_SIZE, 1, DESC_SIZE,
|
||||
0, NULL, NULL, &sc->desc_dma_tag);
|
||||
|
||||
bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE,
|
||||
BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
|
||||
DMA_BUFFER_SIZE, 1, DMA_BUFFER_SIZE,
|
||||
0, NULL, NULL, &sc->dma_buffer_dma_tag);
|
||||
|
||||
bus_dmamap_create(sc->desc_dma_tag, 0,
|
||||
&sc->desc_dma_map);
|
||||
bus_dmamap_create(sc->dma_buffer_dma_tag, 0,
|
||||
&sc->dma_buffer_dma_map);
|
||||
|
||||
bus_dmamem_alloc(sc->desc_dma_tag,
|
||||
(void **)&sc->desc, BUS_DMA_WAITOK,
|
||||
&sc->desc_dma_map);
|
||||
bus_dmamem_alloc(sc->dma_buffer_dma_tag,
|
||||
(void **)&sc->dma_buffer, BUS_DMA_WAITOK,
|
||||
&sc->dma_buffer_dma_map);
|
||||
|
||||
bus_dmamap_load(sc->desc_dma_tag,
|
||||
sc->desc_dma_map, sc->desc, DESC_SIZE,
|
||||
ismt_single_map, &sc->desc_bus_addr, 0);
|
||||
bus_dmamap_load(sc->dma_buffer_dma_tag,
|
||||
sc->dma_buffer_dma_map, sc->dma_buffer, DMA_BUFFER_SIZE,
|
||||
ismt_single_map, &sc->dma_buffer_bus_addr, 0);
|
||||
|
||||
bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA,
|
||||
(sc->desc_bus_addr & 0xFFFFFFFFLL));
|
||||
bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA + 4,
|
||||
(sc->desc_bus_addr >> 32));
|
||||
|
||||
/* initialize the Master Control Register (MCTRL) */
|
||||
bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, ISMT_MCTRL_MEIE);
|
||||
|
||||
/* initialize the Master Status Register (MSTS) */
|
||||
bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, 0);
|
||||
|
||||
/* initialize the Master Descriptor Size (MDS) */
|
||||
val = bus_read_4(sc->mmio_res, ISMT_MSTR_MDS);
|
||||
val &= ~ISMT_MDS_MASK;
|
||||
val |= (ISMT_DESC_ENTRIES - 1);
|
||||
bus_write_4(sc->mmio_res, ISMT_MSTR_MDS, val);
|
||||
|
||||
sc->using_msi = 1;
|
||||
|
||||
if (pci_msi_count(dev) == 0) {
|
||||
sc->using_msi = 0;
|
||||
goto intx;
|
||||
}
|
||||
|
||||
num_vectors = 1;
|
||||
if (pci_alloc_msi(dev, &num_vectors) != 0) {
|
||||
sc->using_msi = 0;
|
||||
goto intx;
|
||||
}
|
||||
|
||||
sc->intr_rid = 1;
|
||||
sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
|
||||
&sc->intr_rid, RF_ACTIVE);
|
||||
|
||||
if (sc->intr_res == NULL) {
|
||||
sc->using_msi = 0;
|
||||
pci_release_msi(dev);
|
||||
}
|
||||
|
||||
intx:
|
||||
if (sc->using_msi == 0) {
|
||||
sc->intr_rid = 0;
|
||||
sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
|
||||
&sc->intr_rid, RF_SHAREABLE | RF_ACTIVE);
|
||||
if (sc->intr_res == NULL) {
|
||||
device_printf(dev, "cannot allocate irq\n");
|
||||
err = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ISMT_DEBUG(dev, "using_msi = %d\n", sc->using_msi);
|
||||
|
||||
err = bus_setup_intr(dev, sc->intr_res,
|
||||
INTR_TYPE_MISC | INTR_MPSAFE, NULL, ismt_intr, sc,
|
||||
&sc->intr_handle);
|
||||
if (err != 0) {
|
||||
device_printf(dev, "cannot setup interrupt\n");
|
||||
err = ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
ismt_detach(dev);
|
||||
return (err);
|
||||
}
|
||||
|
||||
#define ID_INTEL_S1200_SMT0 0x0c598086
|
||||
#define ID_INTEL_S1200_SMT1 0x0c5a8086
|
||||
#define ID_INTEL_C2000_SMT 0x1f158086
|
||||
|
||||
static int
|
||||
ismt_probe(device_t dev)
|
||||
{
|
||||
const char *desc;
|
||||
|
||||
switch (pci_get_devid(dev)) {
|
||||
case ID_INTEL_S1200_SMT0:
|
||||
desc = "Atom Processor S1200 SMBus 2.0 Controller 0";
|
||||
break;
|
||||
case ID_INTEL_S1200_SMT1:
|
||||
desc = "Atom Processor S1200 SMBus 2.0 Controller 1";
|
||||
break;
|
||||
case ID_INTEL_C2000_SMT:
|
||||
desc = "Atom Processor C2000 SMBus 2.0";
|
||||
break;
|
||||
default:
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
device_set_desc(dev, desc);
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
/* Device methods */
|
||||
static device_method_t ismt_pci_methods[] = {
|
||||
DEVMETHOD(device_probe, ismt_probe),
|
||||
DEVMETHOD(device_attach, ismt_attach),
|
||||
DEVMETHOD(device_detach, ismt_detach),
|
||||
|
||||
DEVMETHOD(smbus_callback, ismt_callback),
|
||||
DEVMETHOD(smbus_quick, ismt_quick),
|
||||
DEVMETHOD(smbus_sendb, ismt_sendb),
|
||||
DEVMETHOD(smbus_recvb, ismt_recvb),
|
||||
DEVMETHOD(smbus_writeb, ismt_writeb),
|
||||
DEVMETHOD(smbus_writew, ismt_writew),
|
||||
DEVMETHOD(smbus_readb, ismt_readb),
|
||||
DEVMETHOD(smbus_readw, ismt_readw),
|
||||
DEVMETHOD(smbus_pcall, ismt_pcall),
|
||||
DEVMETHOD(smbus_bwrite, ismt_bwrite),
|
||||
DEVMETHOD(smbus_bread, ismt_bread),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t ismt_pci_driver = {
|
||||
"ismt",
|
||||
ismt_pci_methods,
|
||||
sizeof(struct ismt_softc)
|
||||
};
|
||||
|
||||
static devclass_t ismt_pci_devclass;
|
||||
|
||||
DRIVER_MODULE(ismt, pci, ismt_pci_driver, ismt_pci_devclass, 0, 0);
|
||||
DRIVER_MODULE(smbus, ismt, smbus_driver, smbus_devclass, 0, 0);
|
||||
|
||||
MODULE_DEPEND(ismt, pci, 1, 1, 1);
|
||||
MODULE_DEPEND(ismt, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
|
||||
MODULE_VERSION(ismt, 1);
|
@ -3,7 +3,7 @@
|
||||
.if ${MACHINE} == "pc98"
|
||||
SUBDIR = lpbb
|
||||
.else
|
||||
SUBDIR = alpm amdpm amdsmb ichsmb intpm nfsmb viapm lpbb pcf
|
||||
SUBDIR = alpm amdpm amdsmb ichsmb intpm ismt nfsmb viapm lpbb pcf
|
||||
.endif
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
8
sys/modules/i2c/controllers/ismt/Makefile
Normal file
8
sys/modules/i2c/controllers/ismt/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
#$FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../../../dev/ismt
|
||||
KMOD = ismt
|
||||
SRCS = device_if.h bus_if.h iicbb_if.h pci_if.h smbus_if.h \
|
||||
ismt.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user