-# $OpenBSD: files,v 1.723 2023/04/04 00:38:37 jsg Exp $
+# $OpenBSD: files,v 1.724 2023/04/23 00:20:26 dlg Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
device bwi: ether, ifnet, ifmedia, firmload, wlan
file dev/ic/bwi.c bwi
+# Intel OnChip System Fabric
+device iosf
+file dev/ic/iosf.c iosf needs-flag
+
# Attributes which machine-independent bus support can be attached to.
# These should be defined here, because some of these busses can have
# devices which provide these attributes, and we'd like to avoid hairy
-# $OpenBSD: files.acpi,v 1.68 2023/02/04 23:11:59 mglocker Exp $
+# $OpenBSD: files.acpi,v 1.69 2023/04/23 00:20:26 dlg Exp $
#
# Config file and device description for machine-independent ACPI code.
# Included by ports that need it.
# UFS HC
attach ufshci at acpi with ufshci_acpi
file dev/acpi/ufshci_acpi.c ufshci_acpi
+
+# Intel OnChip System Fabric
+attach iosf at acpi with iosf_acpi
+file dev/acpi/iosf_acpi.c iosf_acpi
--- /dev/null
+/* $OpenBSD: iosf_acpi.c,v 1.1 2023/04/23 00:20:26 dlg Exp $ */
+/*
+ * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and 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/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.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/iosfvar.h>
+
+struct iosf_acpi_softc {
+ struct device sc_dev;
+ struct acpi_softc *sc_acpi;
+ struct aml_node *sc_node;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_size_t sc_ios;
+
+ struct iosf_mbi sc_mbi;
+};
+
+static int iosf_acpi_match(struct device *, void *, void *);
+static void iosf_acpi_attach(struct device *, struct device *, void *);
+
+static uint32_t iosf_acpi_mbi_mdr_rd(struct iosf_mbi *, uint32_t, uint32_t);
+static void iosf_acpi_mbi_mdr_wr(struct iosf_mbi *, uint32_t, uint32_t,
+ uint32_t);
+
+const struct cfattach iosf_acpi_ca = {
+ sizeof(struct iosf_acpi_softc), iosf_acpi_match, iosf_acpi_attach
+};
+
+static const char *iosf_hids[] = {
+ "INT33BD",
+ NULL
+};
+
+static int
+iosf_acpi_match(struct device *parent, void *match, void *aux)
+{
+ struct acpi_attach_args *aaa = aux;
+ struct cfdata *cf = match;
+
+ if (aaa->aaa_naddr < 1)
+ return 0;
+
+ return (acpi_matchhids(aaa, iosf_hids, cf->cf_driver->cd_name));
+}
+
+static void
+iosf_acpi_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct iosf_acpi_softc *sc = (struct iosf_acpi_softc *)self;
+ struct acpi_attach_args *aaa = aux;
+ struct cpu_info *ci;
+ int semaddr = -1;
+
+ sc->sc_acpi = (struct acpi_softc *)parent;
+ sc->sc_node = aaa->aaa_node;
+ printf(" %s", sc->sc_node->name);
+
+ sc->sc_iot = aaa->aaa_bst[0];
+ sc->sc_ios = aaa->aaa_size[0];
+
+ if (bus_space_map(sc->sc_iot, aaa->aaa_addr[0], aaa->aaa_size[0], 0,
+ &sc->sc_ioh)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ ci = curcpu();
+ if (strcmp(cpu_vendor, "GenuineIntel") == 0 &&
+ ci->ci_family == 0x06 && ci->ci_model == 0x4c) {
+ /* cherry trail, braswell */
+ semaddr = 0x10e;
+ }
+
+ if (semaddr != -1) {
+ printf(": mbi");
+
+ sc->sc_mbi.mbi_dev = self;
+ sc->sc_mbi.mbi_prio = 1; /* lower prio than iosf_pci ops */
+ sc->sc_mbi.mbi_semaddr = semaddr;
+ sc->sc_mbi.mbi_mdr_rd = iosf_acpi_mbi_mdr_rd;
+ sc->sc_mbi.mbi_mdr_wr = iosf_acpi_mbi_mdr_wr;
+ }
+
+ printf("\n");
+}
+
+/*
+ * mbi mdr ACPI operations
+ */
+
+#define IOSF_ACPI_MBI_MCR 0x0
+#define IOSF_ACPI_MBI_MDR 0x4
+#define IOSF_ACPI_MBI_MCRX 0x8
+
+static uint32_t
+iosf_acpi_mbi_mdr_rd(struct iosf_mbi *mbi, uint32_t mcr, uint32_t mcrx)
+{
+ struct iosf_acpi_softc *sc = (struct iosf_acpi_softc *)mbi->mbi_dev;
+
+ if (mcrx != 0) {
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ IOSF_ACPI_MBI_MCRX, mcrx);
+ }
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOSF_ACPI_MBI_MCR, mcr);
+
+ return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOSF_ACPI_MBI_MDR));
+}
+
+static void
+iosf_acpi_mbi_mdr_wr(struct iosf_mbi *mbi, uint32_t mcr, uint32_t mcrx,
+ uint32_t mdr)
+{
+ struct iosf_acpi_softc *sc = (struct iosf_acpi_softc *)mbi->mbi_dev;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOSF_ACPI_MBI_MDR, mdr);
+ if (mcrx != 0) {
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ IOSF_ACPI_MBI_MCRX, mcrx);
+ }
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOSF_ACPI_MBI_MCR, mcr);
+}
--- /dev/null
+/* $OpenBSD: iosf.c,v 1.1 2023/04/23 00:20:26 dlg Exp $ */
+
+/*
+ * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and 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/device.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+
+#include <machine/bus.h>
+
+#include <dev/ic/iosfvar.h>
+
+#define IOSF_MBI_MASK_HI 0xffffff00
+#define IOSF_MBI_MASK_LO 0x000000ff
+#define IOSF_MBI_ENABLE 0x000000f0
+
+#define IOSF_MBI_MCR_OP_SHIFT 24
+#define IOSF_MBI_MCR_PORT_SHIFT 16
+#define IOSF_MBI_MCR_OFFSET_SHIFT 8
+
+/* IOSF sideband read/write opcodes */
+#define IOSF_MBI_OP_MMIO_READ 0x00
+#define IOSF_MBI_OP_MMIO_WRITE 0x01
+#define IOSF_MBI_OP_CFG_READ 0x04
+#define IOSF_MBI_OP_CFG_WRITE 0x05
+#define IOSF_MBI_OP_CR_READ 0x06
+#define IOSF_MBI_OP_CR_WRITE 0x07
+#define IOSF_MBI_OP_REG_READ 0x10
+#define IOSF_MBI_OP_REG_WRITE 0x11
+#define IOSF_MBI_OP_ESRAM_READ 0x12
+#define IOSF_MBI_OP_ESRAM_WRITE 0x13
+
+/* Baytrail */
+#define IOSF_BT_MBI_UNIT_AUNIT 0x00
+#define IOSF_BT_MBI_UNIT_SMC 0x01
+#define IOSF_BT_MBI_UNIT_CPU 0x02
+#define IOSF_BT_MBI_UNIT_BUNIT 0x03
+#define IOSF_BT_MBI_UNIT_PMC 0x04
+#define IOSF_BT_MBI_UNIT_GFX 0x06
+#define IOSF_BT_MBI_UNIT_SMI 0x0C
+#define IOSF_BT_MBI_UNIT_CCK 0x14
+#define IOSF_BT_MBI_UNIT_USB 0x43
+#define IOSF_BT_MBI_UNIT_SATA 0xA3
+#define IOSF_BT_MBI_UNIT_PCIE 0xA6
+
+/* semaphore bits */
+#define IOSF_PUNIT_SEM_BIT (1 << 0)
+#define IOSF_PUNIT_SEM_ACQUIRE (1 << 1)
+
+struct cfdriver iosf_cd = {
+ NULL, "iosf", DV_DULL
+};
+
+/*
+ * serialise register ops
+ */
+static struct mutex iosf_mbi_mtx = MUTEX_INITIALIZER(IPL_HIGH);
+
+/*
+ * rwlock for kernel to coordinate access to the mbi with
+ */
+static struct rwlock iosf_lock = RWLOCK_INITIALIZER("iosf");
+
+/*
+ * drivers provide an iosf_mbi that acts as a backend for the code below.
+ */
+static struct iosf_mbi *iosf_mbi;
+
+void
+iosf_mbi_attach(struct iosf_mbi *mbi)
+{
+ /*
+ * assume this is serialised by autoconf being run sequentially
+ * during boot.
+ */
+
+ if (iosf_mbi == NULL || iosf_mbi->mbi_prio < mbi->mbi_prio)
+ iosf_mbi = mbi;
+}
+
+static inline uint32_t
+iosf_mbi_mcr(uint8_t op, uint8_t port, uint32_t offset)
+{
+ uint32_t rv = IOSF_MBI_ENABLE;
+ rv |= op << IOSF_MBI_MCR_OP_SHIFT;
+ rv |= port << IOSF_MBI_MCR_PORT_SHIFT;
+ rv |= (offset & IOSF_MBI_MASK_LO) << IOSF_MBI_MCR_OFFSET_SHIFT;
+ return (rv);
+}
+
+static inline uint32_t
+iosf_mbi_mcrx(uint32_t offset)
+{
+ return (offset & IOSF_MBI_MASK_HI);
+}
+
+/*
+ * serialised mbi mdr operations
+ */
+
+static uint32_t
+iosf_mbi_mdr_read(struct iosf_mbi *mbi, uint8_t port, uint8_t op,
+ uint32_t offset)
+{
+ uint32_t mcr, mcrx, mdr;
+
+ mcr = iosf_mbi_mcr(op, port, offset);
+ mcrx = iosf_mbi_mcrx(offset);
+
+ mtx_enter(&iosf_mbi_mtx);
+ mdr = (*mbi->mbi_mdr_rd)(mbi, mcr, mcrx);
+ mtx_leave(&iosf_mbi_mtx);
+
+ return (mdr);
+}
+
+static void
+iosf_mbi_mdr_write(struct iosf_mbi *mbi, uint8_t port, uint8_t op,
+ uint32_t offset, uint32_t mdr)
+{
+ uint32_t mcr, mcrx;
+
+ mcr = iosf_mbi_mcr(op, port, offset);
+ mcrx = iosf_mbi_mcrx(offset);
+
+ mtx_enter(&iosf_mbi_mtx);
+ (*mbi->mbi_mdr_wr)(mbi, mcr, mcrx, mdr);
+ mtx_leave(&iosf_mbi_mtx);
+}
+
+static void
+iosf_mbi_mdr_modify(struct iosf_mbi *mbi, uint8_t port, uint8_t op,
+ uint32_t offset, uint32_t bits, uint32_t mask)
+{
+ uint32_t mcr, mcrx, mdr;
+
+ mcr = iosf_mbi_mcr(op, port, offset);
+ mcrx = iosf_mbi_mcrx(offset);
+
+ mtx_enter(&iosf_mbi_mtx);
+ mdr = (*mbi->mbi_mdr_rd)(mbi, mcr, mcrx);
+
+ CLR(mdr, mask);
+ SET(mdr, bits & mask);
+
+ (*mbi->mbi_mdr_wr)(mbi, mcr, mcrx, mdr);
+ mtx_leave(&iosf_mbi_mtx);
+}
+
+/*
+ * linux compat api
+ */
+
+int
+iosf_mbi_read(uint8_t port, uint8_t opcode, uint32_t offset, uint32_t *mdrp)
+{
+ struct iosf_mbi *mbi;
+
+ mbi = iosf_mbi;
+ if (mbi == NULL)
+ return (ENODEV);
+
+ /* check port != BT_MBI_UNIT_GFX? */
+
+ *mdrp = iosf_mbi_mdr_read(mbi, port, opcode, offset);
+
+ return (0);
+}
+
+int
+iosf_mbi_write(uint8_t port, uint8_t opcode, uint32_t offset, uint32_t mdr)
+{
+ struct iosf_mbi *mbi;
+
+ mbi = iosf_mbi;
+ if (mbi == NULL)
+ return (ENODEV);
+
+ /* check port != BT_MBI_UNIT_GFX? */
+
+ iosf_mbi_mdr_write(mbi, port, opcode, offset, mdr);
+
+ return (0);
+}
+
+int
+iosf_mbi_modify(uint8_t port, uint8_t opcode, uint32_t offset,
+ uint32_t bits, uint32_t mask)
+{
+ struct iosf_mbi *mbi;
+
+ mbi = iosf_mbi;
+ if (mbi == NULL)
+ return (ENODEV);
+
+ /* check port != BT_MBI_UNIT_GFX? */
+
+ iosf_mbi_mdr_modify(mbi, port, opcode, offset, bits, mask);
+
+ return (0);
+}
+
+int
+iosf_mbi_available(void)
+{
+ return (iosf_mbi != NULL);
+}
+
+static uint32_t
+iosf_mbi_sem_get(struct iosf_mbi *mbi)
+{
+ uint32_t sem;
+
+ sem = iosf_mbi_mdr_read(mbi,
+ IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_READ, mbi->mbi_semaddr);
+
+ return (ISSET(sem, IOSF_PUNIT_SEM_BIT));
+}
+
+static void
+iosf_mbi_sem_reset(struct iosf_mbi *mbi)
+{
+ iosf_mbi_mdr_modify(mbi,
+ IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_READ, mbi->mbi_semaddr,
+ 0, IOSF_PUNIT_SEM_BIT);
+}
+
+void
+iosf_mbi_punit_acquire(void)
+{
+ rw_enter_write(&iosf_lock);
+}
+
+void
+iosf_mbi_punit_release(void)
+{
+ rw_exit_write(&iosf_lock);
+}
+
+void iosf_mbi_assert_punit_acquired(void)
+{
+ int s;
+
+ if (splassert_ctl == 0)
+ return;
+
+ s = rw_status(&iosf_lock);
+ if (s != RW_WRITE)
+ splassert_fail(RW_WRITE, s, __func__);
+}
+
+static void
+iosf_sem_wait(uint64_t usec, int waitok)
+{
+ if (waitok)
+ tsleep_nsec(&nowake, PRIBIO, "iosfsem", USEC_TO_NSEC(usec));
+ else
+ delay(usec);
+}
+
+#include <dev/i2c/i2cvar.h>
+
+int
+iosf_i2c_acquire(int flags)
+{
+ struct iosf_mbi *mbi;
+ int waitok = !cold && !ISSET(flags, I2C_F_POLL);
+ unsigned int i;
+
+ mbi = iosf_mbi;
+ if (mbi == NULL)
+ return (0);
+
+ if (waitok)
+ rw_enter_write(&iosf_lock);
+ else if (iosf_lock.rwl_owner != 0)
+ panic("%s", __func__);
+
+ /* XXX disable C6 and C7 states */
+
+ iosf_mbi_mdr_write(mbi, IOSF_BT_MBI_UNIT_PMC, IOSF_MBI_OP_REG_WRITE,
+ mbi->mbi_semaddr, IOSF_PUNIT_SEM_ACQUIRE);
+
+ for (i = 0; i < 50; i++) {
+ if (iosf_mbi_sem_get(mbi)) {
+ /* success! */
+ return (0);
+ }
+
+ iosf_sem_wait(10000, waitok);
+ }
+
+ iosf_mbi_sem_reset(mbi);
+
+ if (waitok)
+ rw_exit_write(&iosf_lock);
+ else if (iosf_lock.rwl_owner != 0)
+ panic("%s", __func__);
+
+ return (EWOULDBLOCK);
+}
+
+void
+iosf_i2c_release(int flags)
+{
+ struct iosf_mbi *mbi;
+ int waitok = !cold && !ISSET(flags, I2C_F_POLL);
+
+ mbi = iosf_mbi;
+ if (mbi == NULL)
+ return;
+
+ iosf_mbi_sem_reset(mbi);
+
+ if (waitok)
+ rw_exit_write(&iosf_lock);
+ else if (iosf_lock.rwl_owner != 0)
+ panic("%s", __func__);
+}
--- /dev/null
+/* $OpenBSD: iosfvar.h,v 1.1 2023/04/23 00:20:26 dlg Exp $ */
+
+/*
+ * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and 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.
+ */
+
+#ifndef _DEV_IC_IOSFVAR_H_
+#define _DEV_IC_IOSFVAR_H_
+
+/*
+ * iosf provider api
+ */
+
+struct iosf_mbi {
+ struct device *mbi_dev;
+ int mbi_prio;
+ int mbi_semaddr;
+
+ uint32_t (*mbi_mdr_rd)(struct iosf_mbi *sc, uint32_t, uint32_t);
+ void (*mbi_mdr_wr)(struct iosf_mbi *sc, uint32_t, uint32_t,
+ uint32_t);
+};
+
+void iosf_mbi_attach(struct iosf_mbi *);
+
+/*
+ * iosf consumer apis
+ */
+
+int iosf_mbi_available(void);
+
+/* for i2c */
+int iosf_i2c_acquire(int);
+void iosf_i2c_relese(int);
+
+/* for drm to coordinate with the rest of the kernel */
+void iosf_mbi_punit_acquire(void);
+void iosf_mbi_punit_release(void);
+void iosf_mbi_assert_punit_acquired(void);
+
+#ifdef nyetyet
+int iosf_mbi_read(uint8_t, uint8_t, uint32_t, uint32_t *);
+int iosf_mbi_write(uint8_t, uint8_t, uint32_t, uint32_t);
+int iosf_mbi_modify(uint8_t, uint8_t, uint32_t, uint32_t, uint32_t);
+#endif
+
+#endif /* _DEV_IC_IOSFVAR_H_ */
-# $OpenBSD: files.pci,v 1.360 2023/03/31 08:19:41 kevlo Exp $
+# $OpenBSD: files.pci,v 1.361 2023/04/23 00:20:26 dlg Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
attach gcu at pci
file dev/pci/gcu.c gcu needs-flag
+# Intel OnChip System Fabric
+attach iosf at pci with iosf_pci
+file dev/pci/iosf_pci.c iosf_pci
+
# AMD Geode CS5536 Audio
device auglx: audio, ac97
attach auglx at pci
--- /dev/null
+/* $OpenBSD: iosf_pci.c,v 1.1 2023/04/23 00:20:26 dlg Exp $ */
+
+/*
+ * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
+ *
+ * Permission to use, copy, modify, and 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/device.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+
+#include <machine/bus.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/ic/iosfvar.h>
+
+/*
+ * Intel OnChip System Fabric driver
+ */
+
+struct iosf_pci_softc {
+ struct device sc_dev;
+
+ pci_chipset_tag_t sc_pc;
+ pcitag_t sc_pcitag;
+
+ int sc_semaddr;
+
+ struct iosf_mbi sc_mbi;
+};
+
+static int iosf_pci_match(struct device *, void *, void *);
+static void iosf_pci_attach(struct device *, struct device *, void *);
+
+static uint32_t iosf_pci_mbi_mdr_rd(struct iosf_mbi *, uint32_t, uint32_t);
+static void iosf_pci_mbi_mdr_wr(struct iosf_mbi *, uint32_t, uint32_t,
+ uint32_t);
+
+const struct cfattach iosf_pci_ca = {
+ sizeof(struct iosf_pci_softc), iosf_pci_match, iosf_pci_attach
+};
+
+struct iosf_pci_device {
+ struct pci_matchid id_pm;
+ int id_semaddr;
+};
+
+static const struct iosf_pci_device iosf_pci_devices[] = {
+ { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_BAYTRAIL_HB }, 0x7 },
+ { { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_BSW_HB }, 0x10e },
+ /* Quark X1000, -1 */
+ /* Tangier, -1 */
+};
+
+static const struct iosf_pci_device *
+iosf_pci_device_match(struct pci_attach_args *pa)
+{
+ pci_vendor_id_t vid = PCI_VENDOR(pa->pa_id);
+ pci_product_id_t pid = PCI_PRODUCT(pa->pa_id);
+ const struct iosf_pci_device *id;
+ size_t i;
+
+ for (i = 0; i < nitems(iosf_pci_devices); i++) {
+ id = &iosf_pci_devices[i];
+ if (id->id_pm.pm_vid == vid && id->id_pm.pm_pid == pid)
+ return (id);
+ }
+
+ return (NULL);
+}
+
+static int
+iosf_pci_match(struct device *parent, void *match, void *aux)
+{
+ struct pci_attach_args *pa = aux;
+
+ if (iosf_pci_device_match(pa) != NULL) {
+ /* match higher than pchb(4) */
+ return (2);
+ }
+
+ return (0);
+}
+
+static void
+iosf_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct iosf_pci_softc *sc = (struct iosf_pci_softc *)self;
+ struct pci_attach_args *pa = aux;
+ const struct iosf_pci_device *id = iosf_pci_device_match(pa);
+
+ sc->sc_pc = pa->pa_pc;
+ sc->sc_pcitag = pa->pa_tag;
+
+ printf(": mbi\n");
+
+ sc->sc_mbi.mbi_dev = self;
+ sc->sc_mbi.mbi_prio = 2; /* prefer pci over acpi ops */
+ sc->sc_mbi.mbi_semaddr = id->id_semaddr;
+ sc->sc_mbi.mbi_mdr_rd = iosf_pci_mbi_mdr_rd;
+ sc->sc_mbi.mbi_mdr_wr = iosf_pci_mbi_mdr_wr;
+
+ iosf_mbi_attach(&sc->sc_mbi);
+}
+
+/*
+ * mbi mdr pciconf operations
+ */
+
+#define IOSF_PCI_MBI_MCR 0xd0
+#define IOSF_PCI_MBI_MDR 0xd4
+#define IOSF_PCI_MBI_MCRX 0xd8
+
+static uint32_t
+iosf_pci_mbi_mdr_rd(struct iosf_mbi *mbi, uint32_t mcr, uint32_t mcrx)
+{
+ struct iosf_pci_softc *sc = (struct iosf_pci_softc *)mbi->mbi_dev;
+
+ if (mcrx != 0) {
+ pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+ IOSF_PCI_MBI_MCRX, mcrx);
+ }
+ pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_PCI_MBI_MCR, mcr);
+
+ return (pci_conf_read(sc->sc_pc, sc->sc_pcitag, IOSF_PCI_MBI_MDR));
+}
+
+static void
+iosf_pci_mbi_mdr_wr(struct iosf_mbi *mbi, uint32_t mcr, uint32_t mcrx,
+ uint32_t mdr)
+{
+ struct iosf_pci_softc *sc = (struct iosf_pci_softc *)mbi->mbi_dev;
+
+ pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_PCI_MBI_MDR, mdr);
+
+ if (mcrx != 0) {
+ pci_conf_write(sc->sc_pc, sc->sc_pcitag,
+ IOSF_PCI_MBI_MCRX, mcrx);
+ }
+
+ pci_conf_write(sc->sc_pc, sc->sc_pcitag, IOSF_PCI_MBI_MCR, mcr);
+}