1*b63b081bSriastradh /* $NetBSD: imcsmb.c,v 1.6 2023/05/10 00:07:49 riastradh Exp $ */
282ae8dd1Spgoyette
382ae8dd1Spgoyette /*-
482ae8dd1Spgoyette * Copyright (c) 2018 The NetBSD Foundation, Inc.
582ae8dd1Spgoyette * All rights reserved.
682ae8dd1Spgoyette *
782ae8dd1Spgoyette * This code is derived from software contributed to The NetBSD Foundation
882ae8dd1Spgoyette * by Paul Goyette
982ae8dd1Spgoyette *
1082ae8dd1Spgoyette * Redistribution and use in source and binary forms, with or without
1182ae8dd1Spgoyette * modification, are permitted provided that the following conditions
1282ae8dd1Spgoyette * are met:
1382ae8dd1Spgoyette * 1. Redistributions of source code must retain the above copyright
1482ae8dd1Spgoyette * notice, this list of conditions and the following disclaimer.
1582ae8dd1Spgoyette * 2. Redistributions in binary form must reproduce the above copyright
1682ae8dd1Spgoyette * notice, this list of conditions and the following disclaimer in the
1782ae8dd1Spgoyette * documentation and/or other materials provided with the distribution.
1882ae8dd1Spgoyette *
1982ae8dd1Spgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2082ae8dd1Spgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2182ae8dd1Spgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2282ae8dd1Spgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2382ae8dd1Spgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2482ae8dd1Spgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2582ae8dd1Spgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2682ae8dd1Spgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2782ae8dd1Spgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2882ae8dd1Spgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2982ae8dd1Spgoyette * POSSIBILITY OF SUCH DAMAGE.
3082ae8dd1Spgoyette */
3182ae8dd1Spgoyette
3282ae8dd1Spgoyette /*-
3382ae8dd1Spgoyette * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3482ae8dd1Spgoyette *
3582ae8dd1Spgoyette * Authors: Joe Kloss; Ravi Pokala (rpokala@freebsd.org)
3682ae8dd1Spgoyette *
3782ae8dd1Spgoyette * Copyright (c) 2017-2018 Panasas
3882ae8dd1Spgoyette * All rights reserved.
3982ae8dd1Spgoyette *
4082ae8dd1Spgoyette * Redistribution and use in source and binary forms, with or without
4182ae8dd1Spgoyette * modification, are permitted provided that the following conditions
4282ae8dd1Spgoyette * are met:
4382ae8dd1Spgoyette * 1. Redistributions of source code must retain the above copyright
4482ae8dd1Spgoyette * notice, this list of conditions and the following disclaimer.
4582ae8dd1Spgoyette * 2. Redistributions in binary form must reproduce the above copyright
4682ae8dd1Spgoyette * notice, this list of conditions and the following disclaimer in the
4782ae8dd1Spgoyette * documentation and/or other materials provided with the distribution.
4882ae8dd1Spgoyette *
4982ae8dd1Spgoyette * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
5082ae8dd1Spgoyette * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5182ae8dd1Spgoyette * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5282ae8dd1Spgoyette * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
5382ae8dd1Spgoyette * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5482ae8dd1Spgoyette * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5582ae8dd1Spgoyette * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5682ae8dd1Spgoyette * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5782ae8dd1Spgoyette * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5882ae8dd1Spgoyette * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5982ae8dd1Spgoyette * SUCH DAMAGE.
6082ae8dd1Spgoyette */
6182ae8dd1Spgoyette
6282ae8dd1Spgoyette /*
6382ae8dd1Spgoyette * Driver for the SMBus controllers in Intel's Integrated Memory Controllers
6482ae8dd1Spgoyette * in certain CPUs. A more detailed description of this device is present
6582ae8dd1Spgoyette * in imc.c
6682ae8dd1Spgoyette */
6782ae8dd1Spgoyette
6882ae8dd1Spgoyette #include <sys/cdefs.h>
69*b63b081bSriastradh __KERNEL_RCSID(0, "$NetBSD: imcsmb.c,v 1.6 2023/05/10 00:07:49 riastradh Exp $");
7082ae8dd1Spgoyette
7182ae8dd1Spgoyette #include <sys/param.h>
7282ae8dd1Spgoyette #include <sys/kernel.h>
7382ae8dd1Spgoyette #include <sys/module.h>
7482ae8dd1Spgoyette #include <sys/endian.h>
7582ae8dd1Spgoyette #include <sys/errno.h>
7682ae8dd1Spgoyette #include <sys/mutex.h>
7782ae8dd1Spgoyette #include <sys/bus.h>
7882ae8dd1Spgoyette
7982ae8dd1Spgoyette #include <dev/pci/pcidevs.h>
8082ae8dd1Spgoyette #include <dev/pci/pcivar.h>
8182ae8dd1Spgoyette #include <dev/pci/pcireg.h>
8282ae8dd1Spgoyette
8382ae8dd1Spgoyette #include <dev/i2c/i2cvar.h>
8482ae8dd1Spgoyette
8582ae8dd1Spgoyette #include "imcsmb_reg.h"
8682ae8dd1Spgoyette #include "imcsmb_var.h"
8782ae8dd1Spgoyette
8882ae8dd1Spgoyette /* Device methods */
8982ae8dd1Spgoyette static int imcsmb_probe(device_t, cfdata_t, void *);
9082ae8dd1Spgoyette static void imcsmb_attach(device_t, device_t, void *);
9182ae8dd1Spgoyette static int imcsmb_detach(device_t, int flags);
9282ae8dd1Spgoyette static int imcsmb_rescan(device_t, const char *, const int *);
9382ae8dd1Spgoyette static void imcsmb_chdet(device_t, device_t);
9482ae8dd1Spgoyette
9582ae8dd1Spgoyette CFATTACH_DECL3_NEW(imcsmb, sizeof(struct imcsmb_softc),
9682ae8dd1Spgoyette imcsmb_probe, imcsmb_attach, imcsmb_detach, NULL, imcsmb_rescan,
9782ae8dd1Spgoyette imcsmb_chdet, 0);
9882ae8dd1Spgoyette
9982ae8dd1Spgoyette /* Bus access control methods */
10082ae8dd1Spgoyette static int imcsmb_acquire_bus(void *cookie, int flags);
10182ae8dd1Spgoyette static void imcsmb_release_bus(void *cookie, int flags);
10282ae8dd1Spgoyette
10382ae8dd1Spgoyette /* SMBus methods */
10482ae8dd1Spgoyette static int imcsmb_exec(void *cookie, i2c_op_t, i2c_addr_t, const void *,
10582ae8dd1Spgoyette size_t, void *, size_t, int);
10682ae8dd1Spgoyette
10782ae8dd1Spgoyette /**
10882ae8dd1Spgoyette * device_attach() method. Set up the softc, including getting the set of the
10982ae8dd1Spgoyette * parent imcsmb_pci's registers that we will use. Create the smbus(4) device,
11082ae8dd1Spgoyette * which any SMBus slave device drivers will connect to. Probe and attach
11182ae8dd1Spgoyette * anything which might be downstream.
11282ae8dd1Spgoyette *
11382ae8dd1Spgoyette * @author rpokala
11482ae8dd1Spgoyette *
11582ae8dd1Spgoyette * @param[in,out] dev
11682ae8dd1Spgoyette * Device being attached.
11782ae8dd1Spgoyette */
11882ae8dd1Spgoyette
11982ae8dd1Spgoyette static void
imcsmb_attach(device_t parent,device_t self,void * aux)12082ae8dd1Spgoyette imcsmb_attach(device_t parent, device_t self, void *aux)
12182ae8dd1Spgoyette {
12282ae8dd1Spgoyette struct imcsmb_softc *sc = device_private(self);
12382ae8dd1Spgoyette struct imc_attach_args *imca = aux;
12482ae8dd1Spgoyette
12582ae8dd1Spgoyette aprint_naive("\n");
12697f048a5Spgoyette aprint_normal(": SMBus controller\n");
12782ae8dd1Spgoyette
12882ae8dd1Spgoyette /* Initialize private state */
12982ae8dd1Spgoyette sc->sc_dev = self;
13082ae8dd1Spgoyette sc->sc_regs = imca->ia_regs;
13182ae8dd1Spgoyette sc->sc_pci_tag = imca->ia_pci_tag;
13282ae8dd1Spgoyette sc->sc_pci_chipset_tag = imca->ia_pci_chipset_tag;
13382ae8dd1Spgoyette
13482ae8dd1Spgoyette if (!pmf_device_register(self, NULL, NULL))
13582ae8dd1Spgoyette aprint_error_dev(self, "couldn't establish power handler\n");
13682ae8dd1Spgoyette
1372685996bSthorpej imcsmb_rescan(self, NULL, NULL);
13882ae8dd1Spgoyette }
13982ae8dd1Spgoyette
14082ae8dd1Spgoyette static int
imcsmb_rescan(device_t self,const char * ifattr,const int * locs)1412685996bSthorpej imcsmb_rescan(device_t self, const char *ifattr, const int *locs)
14282ae8dd1Spgoyette {
14382ae8dd1Spgoyette struct imcsmb_softc *sc = device_private(self);
14482ae8dd1Spgoyette struct i2cbus_attach_args iba;
14582ae8dd1Spgoyette
14682ae8dd1Spgoyette /* Create the i2cbus child */
14782ae8dd1Spgoyette if (sc->sc_smbus != NULL)
14882ae8dd1Spgoyette return 0;
14982ae8dd1Spgoyette
150601e1783Sthorpej iic_tag_init(&sc->sc_i2c_tag);
15182ae8dd1Spgoyette sc->sc_i2c_tag.ic_cookie = sc;
15282ae8dd1Spgoyette sc->sc_i2c_tag.ic_acquire_bus = imcsmb_acquire_bus;
15382ae8dd1Spgoyette sc->sc_i2c_tag.ic_release_bus = imcsmb_release_bus;
15482ae8dd1Spgoyette sc->sc_i2c_tag.ic_exec = imcsmb_exec;
15582ae8dd1Spgoyette
15682ae8dd1Spgoyette memset(&iba, 0, sizeof(iba));
15782ae8dd1Spgoyette iba.iba_tag = &sc->sc_i2c_tag;
158c7fb772bSthorpej sc->sc_smbus = config_found(self, &iba, iicbus_print, CFARGS_NONE);
15982ae8dd1Spgoyette
16082ae8dd1Spgoyette if (sc->sc_smbus == NULL) {
16182ae8dd1Spgoyette aprint_normal_dev(self, "no child found\n");
16282ae8dd1Spgoyette return ENXIO;
16382ae8dd1Spgoyette }
16482ae8dd1Spgoyette
16582ae8dd1Spgoyette return 0;
16682ae8dd1Spgoyette }
16782ae8dd1Spgoyette
16882ae8dd1Spgoyette static void
imcsmb_chdet(device_t self,device_t child)16982ae8dd1Spgoyette imcsmb_chdet(device_t self, device_t child)
17082ae8dd1Spgoyette {
17182ae8dd1Spgoyette struct imcsmb_softc *sc = device_private(self);
17282ae8dd1Spgoyette
17382ae8dd1Spgoyette if (child == sc->sc_smbus)
17482ae8dd1Spgoyette sc->sc_smbus = NULL;
17582ae8dd1Spgoyette else KASSERT(child == NULL);
17682ae8dd1Spgoyette }
17782ae8dd1Spgoyette
17882ae8dd1Spgoyette /**
17982ae8dd1Spgoyette * device_detach() method. attach() didn't do any allocations, so there's
18082ae8dd1Spgoyette * nothing special needed
18182ae8dd1Spgoyette */
18282ae8dd1Spgoyette static int
imcsmb_detach(device_t self,int flags)18382ae8dd1Spgoyette imcsmb_detach(device_t self, int flags)
18482ae8dd1Spgoyette {
18582ae8dd1Spgoyette struct imcsmb_softc *sc = device_private(self);
186*b63b081bSriastradh int error;
18782ae8dd1Spgoyette
188*b63b081bSriastradh error = config_detach_children(self, flags);
18982ae8dd1Spgoyette if (error)
19082ae8dd1Spgoyette return error;
19182ae8dd1Spgoyette
19282ae8dd1Spgoyette pmf_device_deregister(self);
193601e1783Sthorpej iic_tag_fini(&sc->sc_i2c_tag);
19482ae8dd1Spgoyette return 0;
19582ae8dd1Spgoyette }
19682ae8dd1Spgoyette
19782ae8dd1Spgoyette /**
19882ae8dd1Spgoyette * device_probe() method. All the actual probing was done by the imc
19982ae8dd1Spgoyette * parent, so just report success.
20082ae8dd1Spgoyette *
20182ae8dd1Spgoyette * @author Joe Kloss
20282ae8dd1Spgoyette *
20382ae8dd1Spgoyette * @param[in,out] dev
20482ae8dd1Spgoyette * Device being probed.
20582ae8dd1Spgoyette */
20682ae8dd1Spgoyette static int
imcsmb_probe(device_t parent,cfdata_t match,void * aux)20782ae8dd1Spgoyette imcsmb_probe(device_t parent, cfdata_t match, void *aux)
20882ae8dd1Spgoyette {
20982ae8dd1Spgoyette
21082ae8dd1Spgoyette return 1;
21182ae8dd1Spgoyette }
21282ae8dd1Spgoyette
21382ae8dd1Spgoyette static int
imcsmb_acquire_bus(void * cookie,int flags)21482ae8dd1Spgoyette imcsmb_acquire_bus(void *cookie, int flags)
21582ae8dd1Spgoyette {
21682ae8dd1Spgoyette struct imcsmb_softc *sc = cookie;
21782ae8dd1Spgoyette
21882ae8dd1Spgoyette if (cold)
21982ae8dd1Spgoyette return 0;
22082ae8dd1Spgoyette
22182ae8dd1Spgoyette imc_callback(sc, IMC_BIOS_DISABLE);
22282ae8dd1Spgoyette
22382ae8dd1Spgoyette return 0;
22482ae8dd1Spgoyette }
22582ae8dd1Spgoyette
22682ae8dd1Spgoyette static void
imcsmb_release_bus(void * cookie,int flags)22782ae8dd1Spgoyette imcsmb_release_bus(void *cookie, int flags)
22882ae8dd1Spgoyette {
22982ae8dd1Spgoyette struct imcsmb_softc *sc = cookie;
23082ae8dd1Spgoyette
23182ae8dd1Spgoyette if (cold)
23282ae8dd1Spgoyette return;
23382ae8dd1Spgoyette
23482ae8dd1Spgoyette imc_callback(sc, IMC_BIOS_ENABLE);
23582ae8dd1Spgoyette }
23682ae8dd1Spgoyette
23782ae8dd1Spgoyette static int
imcsmb_exec(void * cookie,i2c_op_t op,i2c_addr_t addr,const void * cmdbuf,size_t cmdlen,void * buf,size_t len,int flags)23882ae8dd1Spgoyette imcsmb_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
23982ae8dd1Spgoyette size_t cmdlen, void *buf, size_t len, int flags)
24082ae8dd1Spgoyette {
24182ae8dd1Spgoyette struct imcsmb_softc *sc = cookie;
24282ae8dd1Spgoyette int i;
24382ae8dd1Spgoyette int rc = 0;
24482ae8dd1Spgoyette uint32_t cmd_val;
24582ae8dd1Spgoyette uint32_t cntl_val;
24682ae8dd1Spgoyette uint32_t orig_cntl_val;
24782ae8dd1Spgoyette uint32_t stat_val;
24882ae8dd1Spgoyette uint16_t *word;
24982ae8dd1Spgoyette uint16_t lword;
25082ae8dd1Spgoyette uint8_t *byte;
25182ae8dd1Spgoyette uint8_t lbyte;
25282ae8dd1Spgoyette uint8_t cmd;
25382ae8dd1Spgoyette
25482ae8dd1Spgoyette if ((cmdlen != 1) || (len > 2) || (len < 1))
25582ae8dd1Spgoyette return EINVAL;
25682ae8dd1Spgoyette
25782ae8dd1Spgoyette byte = (uint8_t *) buf;
25882ae8dd1Spgoyette word = (uint16_t *) buf;
25982ae8dd1Spgoyette lbyte = *byte;
26082ae8dd1Spgoyette lword = *word;
26182ae8dd1Spgoyette
26282ae8dd1Spgoyette /* We modify the value of the control register; save the original, so
26382ae8dd1Spgoyette * we can restore it later
26482ae8dd1Spgoyette */
26582ae8dd1Spgoyette orig_cntl_val = pci_conf_read(sc->sc_pci_chipset_tag, sc->sc_pci_tag,
26682ae8dd1Spgoyette sc->sc_regs->smb_cntl);
26782ae8dd1Spgoyette
26882ae8dd1Spgoyette cntl_val = orig_cntl_val;
26982ae8dd1Spgoyette
27082ae8dd1Spgoyette /*
27182ae8dd1Spgoyette * Set up the SMBCNTL register
27282ae8dd1Spgoyette */
27382ae8dd1Spgoyette
27482ae8dd1Spgoyette /* [31:28] Clear the existing value of the DTI bits, then set them to
27582ae8dd1Spgoyette * the four high bits of the slave address.
27682ae8dd1Spgoyette */
27782ae8dd1Spgoyette cntl_val &= ~IMCSMB_CNTL_DTI_MASK;
27882ae8dd1Spgoyette cntl_val |= ((uint32_t) addr & 0x78) << 25;
27982ae8dd1Spgoyette
28082ae8dd1Spgoyette /* [27:27] Set the CLK_OVERRIDE bit, to enable normal operation */
28182ae8dd1Spgoyette cntl_val |= IMCSMB_CNTL_CLK_OVERRIDE;
28282ae8dd1Spgoyette
28382ae8dd1Spgoyette /* [26:26] Clear the WRITE_DISABLE bit; the datasheet says this isn't
28482ae8dd1Spgoyette * necessary, but empirically, it is.
28582ae8dd1Spgoyette */
28682ae8dd1Spgoyette cntl_val &= ~IMCSMB_CNTL_WRITE_DISABLE_BIT;
28782ae8dd1Spgoyette
28882ae8dd1Spgoyette /* [9:9] Clear the POLL_EN bit, to stop the hardware TSOD polling. */
28982ae8dd1Spgoyette cntl_val &= ~IMCSMB_CNTL_POLL_EN;
29082ae8dd1Spgoyette
29182ae8dd1Spgoyette /*
29282ae8dd1Spgoyette * Set up the SMBCMD register
29382ae8dd1Spgoyette */
29482ae8dd1Spgoyette
29582ae8dd1Spgoyette /* [31:31] Set the TRIGGER bit; when this gets written, the controller
29682ae8dd1Spgoyette * will issue the command.
29782ae8dd1Spgoyette */
29882ae8dd1Spgoyette cmd_val = IMCSMB_CMD_TRIGGER_BIT;
29982ae8dd1Spgoyette
30082ae8dd1Spgoyette /* [29:29] For word operations, set the WORD_ACCESS bit. */
30182ae8dd1Spgoyette if (len == 2) {
30282ae8dd1Spgoyette cmd_val |= IMCSMB_CMD_WORD_ACCESS;
30382ae8dd1Spgoyette }
30482ae8dd1Spgoyette
30582ae8dd1Spgoyette /* [27:27] For write operations, set the WRITE bit. */
30682ae8dd1Spgoyette if (I2C_OP_WRITE_P(op)) {
30782ae8dd1Spgoyette cmd_val |= IMCSMB_CMD_WRITE_BIT;
30882ae8dd1Spgoyette }
30982ae8dd1Spgoyette
31082ae8dd1Spgoyette /* [26:24] The three non-DTI, non-R/W bits of the slave address. */
31182ae8dd1Spgoyette cmd_val |= (uint32_t) ((addr & 0x7) << 24);
31282ae8dd1Spgoyette
31382ae8dd1Spgoyette /* [23:16] The command (offset in the case of an EEPROM, or register in
31482ae8dd1Spgoyette * the case of TSOD or NVDIMM controller).
31582ae8dd1Spgoyette */
31682ae8dd1Spgoyette cmd = *((const uint8_t *) cmdbuf);
31782ae8dd1Spgoyette cmd_val |= (uint32_t) (cmd << 16);
31882ae8dd1Spgoyette
31982ae8dd1Spgoyette /* [15:0] The data to be written for a write operation. */
32082ae8dd1Spgoyette if (I2C_OP_WRITE_P(op)) {
32182ae8dd1Spgoyette if (len == 2) {
32282ae8dd1Spgoyette /* The datasheet says the controller uses different
32382ae8dd1Spgoyette * endianness for word operations on I2C vs SMBus!
32482ae8dd1Spgoyette * I2C: [15:8] = MSB; [7:0] = LSB
32582ae8dd1Spgoyette * SMB: [15:8] = LSB; [7:0] = MSB
32682ae8dd1Spgoyette * As a practical matter, this controller is very
32782ae8dd1Spgoyette * specifically for use with DIMMs, the SPD (and
32882ae8dd1Spgoyette * NVDIMM controllers) are only accessed as bytes,
32982ae8dd1Spgoyette * the temperature sensor is only accessed as words, and
33082ae8dd1Spgoyette * the temperature sensors are I2C. Thus, byte-swap the
33182ae8dd1Spgoyette * word.
33282ae8dd1Spgoyette */
33382ae8dd1Spgoyette lword = htobe16(*(uint16_t *)buf);
33482ae8dd1Spgoyette } else {
33582ae8dd1Spgoyette /* For byte operations, the data goes in the LSB, and
33682ae8dd1Spgoyette * the MSB is a don't care.
33782ae8dd1Spgoyette */
33882ae8dd1Spgoyette lword = *(uint8_t *)buf;
33982ae8dd1Spgoyette }
34082ae8dd1Spgoyette cmd_val |= lword;
34182ae8dd1Spgoyette }
34282ae8dd1Spgoyette
34382ae8dd1Spgoyette /* Write the updated value to the control register first, to disable
34482ae8dd1Spgoyette * the hardware TSOD polling.
34582ae8dd1Spgoyette */
34682ae8dd1Spgoyette pci_conf_write(sc->sc_pci_chipset_tag, sc->sc_pci_tag,
34782ae8dd1Spgoyette sc->sc_regs->smb_cntl, cntl_val);
34882ae8dd1Spgoyette
34982ae8dd1Spgoyette /* Poll on the BUSY bit in the status register until clear, or timeout.
35082ae8dd1Spgoyette * We just cleared the auto-poll bit, so we need to make sure the device
35182ae8dd1Spgoyette * is idle before issuing a command. We can safely timeout after 35 ms,
35282ae8dd1Spgoyette * as this is the maximum time the SMBus spec allows for a transaction.
35382ae8dd1Spgoyette */
35482ae8dd1Spgoyette for (i = 4; i != 0; i--) {
35582ae8dd1Spgoyette stat_val = pci_conf_read(sc->sc_pci_chipset_tag,
35682ae8dd1Spgoyette sc->sc_pci_tag, sc->sc_regs->smb_stat);
35782ae8dd1Spgoyette if (! (stat_val & IMCSMB_STATUS_BUSY_BIT)) {
35882ae8dd1Spgoyette break;
35982ae8dd1Spgoyette }
36082ae8dd1Spgoyette delay(100); /* wait 10ms */
36182ae8dd1Spgoyette }
36282ae8dd1Spgoyette
36382ae8dd1Spgoyette if (i == 0) {
36482ae8dd1Spgoyette aprint_debug_dev(sc->sc_dev,
36582ae8dd1Spgoyette "transfer: timeout waiting for device to settle\n");
36682ae8dd1Spgoyette }
36782ae8dd1Spgoyette
36882ae8dd1Spgoyette /* Now that polling has stopped, we can write the command register. This
36982ae8dd1Spgoyette * starts the SMBus command.
37082ae8dd1Spgoyette */
37182ae8dd1Spgoyette pci_conf_write(sc->sc_pci_chipset_tag, sc->sc_pci_tag,
37282ae8dd1Spgoyette sc->sc_regs->smb_cmd, cmd_val);
37382ae8dd1Spgoyette
37482ae8dd1Spgoyette /* Wait for WRITE_DATA_DONE/READ_DATA_VALID to be set, or timeout and
37582ae8dd1Spgoyette * fail. We wait up to 35ms.
37682ae8dd1Spgoyette */
37782ae8dd1Spgoyette for (i = 35000; i != 0; i -= 10)
37882ae8dd1Spgoyette {
37982ae8dd1Spgoyette delay(10);
38082ae8dd1Spgoyette stat_val = pci_conf_read(sc->sc_pci_chipset_tag,
38182ae8dd1Spgoyette sc->sc_pci_tag, sc->sc_regs->smb_stat);
38282ae8dd1Spgoyette /*
38382ae8dd1Spgoyette * For a write, the bits holding the data contain the data
38482ae8dd1Spgoyette * being written. You would think that would cause the
38582ae8dd1Spgoyette * READ_DATA_VALID bit to be cleared, because the data bits
38682ae8dd1Spgoyette * no longer contain valid data from the most recent read
38782ae8dd1Spgoyette * operation. While that would be logical, that's not the
38882ae8dd1Spgoyette * case here: READ_DATA_VALID is only cleared when starting
38982ae8dd1Spgoyette * a read operation, and WRITE_DATA_DONE is only cleared
39082ae8dd1Spgoyette * when starting a write operation.
39182ae8dd1Spgoyette */
39282ae8dd1Spgoyette if (I2C_OP_WRITE_P(op)) {
39382ae8dd1Spgoyette if (stat_val & IMCSMB_STATUS_WRITE_DATA_DONE) {
39482ae8dd1Spgoyette break;
39582ae8dd1Spgoyette }
39682ae8dd1Spgoyette } else {
39782ae8dd1Spgoyette if (stat_val & IMCSMB_STATUS_READ_DATA_VALID) {
39882ae8dd1Spgoyette break;
39982ae8dd1Spgoyette }
40082ae8dd1Spgoyette }
40182ae8dd1Spgoyette }
40282ae8dd1Spgoyette if (i == 0) {
40382ae8dd1Spgoyette rc = ETIMEDOUT;
40482ae8dd1Spgoyette aprint_debug_dev(sc->sc_dev, "transfer timeout\n");
40582ae8dd1Spgoyette goto out;
40682ae8dd1Spgoyette }
40782ae8dd1Spgoyette
40882ae8dd1Spgoyette /* It is generally the case that this bit indicates non-ACK, but it
40982ae8dd1Spgoyette * could also indicate other bus errors. There's no way to tell the
41082ae8dd1Spgoyette * difference.
41182ae8dd1Spgoyette */
41282ae8dd1Spgoyette if (stat_val & IMCSMB_STATUS_BUS_ERROR_BIT) {
41382ae8dd1Spgoyette /* While it is not documented, empirically, SPD page-change
41482ae8dd1Spgoyette * commands (writes with DTI = 0x30) always complete with the
41582ae8dd1Spgoyette * error bit set. So, ignore it in those cases.
41682ae8dd1Spgoyette */
41782ae8dd1Spgoyette if ((addr & 0x78) != 0x30) {
41882ae8dd1Spgoyette rc = ENODEV;
41982ae8dd1Spgoyette goto out;
42082ae8dd1Spgoyette }
42182ae8dd1Spgoyette }
42282ae8dd1Spgoyette
42382ae8dd1Spgoyette /* For a read operation, copy the data out */
42482ae8dd1Spgoyette if (I2C_OP_READ_P(op)) {
42582ae8dd1Spgoyette if (len == 2) {
42682ae8dd1Spgoyette /* The data is returned in bits [15:0]; as discussed
42782ae8dd1Spgoyette * above, byte-swap.
42882ae8dd1Spgoyette */
42982ae8dd1Spgoyette lword = (uint16_t) (stat_val & 0xffff);
43082ae8dd1Spgoyette lword = htobe16(lword);
43182ae8dd1Spgoyette *(uint16_t *)buf = lword;
43282ae8dd1Spgoyette } else {
43382ae8dd1Spgoyette /* The data is returned in bits [7:0] */
43482ae8dd1Spgoyette lbyte = (uint8_t) (stat_val & 0xff);
43582ae8dd1Spgoyette *(uint8_t *)buf = lbyte;
43682ae8dd1Spgoyette }
43782ae8dd1Spgoyette }
43882ae8dd1Spgoyette
43982ae8dd1Spgoyette out:
44082ae8dd1Spgoyette /* Restore the original value of the control register. */
44182ae8dd1Spgoyette pci_conf_write(sc->sc_pci_chipset_tag, sc->sc_pci_tag,
44282ae8dd1Spgoyette sc->sc_regs->smb_cntl, orig_cntl_val);
44382ae8dd1Spgoyette return rc;
44482ae8dd1Spgoyette };
44582ae8dd1Spgoyette
44682ae8dd1Spgoyette MODULE(MODULE_CLASS_DRIVER, imcsmb, "imc,iic");
44782ae8dd1Spgoyette
44882ae8dd1Spgoyette #ifdef _MODULE
44982ae8dd1Spgoyette #include "ioconf.c"
45082ae8dd1Spgoyette #endif
45182ae8dd1Spgoyette
45282ae8dd1Spgoyette static int
imcsmb_modcmd(modcmd_t cmd,void * opaque)45382ae8dd1Spgoyette imcsmb_modcmd(modcmd_t cmd, void *opaque)
45482ae8dd1Spgoyette {
45582ae8dd1Spgoyette int error = 0;
45682ae8dd1Spgoyette
45782ae8dd1Spgoyette #ifdef _MODULE
45882ae8dd1Spgoyette switch (cmd) {
45982ae8dd1Spgoyette case MODULE_CMD_INIT:
46082ae8dd1Spgoyette error = config_init_component(cfdriver_ioconf_imcsmb,
46182ae8dd1Spgoyette cfattach_ioconf_imcsmb, cfdata_ioconf_imcsmb);
46282ae8dd1Spgoyette break;
46382ae8dd1Spgoyette case MODULE_CMD_FINI:
46482ae8dd1Spgoyette error = config_fini_component(cfdriver_ioconf_imcsmb,
46582ae8dd1Spgoyette cfattach_ioconf_imcsmb, cfdata_ioconf_imcsmb);
46682ae8dd1Spgoyette break;
46782ae8dd1Spgoyette default:
46882ae8dd1Spgoyette error = ENOTTY;
46982ae8dd1Spgoyette break;
47082ae8dd1Spgoyette }
47182ae8dd1Spgoyette #endif
47282ae8dd1Spgoyette
47382ae8dd1Spgoyette return error;
47482ae8dd1Spgoyette }
475