Here is a new version of the dwiic patch that restores the
acpi_attach_deps call, confirmed working by Cesare Gargano.
Any other testers?
Index: sys/conf/files
===================================================================
RCS file: /cvs/src/sys/conf/files,v
retrieving revision 1.654
diff -u -p -u -p -r1.654 files
--- sys/conf/files 3 Nov 2017 13:01:20 -0000 1.654
+++ sys/conf/files 10 Nov 2017 15:56:34 -0000
@@ -524,6 +524,10 @@ file dev/spdmem.c spdmem
device oaic: scsi
file dev/ic/aic6250.c oaic
+# Synopsys DesignWare I2C controller
+device dwiic: i2cbus
+file dev/ic/dwiic.c dwiic
+
# legitimate pseudo-devices
pseudo-device vnd: disk
pseudo-device rd: disk
Index: sys/dev/pci/dwiic_pci.c
===================================================================
RCS file: sys/dev/pci/dwiic_pci.c
diff -N sys/dev/pci/dwiic_pci.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/pci/dwiic_pci.c 10 Nov 2017 15:56:34 -0000
@@ -0,0 +1,204 @@
+/* $OpenBSD$ */
+/*
+ * Synopsys DesignWare I2C controller
+ * PCI attachment
+ *
+ * Copyright (c) 2015-2017 joshua stein <j...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/ic/dwiicvar.h>
+
+/* 13.3: I2C Additional Registers Summary */
+#define LPSS_RESETS 0x204
+#define LPSS_RESETS_I2C (1 << 0) | (1 << 1)
+#define LPSS_RESETS_IDMA (1 << 2)
+#define LPSS_ACTIVELTR 0x210
+#define LPSS_IDLELTR 0x214
+#define LPSS_CAPS 0x2fc
+#define LPSS_CAPS_NO_IDMA (1 << 8)
+#define LPSS_CAPS_TYPE_SHIFT 4
+#define LPSS_CAPS_TYPE_MASK (0xf << LPSS_CAPS_TYPE_SHIFT)
+
+int dwiic_pci_match(struct device *, void *, void *);
+void dwiic_pci_attach(struct device *, struct device *, void *);
+int dwiic_pci_activate(struct device *, int);
+void dwiic_pci_bus_scan(struct device *,
+ struct i2cbus_attach_args *, void *);
+
+#include "acpi.h"
+#if NACPI > 0
+struct aml_node *acpi_pci_match(struct device *dev, struct pci_attach_args
*pa);
+#endif
+
+struct cfattach dwiic_pci_ca = {
+ sizeof(struct dwiic_softc),
+ dwiic_pci_match,
+ dwiic_pci_attach,
+ NULL,
+ dwiic_pci_activate,
+};
+
+const struct pci_matchid dwiic_pci_ids[] = {
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_1 },
+ { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_100SERIES_LP_I2C_2 },
+};
+
+int
+dwiic_pci_match(struct device *parent, void *match, void *aux)
+{
+ return (pci_matchbyid(aux, dwiic_pci_ids, nitems(dwiic_pci_ids)));
+}
+
+void
+dwiic_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct dwiic_softc *sc = (struct dwiic_softc *)self;
+ struct pci_attach_args *pa = aux;
+ bus_size_t iosize;
+ pci_intr_handle_t ih;
+ const char *intrstr = NULL;
+ uint8_t type;
+
+ memcpy(&sc->sc_paa, pa, sizeof(sc->sc_paa));
+
+ pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
+
+ if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_MEM_TYPE_64BIT, 0,
+ &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
+ printf(": can't map mem space\n");
+ return;
+ }
+
+ sc->sc_caps = bus_space_read_4(sc->sc_iot, sc->sc_ioh, LPSS_CAPS);
+ type = sc->sc_caps & LPSS_CAPS_TYPE_MASK;
+ type >>= LPSS_CAPS_TYPE_SHIFT;
+ if (type != 0) {
+ printf(": type %d not supported\n", type);
+ return;
+ }
+
+ /* un-reset - page 958 */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPSS_RESETS,
+ (LPSS_RESETS_I2C | LPSS_RESETS_IDMA));
+
+ /* fetch timing parameters */
+ sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT);
+ sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT);
+ sc->fs_hcnt = dwiic_read(sc, DW_IC_FS_SCL_HCNT);
+ sc->fs_lcnt = dwiic_read(sc, DW_IC_FS_SCL_LCNT);
+ sc->sda_hold_time = dwiic_read(sc, DW_IC_SDA_HOLD);
+
+ if (dwiic_init(sc)) {
+ printf(": failed initializing\n");
+ return;
+ }
+
+ /* leave the controller disabled */
+ dwiic_write(sc, DW_IC_INTR_MASK, 0);
+ dwiic_enable(sc, 0);
+ dwiic_read(sc, DW_IC_CLR_INTR);
+
+ /* install interrupt handler */
+ sc->sc_poll = 1;
+ if (pci_intr_map(&sc->sc_paa, &ih) == 0) {
+ intrstr = pci_intr_string(sc->sc_paa.pa_pc, ih);
+ sc->sc_ih = pci_intr_establish(sc->sc_paa.pa_pc, ih, IPL_BIO,
+ dwiic_intr, sc, sc->sc_dev.dv_xname);
+ if (sc->sc_ih != NULL) {
+ printf(": %s", intrstr);
+ sc->sc_poll = 0;
+ }
+ }
+ if (sc->sc_poll)
+ printf(": polling");
+
+ printf("\n");
+
+ rw_init(&sc->sc_i2c_lock, "iiclk");
+
+ /* setup and attach iic bus */
+ sc->sc_i2c_tag.ic_cookie = sc;
+ sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
+ sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
+ sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
+ sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish;
+ sc->sc_i2c_tag.ic_intr_string = dwiic_i2c_intr_string;
+
+ bzero(&sc->sc_iba, sizeof(sc->sc_iba));
+ sc->sc_iba.iba_name = "iic";
+ sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
+ sc->sc_iba.iba_bus_scan = dwiic_pci_bus_scan;
+ sc->sc_iba.iba_bus_scan_arg = sc;
+
+ config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
+
+ return;
+}
+
+int
+dwiic_pci_activate(struct device *self, int act)
+{
+ struct dwiic_softc *sc = (struct dwiic_softc *)self;
+
+ switch (act) {
+ case DVACT_WAKEUP:
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, LPSS_RESETS,
+ (LPSS_RESETS_I2C | LPSS_RESETS_IDMA));
+
+ dwiic_init(sc);
+
+ break;
+ }
+
+ dwiic_activate(self, act);
+
+ return 0;
+}
+
+void
+dwiic_pci_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
+ void *aux)
+{
+ struct dwiic_softc *sc = (struct dwiic_softc *)aux;
+
+ sc->sc_iic = iic;
+
+#if NACPI > 0
+ {
+ struct aml_node *n = acpi_pci_match((struct device *)aux,
+ &sc->sc_paa);
+ if (n == NULL)
+ return;
+
+ /*
+ * XXX: until we can figure out why interrupts don't arrive for
+ * i2c slave devices on intel 100 series and newer, force
+ * polling for ihidev.
+ */
+ sc->sc_poll_ihidev = 1;
+
+ aml_find_node(n, "_HID", dwiic_acpi_found_hid, sc);
+ }
+#endif
+}
Index: sys/dev/pci/files.pci
===================================================================
RCS file: /cvs/src/sys/dev/pci/files.pci,v
retrieving revision 1.329
diff -u -p -u -p -r1.329 files.pci
--- sys/dev/pci/files.pci 21 Jan 2017 10:58:15 -0000 1.329
+++ sys/dev/pci/files.pci 10 Nov 2017 15:56:34 -0000
@@ -807,5 +807,9 @@ file dev/pci/xspd.c xspd
attach virtio at pci with virtio_pci
file dev/pci/virtio_pci.c virtio_pci
+# Synopsys DesignWare I2C Controller
+attach dwiic at pci with dwiic_pci
+file dev/pci/dwiic_pci.c dwiic_pci
+
include "dev/pci/files.agp"
include "dev/pci/drm/files.drm"
Index: share/man/man4/dwiic.4
===================================================================
RCS file: /cvs/src/share/man/man4/dwiic.4,v
retrieving revision 1.2
diff -u -p -u -p -r1.2 dwiic.4
--- share/man/man4/dwiic.4 30 Jul 2016 15:44:45 -0000 1.2
+++ share/man/man4/dwiic.4 10 Nov 2017 15:56:34 -0000
@@ -22,6 +22,7 @@
.Nd Synopsys DesignWare I2C controller
.Sh SYNOPSIS
.Cd "dwiic* at acpi?"
+.Cd "dwiic* at pci?"
.Cd "iic* at dwiic?"
.Sh DESCRIPTION
The
@@ -33,6 +34,7 @@ framework.
.Sh SEE ALSO
.Xr acpi 4 ,
.Xr iic 4
+.Xr pci 4
.Sh HISTORY
The
.Nm
Index: sys/arch/amd64/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.447
diff -u -p -u -p -r1.447 GENERIC
--- sys/arch/amd64/conf/GENERIC 28 Oct 2017 01:37:52 -0000 1.447
+++ sys/arch/amd64/conf/GENERIC 10 Nov 2017 15:56:35 -0000
@@ -135,6 +135,7 @@ iic* at nviic?
amdpm* at pci? # AMD-7xx/8111 and NForce SMBus controller
iic* at amdpm?
dwiic* at acpi? # DesignWare Synopsys i2c controller
+dwiic* at pci?
iic* at dwiic?
itherm* at pci? # Intel 3400 Thermal Sensor
Index: sys/dev/acpi/acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.332
diff -u -p -u -p -r1.332 acpi.c
--- sys/dev/acpi/acpi.c 17 Aug 2017 05:16:27 -0000 1.332
+++ sys/dev/acpi/acpi.c 10 Nov 2017 15:56:45 -0000
@@ -71,7 +71,7 @@ int acpi_hasprocfvs;
#define ACPIEN_RETRIES 15
-void acpi_pci_match(struct device *, struct pci_attach_args *);
+struct aml_node *acpi_pci_match(struct device *, struct pci_attach_args *);
pcireg_t acpi_pci_min_powerstate(pci_chipset_tag_t, pcitag_t);
void acpi_pci_set_powerstate(pci_chipset_tag_t, pcitag_t, int, int);
int acpi_pci_notify(struct aml_node *, int, void *);
@@ -669,7 +669,7 @@ acpi_getpci(struct aml_node *node, void
return (1);
}
-void
+struct aml_node *
acpi_pci_match(struct device *dev, struct pci_attach_args *pa)
{
struct acpi_pci *pdev;
@@ -695,7 +695,11 @@ acpi_pci_match(struct device *dev, struc
acpi_pci_set_powerstate(pa->pa_pc, pa->pa_tag, state, 0);
aml_register_notify(pdev->node, NULL, acpi_pci_notify, pdev, 0);
+
+ return pdev->node;
}
+
+ return NULL;
}
pcireg_t
Index: sys/dev/acpi/dwiic.c
===================================================================
RCS file: sys/dev/acpi/dwiic.c
diff -N sys/dev/acpi/dwiic.c
--- sys/dev/acpi/dwiic.c 17 Aug 2017 20:41:16 -0000 1.24
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,1095 +0,0 @@
-/* $OpenBSD: dwiic.c,v 1.24 2017/08/17 20:41:16 kettenis Exp $ */
-/*
- * Synopsys DesignWare I2C controller
- *
- * Copyright (c) 2015, 2016 joshua stein <j...@openbsd.org>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/kthread.h>
-
-#include <dev/acpi/acpireg.h>
-#include <dev/acpi/acpivar.h>
-#include <dev/acpi/acpidev.h>
-#include <dev/acpi/amltypes.h>
-#include <dev/acpi/dsdt.h>
-
-#include <dev/i2c/i2cvar.h>
-
-/* #define DWIIC_DEBUG */
-
-#ifdef DWIIC_DEBUG
-#define DPRINTF(x) printf x
-#else
-#define DPRINTF(x)
-#endif
-
-/* register offsets */
-#define DW_IC_CON 0x0
-#define DW_IC_TAR 0x4
-#define DW_IC_DATA_CMD 0x10
-#define DW_IC_SS_SCL_HCNT 0x14
-#define DW_IC_SS_SCL_LCNT 0x18
-#define DW_IC_FS_SCL_HCNT 0x1c
-#define DW_IC_FS_SCL_LCNT 0x20
-#define DW_IC_INTR_STAT 0x2c
-#define DW_IC_INTR_MASK 0x30
-#define DW_IC_RAW_INTR_STAT 0x34
-#define DW_IC_RX_TL 0x38
-#define DW_IC_TX_TL 0x3c
-#define DW_IC_CLR_INTR 0x40
-#define DW_IC_CLR_RX_UNDER 0x44
-#define DW_IC_CLR_RX_OVER 0x48
-#define DW_IC_CLR_TX_OVER 0x4c
-#define DW_IC_CLR_RD_REQ 0x50
-#define DW_IC_CLR_TX_ABRT 0x54
-#define DW_IC_CLR_RX_DONE 0x58
-#define DW_IC_CLR_ACTIVITY 0x5c
-#define DW_IC_CLR_STOP_DET 0x60
-#define DW_IC_CLR_START_DET 0x64
-#define DW_IC_CLR_GEN_CALL 0x68
-#define DW_IC_ENABLE 0x6c
-#define DW_IC_STATUS 0x70
-#define DW_IC_TXFLR 0x74
-#define DW_IC_RXFLR 0x78
-#define DW_IC_SDA_HOLD 0x7c
-#define DW_IC_TX_ABRT_SOURCE 0x80
-#define DW_IC_ENABLE_STATUS 0x9c
-#define DW_IC_COMP_PARAM_1 0xf4
-#define DW_IC_COMP_VERSION 0xf8
-#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
-#define DW_IC_COMP_TYPE 0xfc
-#define DW_IC_COMP_TYPE_VALUE 0x44570140
-
-#define DW_IC_CON_MASTER 0x1
-#define DW_IC_CON_SPEED_STD 0x2
-#define DW_IC_CON_SPEED_FAST 0x4
-#define DW_IC_CON_10BITADDR_MASTER 0x10
-#define DW_IC_CON_RESTART_EN 0x20
-#define DW_IC_CON_SLAVE_DISABLE 0x40
-
-#define DW_IC_DATA_CMD_READ 0x100
-#define DW_IC_DATA_CMD_STOP 0x200
-#define DW_IC_DATA_CMD_RESTART 0x400
-
-#define DW_IC_INTR_RX_UNDER 0x001
-#define DW_IC_INTR_RX_OVER 0x002
-#define DW_IC_INTR_RX_FULL 0x004
-#define DW_IC_INTR_TX_OVER 0x008
-#define DW_IC_INTR_TX_EMPTY 0x010
-#define DW_IC_INTR_RD_REQ 0x020
-#define DW_IC_INTR_TX_ABRT 0x040
-#define DW_IC_INTR_RX_DONE 0x080
-#define DW_IC_INTR_ACTIVITY 0x100
-#define DW_IC_INTR_STOP_DET 0x200
-#define DW_IC_INTR_START_DET 0x400
-#define DW_IC_INTR_GEN_CALL 0x800
-
-#define DW_IC_STATUS_ACTIVITY 0x1
-
-/* hardware abort codes from the DW_IC_TX_ABRT_SOURCE register */
-#define ABRT_7B_ADDR_NOACK 0
-#define ABRT_10ADDR1_NOACK 1
-#define ABRT_10ADDR2_NOACK 2
-#define ABRT_TXDATA_NOACK 3
-#define ABRT_GCALL_NOACK 4
-#define ABRT_GCALL_READ 5
-#define ABRT_SBYTE_ACKDET 7
-#define ABRT_SBYTE_NORSTRT 9
-#define ABRT_10B_RD_NORSTRT 10
-#define ABRT_MASTER_DIS 11
-#define ARB_LOST 12
-
-struct dwiic_crs {
- int irq_int;
- uint8_t irq_flags;
- uint32_t addr_min;
- uint32_t addr_bas;
- uint32_t addr_len;
- uint16_t i2c_addr;
- struct aml_node *devnode;
- struct aml_node *gpio_int_node;
- uint16_t gpio_int_pin;
- uint16_t gpio_int_flags;
-};
-
-struct dwiic_softc {
- struct device sc_dev;
-
- bus_space_tag_t sc_iot;
- bus_space_handle_t sc_ioh;
-
- struct acpi_softc *sc_acpi;
- struct aml_node *sc_devnode;
- char sc_hid[16];
- void *sc_ih;
-
- struct i2cbus_attach_args sc_iba;
- struct device *sc_iic;
-
- int sc_poll;
- int sc_busy;
- int sc_readwait;
- int sc_writewait;
-
- uint32_t master_cfg;
- uint16_t ss_hcnt, ss_lcnt, fs_hcnt, fs_lcnt;
- uint32_t sda_hold_time;
- int tx_fifo_depth;
- int rx_fifo_depth;
-
- struct i2c_controller sc_i2c_tag;
- struct rwlock sc_i2c_lock;
- struct {
- i2c_op_t op;
- void *buf;
- size_t len;
- int flags;
- volatile int error;
- } sc_i2c_xfer;
-};
-
-int dwiic_match(struct device *, void *, void *);
-void dwiic_attach(struct device *, struct device *, void *);
-int dwiic_detach(struct device *, int);
-int dwiic_activate(struct device *, int);
-
-int dwiic_init(struct dwiic_softc *);
-void dwiic_enable(struct dwiic_softc *, int);
-int dwiic_intr(void *);
-
-void * dwiic_i2c_intr_establish(void *, void *, int,
- int (*)(void *), void *, const char *);
-const char * dwiic_i2c_intr_string(void *, void *);
-
-int dwiic_acpi_parse_crs(int, union acpi_resource *, void *);
-int dwiic_acpi_found_hid(struct aml_node *, void *);
-int dwiic_acpi_found_ihidev(struct dwiic_softc *,
- struct aml_node *, char *, struct dwiic_crs);
-int dwiic_acpi_found_iatp(struct dwiic_softc *, struct aml_node *,
- char *, struct dwiic_crs);
-void dwiic_acpi_get_params(struct dwiic_softc *, char *, uint16_t *,
- uint16_t *, uint32_t *);
-void dwiic_acpi_power(struct dwiic_softc *, int);
-void dwiic_bus_scan(struct device *, struct i2cbus_attach_args *,
- void *);
-
-int dwiic_i2c_acquire_bus(void *, int);
-void dwiic_i2c_release_bus(void *, int);
-uint32_t dwiic_read(struct dwiic_softc *, int);
-void dwiic_write(struct dwiic_softc *, int, uint32_t);
-int dwiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
- size_t, void *, size_t, int);
-void dwiic_xfer_msg(struct dwiic_softc *);
-
-struct cfattach dwiic_ca = {
- sizeof(struct dwiic_softc),
- dwiic_match,
- dwiic_attach,
- NULL,
- dwiic_activate
-};
-
-struct cfdriver dwiic_cd = {
- NULL, "dwiic", DV_DULL
-};
-
-const char *dwiic_hids[] = {
- "INT33C2",
- "INT33C3",
- "INT3432",
- "INT3433",
- "80860F41",
- "808622C1",
- NULL
-};
-
-const char *ihidev_hids[] = {
- "PNP0C50",
- "ACPI0C50",
- NULL
-};
-
-const char *iatp_hids[] = {
- "ATML0000",
- "ATML0001",
- NULL
-};
-
-int
-dwiic_match(struct device *parent, void *match, void *aux)
-{
- struct acpi_attach_args *aaa = aux;
- struct cfdata *cf = match;
-
- return acpi_matchhids(aaa, dwiic_hids, cf->cf_driver->cd_name);
-}
-
-void
-dwiic_attach(struct device *parent, struct device *self, void *aux)
-{
- struct dwiic_softc *sc = (struct dwiic_softc *)self;
- struct acpi_attach_args *aa = aux;
- struct aml_value res;
- struct dwiic_crs crs;
-
- sc->sc_acpi = (struct acpi_softc *)parent;
- sc->sc_devnode = aa->aaa_node;
- memcpy(&sc->sc_hid, aa->aaa_dev, sizeof(sc->sc_hid));
-
- printf(": %s", sc->sc_devnode->name);
-
- if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
- printf(", no _CRS method\n");
- return;
- }
- if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
- printf(", invalid _CRS object (type %d len %d)\n",
- res.type, res.length);
- aml_freevalue(&res);
- return;
- }
- memset(&crs, 0, sizeof(crs));
- crs.devnode = sc->sc_devnode;
- aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs);
- aml_freevalue(&res);
-
- if (crs.addr_bas == 0) {
- printf(", can't find address\n");
- return;
- }
-
- printf(" addr 0x%x/0x%x", crs.addr_bas, crs.addr_len);
-
- sc->sc_iot = aa->aaa_memt;
- if (bus_space_map(sc->sc_iot, crs.addr_bas, crs.addr_len, 0,
- &sc->sc_ioh)) {
- printf(", failed mapping at 0x%x\n", crs.addr_bas);
- return;
- }
-
- /* power up the controller */
- dwiic_acpi_power(sc, 1);
-
- /* fetch timing parameters */
- sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT);
- sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT);
- sc->fs_hcnt = dwiic_read(sc, DW_IC_FS_SCL_HCNT);
- sc->fs_lcnt = dwiic_read(sc, DW_IC_FS_SCL_LCNT);
- sc->sda_hold_time = dwiic_read(sc, DW_IC_SDA_HOLD);
- dwiic_acpi_get_params(sc, "SSCN", &sc->ss_hcnt, &sc->ss_lcnt, NULL);
- dwiic_acpi_get_params(sc, "FMCN", &sc->fs_hcnt, &sc->fs_lcnt,
- &sc->sda_hold_time);
-
- if (dwiic_init(sc)) {
- printf(", failed initializing\n");
- bus_space_unmap(sc->sc_iot, sc->sc_ioh, crs.addr_len);
- return;
- }
-
- /* leave the controller disabled */
- dwiic_write(sc, DW_IC_INTR_MASK, 0);
- dwiic_enable(sc, 0);
- dwiic_read(sc, DW_IC_CLR_INTR);
-
- /* try to register interrupt with apic, but not fatal without it */
- if (crs.irq_int > 0) {
- printf(" irq %d", crs.irq_int);
-
- sc->sc_ih = acpi_intr_establish(crs.irq_int, crs.irq_flags,
- IPL_BIO, dwiic_intr, sc, sc->sc_dev.dv_xname);
- if (sc->sc_ih == NULL)
- printf(", can't establish interrupt");
- }
-
- printf("\n");
-
- rw_init(&sc->sc_i2c_lock, "iiclk");
-
- /* setup and attach iic bus */
- sc->sc_i2c_tag.ic_cookie = sc;
- sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
- sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
- sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
- sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish;
- sc->sc_i2c_tag.ic_intr_string = dwiic_i2c_intr_string;
-
- bzero(&sc->sc_iba, sizeof(sc->sc_iba));
- sc->sc_iba.iba_name = "iic";
- sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
- sc->sc_iba.iba_bus_scan = dwiic_bus_scan;
- sc->sc_iba.iba_bus_scan_arg = sc;
-
- config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
-
- return;
-}
-
-int
-dwiic_detach(struct device *self, int flags)
-{
- struct dwiic_softc *sc = (struct dwiic_softc *)self;
-
- if (sc->sc_ih != NULL) {
- intr_disestablish(sc->sc_ih);
- sc->sc_ih = NULL;
- }
-
- return 0;
-}
-
-int
-dwiic_activate(struct device *self, int act)
-{
- struct dwiic_softc *sc = (struct dwiic_softc *)self;
-
- switch (act) {
- case DVACT_SUSPEND:
- /* disable controller */
- dwiic_enable(sc, 0);
-
- /* disable interrupts */
- dwiic_write(sc, DW_IC_INTR_MASK, 0);
- dwiic_read(sc, DW_IC_CLR_INTR);
-
- /* power down the controller */
- dwiic_acpi_power(sc, 0);
-
- break;
- case DVACT_WAKEUP:
- /* power up the controller */
- dwiic_acpi_power(sc, 1);
-
- dwiic_init(sc);
-
- break;
- }
-
- config_activate_children(self, act);
-
- return 0;
-}
-
-int
-dwiic_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
-{
- struct dwiic_crs *sc_crs = arg;
- struct aml_node *node;
- uint16_t pin;
-
- switch (AML_CRSTYPE(crs)) {
- case SR_IRQ:
- sc_crs->irq_int = ffs(letoh16(crs->sr_irq.irq_mask)) - 1;
- sc_crs->irq_flags = crs->sr_irq.irq_flags;
- break;
-
- case LR_EXTIRQ:
- sc_crs->irq_int = letoh32(crs->lr_extirq.irq[0]);
- sc_crs->irq_flags = crs->lr_extirq.flags;
- break;
-
- case LR_GPIO:
- node = aml_searchname(sc_crs->devnode,
- (char *)&crs->pad[crs->lr_gpio.res_off]);
- pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off];
- if (crs->lr_gpio.type == LR_GPIO_INT) {
- sc_crs->gpio_int_node = node;
- sc_crs->gpio_int_pin = pin;
- sc_crs->gpio_int_flags = crs->lr_gpio.tflags;
- }
- break;
-
- case LR_MEM32:
- sc_crs->addr_min = letoh32(crs->lr_m32._min);
- sc_crs->addr_len = letoh32(crs->lr_m32._len);
- break;
-
- case LR_MEM32FIXED:
- sc_crs->addr_bas = letoh32(crs->lr_m32fixed._bas);
- sc_crs->addr_len = letoh32(crs->lr_m32fixed._len);
- break;
-
- case LR_SERBUS:
- if (crs->lr_serbus.type == LR_SERBUS_I2C)
- sc_crs->i2c_addr = letoh16(crs->lr_i2cbus._adr);
- break;
-
- default:
- DPRINTF(("%s: unknown resource type %d\n", __func__,
- AML_CRSTYPE(crs)));
- }
-
- return 0;
-}
-
-void
-dwiic_acpi_get_params(struct dwiic_softc *sc, char *method, uint16_t *hcnt,
- uint16_t *lcnt, uint32_t *sda_hold_time)
-{
- struct aml_value res;
-
- if (!aml_searchname(sc->sc_devnode, method))
- return;
-
- if (aml_evalname(sc->sc_acpi, sc->sc_devnode, method, 0, NULL, &res)) {
- printf(": eval of %s at %s failed", method,
- aml_nodename(sc->sc_devnode));
- return;
- }
-
- if (res.type != AML_OBJTYPE_PACKAGE) {
- printf(": %s is not a package (%d)", method, res.type);
- aml_freevalue(&res);
- return;
- }
-
- if (res.length <= 2) {
- printf(": %s returned package of len %d", method, res.length);
- aml_freevalue(&res);
- return;
- }
-
- *hcnt = aml_val2int(res.v_package[0]);
- *lcnt = aml_val2int(res.v_package[1]);
- if (sda_hold_time)
- *sda_hold_time = aml_val2int(res.v_package[2]);
- aml_freevalue(&res);
-}
-
-void
-dwiic_bus_scan(struct device *iic, struct i2cbus_attach_args *iba, void *aux)
-{
- struct dwiic_softc *sc = (struct dwiic_softc *)aux;
-
- sc->sc_iic = iic;
- aml_find_node(sc->sc_devnode, "_HID", dwiic_acpi_found_hid, sc);
-}
-
-int
-dwiic_i2c_print(void *aux, const char *pnp)
-{
- struct i2c_attach_args *ia = aux;
-
- if (pnp != NULL)
- printf("%s at %s", ia->ia_name, pnp);
-
- printf(" addr 0x%x", ia->ia_addr);
-
- return UNCONF;
-}
-
-void *
-dwiic_i2c_intr_establish(void *cookie, void *ih, int level,
- int (*func)(void *), void *arg, const char *name)
-{
- struct dwiic_crs *crs = ih;
-
- if (crs->gpio_int_node && crs->gpio_int_node->gpio) {
- struct acpi_gpio *gpio = crs->gpio_int_node->gpio;
- gpio->intr_establish(gpio->cookie, crs->gpio_int_pin,
- crs->gpio_int_flags, func, arg);
- return ih;
- }
-
- return acpi_intr_establish(crs->irq_int, crs->irq_flags,
- level, func, arg, name);
-}
-
-const char *
-dwiic_i2c_intr_string(void *cookie, void *ih)
-{
- struct dwiic_crs *crs = ih;
- static char irqstr[64];
-
- if (crs->gpio_int_node && crs->gpio_int_node->gpio)
- snprintf(irqstr, sizeof(irqstr), "gpio %d", crs->gpio_int_pin);
- else
- snprintf(irqstr, sizeof(irqstr), "irq %d", crs->irq_int);
-
- return irqstr;
-}
-
-int
-dwiic_matchhids(const char *hid, const char *hids[])
-{
- int i;
-
- for (i = 0; hids[i]; i++)
- if (!strcmp(hid, hids[i]))
- return (1);
-
- return (0);
-}
-
-int
-dwiic_acpi_found_hid(struct aml_node *node, void *arg)
-{
- struct dwiic_softc *sc = (struct dwiic_softc *)arg;
- struct dwiic_crs crs;
- struct aml_value res;
- int64_t sta;
- char cdev[16], dev[16];
-
- if (acpi_parsehid(node, arg, cdev, dev, 16) != 0)
- return 0;
-
- if (aml_evalinteger(acpi_softc, node->parent, "_STA", 0, NULL, &sta))
- sta = STA_PRESENT | STA_ENABLED | STA_DEV_OK | 0x1000;
-
- if ((sta & STA_PRESENT) == 0)
- return 0;
-
- DPRINTF(("%s: found HID %s at %s\n", sc->sc_dev.dv_xname, dev,
- aml_nodename(node)));
-
- if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res)) {
- printf("%s: no _CRS method at %s\n", sc->sc_dev.dv_xname,
- aml_nodename(node->parent));
- return (0);
- }
- if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
- printf("%s: invalid _CRS object (type %d len %d)\n",
- sc->sc_dev.dv_xname, res.type, res.length);
- aml_freevalue(&res);
- return (0);
- }
- memset(&crs, 0, sizeof(crs));
- crs.devnode = sc->sc_devnode;
- aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs);
- aml_freevalue(&res);
-
- acpi_attach_deps(acpi_softc, node->parent);
-
- if (dwiic_matchhids(cdev, ihidev_hids))
- return dwiic_acpi_found_ihidev(sc, node, dev, crs);
- else if (dwiic_matchhids(dev, iatp_hids))
- return dwiic_acpi_found_iatp(sc, node, dev, crs);
-
- return 0;
-}
-
-int
-dwiic_acpi_found_ihidev(struct dwiic_softc *sc, struct aml_node *node,
- char *dev, struct dwiic_crs crs)
-{
- struct i2c_attach_args ia;
- struct aml_value cmd[4], res;
-
- /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */
- static uint8_t i2c_hid_guid[] = {
- 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
- 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
- };
-
- if (!aml_searchname(node->parent, "_DSM")) {
- printf("%s: couldn't find _DSM at %s\n", sc->sc_dev.dv_xname,
- aml_nodename(node->parent));
- return 0;
- }
-
- bzero(&cmd, sizeof(cmd));
- cmd[0].type = AML_OBJTYPE_BUFFER;
- cmd[0].v_buffer = (uint8_t *)&i2c_hid_guid;
- cmd[0].length = sizeof(i2c_hid_guid);
- /* rev */
- cmd[1].type = AML_OBJTYPE_INTEGER;
- cmd[1].v_integer = 1;
- cmd[1].length = 1;
- /* func */
- cmd[2].type = AML_OBJTYPE_INTEGER;
- cmd[2].v_integer = 1; /* HID */
- cmd[2].length = 1;
- /* not used */
- cmd[3].type = AML_OBJTYPE_PACKAGE;
- cmd[3].length = 0;
-
- if (aml_evalname(acpi_softc, node->parent, "_DSM", 4, cmd, &res)) {
- printf("%s: eval of _DSM at %s failed\n",
- sc->sc_dev.dv_xname, aml_nodename(node->parent));
- return 0;
- }
-
- if (res.type != AML_OBJTYPE_INTEGER) {
- printf("%s: bad _DSM result at %s: %d\n",
- sc->sc_dev.dv_xname, aml_nodename(node->parent), res.type);
- aml_freevalue(&res);
- return 0;
- }
-
- memset(&ia, 0, sizeof(ia));
- ia.ia_tag = sc->sc_iba.iba_tag;
- ia.ia_size = 1;
- ia.ia_name = "ihidev";
- ia.ia_size = aml_val2int(&res); /* hid descriptor address */
- ia.ia_addr = crs.i2c_addr;
- ia.ia_cookie = dev;
-
- aml_freevalue(&res);
-
- if (crs.irq_int <= 0 && crs.gpio_int_node == NULL) {
- printf("%s: couldn't find irq for %s\n", sc->sc_dev.dv_xname,
- aml_nodename(node->parent));
- return 0;
- }
- ia.ia_intr = &crs;
-
- if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
- node->parent->attached = 1;
- return 0;
- }
-
- return 1;
-}
-
-int
-dwiic_acpi_found_iatp(struct dwiic_softc *sc, struct aml_node *node, char *dev,
- struct dwiic_crs crs)
-{
- struct i2c_attach_args ia;
- struct aml_value res;
-
- if (aml_evalname(acpi_softc, node->parent, "GPIO", 0, NULL, &res))
- /* no gpio, assume this is the bootloader interface */
- return (0);
-
- memset(&ia, 0, sizeof(ia));
- ia.ia_tag = sc->sc_iba.iba_tag;
- ia.ia_size = 1;
- ia.ia_name = "iatp";
- ia.ia_addr = crs.i2c_addr;
- ia.ia_cookie = dev;
-
- if (crs.irq_int <= 0 && crs.gpio_int_node == NULL) {
- printf("%s: couldn't find irq for %s\n", sc->sc_dev.dv_xname,
- aml_nodename(node->parent));
- return 0;
- }
- ia.ia_intr = &crs;
-
- if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
- node->parent->attached = 1;
- return 0;
- }
-
- return 1;
-}
-
-uint32_t
-dwiic_read(struct dwiic_softc *sc, int offset)
-{
- u_int32_t b = bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
-
- DPRINTF(("%s: read at 0x%x = 0x%x\n", sc->sc_dev.dv_xname, offset, b));
-
- return b;
-}
-
-void
-dwiic_write(struct dwiic_softc *sc, int offset, uint32_t val)
-{
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
-
- DPRINTF(("%s: write at 0x%x: 0x%x\n", sc->sc_dev.dv_xname, offset,
- val));
-}
-
-int
-dwiic_i2c_acquire_bus(void *cookie, int flags)
-{
- struct dwiic_softc *sc = cookie;
-
- if (cold || sc->sc_poll || (flags & I2C_F_POLL))
- return (0);
-
- return rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR);
-}
-
-void
-dwiic_i2c_release_bus(void *cookie, int flags)
-{
- struct dwiic_softc *sc = cookie;
-
- if (cold || sc->sc_poll || (flags & I2C_F_POLL))
- return;
-
- rw_exit(&sc->sc_i2c_lock);
-}
-
-int
-dwiic_init(struct dwiic_softc *sc)
-{
- uint32_t reg;
-
- /* make sure we're talking to a device we know */
- reg = dwiic_read(sc, DW_IC_COMP_TYPE);
- if (reg != DW_IC_COMP_TYPE_VALUE) {
- DPRINTF(("%s: invalid component type 0x%x\n",
- sc->sc_dev.dv_xname, reg));
- return 1;
- }
-
- /* disable the adapter */
- dwiic_enable(sc, 0);
-
- /* write standard-mode SCL timing parameters */
- dwiic_write(sc, DW_IC_SS_SCL_HCNT, sc->ss_hcnt);
- dwiic_write(sc, DW_IC_SS_SCL_LCNT, sc->ss_lcnt);
-
- /* and fast-mode SCL timing parameters */
- dwiic_write(sc, DW_IC_FS_SCL_HCNT, sc->fs_hcnt);
- dwiic_write(sc, DW_IC_FS_SCL_LCNT, sc->fs_lcnt);
-
- /* SDA hold time */
- reg = dwiic_read(sc, DW_IC_COMP_VERSION);
- if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
- dwiic_write(sc, DW_IC_SDA_HOLD, sc->sda_hold_time);
-
- /* FIFO threshold levels */
- sc->tx_fifo_depth = 32;
- sc->rx_fifo_depth = 32;
- dwiic_write(sc, DW_IC_TX_TL, sc->tx_fifo_depth / 2);
- dwiic_write(sc, DW_IC_RX_TL, 0);
-
- /* configure as i2c master with fast speed */
- sc->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
- DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
- dwiic_write(sc, DW_IC_CON, sc->master_cfg);
-
- return 0;
-}
-
-void
-dwiic_enable(struct dwiic_softc *sc, int enable)
-{
- int retries;
-
- for (retries = 100; retries > 0; retries--) {
- dwiic_write(sc, DW_IC_ENABLE, enable);
- if ((dwiic_read(sc, DW_IC_ENABLE_STATUS) & 1) == enable)
- return;
-
- DELAY(25);
- }
-
- printf("%s: failed to %sable\n", sc->sc_dev.dv_xname,
- (enable ? "en" : "dis"));
-}
-
-void
-dwiic_acpi_power(struct dwiic_softc *sc, int power)
-{
- char ps[] = "_PS0";
-
- if (!power)
- ps[3] = '3';
-
- if (aml_searchname(sc->sc_devnode, ps)) {
- if (aml_evalname(sc->sc_acpi, sc->sc_devnode, ps, 0, NULL,
- NULL)) {
- printf("%s: failed powering %s with %s\n",
- sc->sc_dev.dv_xname, power ? "on" : "off",
- ps);
- return;
- }
-
- DELAY(10000); /* 10 milliseconds */
- } else
- DPRINTF(("%s: no %s method\n", sc->sc_dev.dv_xname, ps));
-
- if (strcmp(sc->sc_hid, "INT3432") == 0 ||
- strcmp(sc->sc_hid, "INT3433") == 0) {
- /*
- * XXX: broadwell i2c devices may need this for initial power
- * up and/or after s3 resume.
- *
- * linux does this write via LPSS -> clk_register_gate ->
- * clk_gate_enable -> clk_gate_endisable -> clk_writel
- */
- dwiic_write(sc, 0x800, 1);
- }
-}
-
-int
-dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
- size_t cmdlen, void *buf, size_t len, int flags)
-{
- struct dwiic_softc *sc = cookie;
- u_int32_t ic_con, st, cmd, resp;
- int retries, tx_limit, rx_avail, x, readpos;
- uint8_t *b;
-
- if (sc->sc_busy)
- return 1;
-
- sc->sc_busy++;
-
- DPRINTF(("%s: %s: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
- "flags 0x%02x\n", sc->sc_dev.dv_xname, __func__, op, addr, cmdlen,
- len, flags));
-
- /* setup transfer */
- sc->sc_i2c_xfer.op = op;
- sc->sc_i2c_xfer.buf = buf;
- sc->sc_i2c_xfer.len = len;
- sc->sc_i2c_xfer.flags = flags;
- sc->sc_i2c_xfer.error = 0;
-
- /* wait for bus to be idle */
- for (retries = 100; retries > 0; retries--) {
- st = dwiic_read(sc, DW_IC_STATUS);
- if (!(st & DW_IC_STATUS_ACTIVITY))
- break;
- DELAY(1000);
- }
- DPRINTF(("%s: %s: status 0x%x\n", sc->sc_dev.dv_xname, __func__, st));
- if (st & DW_IC_STATUS_ACTIVITY) {
- sc->sc_busy = 0;
- return (1);
- }
-
- if (cold || sc->sc_poll)
- flags |= I2C_F_POLL;
-
- /* disable controller */
- dwiic_enable(sc, 0);
-
- /* set slave address */
- ic_con = dwiic_read(sc, DW_IC_CON);
- ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
- dwiic_write(sc, DW_IC_CON, ic_con);
- dwiic_write(sc, DW_IC_TAR, addr);
-
- /* disable interrupts */
- dwiic_write(sc, DW_IC_INTR_MASK, 0);
- dwiic_read(sc, DW_IC_CLR_INTR);
-
- /* enable controller */
- dwiic_enable(sc, 1);
-
- /* wait until the controller is ready for commands */
- if (flags & I2C_F_POLL)
- DELAY(200);
- else {
- dwiic_read(sc, DW_IC_CLR_INTR);
- dwiic_write(sc, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY);
-
- if (tsleep(&sc->sc_writewait, PRIBIO, "dwiic", hz / 2) != 0)
- printf("%s: timed out waiting for tx_empty intr\n",
- sc->sc_dev.dv_xname);
- }
-
- /* send our command, one byte at a time */
- if (cmdlen > 0) {
- b = (void *)cmdbuf;
-
- DPRINTF(("%s: %s: sending cmd (len %zu):", sc->sc_dev.dv_xname,
- __func__, cmdlen));
- for (x = 0; x < cmdlen; x++)
- DPRINTF((" %02x", b[x]));
- DPRINTF(("\n"));
-
- tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
- if (cmdlen > tx_limit) {
- /* TODO */
- printf("%s: can't write %zu (> %d)\n",
- sc->sc_dev.dv_xname, cmdlen, tx_limit);
- sc->sc_i2c_xfer.error = 1;
- sc->sc_busy = 0;
- return (1);
- }
-
- for (x = 0; x < cmdlen; x++) {
- cmd = b[x];
- /*
- * Generate STOP condition if this is the last
- * byte of the transfer.
- */
- if (x == (cmdlen - 1) && len == 0 && I2C_OP_STOP_P(op))
- cmd |= DW_IC_DATA_CMD_STOP;
- dwiic_write(sc, DW_IC_DATA_CMD, cmd);
- }
- }
-
- b = (void *)buf;
- x = readpos = 0;
- tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
-
- DPRINTF(("%s: %s: need to read %zu bytes, can send %d read reqs\n",
- sc->sc_dev.dv_xname, __func__, len, tx_limit));
-
- while (x < len) {
- if (I2C_OP_WRITE_P(op))
- cmd = b[x];
- else
- cmd = DW_IC_DATA_CMD_READ;
-
- /*
- * Generate RESTART condition if we're reversing
- * direction.
- */
- if (x == 0 && cmdlen > 0 && I2C_OP_READ_P(op))
- cmd |= DW_IC_DATA_CMD_RESTART;
- /*
- * Generate STOP conditon on the last byte of the
- * transfer.
- */
- if (x == (len - 1) && I2C_OP_STOP_P(op))
- cmd |= DW_IC_DATA_CMD_STOP;
-
- dwiic_write(sc, DW_IC_DATA_CMD, cmd);
-
- tx_limit--;
- x++;
-
- /*
- * As TXFLR fills up, we need to clear it out by reading all
- * available data.
- */
- while (tx_limit == 0 || x == len) {
- DPRINTF(("%s: %s: tx_limit %d, sent %d read reqs\n",
- sc->sc_dev.dv_xname, __func__, tx_limit, x));
-
- if (flags & I2C_F_POLL) {
- for (retries = 100; retries > 0; retries--) {
- rx_avail = dwiic_read(sc, DW_IC_RXFLR);
- if (rx_avail > 0)
- break;
- DELAY(50);
- }
- } else {
- dwiic_read(sc, DW_IC_CLR_INTR);
- dwiic_write(sc, DW_IC_INTR_MASK,
- DW_IC_INTR_RX_FULL);
-
- if (tsleep(&sc->sc_readwait, PRIBIO, "dwiic",
- hz / 2) != 0)
- printf("%s: timed out waiting for "
- "rx_full intr\n",
- sc->sc_dev.dv_xname);
-
- rx_avail = dwiic_read(sc, DW_IC_RXFLR);
- }
-
- if (rx_avail == 0) {
- printf("%s: timed out reading remaining %d\n",
- sc->sc_dev.dv_xname,
- (int)(len - 1 - readpos));
- sc->sc_i2c_xfer.error = 1;
- sc->sc_busy = 0;
-
- return (1);
- }
-
- DPRINTF(("%s: %s: %d avail to read (%zu remaining)\n",
- sc->sc_dev.dv_xname, __func__, rx_avail,
- len - readpos));
-
- while (rx_avail > 0) {
- resp = dwiic_read(sc, DW_IC_DATA_CMD);
- if (readpos < len) {
- b[readpos] = resp;
- readpos++;
- }
- rx_avail--;
- }
-
- if (readpos >= len)
- break;
-
- DPRINTF(("%s: still need to read %d bytes\n",
- sc->sc_dev.dv_xname, (int)(len - readpos)));
- tx_limit = sc->tx_fifo_depth -
- dwiic_read(sc, DW_IC_TXFLR);
- }
- }
-
- sc->sc_busy = 0;
-
- return 0;
-}
-
-uint32_t
-dwiic_read_clear_intrbits(struct dwiic_softc *sc)
-{
- uint32_t stat;
-
- stat = dwiic_read(sc, DW_IC_INTR_STAT);
-
- if (stat & DW_IC_INTR_RX_UNDER)
- dwiic_read(sc, DW_IC_CLR_RX_UNDER);
- if (stat & DW_IC_INTR_RX_OVER)
- dwiic_read(sc, DW_IC_CLR_RX_OVER);
- if (stat & DW_IC_INTR_TX_OVER)
- dwiic_read(sc, DW_IC_CLR_TX_OVER);
- if (stat & DW_IC_INTR_RD_REQ)
- dwiic_read(sc, DW_IC_CLR_RD_REQ);
- if (stat & DW_IC_INTR_TX_ABRT)
- dwiic_read(sc, DW_IC_CLR_TX_ABRT);
- if (stat & DW_IC_INTR_RX_DONE)
- dwiic_read(sc, DW_IC_CLR_RX_DONE);
- if (stat & DW_IC_INTR_ACTIVITY)
- dwiic_read(sc, DW_IC_CLR_ACTIVITY);
- if (stat & DW_IC_INTR_STOP_DET)
- dwiic_read(sc, DW_IC_CLR_STOP_DET);
- if (stat & DW_IC_INTR_START_DET)
- dwiic_read(sc, DW_IC_CLR_START_DET);
- if (stat & DW_IC_INTR_GEN_CALL)
- dwiic_read(sc, DW_IC_CLR_GEN_CALL);
-
- return stat;
-}
-
-int
-dwiic_intr(void *arg)
-{
- struct dwiic_softc *sc = arg;
- uint32_t en, stat;
-
- en = dwiic_read(sc, DW_IC_ENABLE);
- /* probably for the other controller */
- if (!en)
- return 0;
-
- stat = dwiic_read_clear_intrbits(sc);
- DPRINTF(("%s: %s: enabled=0x%x stat=0x%x\n", sc->sc_dev.dv_xname,
- __func__, en, stat));
- if (!(stat & ~DW_IC_INTR_ACTIVITY))
- return 1;
-
- if (stat & DW_IC_INTR_TX_ABRT)
- sc->sc_i2c_xfer.error = 1;
-
- if (sc->sc_i2c_xfer.flags & I2C_F_POLL)
- DPRINTF(("%s: %s: intr in poll mode?\n", sc->sc_dev.dv_xname,
- __func__));
- else {
- if (stat & DW_IC_INTR_RX_FULL) {
- dwiic_write(sc, DW_IC_INTR_MASK, 0);
- DPRINTF(("%s: %s: waking up reader\n",
- sc->sc_dev.dv_xname, __func__));
- wakeup(&sc->sc_readwait);
- }
- if (stat & DW_IC_INTR_TX_EMPTY) {
- dwiic_write(sc, DW_IC_INTR_MASK, 0);
- DPRINTF(("%s: %s: waking up writer\n",
- sc->sc_dev.dv_xname, __func__));
- wakeup(&sc->sc_writewait);
- }
- }
-
- return 1;
-}
Index: sys/dev/acpi/dwiic_acpi.c
===================================================================
RCS file: sys/dev/acpi/dwiic_acpi.c
diff -N sys/dev/acpi/dwiic_acpi.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/acpi/dwiic_acpi.c 10 Nov 2017 15:56:45 -0000
@@ -0,0 +1,536 @@
+/* $OpenBSD: dwiic.c,v 1.22 2016/10/25 06:48:58 pirofti Exp $ */
+/*
+ * Synopsys DesignWare I2C controller
+ *
+ * Copyright (c) 2015, 2016 joshua stein <j...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#include <dev/ic/dwiicvar.h>
+
+struct dwiic_crs {
+ int irq_int;
+ uint8_t irq_flags;
+ uint32_t addr_min;
+ uint32_t addr_bas;
+ uint32_t addr_len;
+ uint16_t i2c_addr;
+ struct aml_node *devnode;
+ struct aml_node *gpio_int_node;
+ uint16_t gpio_int_pin;
+ uint16_t gpio_int_flags;
+};
+
+int dwiic_acpi_match(struct device *, void *, void *);
+void dwiic_acpi_attach(struct device *, struct device *, void *);
+
+int dwiic_init(struct dwiic_softc *);
+void dwiic_enable(struct dwiic_softc *, int);
+int dwiic_intr(void *);
+
+void * dwiic_i2c_intr_establish(void *, void *, int,
+ int (*)(void *), void *, const char *);
+const char * dwiic_i2c_intr_string(void *, void *);
+
+int dwiic_acpi_parse_crs(int, union acpi_resource *, void *);
+int dwiic_acpi_found_ihidev(struct dwiic_softc *,
+ struct aml_node *, char *, struct dwiic_crs);
+int dwiic_acpi_found_iatp(struct dwiic_softc *, struct aml_node *,
+ char *, struct dwiic_crs);
+void dwiic_acpi_get_params(struct dwiic_softc *, char *, uint16_t *,
+ uint16_t *, uint32_t *);
+void dwiic_acpi_power(struct dwiic_softc *, int);
+void dwiic_acpi_bus_scan(struct device *,
+ struct i2cbus_attach_args *, void *);
+
+int dwiic_i2c_acquire_bus(void *, int);
+void dwiic_i2c_release_bus(void *, int);
+uint32_t dwiic_read(struct dwiic_softc *, int);
+void dwiic_write(struct dwiic_softc *, int, uint32_t);
+int dwiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
+ size_t, void *, size_t, int);
+void dwiic_xfer_msg(struct dwiic_softc *);
+
+struct cfattach dwiic_acpi_ca = {
+ sizeof(struct dwiic_softc),
+ dwiic_acpi_match,
+ dwiic_acpi_attach,
+ NULL,
+ dwiic_activate
+};
+
+const char *dwiic_hids[] = {
+ "INT33C2",
+ "INT33C3",
+ "INT3432",
+ "INT3433",
+ "80860F41",
+ "808622C1",
+ NULL
+};
+
+const char *ihidev_hids[] = {
+ "PNP0C50",
+ "ACPI0C50",
+ NULL
+};
+
+const char *iatp_hids[] = {
+ "ATML0000",
+ "ATML0001",
+ NULL
+};
+
+int
+dwiic_acpi_match(struct device *parent, void *match, void *aux)
+{
+ struct acpi_attach_args *aaa = aux;
+ struct cfdata *cf = match;
+
+ return acpi_matchhids(aaa, dwiic_hids, cf->cf_driver->cd_name);
+}
+
+void
+dwiic_acpi_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct dwiic_softc *sc = (struct dwiic_softc *)self;
+ struct acpi_attach_args *aa = aux;
+ struct aml_value res;
+ struct dwiic_crs crs;
+
+ sc->sc_acpi = (struct acpi_softc *)parent;
+ sc->sc_devnode = aa->aaa_node;
+ memcpy(&sc->sc_hid, aa->aaa_dev, sizeof(sc->sc_hid));
+
+ printf(": %s", sc->sc_devnode->name);
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
+ printf(", no _CRS method\n");
+ return;
+ }
+ if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
+ printf(", invalid _CRS object (type %d len %d)\n",
+ res.type, res.length);
+ aml_freevalue(&res);
+ return;
+ }
+ memset(&crs, 0, sizeof(crs));
+ crs.devnode = sc->sc_devnode;
+ aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs);
+ aml_freevalue(&res);
+
+ if (crs.addr_bas == 0) {
+ printf(", can't find address\n");
+ return;
+ }
+
+ printf(" addr 0x%x/0x%x", crs.addr_bas, crs.addr_len);
+
+ sc->sc_iot = aa->aaa_memt;
+ if (bus_space_map(sc->sc_iot, crs.addr_bas, crs.addr_len, 0,
+ &sc->sc_ioh)) {
+ printf(", failed mapping at 0x%x\n", crs.addr_bas);
+ return;
+ }
+
+ /* power up the controller */
+ dwiic_acpi_power(sc, 1);
+
+ /* fetch timing parameters */
+ sc->ss_hcnt = dwiic_read(sc, DW_IC_SS_SCL_HCNT);
+ sc->ss_lcnt = dwiic_read(sc, DW_IC_SS_SCL_LCNT);
+ sc->fs_hcnt = dwiic_read(sc, DW_IC_FS_SCL_HCNT);
+ sc->fs_lcnt = dwiic_read(sc, DW_IC_FS_SCL_LCNT);
+ sc->sda_hold_time = dwiic_read(sc, DW_IC_SDA_HOLD);
+ dwiic_acpi_get_params(sc, "SSCN", &sc->ss_hcnt, &sc->ss_lcnt, NULL);
+ dwiic_acpi_get_params(sc, "FMCN", &sc->fs_hcnt, &sc->fs_lcnt,
+ &sc->sda_hold_time);
+
+ if (dwiic_init(sc)) {
+ printf(", failed initializing\n");
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, crs.addr_len);
+ return;
+ }
+
+ /* leave the controller disabled */
+ dwiic_write(sc, DW_IC_INTR_MASK, 0);
+ dwiic_enable(sc, 0);
+ dwiic_read(sc, DW_IC_CLR_INTR);
+
+ /* try to register interrupt with apic, but not fatal without it */
+ if (crs.irq_int > 0) {
+ printf(" irq %d", crs.irq_int);
+
+ sc->sc_ih = acpi_intr_establish(crs.irq_int, crs.irq_flags,
+ IPL_BIO, dwiic_intr, sc, sc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL)
+ printf(", can't establish interrupt");
+ }
+
+ printf("\n");
+
+ rw_init(&sc->sc_i2c_lock, "iiclk");
+
+ /* setup and attach iic bus */
+ sc->sc_i2c_tag.ic_cookie = sc;
+ sc->sc_i2c_tag.ic_acquire_bus = dwiic_i2c_acquire_bus;
+ sc->sc_i2c_tag.ic_release_bus = dwiic_i2c_release_bus;
+ sc->sc_i2c_tag.ic_exec = dwiic_i2c_exec;
+ sc->sc_i2c_tag.ic_intr_establish = dwiic_i2c_intr_establish;
+ sc->sc_i2c_tag.ic_intr_string = dwiic_i2c_intr_string;
+
+ bzero(&sc->sc_iba, sizeof(sc->sc_iba));
+ sc->sc_iba.iba_name = "iic";
+ sc->sc_iba.iba_tag = &sc->sc_i2c_tag;
+ sc->sc_iba.iba_bus_scan = dwiic_acpi_bus_scan;
+ sc->sc_iba.iba_bus_scan_arg = sc;
+
+ config_found((struct device *)sc, &sc->sc_iba, iicbus_print);
+
+ return;
+}
+
+int
+dwiic_acpi_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
+{
+ struct dwiic_crs *sc_crs = arg;
+ struct aml_node *node;
+ uint16_t pin;
+
+ switch (AML_CRSTYPE(crs)) {
+ case SR_IRQ:
+ sc_crs->irq_int = ffs(letoh16(crs->sr_irq.irq_mask)) - 1;
+ sc_crs->irq_flags = crs->sr_irq.irq_flags;
+ break;
+
+ case LR_EXTIRQ:
+ sc_crs->irq_int = letoh32(crs->lr_extirq.irq[0]);
+ sc_crs->irq_flags = crs->lr_extirq.flags;
+ break;
+
+ case LR_GPIO:
+ node = aml_searchname(sc_crs->devnode,
+ (char *)&crs->pad[crs->lr_gpio.res_off]);
+ pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off];
+ if (crs->lr_gpio.type == LR_GPIO_INT) {
+ sc_crs->gpio_int_node = node;
+ sc_crs->gpio_int_pin = pin;
+ sc_crs->gpio_int_flags = crs->lr_gpio.tflags;
+ }
+ break;
+
+ case LR_MEM32:
+ sc_crs->addr_min = letoh32(crs->lr_m32._min);
+ sc_crs->addr_len = letoh32(crs->lr_m32._len);
+ break;
+
+ case LR_MEM32FIXED:
+ sc_crs->addr_bas = letoh32(crs->lr_m32fixed._bas);
+ sc_crs->addr_len = letoh32(crs->lr_m32fixed._len);
+ break;
+
+ case LR_SERBUS:
+ if (crs->lr_serbus.type == LR_SERBUS_I2C)
+ sc_crs->i2c_addr = letoh16(crs->lr_i2cbus._adr);
+ break;
+
+ default:
+ DPRINTF(("%s: unknown resource type %d\n", __func__,
+ AML_CRSTYPE(crs)));
+ }
+
+ return 0;
+}
+
+void
+dwiic_acpi_get_params(struct dwiic_softc *sc, char *method, uint16_t *hcnt,
+ uint16_t *lcnt, uint32_t *sda_hold_time)
+{
+ struct aml_value res;
+
+ if (!aml_searchname(sc->sc_devnode, method))
+ return;
+
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, method, 0, NULL, &res)) {
+ printf(": eval of %s at %s failed", method,
+ aml_nodename(sc->sc_devnode));
+ return;
+ }
+
+ if (res.type != AML_OBJTYPE_PACKAGE) {
+ printf(": %s is not a package (%d)", method, res.type);
+ aml_freevalue(&res);
+ return;
+ }
+
+ if (res.length <= 2) {
+ printf(": %s returned package of len %d", method, res.length);
+ aml_freevalue(&res);
+ return;
+ }
+
+ *hcnt = aml_val2int(res.v_package[0]);
+ *lcnt = aml_val2int(res.v_package[1]);
+ if (sda_hold_time)
+ *sda_hold_time = aml_val2int(res.v_package[2]);
+ aml_freevalue(&res);
+}
+
+void
+dwiic_acpi_bus_scan(struct device *iic, struct i2cbus_attach_args *iba,
+ void *aux)
+{
+ struct dwiic_softc *sc = (struct dwiic_softc *)aux;
+
+ sc->sc_iic = iic;
+ aml_find_node(sc->sc_devnode, "_HID", dwiic_acpi_found_hid, sc);
+}
+
+void *
+dwiic_i2c_intr_establish(void *cookie, void *ih, int level,
+ int (*func)(void *), void *arg, const char *name)
+{
+ struct dwiic_crs *crs = ih;
+
+ if (crs->gpio_int_node && crs->gpio_int_node->gpio) {
+ struct acpi_gpio *gpio = crs->gpio_int_node->gpio;
+ gpio->intr_establish(gpio->cookie, crs->gpio_int_pin,
+ crs->gpio_int_flags, func, arg);
+ return ih;
+ }
+
+ return acpi_intr_establish(crs->irq_int, crs->irq_flags,
+ level, func, arg, name);
+}
+
+const char *
+dwiic_i2c_intr_string(void *cookie, void *ih)
+{
+ struct dwiic_crs *crs = ih;
+ static char irqstr[64];
+
+ if (crs->gpio_int_node && crs->gpio_int_node->gpio)
+ snprintf(irqstr, sizeof(irqstr), "gpio %d", crs->gpio_int_pin);
+ else
+ snprintf(irqstr, sizeof(irqstr), "irq %d", crs->irq_int);
+
+ return irqstr;
+}
+
+int
+dwiic_matchhids(const char *hid, const char *hids[])
+{
+ int i;
+
+ for (i = 0; hids[i]; i++)
+ if (!strcmp(hid, hids[i]))
+ return (1);
+
+ return (0);
+}
+
+int
+dwiic_acpi_found_hid(struct aml_node *node, void *arg)
+{
+ struct dwiic_softc *sc = (struct dwiic_softc *)arg;
+ struct dwiic_crs crs;
+ struct aml_value res;
+ int64_t sta;
+ char cdev[16], dev[16];
+
+ if (acpi_parsehid(node, arg, cdev, dev, 16) != 0)
+ return 0;
+
+ if (aml_evalinteger(acpi_softc, node->parent, "_STA", 0, NULL, &sta))
+ sta = STA_PRESENT | STA_ENABLED | STA_DEV_OK | 0x1000;
+
+ if ((sta & STA_PRESENT) == 0)
+ return 0;
+
+ DPRINTF(("%s: found HID %s at %s\n", sc->sc_dev.dv_xname, dev,
+ aml_nodename(node)));
+
+ if (aml_evalname(acpi_softc, node->parent, "_CRS", 0, NULL, &res)) {
+ printf("%s: no _CRS method at %s\n", sc->sc_dev.dv_xname,
+ aml_nodename(node->parent));
+ return (0);
+ }
+ if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
+ printf("%s: invalid _CRS object (type %d len %d)\n",
+ sc->sc_dev.dv_xname, res.type, res.length);
+ aml_freevalue(&res);
+ return (0);
+ }
+ memset(&crs, 0, sizeof(crs));
+ crs.devnode = sc->sc_devnode;
+ aml_parse_resource(&res, dwiic_acpi_parse_crs, &crs);
+ aml_freevalue(&res);
+
+ acpi_attach_deps(acpi_softc, node->parent);
+
+ if (dwiic_matchhids(cdev, ihidev_hids))
+ return dwiic_acpi_found_ihidev(sc, node, dev, crs);
+ else if (dwiic_matchhids(dev, iatp_hids))
+ return dwiic_acpi_found_iatp(sc, node, dev, crs);
+
+ return 0;
+}
+
+int
+dwiic_acpi_found_ihidev(struct dwiic_softc *sc, struct aml_node *node,
+ char *dev, struct dwiic_crs crs)
+{
+ struct i2c_attach_args ia;
+ struct aml_value cmd[4], res;
+
+ /* 3cdff6f7-4267-4555-ad05-b30a3d8938de */
+ static uint8_t i2c_hid_guid[] = {
+ 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
+ 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
+ };
+
+ if (!aml_searchname(node->parent, "_DSM")) {
+ printf("%s: couldn't find _DSM at %s\n", sc->sc_dev.dv_xname,
+ aml_nodename(node->parent));
+ return 0;
+ }
+
+ bzero(&cmd, sizeof(cmd));
+ cmd[0].type = AML_OBJTYPE_BUFFER;
+ cmd[0].v_buffer = (uint8_t *)&i2c_hid_guid;
+ cmd[0].length = sizeof(i2c_hid_guid);
+ /* rev */
+ cmd[1].type = AML_OBJTYPE_INTEGER;
+ cmd[1].v_integer = 1;
+ cmd[1].length = 1;
+ /* func */
+ cmd[2].type = AML_OBJTYPE_INTEGER;
+ cmd[2].v_integer = 1; /* HID */
+ cmd[2].length = 1;
+ /* not used */
+ cmd[3].type = AML_OBJTYPE_PACKAGE;
+ cmd[3].length = 0;
+
+ if (aml_evalname(acpi_softc, node->parent, "_DSM", 4, cmd, &res)) {
+ printf("%s: eval of _DSM at %s failed\n",
+ sc->sc_dev.dv_xname, aml_nodename(node->parent));
+ return 0;
+ }
+
+ if (res.type != AML_OBJTYPE_INTEGER) {
+ printf("%s: bad _DSM result at %s: %d\n",
+ sc->sc_dev.dv_xname, aml_nodename(node->parent), res.type);
+ aml_freevalue(&res);
+ return 0;
+ }
+
+ memset(&ia, 0, sizeof(ia));
+ ia.ia_tag = sc->sc_iba.iba_tag;
+ ia.ia_size = 1;
+ ia.ia_name = "ihidev";
+ ia.ia_size = aml_val2int(&res); /* hid descriptor address */
+ ia.ia_addr = crs.i2c_addr;
+ ia.ia_cookie = dev;
+
+ aml_freevalue(&res);
+
+ if (!sc->sc_poll_ihidev &&
+ !(crs.irq_int == 0 && crs.gpio_int_node == NULL))
+ ia.ia_intr = &crs;
+
+ if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
+ node->parent->attached = 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+dwiic_acpi_found_iatp(struct dwiic_softc *sc, struct aml_node *node, char *dev,
+ struct dwiic_crs crs)
+{
+ struct i2c_attach_args ia;
+ struct aml_value res;
+
+ if (aml_evalname(acpi_softc, node->parent, "GPIO", 0, NULL, &res))
+ /* no gpio, assume this is the bootloader interface */
+ return (0);
+
+ memset(&ia, 0, sizeof(ia));
+ ia.ia_tag = sc->sc_iba.iba_tag;
+ ia.ia_size = 1;
+ ia.ia_name = "iatp";
+ ia.ia_addr = crs.i2c_addr;
+ ia.ia_cookie = dev;
+
+ if (crs.irq_int <= 0 && crs.gpio_int_node == NULL) {
+ printf("%s: couldn't find irq for %s\n", sc->sc_dev.dv_xname,
+ aml_nodename(node->parent));
+ return 0;
+ }
+ ia.ia_intr = &crs;
+
+ if (config_found(sc->sc_iic, &ia, dwiic_i2c_print)) {
+ node->parent->attached = 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+dwiic_acpi_power(struct dwiic_softc *sc, int power)
+{
+ char ps[] = "_PS0";
+
+ if (!power)
+ ps[3] = '3';
+
+ if (aml_searchname(sc->sc_devnode, ps)) {
+ if (aml_evalname(sc->sc_acpi, sc->sc_devnode, ps, 0, NULL,
+ NULL)) {
+ printf("%s: failed powering %s with %s\n",
+ sc->sc_dev.dv_xname, power ? "on" : "off",
+ ps);
+ return;
+ }
+
+ DELAY(10000); /* 10 milliseconds */
+ } else
+ DPRINTF(("%s: no %s method\n", sc->sc_dev.dv_xname, ps));
+
+ if (strcmp(sc->sc_hid, "INT3432") == 0 ||
+ strcmp(sc->sc_hid, "INT3433") == 0) {
+ /*
+ * XXX: broadwell i2c devices may need this for initial power
+ * up and/or after s3 resume.
+ *
+ * linux does this write via LPSS -> clk_register_gate ->
+ * clk_gate_enable -> clk_gate_endisable -> clk_writel
+ */
+ dwiic_write(sc, 0x800, 1);
+ }
+}
Index: sys/dev/acpi/files.acpi
===================================================================
RCS file: /cvs/src/sys/dev/acpi/files.acpi,v
retrieving revision 1.37
diff -u -p -u -p -r1.37 files.acpi
--- sys/dev/acpi/files.acpi 22 Feb 2017 16:39:56 -0000 1.37
+++ sys/dev/acpi/files.acpi 10 Nov 2017 15:56:45 -0000
@@ -127,9 +127,8 @@ attach sdhc at acpi with sdhc_acpi
file dev/acpi/sdhc_acpi.c sdhc_acpi
# Synopsys DesignWare I2C controller
-device dwiic: i2cbus
-attach dwiic at acpi
-file dev/acpi/dwiic.c dwiic
+attach dwiic at acpi with dwiic_acpi
+file dev/acpi/dwiic_acpi.c dwiic_acpi
# Chromebook keyboard backlight
device acpicbkbd
Index: sys/dev/ic/dwiic.c
===================================================================
RCS file: sys/dev/ic/dwiic.c
diff -N sys/dev/ic/dwiic.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/ic/dwiic.c 10 Nov 2017 15:56:47 -0000
@@ -0,0 +1,490 @@
+/* $OpenBSD: dwiic.c,v 1.22 2016/10/25 06:48:58 pirofti Exp $ */
+/*
+ * Synopsys DesignWare I2C controller
+ *
+ * Copyright (c) 2015-2017 joshua stein <j...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <dev/ic/dwiicvar.h>
+
+int dwiic_match(struct device *, void *, void *);
+void dwiic_attach(struct device *, struct device *, void *);
+int dwiic_detach(struct device *, int);
+int dwiic_activate(struct device *, int);
+
+int dwiic_init(struct dwiic_softc *);
+void dwiic_enable(struct dwiic_softc *, int);
+int dwiic_intr(void *);
+
+void * dwiic_i2c_intr_establish(void *, void *, int,
+ int (*)(void *), void *, const char *);
+const char * dwiic_i2c_intr_string(void *, void *);
+
+int dwiic_i2c_acquire_bus(void *, int);
+void dwiic_i2c_release_bus(void *, int);
+uint32_t dwiic_read(struct dwiic_softc *, int);
+void dwiic_write(struct dwiic_softc *, int, uint32_t);
+int dwiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
+ size_t, void *, size_t, int);
+void dwiic_xfer_msg(struct dwiic_softc *);
+
+struct cfdriver dwiic_cd = {
+ NULL, "dwiic", DV_DULL
+};
+
+int
+dwiic_detach(struct device *self, int flags)
+{
+ struct dwiic_softc *sc = (struct dwiic_softc *)self;
+
+ if (sc->sc_ih != NULL) {
+ intr_disestablish(sc->sc_ih);
+ sc->sc_ih = NULL;
+ }
+
+ return 0;
+}
+
+int
+dwiic_activate(struct device *self, int act)
+{
+ struct dwiic_softc *sc = (struct dwiic_softc *)self;
+
+ switch (act) {
+ case DVACT_SUSPEND:
+ /* disable controller */
+ dwiic_enable(sc, 0);
+
+ /* disable interrupts */
+ dwiic_write(sc, DW_IC_INTR_MASK, 0);
+ dwiic_read(sc, DW_IC_CLR_INTR);
+
+#if notyet
+ /* power down the controller */
+ dwiic_acpi_power(sc, 0);
+#endif
+ break;
+ case DVACT_WAKEUP:
+#if notyet
+ /* power up the controller */
+ dwiic_acpi_power(sc, 1);
+#endif
+ dwiic_init(sc);
+
+ break;
+ }
+
+ config_activate_children(self, act);
+
+ return 0;
+}
+
+int
+dwiic_i2c_print(void *aux, const char *pnp)
+{
+ struct i2c_attach_args *ia = aux;
+
+ if (pnp != NULL)
+ printf("%s at %s", ia->ia_name, pnp);
+
+ printf(" addr 0x%x", ia->ia_addr);
+
+ return UNCONF;
+}
+
+uint32_t
+dwiic_read(struct dwiic_softc *sc, int offset)
+{
+ u_int32_t b = bus_space_read_4(sc->sc_iot, sc->sc_ioh, offset);
+
+ DPRINTF(("%s: read at 0x%x = 0x%x\n", sc->sc_dev.dv_xname, offset, b));
+
+ return b;
+}
+
+void
+dwiic_write(struct dwiic_softc *sc, int offset, uint32_t val)
+{
+ DPRINTF(("%s: write at 0x%x: 0x%x\n", sc->sc_dev.dv_xname, offset,
+ val));
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, offset, val);
+}
+
+int
+dwiic_i2c_acquire_bus(void *cookie, int flags)
+{
+ struct dwiic_softc *sc = cookie;
+
+ if (cold || sc->sc_poll || (flags & I2C_F_POLL))
+ return (0);
+
+ return rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR);
+}
+
+void
+dwiic_i2c_release_bus(void *cookie, int flags)
+{
+ struct dwiic_softc *sc = cookie;
+
+ if (cold || sc->sc_poll || (flags & I2C_F_POLL))
+ return;
+
+ rw_exit(&sc->sc_i2c_lock);
+}
+
+int
+dwiic_init(struct dwiic_softc *sc)
+{
+ uint32_t reg;
+
+ /* make sure we're talking to a device we know */
+ reg = dwiic_read(sc, DW_IC_COMP_TYPE);
+ if (reg != DW_IC_COMP_TYPE_VALUE) {
+ DPRINTF(("%s: invalid component type 0x%x\n",
+ sc->sc_dev.dv_xname, reg));
+ return 1;
+ }
+
+ /* disable the adapter */
+ dwiic_enable(sc, 0);
+
+ /* write standard-mode SCL timing parameters */
+ dwiic_write(sc, DW_IC_SS_SCL_HCNT, sc->ss_hcnt);
+ dwiic_write(sc, DW_IC_SS_SCL_LCNT, sc->ss_lcnt);
+
+ /* and fast-mode SCL timing parameters */
+ dwiic_write(sc, DW_IC_FS_SCL_HCNT, sc->fs_hcnt);
+ dwiic_write(sc, DW_IC_FS_SCL_LCNT, sc->fs_lcnt);
+
+ /* SDA hold time */
+ reg = dwiic_read(sc, DW_IC_COMP_VERSION);
+ if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
+ dwiic_write(sc, DW_IC_SDA_HOLD, sc->sda_hold_time);
+
+ /* FIFO threshold levels */
+ sc->tx_fifo_depth = 32;
+ sc->rx_fifo_depth = 32;
+ dwiic_write(sc, DW_IC_TX_TL, sc->tx_fifo_depth / 2);
+ dwiic_write(sc, DW_IC_RX_TL, 0);
+
+ /* configure as i2c master with fast speed */
+ sc->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+ DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
+ dwiic_write(sc, DW_IC_CON, sc->master_cfg);
+
+ return 0;
+}
+
+void
+dwiic_enable(struct dwiic_softc *sc, int enable)
+{
+ int retries;
+
+ for (retries = 100; retries > 0; retries--) {
+ dwiic_write(sc, DW_IC_ENABLE, enable);
+ if ((dwiic_read(sc, DW_IC_ENABLE_STATUS) & 1) == enable)
+ return;
+
+ DELAY(25);
+ }
+
+ printf("%s: failed to %sable\n", sc->sc_dev.dv_xname,
+ (enable ? "en" : "dis"));
+}
+
+int
+dwiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
+ size_t cmdlen, void *buf, size_t len, int flags)
+{
+ struct dwiic_softc *sc = cookie;
+ u_int32_t ic_con, st, cmd, resp;
+ int retries, tx_limit, rx_avail, x, readpos;
+ uint8_t *b;
+
+ if (sc->sc_busy)
+ return 1;
+
+ sc->sc_busy++;
+
+ DPRINTF(("%s: %s: op %d, addr 0x%02x, cmdlen %zu, len %zu, "
+ "flags 0x%02x\n", sc->sc_dev.dv_xname, __func__, op, addr, cmdlen,
+ len, flags));
+
+ /* setup transfer */
+ sc->sc_i2c_xfer.op = op;
+ sc->sc_i2c_xfer.buf = buf;
+ sc->sc_i2c_xfer.len = len;
+ sc->sc_i2c_xfer.flags = flags;
+ sc->sc_i2c_xfer.error = 0;
+
+ /* wait for bus to be idle */
+ for (retries = 100; retries > 0; retries--) {
+ st = dwiic_read(sc, DW_IC_STATUS);
+ if (!(st & DW_IC_STATUS_ACTIVITY))
+ break;
+ DELAY(1000);
+ }
+ DPRINTF(("%s: %s: status 0x%x\n", sc->sc_dev.dv_xname, __func__, st));
+ if (st & DW_IC_STATUS_ACTIVITY) {
+ sc->sc_busy = 0;
+ return (1);
+ }
+
+ if (cold || sc->sc_poll)
+ flags |= I2C_F_POLL;
+
+ /* disable controller */
+ dwiic_enable(sc, 0);
+
+ /* set slave address */
+ ic_con = dwiic_read(sc, DW_IC_CON);
+ ic_con &= ~DW_IC_CON_10BITADDR_MASTER;
+ dwiic_write(sc, DW_IC_CON, ic_con);
+ dwiic_write(sc, DW_IC_TAR, addr);
+
+ /* disable interrupts */
+ dwiic_write(sc, DW_IC_INTR_MASK, 0);
+ dwiic_read(sc, DW_IC_CLR_INTR);
+
+ /* enable controller */
+ dwiic_enable(sc, 1);
+
+ /* wait until the controller is ready for commands */
+ if (flags & I2C_F_POLL)
+ DELAY(200);
+ else {
+ dwiic_read(sc, DW_IC_CLR_INTR);
+ dwiic_write(sc, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY);
+
+ if (tsleep(&sc->sc_writewait, PRIBIO, "dwiic", hz / 2) != 0)
+ printf("%s: timed out waiting for tx_empty intr\n",
+ sc->sc_dev.dv_xname);
+ }
+
+ /* send our command, one byte at a time */
+ if (cmdlen > 0) {
+ b = (void *)cmdbuf;
+
+ DPRINTF(("%s: %s: sending cmd (len %zu):", sc->sc_dev.dv_xname,
+ __func__, cmdlen));
+ for (x = 0; x < cmdlen; x++)
+ DPRINTF((" %02x", b[x]));
+ DPRINTF(("\n"));
+
+ tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
+ if (cmdlen > tx_limit) {
+ /* TODO */
+ printf("%s: can't write %zu (> %d)\n",
+ sc->sc_dev.dv_xname, cmdlen, tx_limit);
+ sc->sc_i2c_xfer.error = 1;
+ sc->sc_busy = 0;
+ return (1);
+ }
+
+ for (x = 0; x < cmdlen; x++) {
+ cmd = b[x];
+ /*
+ * Generate STOP condition if this is the last
+ * byte of the transfer.
+ */
+ if (x == (cmdlen - 1) && len == 0 && I2C_OP_STOP_P(op))
+ cmd |= DW_IC_DATA_CMD_STOP;
+ dwiic_write(sc, DW_IC_DATA_CMD, cmd);
+ }
+ }
+
+ b = (void *)buf;
+ x = readpos = 0;
+ tx_limit = sc->tx_fifo_depth - dwiic_read(sc, DW_IC_TXFLR);
+
+ DPRINTF(("%s: %s: need to read %zu bytes, can send %d read reqs\n",
+ sc->sc_dev.dv_xname, __func__, len, tx_limit));
+
+ while (x < len) {
+ if (I2C_OP_WRITE_P(op))
+ cmd = b[x];
+ else
+ cmd = DW_IC_DATA_CMD_READ;
+
+ /*
+ * Generate RESTART condition if we're reversing
+ * direction.
+ */
+ if (x == 0 && cmdlen > 0 && I2C_OP_READ_P(op))
+ cmd |= DW_IC_DATA_CMD_RESTART;
+ /*
+ * Generate STOP conditon on the last byte of the
+ * transfer.
+ */
+ if (x == (len - 1) && I2C_OP_STOP_P(op))
+ cmd |= DW_IC_DATA_CMD_STOP;
+
+ dwiic_write(sc, DW_IC_DATA_CMD, cmd);
+
+ tx_limit--;
+ x++;
+
+ /*
+ * As TXFLR fills up, we need to clear it out by reading all
+ * available data.
+ */
+ while (tx_limit == 0 || x == len) {
+ DPRINTF(("%s: %s: tx_limit %d, sent %d read reqs\n",
+ sc->sc_dev.dv_xname, __func__, tx_limit, x));
+
+ if (flags & I2C_F_POLL) {
+ for (retries = 100; retries > 0; retries--) {
+ rx_avail = dwiic_read(sc, DW_IC_RXFLR);
+ if (rx_avail > 0)
+ break;
+ DELAY(50);
+ }
+ } else {
+ dwiic_read(sc, DW_IC_CLR_INTR);
+ dwiic_write(sc, DW_IC_INTR_MASK,
+ DW_IC_INTR_RX_FULL);
+
+ if (tsleep(&sc->sc_readwait, PRIBIO, "dwiic",
+ hz / 2) != 0)
+ printf("%s: timed out waiting for "
+ "rx_full intr\n",
+ sc->sc_dev.dv_xname);
+
+ rx_avail = dwiic_read(sc, DW_IC_RXFLR);
+ }
+
+ if (rx_avail == 0) {
+ printf("%s: timed out reading remaining %d\n",
+ sc->sc_dev.dv_xname,
+ (int)(len - 1 - readpos));
+ sc->sc_i2c_xfer.error = 1;
+ sc->sc_busy = 0;
+
+ return (1);
+ }
+
+ DPRINTF(("%s: %s: %d avail to read (%zu remaining)\n",
+ sc->sc_dev.dv_xname, __func__, rx_avail,
+ len - readpos));
+
+ while (rx_avail > 0) {
+ resp = dwiic_read(sc, DW_IC_DATA_CMD);
+ if (readpos < len) {
+ b[readpos] = resp;
+ readpos++;
+ }
+ rx_avail--;
+ }
+
+ if (readpos >= len)
+ break;
+
+ DPRINTF(("%s: still need to read %d bytes\n",
+ sc->sc_dev.dv_xname, (int)(len - readpos)));
+ tx_limit = sc->tx_fifo_depth -
+ dwiic_read(sc, DW_IC_TXFLR);
+ }
+ }
+
+ sc->sc_busy = 0;
+
+ return 0;
+}
+
+uint32_t
+dwiic_read_clear_intrbits(struct dwiic_softc *sc)
+{
+ uint32_t stat;
+
+ stat = dwiic_read(sc, DW_IC_INTR_STAT);
+
+ if (stat & DW_IC_INTR_RX_UNDER)
+ dwiic_read(sc, DW_IC_CLR_RX_UNDER);
+ if (stat & DW_IC_INTR_RX_OVER)
+ dwiic_read(sc, DW_IC_CLR_RX_OVER);
+ if (stat & DW_IC_INTR_TX_OVER)
+ dwiic_read(sc, DW_IC_CLR_TX_OVER);
+ if (stat & DW_IC_INTR_RD_REQ)
+ dwiic_read(sc, DW_IC_CLR_RD_REQ);
+ if (stat & DW_IC_INTR_TX_ABRT)
+ dwiic_read(sc, DW_IC_CLR_TX_ABRT);
+ if (stat & DW_IC_INTR_RX_DONE)
+ dwiic_read(sc, DW_IC_CLR_RX_DONE);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dwiic_read(sc, DW_IC_CLR_ACTIVITY);
+ if (stat & DW_IC_INTR_STOP_DET)
+ dwiic_read(sc, DW_IC_CLR_STOP_DET);
+ if (stat & DW_IC_INTR_START_DET)
+ dwiic_read(sc, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_GEN_CALL)
+ dwiic_read(sc, DW_IC_CLR_GEN_CALL);
+
+ return stat;
+}
+
+int
+dwiic_intr(void *arg)
+{
+ struct dwiic_softc *sc = arg;
+ uint32_t en, stat;
+
+ en = dwiic_read(sc, DW_IC_ENABLE);
+ /* probably for the other controller */
+ if (!en)
+ return 0;
+
+ stat = dwiic_read_clear_intrbits(sc);
+ DPRINTF(("%s: %s: enabled=0x%x stat=0x%x\n", sc->sc_dev.dv_xname,
+ __func__, en, stat));
+ if (!(stat & ~DW_IC_INTR_ACTIVITY))
+ return 1;
+
+ if (stat & DW_IC_INTR_TX_ABRT)
+ sc->sc_i2c_xfer.error = 1;
+
+ if (sc->sc_i2c_xfer.flags & I2C_F_POLL)
+ DPRINTF(("%s: %s: intr in poll mode?\n", sc->sc_dev.dv_xname,
+ __func__));
+ else {
+ if (stat & DW_IC_INTR_RX_FULL) {
+ dwiic_write(sc, DW_IC_INTR_MASK, 0);
+ DPRINTF(("%s: %s: waking up reader\n",
+ sc->sc_dev.dv_xname, __func__));
+ wakeup(&sc->sc_readwait);
+ }
+ if (stat & DW_IC_INTR_TX_EMPTY) {
+ dwiic_write(sc, DW_IC_INTR_MASK, 0);
+ DPRINTF(("%s: %s: waking up writer\n",
+ sc->sc_dev.dv_xname, __func__));
+ wakeup(&sc->sc_writewait);
+ }
+ }
+
+ return 1;
+}
Index: sys/dev/ic/dwiicreg.h
===================================================================
RCS file: sys/dev/ic/dwiicreg.h
diff -N sys/dev/ic/dwiicreg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/ic/dwiicreg.h 10 Nov 2017 15:56:47 -0000
@@ -0,0 +1,94 @@
+/* $OpenBSD$ */
+/*
+ * Synopsys DesignWare I2C controller
+ *
+ * Copyright (c) 2015, 2016 joshua stein <j...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* register offsets */
+#define DW_IC_CON 0x0
+#define DW_IC_TAR 0x4
+#define DW_IC_DATA_CMD 0x10
+#define DW_IC_SS_SCL_HCNT 0x14
+#define DW_IC_SS_SCL_LCNT 0x18
+#define DW_IC_FS_SCL_HCNT 0x1c
+#define DW_IC_FS_SCL_LCNT 0x20
+#define DW_IC_INTR_STAT 0x2c
+#define DW_IC_INTR_MASK 0x30
+#define DW_IC_RAW_INTR_STAT 0x34
+#define DW_IC_RX_TL 0x38
+#define DW_IC_TX_TL 0x3c
+#define DW_IC_CLR_INTR 0x40
+#define DW_IC_CLR_RX_UNDER 0x44
+#define DW_IC_CLR_RX_OVER 0x48
+#define DW_IC_CLR_TX_OVER 0x4c
+#define DW_IC_CLR_RD_REQ 0x50
+#define DW_IC_CLR_TX_ABRT 0x54
+#define DW_IC_CLR_RX_DONE 0x58
+#define DW_IC_CLR_ACTIVITY 0x5c
+#define DW_IC_CLR_STOP_DET 0x60
+#define DW_IC_CLR_START_DET 0x64
+#define DW_IC_CLR_GEN_CALL 0x68
+#define DW_IC_ENABLE 0x6c
+#define DW_IC_STATUS 0x70
+#define DW_IC_TXFLR 0x74
+#define DW_IC_RXFLR 0x78
+#define DW_IC_SDA_HOLD 0x7c
+#define DW_IC_TX_ABRT_SOURCE 0x80
+#define DW_IC_ENABLE_STATUS 0x9c
+#define DW_IC_COMP_PARAM_1 0xf4
+#define DW_IC_COMP_VERSION 0xf8
+#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
+#define DW_IC_COMP_TYPE 0xfc
+#define DW_IC_COMP_TYPE_VALUE 0x44570140
+
+#define DW_IC_CON_MASTER 0x1
+#define DW_IC_CON_SPEED_STD 0x2
+#define DW_IC_CON_SPEED_FAST 0x4
+#define DW_IC_CON_10BITADDR_MASTER 0x10
+#define DW_IC_CON_RESTART_EN 0x20
+#define DW_IC_CON_SLAVE_DISABLE 0x40
+
+#define DW_IC_DATA_CMD_READ 0x100
+#define DW_IC_DATA_CMD_STOP 0x200
+#define DW_IC_DATA_CMD_RESTART 0x400
+
+#define DW_IC_INTR_RX_UNDER 0x001
+#define DW_IC_INTR_RX_OVER 0x002
+#define DW_IC_INTR_RX_FULL 0x004
+#define DW_IC_INTR_TX_OVER 0x008
+#define DW_IC_INTR_TX_EMPTY 0x010
+#define DW_IC_INTR_RD_REQ 0x020
+#define DW_IC_INTR_TX_ABRT 0x040
+#define DW_IC_INTR_RX_DONE 0x080
+#define DW_IC_INTR_ACTIVITY 0x100
+#define DW_IC_INTR_STOP_DET 0x200
+#define DW_IC_INTR_START_DET 0x400
+#define DW_IC_INTR_GEN_CALL 0x800
+
+#define DW_IC_STATUS_ACTIVITY 0x1
+
+/* hardware abort codes from the DW_IC_TX_ABRT_SOURCE register */
+#define ABRT_7B_ADDR_NOACK 0
+#define ABRT_10ADDR1_NOACK 1
+#define ABRT_10ADDR2_NOACK 2
+#define ABRT_TXDATA_NOACK 3
+#define ABRT_GCALL_NOACK 4
+#define ABRT_GCALL_READ 5
+#define ABRT_SBYTE_ACKDET 7
+#define ABRT_SBYTE_NORSTRT 9
+#define ABRT_10B_RD_NORSTRT 10
+#define ABRT_MASTER_DIS 11
+#define ARB_LOST 12
Index: sys/dev/ic/dwiicvar.h
===================================================================
RCS file: sys/dev/ic/dwiicvar.h
diff -N sys/dev/ic/dwiicvar.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/ic/dwiicvar.h 10 Nov 2017 15:56:47 -0000
@@ -0,0 +1,103 @@
+/* $OpenBSD: dwiic.c,v 1.22 2016/10/25 06:48:58 pirofti Exp $ */
+/*
+ * Synopsys DesignWare I2C controller
+ *
+ * Copyright (c) 2015, 2016 joshua stein <j...@openbsd.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/i2c/i2cvar.h>
+
+#include <dev/ic/dwiicreg.h>
+
+/* #define DWIIC_DEBUG */
+
+#ifdef DWIIC_DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+struct dwiic_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ struct acpi_softc *sc_acpi;
+ struct aml_node *sc_devnode;
+ char sc_hid[16];
+ void *sc_ih;
+
+ struct pci_attach_args sc_paa;
+
+ struct i2cbus_attach_args sc_iba;
+ struct device *sc_iic;
+
+ u_int32_t sc_caps;
+ int sc_poll;
+ int sc_poll_ihidev;
+ int sc_busy;
+ int sc_readwait;
+ int sc_writewait;
+
+ uint32_t master_cfg;
+ uint16_t ss_hcnt, ss_lcnt, fs_hcnt, fs_lcnt;
+ uint32_t sda_hold_time;
+ int tx_fifo_depth;
+ int rx_fifo_depth;
+
+ struct i2c_controller sc_i2c_tag;
+ struct rwlock sc_i2c_lock;
+ struct {
+ i2c_op_t op;
+ void *buf;
+ size_t len;
+ int flags;
+ volatile int error;
+ } sc_i2c_xfer;
+};
+
+int dwiic_activate(struct device *, int);
+int dwiic_init(struct dwiic_softc *);
+void dwiic_enable(struct dwiic_softc *, int);
+int dwiic_intr(void *);
+
+void * dwiic_i2c_intr_establish(void *, void *, int,
+ int (*)(void *), void *, const char *);
+const char * dwiic_i2c_intr_string(void *, void *);
+int dwiic_i2c_print(void *, const char *);
+
+int dwiic_i2c_acquire_bus(void *, int);
+void dwiic_i2c_release_bus(void *, int);
+uint32_t dwiic_read(struct dwiic_softc *, int);
+void dwiic_write(struct dwiic_softc *, int, uint32_t);
+int dwiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
+ size_t, void *, size_t, int);
+void dwiic_xfer_msg(struct dwiic_softc *);
+
+int dwiic_acpi_found_hid(struct aml_node *node, void *arg);