diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -248,6 +248,7 @@ ismt.4 \ isp.4 \ ispfw.4 \ + ${_it8613hwm.4} \ ${_itwd.4} \ iwi.4 \ iwifw.4 \ @@ -837,6 +838,7 @@ _igc.4= igc.4 _imcsmb.4= imcsmb.4 _io.4= io.4 +_it8613hwm.4= it8613hwm.4 _itwd.4= itwd.4 _mgb.4= mgb.4 _nda.4= nda.4 diff --git a/share/man/man4/it8613hwm.4 b/share/man/man4/it8613hwm.4 new file mode 100644 --- /dev/null +++ b/share/man/man4/it8613hwm.4 @@ -0,0 +1,85 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD +.\" +.\" Copyright (c) 2022 Johannes Totz +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 8, 2022 +.Dt IT8613HWM 4 +.Os +.Sh NAME +.Nm it8613hwm +.Nd device driver for the ITE IT8613E Super I/O hardware monitor +.Sh SYNOPSIS +To compile this driver into the kernel, place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device superio" +.Cd "device it8613hwm" +.Ed +.Pp +Alternatively, to load the driver as a module at boot time, place the following +line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +it8613hwm_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver supports reading the temperature sensor and fan speed from the hardware +monitor present in the IT8613E Super I/O chip. + +There are 3 temperature sensor channels but not all may be connected on the +mainboard. These are reported through a sysctl node named +.Va dev.it8613hwm.0.temperature%d , +where %d goes from 0 to 2 inclusive. + +There are also 3 fan speed channels, again not all of those may be connected on +the mainboard, reported in units of RPM via +.Va dev.it8613hwm.0.fan%d . +.Sh EXAMPLES +To get the current values for all temperature sensors and fans: +.Pp +.Dl "$ sysctl dev.it8613hwm" +.Dl "dev.it8613hwm.0.fan2: 1470" +.Dl "dev.it8613hwm.0.fan1: 648" +.Dl "dev.it8613hwm.0.fan0: 0" +.Dl "dev.it8613hwm.0.temperature2: 35C" +.Dl "dev.it8613hwm.0.temperature1: 40C" +.Dl "dev.it8613hwm.0.temperature0: 49C" +.Pp +As can be seen in this example, there is no fan connected to fan0. +.Sh SEE ALSO +.Xr superio 4 , +.Xr sysctl 8 +.Sh AUTHORS +.An -nosplit +The driver and manual page was written by +.An Johannes Totz . +.Sh BUGS +No public datasheet is available for this chip. The information to write this +driver was obtained through trial-and-error and datasheets for similar (but +ultimately different) chips. diff --git a/share/man/man4/superio.4 b/share/man/man4/superio.4 --- a/share/man/man4/superio.4 +++ b/share/man/man4/superio.4 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 11, 2019 +.Dd September 8, 2022 .Dt SUPERIO 4 .Os .Sh NAME @@ -101,9 +101,10 @@ The .Nm driver supports a multitude of Super I/O controllers produced by Nuvoton, -formerly known as Winbond, and ITE. +formerly known as Winbond, Fintek and ITE. .Sh SEE ALSO -.Xr superio 9 +.Xr superio 9 , +.Xr it8613hwm 4 .Sh HISTORY The .Nm diff --git a/sys/dev/it8613hwm/it8613hwm.c b/sys/dev/it8613hwm/it8613hwm.c new file mode 100644 --- /dev/null +++ b/sys/dev/it8613hwm/it8613hwm.c @@ -0,0 +1,224 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Johannes Totz + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +struct it8613hwm_softc { + struct resource* ioport_res; + int ioport_rid; + + struct mtx lock; +}; + +static int it8613hwm_get_temp_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t) arg1; + struct it8613hwm_softc* sc = device_get_softc(dev); + int tempindex = arg2; + int tempkelvin = 0; + uint8_t tempcelsius; + int8_t tempoffset; + + if (tempindex >= 0 && tempindex < 3) + { + mtx_lock(&sc->lock); + + bus_write_1(sc->ioport_res, 0, 0x29 + tempindex); + tempcelsius = bus_read_1(sc->ioport_res, 1); + + /* + * The offset registers are: 0x56, 0x57, 0x59. + * (Register 0x58 is the vendor id for the chip.) + */ + bus_write_1(sc->ioport_res, 0, 0x56 + (tempindex < 2 ? tempindex : 3)); + tempoffset = bus_read_1(sc->ioport_res, 1); + + tempkelvin = tempcelsius - tempoffset + 273; + + mtx_unlock(&sc->lock); + } + + return sysctl_handle_int(oidp, &tempkelvin, 0, req); +} + +static int it8613hwm_get_fan_sysctl(SYSCTL_HANDLER_ARGS) +{ + device_t dev = (device_t) arg1; + struct it8613hwm_softc* sc = device_get_softc(dev); + int fanindex = arg2; + unsigned int fanspeedrpm = 0; + + if (fanindex >= 0 && fanindex < 3) + { + mtx_lock(&sc->lock); + + /* High bits of fan tachometer. */ + bus_write_1(sc->ioport_res, 0, 0x18 + fanindex); + fanspeedrpm = bus_read_1(sc->ioport_res, 1) << 8; + /* Low bits of fan tachometer. */ + bus_write_1(sc->ioport_res, 0, 0x0D + fanindex); + fanspeedrpm |= bus_read_1(sc->ioport_res, 1); + + /* + * The fan tacho has a 22.5 kHz clock and produces 2 pulses per + * revolution. + */ + if (fanspeedrpm > 0) + fanspeedrpm = (22500 * 60) / (fanspeedrpm * 2); + + mtx_unlock(&sc->lock); + } + + return sysctl_handle_int(oidp, &fanspeedrpm, 0, req); +} + +static int it8613hwm_probe(device_t dev) +{ + if (superio_vendor(dev) != SUPERIO_VENDOR_ITE) + return (ENXIO); + if (superio_get_type(dev) != SUPERIO_DEV_HWM) + return (ENXIO); + if (superio_devid(dev) != 0x8613) + return (ENXIO); + + device_set_desc(dev, "Hardware monitor on ITE SuperIO"); + return (BUS_PROBE_DEFAULT); +} + +static int it8613hwm_attach(device_t dev) +{ + struct it8613hwm_softc* sc = device_get_softc(dev); + struct sysctl_ctx_list* ctx; + int error; + uint16_t iobase; + uint8_t chipid; + + /* + * The hardware monitor sits at offset 5 in the chip's io address space. + * We'll claim two ports: first (iobase + 5 + 0) is the chip's register + * selector; the second (iobase + 5 + 1) is the data register. + */ + iobase = superio_get_iobase(dev); + error = bus_set_resource(dev, SYS_RES_IOPORT, sc->ioport_rid, + iobase + 5, 2); + if (error != 0) + { + device_printf(dev, "bus_set_resource failed\n"); + return (ENXIO); + } + sc->ioport_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, + &sc->ioport_rid, RF_ACTIVE); + if (sc->ioport_res == NULL) + { + device_printf(dev, "bus_alloc_resource_any failed\n"); + return (ENXIO); + } + + /* Check hardware monitor vendor id. This should be 0x90 for the it8613. */ + bus_write_1(sc->ioport_res, 0, 0x58); + chipid = bus_read_1(sc->ioport_res, 1); + if (chipid != 0x90) + { + device_printf(dev, "unexpected chip id: actual %i != expected %i\n", + chipid, 0x90); + bus_release_resource(dev, SYS_RES_IOPORT, sc->ioport_rid, + sc->ioport_res); + return (ENXIO); + } + + mtx_init(&sc->lock, device_get_nameunit(dev), "it8613hwm", MTX_DEF); + + ctx = device_get_sysctl_ctx(dev); + /* Gets us "dev.it8613hwm.0.temperature0" etc */ + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "temperature0", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, it8613hwm_get_temp_sysctl, "IK0", "Temperature sensor 0"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "temperature1", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 1, it8613hwm_get_temp_sysctl, "IK0", "Temperature sensor 1"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "temperature2", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 2, it8613hwm_get_temp_sysctl, "IK0", "Temperature sensor 2"); + + /* Gets us "dev.it8613hwm.0.fan0" etc */ + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "fan0", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, it8613hwm_get_fan_sysctl, "I", "RPM of fan 0"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "fan1", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 1, it8613hwm_get_fan_sysctl, "I", "RPM of fan 1"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "fan2", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 2, it8613hwm_get_fan_sysctl, "I", "RPM of fan 2"); + + return (0); +} + +static int it8613hwm_detach(device_t dev) +{ + struct it8613hwm_softc* sc = device_get_softc(dev); + + bus_release_resource(dev, SYS_RES_IOPORT, sc->ioport_rid, + sc->ioport_res); + mtx_destroy(&sc->lock); + + return (0); +} + +static device_method_t it8613hwm_methods[] = { + /* Methods from the device interface */ + DEVMETHOD(device_probe, it8613hwm_probe), + DEVMETHOD(device_attach, it8613hwm_attach), + DEVMETHOD(device_detach, it8613hwm_detach), + + /* Terminate method list */ + { 0, 0 } +}; + +static driver_t it8613hwm_driver = { + "it8613hwm", + it8613hwm_methods, + sizeof(struct it8613hwm_softc) +}; + +static devclass_t it8613hwm_devclass; + +DRIVER_MODULE(it8613hwm, superio, it8613hwm_driver, it8613hwm_devclass, NULL, + NULL); +MODULE_DEPEND(it8613hwm, superio, 1, 1, 1); +MODULE_VERSION(it8613hwm, 1); diff --git a/sys/dev/superio/superio.c b/sys/dev/superio/superio.c --- a/sys/dev/superio/superio.c +++ b/sys/dev/superio/superio.c @@ -293,6 +293,10 @@ const char *descr; const struct sio_device *devices; } superio_table[] = { + { + .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8613, + .devices = ite_devices, + }, { .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8712, .devices = ite_devices, @@ -549,8 +553,9 @@ sc->revid = revid; KASSERT(sc->vendor == SUPERIO_VENDOR_ITE || - sc->vendor == SUPERIO_VENDOR_NUVOTON, - ("Only ITE and Nuvoton SuperIO-s are supported")); + sc->vendor == SUPERIO_VENDOR_NUVOTON || + sc->vendor == SUPERIO_VENDOR_FINTEK, + ("Only ITE, Nuvoton or Fintek SuperIO-s are supported")); sc->ldn_reg = 0x07; sc->enable_reg = 0x30; sc->current_ldn = 0xff; /* no device should have this */ diff --git a/sys/modules/Makefile b/sys/modules/Makefile --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -192,6 +192,7 @@ ${_iser} \ isp \ ${_ispfw} \ + ${_it8613hwm} \ ${_itwd} \ ${_iwi} \ ${_iwifw} \ @@ -685,6 +686,7 @@ _if_ndis= if_ndis _igc= igc _io= io +_it8613hwm= it8613hwm _itwd= itwd _ix= ix _ixv= ixv diff --git a/sys/modules/it8613hwm/Makefile b/sys/modules/it8613hwm/Makefile new file mode 100644 --- /dev/null +++ b/sys/modules/it8613hwm/Makefile @@ -0,0 +1,7 @@ +.PATH: ${SRCTOP}/sys/dev/it8613hwm + +KMOD= it8613hwm +SRCS= it8613hwm.c +SRCS+= device_if.h bus_if.h isa_if.h + +.include