1293675Sjimharris/*- 2293675Sjimharris * Copyright (C) 2014 Intel Corporation 3293675Sjimharris * All rights reserved. 4293675Sjimharris * 5293675Sjimharris * Redistribution and use in source and binary forms, with or without 6293675Sjimharris * modification, are permitted provided that the following conditions 7293675Sjimharris * are met: 8293675Sjimharris * 1. Redistributions of source code must retain the above copyright 9293675Sjimharris * notice, this list of conditions and the following disclaimer. 10293675Sjimharris * 2. Redistributions in binary form must reproduce the above copyright 11293675Sjimharris * notice, this list of conditions and the following disclaimer in the 12293675Sjimharris * documentation and/or other materials provided with the distribution. 13293675Sjimharris * 3. Neither the name of Intel Corporation nor the names of its 14293675Sjimharris * contributors may be used to endorse or promote products derived from 15293675Sjimharris * this software without specific prior written permission. 16293675Sjimharris * 17293675Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18293675Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19293675Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20293675Sjimharris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21293675Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22293675Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23293675Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24293675Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25293675Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26293675Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27293675Sjimharris * SUCH DAMAGE. 28293675Sjimharris */ 29293675Sjimharris 30293675Sjimharris#include <sys/cdefs.h> 31293675Sjimharris__FBSDID("$FreeBSD$"); 32293675Sjimharris 33293675Sjimharris#include <sys/param.h> 34293675Sjimharris#include <sys/systm.h> 35293675Sjimharris#include <sys/bus.h> 36293675Sjimharris#include <sys/errno.h> 37293675Sjimharris#include <sys/kernel.h> 38293675Sjimharris#include <sys/lock.h> 39293675Sjimharris#include <sys/module.h> 40293675Sjimharris#include <sys/priority.h> 41293675Sjimharris#include <sys/proc.h> 42293675Sjimharris#include <sys/syslog.h> 43293675Sjimharris 44293675Sjimharris#include <machine/bus.h> 45293675Sjimharris#include <sys/rman.h> 46293675Sjimharris#include <machine/resource.h> 47293675Sjimharris 48293675Sjimharris#include <dev/pci/pcireg.h> 49293675Sjimharris#include <dev/pci/pcivar.h> 50293675Sjimharris#include <dev/smbus/smbconf.h> 51293675Sjimharris 52293675Sjimharris#include "smbus_if.h" 53293675Sjimharris 54293675Sjimharris#define ISMT_DESC_ENTRIES 32 55293675Sjimharris 56293675Sjimharris/* Hardware Descriptor Constants - Control Field */ 57293675Sjimharris#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */ 58293675Sjimharris#define ISMT_DESC_BLK 0X04 /* Perform Block Transaction */ 59293675Sjimharris#define ISMT_DESC_FAIR 0x08 /* Set fairness flag upon successful arbit. */ 60293675Sjimharris#define ISMT_DESC_PEC 0x10 /* Packet Error Code */ 61293675Sjimharris#define ISMT_DESC_I2C 0x20 /* I2C Enable */ 62293675Sjimharris#define ISMT_DESC_INT 0x40 /* Interrupt */ 63293675Sjimharris#define ISMT_DESC_SOE 0x80 /* Stop On Error */ 64293675Sjimharris 65293675Sjimharris/* Hardware Descriptor Constants - Status Field */ 66293675Sjimharris#define ISMT_DESC_SCS 0x01 /* Success */ 67293675Sjimharris#define ISMT_DESC_DLTO 0x04 /* Data Low Time Out */ 68293675Sjimharris#define ISMT_DESC_NAK 0x08 /* NAK Received */ 69293675Sjimharris#define ISMT_DESC_CRC 0x10 /* CRC Error */ 70293675Sjimharris#define ISMT_DESC_CLTO 0x20 /* Clock Low Time Out */ 71293675Sjimharris#define ISMT_DESC_COL 0x40 /* Collisions */ 72293675Sjimharris#define ISMT_DESC_LPR 0x80 /* Large Packet Received */ 73293675Sjimharris 74293675Sjimharris/* Macros */ 75293676Sjimharris#define ISMT_DESC_ADDR_RW(addr, is_read) ((addr << 1) | (is_read)) 76293675Sjimharris 77293675Sjimharris/* iSMT General Register address offsets (SMBBAR + <addr>) */ 78293675Sjimharris#define ISMT_GR_GCTRL 0x000 /* General Control */ 79293675Sjimharris#define ISMT_GR_SMTICL 0x008 /* SMT Interrupt Cause Location */ 80293675Sjimharris#define ISMT_GR_ERRINTMSK 0x010 /* Error Interrupt Mask */ 81293675Sjimharris#define ISMT_GR_ERRAERMSK 0x014 /* Error AER Mask */ 82293675Sjimharris#define ISMT_GR_ERRSTS 0x018 /* Error Status */ 83293675Sjimharris#define ISMT_GR_ERRINFO 0x01c /* Error Information */ 84293675Sjimharris 85293675Sjimharris/* iSMT Master Registers */ 86293675Sjimharris#define ISMT_MSTR_MDBA 0x100 /* Master Descriptor Base Address */ 87293675Sjimharris#define ISMT_MSTR_MCTRL 0x108 /* Master Control */ 88293675Sjimharris#define ISMT_MSTR_MSTS 0x10c /* Master Status */ 89293675Sjimharris#define ISMT_MSTR_MDS 0x110 /* Master Descriptor Size */ 90293675Sjimharris#define ISMT_MSTR_RPOLICY 0x114 /* Retry Policy */ 91293675Sjimharris 92293675Sjimharris/* iSMT Miscellaneous Registers */ 93293675Sjimharris#define ISMT_SPGT 0x300 /* SMBus PHY Global Timing */ 94293675Sjimharris 95293675Sjimharris/* General Control Register (GCTRL) bit definitions */ 96293675Sjimharris#define ISMT_GCTRL_TRST 0x04 /* Target Reset */ 97293675Sjimharris#define ISMT_GCTRL_KILL 0x08 /* Kill */ 98293675Sjimharris#define ISMT_GCTRL_SRST 0x40 /* Soft Reset */ 99293675Sjimharris 100293675Sjimharris/* Master Control Register (MCTRL) bit definitions */ 101293675Sjimharris#define ISMT_MCTRL_SS 0x01 /* Start/Stop */ 102293675Sjimharris#define ISMT_MCTRL_MEIE 0x10 /* Master Error Interrupt Enable */ 103293675Sjimharris#define ISMT_MCTRL_FMHP 0x00ff0000 /* Firmware Master Head Ptr (FMHP) */ 104293675Sjimharris 105293675Sjimharris/* Master Status Register (MSTS) bit definitions */ 106293675Sjimharris#define ISMT_MSTS_HMTP 0xff0000 /* HW Master Tail Pointer (HMTP) */ 107293675Sjimharris#define ISMT_MSTS_MIS 0x20 /* Master Interrupt Status (MIS) */ 108293675Sjimharris#define ISMT_MSTS_MEIS 0x10 /* Master Error Int Status (MEIS) */ 109293675Sjimharris#define ISMT_MSTS_IP 0x01 /* In Progress */ 110293675Sjimharris 111293675Sjimharris/* Master Descriptor Size (MDS) bit definitions */ 112293675Sjimharris#define ISMT_MDS_MASK 0xff /* Master Descriptor Size mask (MDS) */ 113293675Sjimharris 114293675Sjimharris/* SMBus PHY Global Timing Register (SPGT) bit definitions */ 115293675Sjimharris#define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */ 116293675Sjimharris#define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */ 117293675Sjimharris#define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */ 118293675Sjimharris#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */ 119293675Sjimharris#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */ 120293675Sjimharris 121293675Sjimharris/* MSI Control Register (MSICTL) bit definitions */ 122293675Sjimharris#define ISMT_MSICTL_MSIE 0x01 /* MSI Enable */ 123293675Sjimharris 124293675Sjimharris#define ISMT_MAX_BLOCK_SIZE 32 /* per SMBus spec */ 125293675Sjimharris 126293675Sjimharris//#define ISMT_DEBUG device_printf 127293675Sjimharris#ifndef ISMT_DEBUG 128293675Sjimharris#define ISMT_DEBUG(...) 129293675Sjimharris#endif 130293675Sjimharris 131293675Sjimharris/* iSMT Hardware Descriptor */ 132293675Sjimharrisstruct ismt_desc { 133293675Sjimharris uint8_t tgtaddr_rw; /* target address & r/w bit */ 134293675Sjimharris uint8_t wr_len_cmd; /* write length in bytes or a command */ 135293675Sjimharris uint8_t rd_len; /* read length */ 136293675Sjimharris uint8_t control; /* control bits */ 137293675Sjimharris uint8_t status; /* status bits */ 138293675Sjimharris uint8_t retry; /* collision retry and retry count */ 139293675Sjimharris uint8_t rxbytes; /* received bytes */ 140293675Sjimharris uint8_t txbytes; /* transmitted bytes */ 141293675Sjimharris uint32_t dptr_low; /* lower 32 bit of the data pointer */ 142293675Sjimharris uint32_t dptr_high; /* upper 32 bit of the data pointer */ 143293675Sjimharris} __packed; 144293675Sjimharris 145293675Sjimharris#define DESC_SIZE (ISMT_DESC_ENTRIES * sizeof(struct ismt_desc)) 146293675Sjimharris 147293675Sjimharris#define DMA_BUFFER_SIZE 64 148293675Sjimharris 149293675Sjimharrisstruct ismt_softc { 150293675Sjimharris device_t pcidev; 151293675Sjimharris device_t smbdev; 152293675Sjimharris 153293675Sjimharris struct thread *bus_reserved; 154293675Sjimharris 155293675Sjimharris int intr_rid; 156293675Sjimharris struct resource *intr_res; 157293675Sjimharris void *intr_handle; 158293675Sjimharris 159293675Sjimharris bus_space_tag_t mmio_tag; 160293675Sjimharris bus_space_handle_t mmio_handle; 161293675Sjimharris int mmio_rid; 162293675Sjimharris struct resource *mmio_res; 163293675Sjimharris 164293675Sjimharris uint8_t head; 165293675Sjimharris 166293675Sjimharris struct ismt_desc *desc; 167293675Sjimharris bus_dma_tag_t desc_dma_tag; 168293675Sjimharris bus_dmamap_t desc_dma_map; 169293675Sjimharris uint64_t desc_bus_addr; 170293675Sjimharris 171293675Sjimharris uint8_t *dma_buffer; 172293675Sjimharris bus_dma_tag_t dma_buffer_dma_tag; 173293675Sjimharris bus_dmamap_t dma_buffer_dma_map; 174293675Sjimharris uint64_t dma_buffer_bus_addr; 175293675Sjimharris 176293675Sjimharris uint8_t using_msi; 177293675Sjimharris}; 178293675Sjimharris 179293675Sjimharrisstatic void 180293675Sjimharrisismt_intr(void *arg) 181293675Sjimharris{ 182293675Sjimharris struct ismt_softc *sc = arg; 183293675Sjimharris uint32_t val; 184293675Sjimharris 185293675Sjimharris val = bus_read_4(sc->mmio_res, ISMT_MSTR_MSTS); 186293675Sjimharris ISMT_DEBUG(sc->pcidev, "%s MSTS=0x%x\n", __func__, val); 187293675Sjimharris 188293675Sjimharris val |= (ISMT_MSTS_MIS | ISMT_MSTS_MEIS); 189293675Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, val); 190293675Sjimharris 191293675Sjimharris wakeup(sc); 192293675Sjimharris} 193293675Sjimharris 194293675Sjimharrisstatic int 195293675Sjimharrisismt_callback(device_t dev, int index, void *data) 196293675Sjimharris{ 197293675Sjimharris struct ismt_softc *sc; 198293675Sjimharris int acquired, err; 199293675Sjimharris 200293675Sjimharris sc = device_get_softc(dev); 201293675Sjimharris 202293675Sjimharris switch (index) { 203293675Sjimharris case SMB_REQUEST_BUS: 204293675Sjimharris acquired = atomic_cmpset_ptr( 205293675Sjimharris (uintptr_t *)&sc->bus_reserved, 206293675Sjimharris (uintptr_t)NULL, (uintptr_t)curthread); 207293675Sjimharris ISMT_DEBUG(dev, "SMB_REQUEST_BUS acquired=%d\n", acquired); 208293675Sjimharris if (acquired) 209293675Sjimharris err = 0; 210293675Sjimharris else 211293675Sjimharris err = EWOULDBLOCK; 212293675Sjimharris break; 213293675Sjimharris case SMB_RELEASE_BUS: 214293675Sjimharris KASSERT(sc->bus_reserved == curthread, 215293675Sjimharris ("SMB_RELEASE_BUS called by wrong thread\n")); 216293675Sjimharris ISMT_DEBUG(dev, "SMB_RELEASE_BUS\n"); 217293675Sjimharris atomic_store_rel_ptr((uintptr_t *)&sc->bus_reserved, 218293675Sjimharris (uintptr_t)NULL); 219293675Sjimharris err = 0; 220293675Sjimharris break; 221293675Sjimharris default: 222293675Sjimharris err = SMB_EABORT; 223293675Sjimharris break; 224293675Sjimharris } 225293675Sjimharris 226293675Sjimharris return (err); 227293675Sjimharris} 228293675Sjimharris 229293675Sjimharrisstatic struct ismt_desc * 230293675Sjimharrisismt_alloc_desc(struct ismt_softc *sc) 231293675Sjimharris{ 232293675Sjimharris struct ismt_desc *desc; 233293675Sjimharris 234293675Sjimharris KASSERT(sc->bus_reserved == curthread, 235293675Sjimharris ("curthread %p did not request bus (%p has reserved)\n", 236293675Sjimharris curthread, sc->bus_reserved)); 237293675Sjimharris 238293675Sjimharris desc = &sc->desc[sc->head++]; 239293675Sjimharris if (sc->head == ISMT_DESC_ENTRIES) 240293675Sjimharris sc->head = 0; 241293675Sjimharris 242293675Sjimharris memset(desc, 0, sizeof(*desc)); 243293675Sjimharris 244293675Sjimharris return (desc); 245293675Sjimharris} 246293675Sjimharris 247293675Sjimharrisstatic int 248293675Sjimharrisismt_submit(struct ismt_softc *sc, struct ismt_desc *desc, uint8_t slave, 249293675Sjimharris uint8_t is_read) 250293675Sjimharris{ 251293675Sjimharris uint32_t err, fmhp, val; 252293675Sjimharris 253293675Sjimharris desc->control |= ISMT_DESC_FAIR; 254293675Sjimharris if (sc->using_msi) 255293675Sjimharris desc->control |= ISMT_DESC_INT; 256293675Sjimharris 257293675Sjimharris desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(slave, is_read); 258293675Sjimharris desc->dptr_low = (sc->dma_buffer_bus_addr & 0xFFFFFFFFLL); 259293675Sjimharris desc->dptr_high = (sc->dma_buffer_bus_addr >> 32); 260293675Sjimharris 261293675Sjimharris wmb(); 262293675Sjimharris 263293675Sjimharris fmhp = sc->head << 16; 264293675Sjimharris val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL); 265293675Sjimharris val &= ~ISMT_MCTRL_FMHP; 266293675Sjimharris val |= fmhp; 267293675Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val); 268293675Sjimharris 269293675Sjimharris /* set the start bit */ 270293675Sjimharris val = bus_read_4(sc->mmio_res, ISMT_MSTR_MCTRL); 271293675Sjimharris val |= ISMT_MCTRL_SS; 272293675Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, val); 273293675Sjimharris 274293675Sjimharris err = tsleep(sc, PWAIT, "ismt_wait", 5 * hz); 275293675Sjimharris 276293675Sjimharris if (err != 0) { 277293675Sjimharris ISMT_DEBUG(sc->pcidev, "%s timeout\n", __func__); 278293675Sjimharris return (SMB_ETIMEOUT); 279293675Sjimharris } 280293675Sjimharris 281293675Sjimharris ISMT_DEBUG(sc->pcidev, "%s status=0x%x\n", __func__, desc->status); 282293675Sjimharris 283293675Sjimharris if (desc->status & ISMT_DESC_SCS) 284293675Sjimharris return (SMB_ENOERR); 285293675Sjimharris 286293675Sjimharris if (desc->status & ISMT_DESC_NAK) 287293675Sjimharris return (SMB_ENOACK); 288293675Sjimharris 289293675Sjimharris if (desc->status & ISMT_DESC_CRC) 290293675Sjimharris return (SMB_EBUSERR); 291293675Sjimharris 292293675Sjimharris if (desc->status & ISMT_DESC_COL) 293293675Sjimharris return (SMB_ECOLLI); 294293675Sjimharris 295293675Sjimharris if (desc->status & ISMT_DESC_LPR) 296293675Sjimharris return (SMB_EINVAL); 297293675Sjimharris 298293675Sjimharris if (desc->status & (ISMT_DESC_DLTO | ISMT_DESC_CLTO)) 299293675Sjimharris return (SMB_ETIMEOUT); 300293675Sjimharris 301293675Sjimharris return (SMB_EBUSERR); 302293675Sjimharris} 303293675Sjimharris 304293675Sjimharris 305293675Sjimharrisstatic int 306293675Sjimharrisismt_quick(device_t dev, u_char slave, int how) 307293675Sjimharris{ 308293675Sjimharris struct ismt_desc *desc; 309293675Sjimharris struct ismt_softc *sc; 310293675Sjimharris int is_read; 311293675Sjimharris 312293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 313293675Sjimharris 314293675Sjimharris if (how != SMB_QREAD && how != SMB_QWRITE) { 315293675Sjimharris return (SMB_ENOTSUPP); 316293675Sjimharris } 317293675Sjimharris 318293675Sjimharris sc = device_get_softc(dev); 319293675Sjimharris desc = ismt_alloc_desc(sc); 320293675Sjimharris is_read = (how == SMB_QREAD ? 1 : 0); 321293675Sjimharris return (ismt_submit(sc, desc, slave, is_read)); 322293675Sjimharris} 323293675Sjimharris 324293675Sjimharrisstatic int 325293675Sjimharrisismt_sendb(device_t dev, u_char slave, char byte) 326293675Sjimharris{ 327293675Sjimharris struct ismt_desc *desc; 328293675Sjimharris struct ismt_softc *sc; 329293675Sjimharris 330293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 331293675Sjimharris 332293675Sjimharris sc = device_get_softc(dev); 333293675Sjimharris desc = ismt_alloc_desc(sc); 334293675Sjimharris desc->control = ISMT_DESC_CWRL; 335293675Sjimharris desc->wr_len_cmd = byte; 336293675Sjimharris 337293675Sjimharris return (ismt_submit(sc, desc, slave, 0)); 338293675Sjimharris} 339293675Sjimharris 340293675Sjimharrisstatic int 341293675Sjimharrisismt_recvb(device_t dev, u_char slave, char *byte) 342293675Sjimharris{ 343293675Sjimharris struct ismt_desc *desc; 344293675Sjimharris struct ismt_softc *sc; 345293675Sjimharris int err; 346293675Sjimharris 347293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 348293675Sjimharris 349293675Sjimharris sc = device_get_softc(dev); 350293675Sjimharris desc = ismt_alloc_desc(sc); 351293675Sjimharris desc->rd_len = 1; 352293675Sjimharris 353293675Sjimharris err = ismt_submit(sc, desc, slave, 1); 354293675Sjimharris 355293675Sjimharris if (err != SMB_ENOERR) 356293675Sjimharris return (err); 357293675Sjimharris 358293675Sjimharris *byte = sc->dma_buffer[0]; 359293675Sjimharris 360293675Sjimharris return (err); 361293675Sjimharris} 362293675Sjimharris 363293675Sjimharrisstatic int 364293675Sjimharrisismt_writeb(device_t dev, u_char slave, char cmd, char byte) 365293675Sjimharris{ 366293675Sjimharris struct ismt_desc *desc; 367293675Sjimharris struct ismt_softc *sc; 368293675Sjimharris 369293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 370293675Sjimharris 371293675Sjimharris sc = device_get_softc(dev); 372293675Sjimharris desc = ismt_alloc_desc(sc); 373293675Sjimharris desc->wr_len_cmd = 2; 374293675Sjimharris sc->dma_buffer[0] = cmd; 375293675Sjimharris sc->dma_buffer[1] = byte; 376293675Sjimharris 377293675Sjimharris return (ismt_submit(sc, desc, slave, 0)); 378293675Sjimharris} 379293675Sjimharris 380293675Sjimharrisstatic int 381293675Sjimharrisismt_writew(device_t dev, u_char slave, char cmd, short word) 382293675Sjimharris{ 383293675Sjimharris struct ismt_desc *desc; 384293675Sjimharris struct ismt_softc *sc; 385293675Sjimharris 386293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 387293675Sjimharris 388293675Sjimharris sc = device_get_softc(dev); 389293675Sjimharris desc = ismt_alloc_desc(sc); 390293675Sjimharris desc->wr_len_cmd = 3; 391293675Sjimharris sc->dma_buffer[0] = cmd; 392293675Sjimharris sc->dma_buffer[1] = word & 0xFF; 393293675Sjimharris sc->dma_buffer[2] = word >> 8; 394293675Sjimharris 395293675Sjimharris return (ismt_submit(sc, desc, slave, 0)); 396293675Sjimharris} 397293675Sjimharris 398293675Sjimharrisstatic int 399293675Sjimharrisismt_readb(device_t dev, u_char slave, char cmd, char *byte) 400293675Sjimharris{ 401293675Sjimharris struct ismt_desc *desc; 402293675Sjimharris struct ismt_softc *sc; 403293675Sjimharris int err; 404293675Sjimharris 405293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 406293675Sjimharris 407293675Sjimharris sc = device_get_softc(dev); 408293675Sjimharris desc = ismt_alloc_desc(sc); 409293675Sjimharris desc->control = ISMT_DESC_CWRL; 410293675Sjimharris desc->wr_len_cmd = cmd; 411293675Sjimharris desc->rd_len = 1; 412293675Sjimharris 413293675Sjimharris err = ismt_submit(sc, desc, slave, 1); 414293675Sjimharris 415293675Sjimharris if (err != SMB_ENOERR) 416293675Sjimharris return (err); 417293675Sjimharris 418293675Sjimharris *byte = sc->dma_buffer[0]; 419293675Sjimharris 420293675Sjimharris return (err); 421293675Sjimharris} 422293675Sjimharris 423293675Sjimharrisstatic int 424293675Sjimharrisismt_readw(device_t dev, u_char slave, char cmd, short *word) 425293675Sjimharris{ 426293675Sjimharris struct ismt_desc *desc; 427293675Sjimharris struct ismt_softc *sc; 428293675Sjimharris int err; 429293675Sjimharris 430293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 431293675Sjimharris 432293675Sjimharris sc = device_get_softc(dev); 433293675Sjimharris desc = ismt_alloc_desc(sc); 434293675Sjimharris desc->control = ISMT_DESC_CWRL; 435293675Sjimharris desc->wr_len_cmd = cmd; 436293675Sjimharris desc->rd_len = 2; 437293675Sjimharris 438293675Sjimharris err = ismt_submit(sc, desc, slave, 1); 439293675Sjimharris 440293675Sjimharris if (err != SMB_ENOERR) 441293675Sjimharris return (err); 442293675Sjimharris 443293675Sjimharris *word = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8); 444293675Sjimharris 445293675Sjimharris return (err); 446293675Sjimharris} 447293675Sjimharris 448293675Sjimharrisstatic int 449293675Sjimharrisismt_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 450293675Sjimharris{ 451293675Sjimharris struct ismt_desc *desc; 452293675Sjimharris struct ismt_softc *sc; 453293675Sjimharris int err; 454293675Sjimharris 455293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 456293675Sjimharris 457293675Sjimharris sc = device_get_softc(dev); 458293675Sjimharris desc = ismt_alloc_desc(sc); 459293675Sjimharris desc->wr_len_cmd = 3; 460293675Sjimharris desc->rd_len = 2; 461293675Sjimharris sc->dma_buffer[0] = cmd; 462293675Sjimharris sc->dma_buffer[1] = sdata & 0xff; 463293675Sjimharris sc->dma_buffer[2] = sdata >> 8; 464293675Sjimharris 465293675Sjimharris err = ismt_submit(sc, desc, slave, 0); 466293675Sjimharris 467293675Sjimharris if (err != SMB_ENOERR) 468293675Sjimharris return (err); 469293675Sjimharris 470293675Sjimharris *rdata = sc->dma_buffer[0] | (sc->dma_buffer[1] << 8); 471293675Sjimharris 472293675Sjimharris return (err); 473293675Sjimharris} 474293675Sjimharris 475293675Sjimharrisstatic int 476293675Sjimharrisismt_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 477293675Sjimharris{ 478293675Sjimharris struct ismt_desc *desc; 479293675Sjimharris struct ismt_softc *sc; 480293675Sjimharris 481293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 482293675Sjimharris 483293675Sjimharris if (count == 0 || count > ISMT_MAX_BLOCK_SIZE) 484293675Sjimharris return (SMB_EINVAL); 485293675Sjimharris 486293675Sjimharris sc = device_get_softc(dev); 487293675Sjimharris desc = ismt_alloc_desc(sc); 488293675Sjimharris desc->control = ISMT_DESC_I2C; 489293675Sjimharris desc->wr_len_cmd = count + 1; 490293675Sjimharris sc->dma_buffer[0] = cmd; 491293675Sjimharris memcpy(&sc->dma_buffer[1], buf, count); 492293675Sjimharris 493293675Sjimharris return (ismt_submit(sc, desc, slave, 0)); 494293675Sjimharris} 495293675Sjimharris 496293675Sjimharrisstatic int 497293675Sjimharrisismt_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 498293675Sjimharris{ 499293675Sjimharris struct ismt_desc *desc; 500293675Sjimharris struct ismt_softc *sc; 501293675Sjimharris int err; 502293675Sjimharris 503293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 504293675Sjimharris 505293675Sjimharris if (*count == 0 || *count > ISMT_MAX_BLOCK_SIZE) 506293675Sjimharris return (SMB_EINVAL); 507293675Sjimharris 508293675Sjimharris sc = device_get_softc(dev); 509293675Sjimharris desc = ismt_alloc_desc(sc); 510293675Sjimharris desc->control = ISMT_DESC_I2C | ISMT_DESC_CWRL; 511293675Sjimharris desc->wr_len_cmd = cmd; 512293675Sjimharris desc->rd_len = *count; 513293675Sjimharris 514293675Sjimharris err = ismt_submit(sc, desc, slave, 0); 515293675Sjimharris 516293675Sjimharris if (err != SMB_ENOERR) 517293675Sjimharris return (err); 518293675Sjimharris 519293675Sjimharris memcpy(buf, sc->dma_buffer, desc->rxbytes); 520293675Sjimharris *count = desc->rxbytes; 521293675Sjimharris 522293675Sjimharris return (err); 523293675Sjimharris} 524293675Sjimharris 525293675Sjimharrisstatic int 526293675Sjimharrisismt_detach(device_t dev) 527293675Sjimharris{ 528293675Sjimharris struct ismt_softc *sc; 529293675Sjimharris int error; 530293675Sjimharris 531293675Sjimharris ISMT_DEBUG(dev, "%s\n", __func__); 532293675Sjimharris sc = device_get_softc(dev); 533293675Sjimharris 534293675Sjimharris error = bus_generic_detach(dev); 535293675Sjimharris if (error) 536293675Sjimharris return (error); 537293675Sjimharris 538293675Sjimharris device_delete_child(dev, sc->smbdev); 539293675Sjimharris 540293675Sjimharris if (sc->intr_handle != NULL) { 541293675Sjimharris bus_teardown_intr(dev, sc->intr_res, sc->intr_handle); 542293675Sjimharris sc->intr_handle = NULL; 543293675Sjimharris } 544293675Sjimharris if (sc->intr_res != NULL) { 545293675Sjimharris bus_release_resource(dev, 546293675Sjimharris SYS_RES_IRQ, sc->intr_rid, sc->intr_res); 547293675Sjimharris sc->intr_res = NULL; 548293675Sjimharris } 549293675Sjimharris if (sc->using_msi == 1) 550293675Sjimharris pci_release_msi(dev); 551293675Sjimharris 552293675Sjimharris if (sc->mmio_res != NULL) { 553293675Sjimharris bus_release_resource(dev, 554293675Sjimharris SYS_RES_MEMORY, sc->mmio_rid, sc->mmio_res); 555293675Sjimharris sc->mmio_res = NULL; 556293675Sjimharris } 557293675Sjimharris 558293675Sjimharris bus_dmamap_unload(sc->desc_dma_tag, sc->desc_dma_map); 559293675Sjimharris bus_dmamap_unload(sc->dma_buffer_dma_tag, sc->dma_buffer_dma_map); 560293675Sjimharris 561293675Sjimharris bus_dmamem_free(sc->desc_dma_tag, sc->desc, 562293675Sjimharris sc->desc_dma_map); 563293675Sjimharris bus_dmamem_free(sc->dma_buffer_dma_tag, sc->dma_buffer, 564293675Sjimharris sc->dma_buffer_dma_map); 565293675Sjimharris 566293675Sjimharris bus_dma_tag_destroy(sc->desc_dma_tag); 567293675Sjimharris bus_dma_tag_destroy(sc->dma_buffer_dma_tag); 568293675Sjimharris 569293675Sjimharris pci_disable_busmaster(dev); 570293675Sjimharris 571293675Sjimharris return 0; 572293675Sjimharris} 573293675Sjimharris 574293675Sjimharrisstatic void 575293675Sjimharrisismt_single_map(void *arg, bus_dma_segment_t *seg, int nseg, int error) 576293675Sjimharris{ 577293675Sjimharris uint64_t *bus_addr = (uint64_t *)arg; 578293675Sjimharris 579293675Sjimharris KASSERT(error == 0, ("%s: error=%d\n", __func__, error)); 580293675Sjimharris KASSERT(nseg == 1, ("%s: nseg=%d\n", __func__, nseg)); 581293675Sjimharris 582293675Sjimharris *bus_addr = seg[0].ds_addr; 583293675Sjimharris} 584293675Sjimharris 585293675Sjimharrisstatic int 586293675Sjimharrisismt_attach(device_t dev) 587293675Sjimharris{ 588293675Sjimharris struct ismt_softc *sc = device_get_softc(dev); 589293675Sjimharris int err, num_vectors, val; 590293675Sjimharris 591293675Sjimharris sc->pcidev = dev; 592293675Sjimharris pci_enable_busmaster(dev); 593293675Sjimharris 594293675Sjimharris if ((sc->smbdev = device_add_child(dev, "smbus", -1)) == NULL) { 595293675Sjimharris device_printf(dev, "no smbus child found\n"); 596293675Sjimharris err = ENXIO; 597293675Sjimharris goto fail; 598293675Sjimharris } 599293675Sjimharris 600293675Sjimharris sc->mmio_rid = PCIR_BAR(0); 601293675Sjimharris sc->mmio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 602293675Sjimharris &sc->mmio_rid, RF_ACTIVE); 603293675Sjimharris if (sc->mmio_res == NULL) { 604293675Sjimharris device_printf(dev, "cannot allocate mmio region\n"); 605293675Sjimharris err = ENOMEM; 606293675Sjimharris goto fail; 607293675Sjimharris } 608293675Sjimharris 609293675Sjimharris sc->mmio_tag = rman_get_bustag(sc->mmio_res); 610293675Sjimharris sc->mmio_handle = rman_get_bushandle(sc->mmio_res); 611293675Sjimharris 612293675Sjimharris /* Attach "smbus" child */ 613293675Sjimharris if ((err = bus_generic_attach(dev)) != 0) { 614293675Sjimharris device_printf(dev, "failed to attach child: %d\n", err); 615293675Sjimharris err = ENXIO; 616293675Sjimharris goto fail; 617293675Sjimharris } 618293675Sjimharris 619293675Sjimharris bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE, 620293675Sjimharris BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 621293675Sjimharris DESC_SIZE, 1, DESC_SIZE, 622293675Sjimharris 0, NULL, NULL, &sc->desc_dma_tag); 623293675Sjimharris 624293675Sjimharris bus_dma_tag_create(bus_get_dma_tag(dev), 4, PAGE_SIZE, 625293675Sjimharris BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, 626293675Sjimharris DMA_BUFFER_SIZE, 1, DMA_BUFFER_SIZE, 627293675Sjimharris 0, NULL, NULL, &sc->dma_buffer_dma_tag); 628293675Sjimharris 629293675Sjimharris bus_dmamap_create(sc->desc_dma_tag, 0, 630293675Sjimharris &sc->desc_dma_map); 631293675Sjimharris bus_dmamap_create(sc->dma_buffer_dma_tag, 0, 632293675Sjimharris &sc->dma_buffer_dma_map); 633293675Sjimharris 634293675Sjimharris bus_dmamem_alloc(sc->desc_dma_tag, 635293675Sjimharris (void **)&sc->desc, BUS_DMA_WAITOK, 636293675Sjimharris &sc->desc_dma_map); 637293675Sjimharris bus_dmamem_alloc(sc->dma_buffer_dma_tag, 638293675Sjimharris (void **)&sc->dma_buffer, BUS_DMA_WAITOK, 639293675Sjimharris &sc->dma_buffer_dma_map); 640293675Sjimharris 641293675Sjimharris bus_dmamap_load(sc->desc_dma_tag, 642293675Sjimharris sc->desc_dma_map, sc->desc, DESC_SIZE, 643293675Sjimharris ismt_single_map, &sc->desc_bus_addr, 0); 644293675Sjimharris bus_dmamap_load(sc->dma_buffer_dma_tag, 645293675Sjimharris sc->dma_buffer_dma_map, sc->dma_buffer, DMA_BUFFER_SIZE, 646293675Sjimharris ismt_single_map, &sc->dma_buffer_bus_addr, 0); 647293675Sjimharris 648293675Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA, 649293675Sjimharris (sc->desc_bus_addr & 0xFFFFFFFFLL)); 650293675Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MDBA + 4, 651293675Sjimharris (sc->desc_bus_addr >> 32)); 652293675Sjimharris 653293675Sjimharris /* initialize the Master Control Register (MCTRL) */ 654293675Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MCTRL, ISMT_MCTRL_MEIE); 655293675Sjimharris 656293675Sjimharris /* initialize the Master Status Register (MSTS) */ 657293675Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MSTS, 0); 658293675Sjimharris 659293675Sjimharris /* initialize the Master Descriptor Size (MDS) */ 660293675Sjimharris val = bus_read_4(sc->mmio_res, ISMT_MSTR_MDS); 661293675Sjimharris val &= ~ISMT_MDS_MASK; 662293675Sjimharris val |= (ISMT_DESC_ENTRIES - 1); 663293675Sjimharris bus_write_4(sc->mmio_res, ISMT_MSTR_MDS, val); 664293675Sjimharris 665293675Sjimharris sc->using_msi = 1; 666293675Sjimharris 667293675Sjimharris if (pci_msi_count(dev) == 0) { 668293675Sjimharris sc->using_msi = 0; 669293675Sjimharris goto intx; 670293675Sjimharris } 671293675Sjimharris 672293675Sjimharris num_vectors = 1; 673293675Sjimharris if (pci_alloc_msi(dev, &num_vectors) != 0) { 674293675Sjimharris sc->using_msi = 0; 675293675Sjimharris goto intx; 676293675Sjimharris } 677293675Sjimharris 678293675Sjimharris sc->intr_rid = 1; 679293675Sjimharris sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 680293675Sjimharris &sc->intr_rid, RF_ACTIVE); 681293675Sjimharris 682293675Sjimharris if (sc->intr_res == NULL) { 683293675Sjimharris sc->using_msi = 0; 684293675Sjimharris pci_release_msi(dev); 685293675Sjimharris } 686293675Sjimharris 687293675Sjimharrisintx: 688293675Sjimharris if (sc->using_msi == 0) { 689293675Sjimharris sc->intr_rid = 0; 690293675Sjimharris sc->intr_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 691293675Sjimharris &sc->intr_rid, RF_SHAREABLE | RF_ACTIVE); 692293675Sjimharris if (sc->intr_res == NULL) { 693293675Sjimharris device_printf(dev, "cannot allocate irq\n"); 694293675Sjimharris err = ENXIO; 695293675Sjimharris goto fail; 696293675Sjimharris } 697293675Sjimharris } 698293675Sjimharris 699293675Sjimharris ISMT_DEBUG(dev, "using_msi = %d\n", sc->using_msi); 700293675Sjimharris 701293675Sjimharris err = bus_setup_intr(dev, sc->intr_res, 702293675Sjimharris INTR_TYPE_MISC | INTR_MPSAFE, NULL, ismt_intr, sc, 703293675Sjimharris &sc->intr_handle); 704293675Sjimharris if (err != 0) { 705293675Sjimharris device_printf(dev, "cannot setup interrupt\n"); 706293675Sjimharris err = ENXIO; 707293675Sjimharris goto fail; 708293675Sjimharris } 709293675Sjimharris 710293675Sjimharris return (0); 711293675Sjimharris 712293675Sjimharrisfail: 713293675Sjimharris ismt_detach(dev); 714293675Sjimharris return (err); 715293675Sjimharris} 716293675Sjimharris 717293675Sjimharris#define ID_INTEL_S1200_SMT0 0x0c598086 718293675Sjimharris#define ID_INTEL_S1200_SMT1 0x0c5a8086 719293675Sjimharris#define ID_INTEL_C2000_SMT 0x1f158086 720293675Sjimharris 721293675Sjimharrisstatic int 722293675Sjimharrisismt_probe(device_t dev) 723293675Sjimharris{ 724293675Sjimharris const char *desc; 725293675Sjimharris 726293675Sjimharris switch (pci_get_devid(dev)) { 727293675Sjimharris case ID_INTEL_S1200_SMT0: 728293675Sjimharris desc = "Atom Processor S1200 SMBus 2.0 Controller 0"; 729293675Sjimharris break; 730293675Sjimharris case ID_INTEL_S1200_SMT1: 731293675Sjimharris desc = "Atom Processor S1200 SMBus 2.0 Controller 1"; 732293675Sjimharris break; 733293675Sjimharris case ID_INTEL_C2000_SMT: 734293675Sjimharris desc = "Atom Processor C2000 SMBus 2.0"; 735293675Sjimharris break; 736293675Sjimharris default: 737293675Sjimharris return (ENXIO); 738293675Sjimharris } 739293675Sjimharris 740293675Sjimharris device_set_desc(dev, desc); 741293675Sjimharris return (BUS_PROBE_DEFAULT); 742293675Sjimharris} 743293675Sjimharris 744293675Sjimharris/* Device methods */ 745293675Sjimharrisstatic device_method_t ismt_pci_methods[] = { 746293675Sjimharris DEVMETHOD(device_probe, ismt_probe), 747293675Sjimharris DEVMETHOD(device_attach, ismt_attach), 748293675Sjimharris DEVMETHOD(device_detach, ismt_detach), 749293675Sjimharris 750293675Sjimharris DEVMETHOD(smbus_callback, ismt_callback), 751293675Sjimharris DEVMETHOD(smbus_quick, ismt_quick), 752293675Sjimharris DEVMETHOD(smbus_sendb, ismt_sendb), 753293675Sjimharris DEVMETHOD(smbus_recvb, ismt_recvb), 754293675Sjimharris DEVMETHOD(smbus_writeb, ismt_writeb), 755293675Sjimharris DEVMETHOD(smbus_writew, ismt_writew), 756293675Sjimharris DEVMETHOD(smbus_readb, ismt_readb), 757293675Sjimharris DEVMETHOD(smbus_readw, ismt_readw), 758293675Sjimharris DEVMETHOD(smbus_pcall, ismt_pcall), 759293675Sjimharris DEVMETHOD(smbus_bwrite, ismt_bwrite), 760293675Sjimharris DEVMETHOD(smbus_bread, ismt_bread), 761293675Sjimharris 762293675Sjimharris DEVMETHOD_END 763293675Sjimharris}; 764293675Sjimharris 765293675Sjimharrisstatic driver_t ismt_pci_driver = { 766293675Sjimharris "ismt", 767293675Sjimharris ismt_pci_methods, 768293675Sjimharris sizeof(struct ismt_softc) 769293675Sjimharris}; 770293675Sjimharris 771293675Sjimharrisstatic devclass_t ismt_pci_devclass; 772293675Sjimharris 773293675SjimharrisDRIVER_MODULE(ismt, pci, ismt_pci_driver, ismt_pci_devclass, 0, 0); 774293675SjimharrisDRIVER_MODULE(smbus, ismt, smbus_driver, smbus_devclass, 0, 0); 775293675Sjimharris 776293675SjimharrisMODULE_DEPEND(ismt, pci, 1, 1, 1); 777293675SjimharrisMODULE_DEPEND(ismt, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 778293675SjimharrisMODULE_VERSION(ismt, 1); 779