FreeBSD Bugzilla – Attachment 255458 Details for
Bug 282738
Add support for Nuvoton NCT6122D/NCT6126D.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch implementing described changes.
NCT6126D.patch (text/plain), 43.22 KB, created by
Matthew.Nygard.Dodd
on 2024-11-25 23:06:56 UTC
(
hide
)
Description:
Patch implementing described changes.
Filename:
MIME Type:
Creator:
Matthew.Nygard.Dodd
Created:
2024-11-25 23:06:56 UTC
Size:
43.22 KB
patch
obsolete
>diff --git a/sys/dev/nctgpio/nctgpio.c b/sys/dev/nctgpio/nctgpio.c >index 75ea1fbdba17..37655fe13c89 100644 >--- a/sys/dev/nctgpio/nctgpio.c >+++ b/sys/dev/nctgpio/nctgpio.c >@@ -1,245 +1,248 @@ > /*- > * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.com> > * All rights reserved. > * > * 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. > * > */ > > /* > * Nuvoton GPIO driver. > */ > > #include <sys/cdefs.h> > > #include <sys/param.h> > #include <sys/kernel.h> > #include <sys/systm.h> > #include <sys/bus.h> > #include <sys/eventhandler.h> > #include <sys/lock.h> > > #include <sys/module.h> > #include <sys/gpio.h> > > #include <machine/bus.h> > > #include <dev/gpio/gpiobusvar.h> > #include <dev/superio/superio.h> > > #include "gpio_if.h" > > #define NCT_PPOD_LDN 0xf /* LDN used to select Push-Pull/Open-Drain */ > > /* Direct access through GPIO register table */ > #define NCT_IO_GSR 0 /* Group Select */ > #define NCT_IO_IOR 1 /* I/O */ > #define NCT_IO_DAT 2 /* Data */ > #define NCT_IO_INV 3 /* Inversion */ > #define NCT_IO_DST 4 /* Status */ > > #define NCT_MAX_GROUP 9 > #define NCT_MAX_PIN 75 > > #define NCT_PIN_IS_VALID(_sc, _p) ((_p) < (_sc)->npins) > #define NCT_PIN_GROUP(_sc, _p) ((_sc)->pinmap[(_p)].group) > #define NCT_PIN_GRPNUM(_sc, _p) ((_sc)->pinmap[(_p)].grpnum) > #define NCT_PIN_BIT(_sc, _p) ((_sc)->pinmap[(_p)].bit) > #define NCT_PIN_BITMASK(_p) (1 << ((_p) & 7)) > > #define NCT_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ > GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \ > GPIO_PIN_INVIN | GPIO_PIN_INVOUT) > > #define NCT_PREFER_INDIRECT_CHANNEL 2 >+#define NCT_NO_ENABLE 4 > > #define NCT_VERBOSE_PRINTF(dev, ...) \ > do { \ > if (__predict_false(bootverbose)) \ > device_printf(dev, __VA_ARGS__); \ > } while (0) > > /* > * Note that the values are important. > * They match actual register offsets. > */ > typedef enum { > REG_IOR = 0, > REG_DAT = 1, > REG_INV = 2, > } reg_t; > > struct nct_gpio_group { > uint32_t caps; > uint8_t enable_ldn; > uint8_t enable_reg; > uint8_t enable_mask; > uint8_t data_ldn; > uint8_t iobase; > uint8_t ppod_reg; /* Push-Pull/Open-Drain */ > uint8_t grpnum; > uint8_t pinbits[8]; > uint8_t npins; > }; > > struct nct_softc { > device_t dev; > device_t busdev; > struct mtx mtx; > struct resource *iores; > int iorid; > int curgrp; > struct { > uint8_t ior[NCT_MAX_GROUP + 1]; /* direction, 1: input 0: output */ > uint8_t out[NCT_MAX_GROUP + 1]; /* output value */ > uint8_t out_known[NCT_MAX_GROUP + 1]; /* whether out is valid */ > uint8_t inv[NCT_MAX_GROUP + 1]; /* inversion, 1: inverted */ > } cache; > struct gpio_pin pins[NCT_MAX_PIN + 1]; > struct nct_device *nctdevp; > int npins; /* Total number of pins */ > > /* Lookup tables */ > struct { > struct nct_gpio_group *group; > uint8_t grpnum; > uint8_t bit; > } pinmap[NCT_MAX_PIN+1]; > struct nct_gpio_group *grpmap[NCT_MAX_GROUP+1]; > }; > > #define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \ > device_get_nameunit(dev), NULL, MTX_DEF) > #define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx) > #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx) > #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) > #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED) > #define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED) > > #define GET_BIT(v, b) (((v) >> (b)) & 1) > > /* > * For most devices there are several GPIO devices, we attach only to one of > * them and use the rest without attaching. > */ > struct nct_device { > uint16_t devid; >+ uint16_t mask; > int extid; >+ uint8_t ldn; > const char *descr; > int ngroups; > struct nct_gpio_group groups[NCT_MAX_GROUP + 1]; > } nct_devices[] = { > { > .devid = 0xa025, > .descr = "GPIO on Winbond 83627DHG IC ver. 5", > .ngroups = 5, > .groups = { > { > .grpnum = 2, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x09, > .enable_reg = 0x30, > .enable_mask = 0x01, > .data_ldn = 0x09, > .ppod_reg = 0xe0, /* FIXME Need to check for this group. */ > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xe3, > }, > { > .grpnum = 3, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x09, > .enable_reg = 0x30, > .enable_mask = 0x02, > .data_ldn = 0x09, > .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xf0, > }, > { > .grpnum = 4, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x09, > .enable_reg = 0x30, > .enable_mask = 0x04, > .data_ldn = 0x09, > .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xf4, > }, > { > .grpnum = 5, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x09, > .enable_reg = 0x30, > .enable_mask = 0x08, > .data_ldn = 0x09, > .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xe0, > }, > { > .grpnum = 6, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x01, > .data_ldn = 0x07, > .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xf4, > }, > }, > }, > { > .devid = 0x1061, > .descr = "GPIO on Nuvoton NCT5104D", > .ngroups = 2, > .groups = { > { > .grpnum = 0, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x01, > .data_ldn = 0x07, > .ppod_reg = 0xe0, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xe0, > }, > { > .grpnum = 1, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x02, > .data_ldn = 0x07, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xe4, >@@ -651,198 +654,362 @@ struct nct_device { > }, > { > .grpnum = 1, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x02, > .data_ldn = 0x07, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xe4, > }, > { > .grpnum = 2, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x04, > .data_ldn = 0x07, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xe8, > }, > { > .grpnum = 3, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x08, > .data_ldn = 0x07, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xec, > }, > { > .grpnum = 4, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x10, > .data_ldn = 0x07, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xf0, > }, > { > .grpnum = 5, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x20, > .data_ldn = 0x07, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xf4, > }, > { > .grpnum = 6, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x40, > .data_ldn = 0x07, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xf8, > }, > { > .grpnum = 7, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x07, > .enable_reg = 0x30, > .enable_mask = 0x80, > .data_ldn = 0x07, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xfc, > }, > { > .grpnum = 8, > .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, > .enable_ldn = 0x09, > .enable_reg = 0x30, > .enable_mask = 0x01, > .data_ldn = 0x09, > .ppod_reg = 0xe1, > .caps = NCT_GPIO_CAPS, > .npins = 8, > .iobase = 0xf0, > }, > }, > }, >+ { >+ .devid = 0xd284, >+ .mask = 0xffdf, >+ .ldn = 7, >+ .descr = "GPIO on Nuvoton NCT6122D/NCT6126D", >+ .ngroups = 8, >+ .groups = { >+ // LDN7, GPIO0-7 >+ { >+ .grpnum = 0, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x07, >+ .enable_reg = 0x30, >+ .enable_mask = 0x01, >+ .data_ldn = 0x07, >+ .ppod_reg = 0xe0, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xe0, >+ }, >+ { >+ .grpnum = 1, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x07, >+ .enable_reg = 0x30, >+ .enable_mask = 0x02, >+ .data_ldn = 0x07, >+ .ppod_reg = 0xe1, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xe4, >+ }, >+ { >+ .grpnum = 2, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x07, >+ .enable_reg = 0x30, >+ .enable_mask = 0x04, >+ .data_ldn = 0x07, >+ .ppod_reg = 0xe2, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xe8, >+ }, >+ { >+ .grpnum = 3, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x07, >+ .enable_reg = 0x30, >+ .enable_mask = 0x08, >+ .data_ldn = 0x07, >+ .ppod_reg = 0xe3, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xec, >+ }, >+ { >+ .grpnum = 4, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x07, >+ .enable_reg = 0x30, >+ .enable_mask = 0x10, >+ .data_ldn = 0x07, >+ .ppod_reg = 0xe4, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xf0, >+ }, >+ { >+ .grpnum = 5, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x07, >+ .enable_reg = 0x30, >+ .enable_mask = 0x20, >+ .data_ldn = 0x07, >+ .ppod_reg = 0xe5, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xf4, >+ }, >+ { >+ .grpnum = 6, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x07, >+ .enable_reg = 0x30, >+ .enable_mask = 0x40, >+ .data_ldn = 0x07, >+ .ppod_reg = 0xe6, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xf8, >+ }, >+ { >+ .grpnum = 7, >+ .pinbits = { 0, 1 }, >+ .enable_ldn = 0x07, >+ .enable_reg = 0x30, >+ .enable_mask = 0x80, >+ .data_ldn = 0x07, >+ .ppod_reg = 0xe7, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 2, >+ .iobase = 0xfc, >+ }, >+ }, >+ }, >+ { >+ .devid = 0xd284, >+ .mask = 0xffdf, >+ .ldn = 9, >+ .descr = "GPIO on Nuvoton NCT6122D/NCT6126D", >+ .ngroups = 4, >+ .groups = { >+ // LDN9, GPIO8,GPIO9,GPIOA,GPIOB >+ { >+ .grpnum = 8, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x09, >+ .enable_reg = 0x30, >+ .enable_mask = 0x01, >+ .data_ldn = 0x09, >+ .ppod_reg = 0xe8, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xf0, >+ }, >+ { >+ .grpnum = 9, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x09, >+ .enable_reg = 0x30, >+ .enable_mask = 0x02, >+ .data_ldn = 0x09, >+ .ppod_reg = 0xe9, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xf4, >+ }, >+ { >+ .grpnum = 0xa, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x09, >+ .enable_reg = 0x30, >+ .enable_mask = 0x04, >+ .data_ldn = 0x09, >+ .ppod_reg = 0xea, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xf8, >+ }, >+ { >+ .grpnum = 0xb, >+ .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, >+ .enable_ldn = 0x09, >+ .enable_reg = 0x30, >+ .enable_mask = 0x08, >+ .data_ldn = 0x09, >+ .ppod_reg = 0xeb, >+ .caps = NCT_GPIO_CAPS, >+ .npins = 8, >+ .iobase = 0xfc, >+ }, >+ }, >+ }, > }; > > static const char * > io2str(uint8_t ioport) > { > switch (ioport) { > case NCT_IO_GSR: return ("grpsel"); > case NCT_IO_IOR: return ("io"); > case NCT_IO_DAT: return ("data"); > case NCT_IO_INV: return ("inv"); > case NCT_IO_DST: return ("status"); > default: return ("?"); > } > } > > static void > nct_io_set_group(struct nct_softc *sc, uint8_t grpnum) > { > GPIO_ASSERT_LOCKED(sc); > > if (grpnum == sc->curgrp) > return; > > NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n", > io2str(NCT_IO_GSR), grpnum, NCT_IO_GSR); > bus_write_1(sc->iores, NCT_IO_GSR, grpnum); > sc->curgrp = grpnum; > } > > static uint8_t > nct_io_read(struct nct_softc *sc, uint8_t grpnum, uint8_t reg) > { > uint8_t val; > > nct_io_set_group(sc, grpnum); > > val = bus_read_1(sc->iores, reg); > NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x ioport %d\n", > io2str(reg), val, reg); > return (val); > } > > static void > nct_io_write(struct nct_softc *sc, uint8_t grpnum, uint8_t reg, uint8_t val) > { > nct_io_set_group(sc, grpnum); > > NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n", > io2str(reg), val, reg); > bus_write_1(sc->iores, reg, val); > } > > static uint8_t > nct_get_ioreg(struct nct_softc *sc, reg_t reg, uint8_t grpnum) > { > uint8_t iobase; > > if (sc->iores != NULL) > iobase = NCT_IO_IOR; > else > iobase = sc->grpmap[grpnum]->iobase; > return (iobase + reg); > } > > static const char * > reg2str(reg_t reg) > { > switch (reg) { > case REG_IOR: return ("io"); > case REG_DAT: return ("data"); > case REG_INV: return ("inv"); > default: return ("?"); > } > } > > static uint8_t > nct_read_reg(struct nct_softc *sc, reg_t reg, uint8_t grpnum) > { > struct nct_gpio_group *gp; > uint8_t ioreg; > uint8_t val; > > ioreg = nct_get_ioreg(sc, reg, grpnum); > > if (sc->iores != NULL) > return (nct_io_read(sc, grpnum, ioreg)); > > gp = sc->grpmap[grpnum]; > val = superio_ldn_read(sc->dev, gp->data_ldn, ioreg); > NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x from group GPIO%u ioreg 0x%x\n", > reg2str(reg), val, grpnum, ioreg); > return (val); > } > > static int > nct_get_pin_cache(struct nct_softc *sc, uint32_t pin_num, uint8_t *cache) > { > uint8_t bit; > uint8_t group; >@@ -993,310 +1160,339 @@ nct_get_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num) > else > NCT_VERBOSE_PRINTF(sc->dev, > "read %d from output pin %u<GPIO%u%u>, cache miss\n", > b, pin_num, group, bit); > } > > return (b); > } > > /* > * NB: state of an input pin cannot be cached, of course. > * For an output we can either take the value from the cache if it's valid > * or read the state from the hadrware and cache it. > */ > static bool > nct_read_pin(struct nct_softc *sc, uint32_t pin_num) > { > uint8_t bit; > uint8_t group; > bool val; > > if (nct_pin_is_input(sc, pin_num)) { > return (nct_get_pin_reg(sc, REG_DAT, pin_num)); > } > > group = NCT_PIN_GRPNUM(sc, pin_num); > bit = NCT_PIN_BIT(sc, pin_num); > > if (GET_BIT(sc->cache.out_known[group], bit)) { > val = GET_BIT(sc->cache.out[group], bit); > > NCT_VERBOSE_PRINTF(sc->dev, > "read %d from output pin %u<GPIO%u%u>, cache hit\n", > val, pin_num, group, bit); > > return (val); > } > > val = nct_get_pin_reg(sc, REG_DAT, pin_num); > sc->cache.out_known[group] |= 1 << bit; > if (val) > sc->cache.out[group] |= 1 << bit; > else > sc->cache.out[group] &= ~(1 << bit); > return (val); > } > > /* FIXME Incorret for NCT5585D and probably other chips. */ > static uint8_t > nct_ppod_reg(struct nct_softc *sc, uint32_t pin_num) > { > uint8_t group = NCT_PIN_GRPNUM(sc, pin_num); > > return (sc->grpmap[group]->ppod_reg); > } > > /* > * NB: PP/OD can be configured only via configuration registers. > * Also, the registers are in a different logical device. > * So, this is a special case. No caching too. > */ > static void > nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num) > { > uint8_t reg; > uint8_t outcfg; > > reg = nct_ppod_reg(sc, pin_num); > outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg); > outcfg |= NCT_PIN_BITMASK(pin_num); > superio_ldn_write(sc->dev, 0xf, reg, outcfg); > } > > static void > nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num) > { > uint8_t reg; > uint8_t outcfg; > > reg = nct_ppod_reg(sc, pin_num); > outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg); > outcfg &= ~NCT_PIN_BITMASK(pin_num); > superio_ldn_write(sc->dev, 0xf, reg, outcfg); > } > > static bool > nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num) > { > uint8_t reg; > uint8_t outcfg; > > reg = nct_ppod_reg(sc, pin_num); > outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg); > return (outcfg & NCT_PIN_BITMASK(pin_num)); > } > > static struct nct_device * > nct_lookup_device(device_t dev) > { >- struct nct_device *nctdevp; >+ struct nct_device *nd; > uint16_t devid; > int i, extid; >+ uint8_t ldn; > > devid = superio_devid(dev); > extid = superio_extid(dev); >- for (i = 0, nctdevp = nct_devices; i < nitems(nct_devices); i++, nctdevp++) { >- if (devid == nctdevp->devid && nctdevp->extid == extid) >- return (nctdevp); >+ ldn = superio_get_ldn(dev); >+ for (i = 0, nd = nct_devices; i < nitems(nct_devices); i++, nd++) { >+ if (nd->devid != (nd->mask ? (devid & nd->mask) : devid)) >+ continue; >+ if (nd->extid && (nd->extid != extid)) >+ continue; >+ if (nd->ldn && (nd->ldn != ldn)) >+ continue; >+ >+ return (nd); > } > return (NULL); > } > > static int > nct_probe(device_t dev) > { > struct nct_device *nctdevp; > uint8_t ldn; > > ldn = superio_get_ldn(dev); > > if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) { > NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn); > return (ENXIO); > } > if (superio_get_type(dev) != SUPERIO_DEV_GPIO) { > NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a GPIO device\n", ldn); > return (ENXIO); > } > > nctdevp = nct_lookup_device(dev); > if (nctdevp == NULL) { > NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn); > return (ENXIO); > } > device_set_desc(dev, nctdevp->descr); > return (BUS_PROBE_DEFAULT); > } > >+static void >+nct_enable_gpios (device_t dev, struct nct_softc *sc) >+{ >+ struct nct_gpio_group *gp; >+ uint8_t v; >+ int g; >+ >+ /* Enable GPIO groups */ >+ for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) { >+ NCT_VERBOSE_PRINTF(dev, >+ "GPIO%d: %d pins, enable with mask 0x%x via ldn 0x%x reg 0x%x\n", >+ gp->grpnum, gp->npins, gp->enable_mask, gp->enable_ldn, >+ gp->enable_reg); >+ v = superio_ldn_read(dev, gp->enable_ldn, gp->enable_reg); >+ v |= gp->enable_mask; >+ superio_ldn_write(dev, gp->enable_ldn, gp->enable_reg, v); >+ } >+ return; >+} >+ > static int > nct_attach(device_t dev) > { > struct nct_softc *sc; > struct nct_gpio_group *gp; > uint32_t pin_num; > uint8_t v; > int flags, i, g; > > sc = device_get_softc(dev); > sc->dev = dev; > sc->nctdevp = nct_lookup_device(dev); > > flags = 0; > (void)resource_int_value(device_get_name(dev), device_get_unit(dev), "flags", &flags); > > if ((flags & NCT_PREFER_INDIRECT_CHANNEL) == 0) { > uint16_t iobase; > device_t dev_8; > > /* > * As strange as it may seem, I/O port base is configured in the > * Logical Device 8 which is primarily used for WDT, but also plays > * a role in GPIO configuration. > */ > iobase = 0; > dev_8 = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_WDT, 8); > if (dev_8 != NULL) > iobase = superio_get_iobase(dev_8); > if (iobase != 0 && iobase != 0xffff) { > int err; > > NCT_VERBOSE_PRINTF(dev, "iobase %#x\n", iobase); > sc->curgrp = -1; > sc->iorid = 0; > err = bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid, > iobase, 7); /* FIXME NCT6796D-E have 8 registers according to table 18.3. */ > if (err == 0) { > sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, >- &sc->iorid, RF_ACTIVE); >+ &sc->iorid, RF_ACTIVE|RF_SHAREABLE); > if (sc->iores == NULL) { > device_printf(dev, "can't map i/o space, " > "iobase=%#x\n", iobase); > } > } else { > device_printf(dev, > "failed to set io port resource at %#x\n", iobase); > } > } > } > NCT_VERBOSE_PRINTF(dev, "iores %p %s channel\n", > sc->iores, (sc->iores ? "direct" : "indirect")); > >- /* Enable GPIO groups */ >- for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) { >- NCT_VERBOSE_PRINTF(dev, >- "GPIO%d: %d pins, enable with mask 0x%x via ldn 0x%x reg 0x%x\n", >- gp->grpnum, gp->npins, gp->enable_mask, gp->enable_ldn, >- gp->enable_reg); >- v = superio_ldn_read(dev, gp->enable_ldn, gp->enable_reg); >- v |= gp->enable_mask; >- superio_ldn_write(dev, gp->enable_ldn, gp->enable_reg, v); >+ if (flags & NCT_NO_ENABLE) { >+ NCT_VERBOSE_PRINTF(dev, "skipping enable.\n"); >+ } else { >+ nct_enable_gpios(dev, sc); > } > > GPIO_LOCK_INIT(sc); > GPIO_LOCK(sc); > > pin_num = 0; > sc->npins = 0; > for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) { > > sc->grpmap[gp->grpnum] = gp; > >+ if (flags & NCT_NO_ENABLE) { >+ v = superio_ldn_read(dev, gp->enable_ldn, gp->enable_reg); >+ if ((v & gp->enable_mask) == 0) >+ continue; >+ } >+ > /* > * Caching input values is meaningless as an input can be changed at any > * time by an external agent. But outputs are controlled by this > * driver, so it can cache their state. Also, the hardware remembers > * the output state of a pin when the pin is switched to input mode and > * then back to output mode. So, the cache stays valid. > * The only problem is with pins that are in input mode at the attach > * time. For them the output state is not known until it is set by the > * driver for the first time. > * 'out' and 'out_known' bits form a tri-state output cache: > * |-----+-----------+---------| > * | out | out_known | cache | > * |-----+-----------+---------| > * | X | 0 | invalid | > * | 0 | 1 | 0 | > * | 1 | 1 | 1 | > * |-----+-----------+---------| > */ > sc->cache.inv[gp->grpnum] = nct_read_reg(sc, REG_INV, gp->grpnum); > sc->cache.ior[gp->grpnum] = nct_read_reg(sc, REG_IOR, gp->grpnum); > sc->cache.out[gp->grpnum] = nct_read_reg(sc, REG_DAT, gp->grpnum); > sc->cache.out_known[gp->grpnum] = ~sc->cache.ior[gp->grpnum]; > > sc->npins += gp->npins; > for (i = 0; i < gp->npins; i++, pin_num++) { > struct gpio_pin *pin; > > sc->pinmap[pin_num].group = gp; > sc->pinmap[pin_num].grpnum = gp->grpnum; > sc->pinmap[pin_num].bit = gp->pinbits[i]; > > pin = &sc->pins[pin_num]; > pin->gp_pin = pin_num; > pin->gp_caps = gp->caps; > pin->gp_flags = 0; > > snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u%u", > gp->grpnum, gp->pinbits[i]); > > if (nct_pin_is_input(sc, pin_num)) > pin->gp_flags |= GPIO_PIN_INPUT; > else > pin->gp_flags |= GPIO_PIN_OUTPUT; > > if (nct_pin_is_opendrain(sc, pin_num)) > pin->gp_flags |= GPIO_PIN_OPENDRAIN; > else > pin->gp_flags |= GPIO_PIN_PUSHPULL; > > if (nct_pin_is_inverted(sc, pin_num)) > pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); > } > } > NCT_VERBOSE_PRINTF(dev, "%d pins available\n", sc->npins); > > GPIO_UNLOCK(sc); > > sc->busdev = gpiobus_attach_bus(dev); > if (sc->busdev == NULL) { > device_printf(dev, "failed to attach to gpiobus\n"); > GPIO_LOCK_DESTROY(sc); > return (ENXIO); > } > > return (0); > } > > static int > nct_detach(device_t dev) > { > struct nct_softc *sc; > > sc = device_get_softc(dev); > gpiobus_detach_bus(dev); > > if (sc->iores != NULL) > bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores); > GPIO_ASSERT_UNLOCKED(sc); > GPIO_LOCK_DESTROY(sc); > > return (0); > } > > static device_t > nct_gpio_get_bus(device_t dev) > { > struct nct_softc *sc; > > sc = device_get_softc(dev); > > return (sc->busdev); > } > > static int > nct_gpio_pin_max(device_t dev, int *maxpin) > { > struct nct_softc *sc; > > sc = device_get_softc(dev); >diff --git a/sys/dev/ncthwm/ncthwm.c b/sys/dev/ncthwm/ncthwm.c >index 45a9111c6bee..3989f81f7e0b 100644 >--- a/sys/dev/ncthwm/ncthwm.c >+++ b/sys/dev/ncthwm/ncthwm.c >@@ -1,213 +1,230 @@ > /*- > * SPDX-License-Identifier: BSD-2-Clause > * > * Copyright (c) 2016-2022 Stormshield > * > * 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 <sys/cdefs.h> > #include <sys/param.h> > #include <sys/systm.h> > #include <sys/bus.h> > #include <sys/kernel.h> > #include <sys/module.h> > #include <sys/rman.h> > #include <sys/sysctl.h> > #include <sys/watchdog.h> > > #include <dev/superio/superio.h> > > #include <machine/bus.h> > #include <machine/resource.h> > > #define NCTHWM_FAN_MAX 5 > > #define NCTHWM_BANK_SELECT 0x4e > #define NCTHWM_VENDOR_ID 0x4f > > #define NCTHWM_VERBOSE_PRINTF(dev, ...) \ > do { \ > if (__predict_false(bootverbose)) \ > device_printf(dev, __VA_ARGS__); \ > } while (0) > > struct ncthwm_softc { > device_t dev; > struct ncthwm_device *nctdevp; > struct resource *iores; > int iorid; > }; > > struct ncthwm_fan_info > { > const char *name; > uint8_t low_byte_offset; > uint8_t high_byte_offset; > }; > > struct ncthwm_device { > uint16_t devid; >+ uint16_t mask; > const char *descr; > uint8_t base_offset; > uint8_t fan_bank; > uint8_t fan_count; > struct ncthwm_fan_info fan_info[NCTHWM_FAN_MAX]; > } ncthwm_devices[] = { > { > .devid = 0xc562, > .descr = "HWM on Nuvoton NCT6779D", > .base_offset = 5, > .fan_bank = 4, > .fan_count = 5, > .fan_info = { > { .name = "SYSFAN", .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 }, > { .name = "CPUFAN", .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 }, > { .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 }, > { .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 }, > { .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 }, > }, > }, { > .devid = 0xd42a, > .descr = "HWM on Nuvoton NCT6796D-E", > .base_offset = 5, > .fan_bank = 4, > .fan_count = 5, > .fan_info = { > { .name = "SYSFAN", .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 }, > { .name = "CPUFAN", .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 }, > { .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 }, > { .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 }, > { .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 }, > }, >+ }, { >+ .devid = 0xd284, >+ .mask = 0xffdf, >+ .descr = "HWM on Nuvoton NCT6122D/NCT6126D", >+ .base_offset = 5, >+ .fan_bank = 0, >+ .fan_count = 5, >+ .fan_info = { >+ { .name = "SYSFAN", .low_byte_offset = 0x31, .high_byte_offset = 0x30 }, >+ { .name = "CPUFAN", .low_byte_offset = 0x33, .high_byte_offset = 0x32 }, >+ { .name = "AUXFAN0", .low_byte_offset = 0x35, .high_byte_offset = 0x34 }, >+ { .name = "AUXFAN1", .low_byte_offset = 0x37, .high_byte_offset = 0x36 }, >+ { .name = "AUXFAN2", .low_byte_offset = 0x39, .high_byte_offset = 0x38 }, >+ }, > } > }; > > static struct ncthwm_device * > ncthwm_lookup_device(device_t dev) > { >- int i; >+ struct ncthwm_device *d = ncthwm_devices; > uint16_t devid; > > devid = superio_devid(dev); >- for (i = 0; i < nitems(ncthwm_devices); i++) { >- if (devid == ncthwm_devices[i].devid) >- return (ncthwm_devices + i); >+ for (int i = 0; i < nitems(ncthwm_devices); i++, d++) { >+ if (d->devid != (d->mask ? (devid & d->mask) : devid)) >+ continue; >+ >+ return (d); > } > return (NULL); > } > > static void > ncthwm_write(struct ncthwm_softc *sc, uint8_t reg, uint8_t val) > { > bus_write_1(sc->iores, 0, reg); > bus_write_1(sc->iores, 1, val); > } > > static uint8_t > ncthwm_read(struct ncthwm_softc *sc, uint8_t reg) > { > bus_write_1(sc->iores, 0, reg); > return (bus_read_1(sc->iores, 1)); > } > > static int > ncthwm_query_fan_speed(SYSCTL_HANDLER_ARGS) > { > struct ncthwm_softc *sc; > struct ncthwm_fan_info *fan; > uint16_t val; > > sc = arg1; > if (sc == NULL) > return (EINVAL); > > KASSERT(sc->nctdevp != NULL, ("Unreachable")); > > if (sc->nctdevp->fan_count <= arg2) > return (EINVAL); > fan = &sc->nctdevp->fan_info[arg2]; > > KASSERT(sc->iores != NULL, ("Unreachable")); > > ncthwm_write(sc, NCTHWM_BANK_SELECT, sc->nctdevp->fan_bank); > val = ncthwm_read(sc, fan->high_byte_offset) << 8; > val |= ncthwm_read(sc, fan->low_byte_offset); > > NCTHWM_VERBOSE_PRINTF(sc->dev, "%s: read %u from bank %u offset 0x%x-0x%x\n", > fan->name, val, sc->nctdevp->fan_bank, fan->high_byte_offset, fan->low_byte_offset); > > return (sysctl_handle_16(oidp, &val, 0, req)); > } > > static int > ncthwm_probe(device_t dev) > { > struct ncthwm_device *nctdevp; > uint8_t ldn; > > ldn = superio_get_ldn(dev); > > if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) { > NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn); > return (ENXIO); > } > if (superio_get_type(dev) != SUPERIO_DEV_HWM) { > NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a HWM device\n", ldn); > return (ENXIO); > } > > nctdevp = ncthwm_lookup_device(dev); > if (nctdevp == NULL) { > NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn); > return (ENXIO); > } > device_set_desc(dev, nctdevp->descr); > return (BUS_PROBE_DEFAULT); > } > > static int > ncthwm_attach(device_t dev) > { > struct ncthwm_softc *sc; > int i; > uint16_t iobase; > > sc = device_get_softc(dev); > sc->dev = dev; > > sc->nctdevp = ncthwm_lookup_device(dev); > if (sc->nctdevp == NULL) { > device_printf(dev, "device not supported\n"); > return (ENXIO); > } > > iobase = superio_get_iobase(dev) + sc->nctdevp->base_offset; > sc->iorid = 0; > if (bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid, iobase, 2) != 0) { > device_printf(dev, "failed to set I/O port resource at 0x%x\n", iobase); > return (ENXIO); > } > sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, > &sc->iorid, RF_ACTIVE); > if (sc->iores == NULL) { > device_printf(dev, "can't map I/O space at 0x%x\n", iobase); >diff --git a/sys/dev/superio/superio.c b/sys/dev/superio/superio.c >index 6333cb06a7c1..374f5f7c68bc 100644 >--- a/sys/dev/superio/superio.c >+++ b/sys/dev/superio/superio.c >@@ -200,375 +200,403 @@ ite_conf_enter(struct resource* res, uint16_t port) > bus_write_1(res, 0, port == 0x2e ? 0x55 : 0xaa); > } > > static void > ite_conf_exit(struct resource* res, uint16_t port) > { > sio_write(res, 0x02, 0x02); > } > > static const struct sio_conf_methods ite_conf_methods = { > .enter = ite_conf_enter, > .exit = ite_conf_exit, > .vendor = SUPERIO_VENDOR_ITE > }; > > static void > nvt_conf_enter(struct resource* res, uint16_t port) > { > bus_write_1(res, 0, 0x87); > bus_write_1(res, 0, 0x87); > } > > static void > nvt_conf_exit(struct resource* res, uint16_t port) > { > bus_write_1(res, 0, 0xaa); > } > > static const struct sio_conf_methods nvt_conf_methods = { > .enter = nvt_conf_enter, > .exit = nvt_conf_exit, > .vendor = SUPERIO_VENDOR_NUVOTON > }; > > static void > fintek_conf_enter(struct resource* res, uint16_t port) > { > bus_write_1(res, 0, 0x87); > bus_write_1(res, 0, 0x87); > } > > static void > fintek_conf_exit(struct resource* res, uint16_t port) > { > bus_write_1(res, 0, 0xaa); > } > > static const struct sio_conf_methods fintek_conf_methods = { > .enter = fintek_conf_enter, > .exit = fintek_conf_exit, > .vendor = SUPERIO_VENDOR_FINTEK > }; > > static const struct sio_conf_methods * const methods_table[] = { > &ite_conf_methods, > &nvt_conf_methods, > &fintek_conf_methods, > NULL > }; > > static const uint16_t ports_table[] = { > 0x2e, 0x4e, 0 > }; > > const struct sio_device ite_devices[] = { > { .ldn = 4, .type = SUPERIO_DEV_HWM }, > { .ldn = 7, .type = SUPERIO_DEV_WDT }, > { .type = SUPERIO_DEV_NONE }, > }; > > const struct sio_device w83627_devices[] = { > { .ldn = 8, .type = SUPERIO_DEV_WDT }, > { .ldn = 9, .type = SUPERIO_DEV_GPIO }, > { .type = SUPERIO_DEV_NONE }, > }; > > const struct sio_device nvt_devices[] = { > { .ldn = 8, .type = SUPERIO_DEV_WDT }, > { .type = SUPERIO_DEV_NONE }, > }; > > const struct sio_device nct5104_devices[] = { > { .ldn = 7, .type = SUPERIO_DEV_GPIO }, > { .ldn = 8, .type = SUPERIO_DEV_WDT }, > { .ldn = 15, .type = SUPERIO_DEV_GPIO }, > { .type = SUPERIO_DEV_NONE }, > }; > > const struct sio_device nct5585_devices[] = { > { .ldn = 9, .type = SUPERIO_DEV_GPIO }, > { .type = SUPERIO_DEV_NONE }, > }; > > const struct sio_device nct611x_devices[] = { > { .ldn = 0x7, .type = SUPERIO_DEV_GPIO }, > { .ldn = 0x8, .type = SUPERIO_DEV_WDT }, > { .type = SUPERIO_DEV_NONE }, > }; > >+const struct sio_device nct612x_devices[] = { >+ { .ldn = 0x7, .type = SUPERIO_DEV_GPIO }, >+ { .ldn = 0x8, .type = SUPERIO_DEV_WDT }, >+ { .ldn = 0x9, .type = SUPERIO_DEV_GPIO }, >+ { .ldn = 0xb, .type = SUPERIO_DEV_HWM }, >+ { .type = SUPERIO_DEV_NONE }, >+}; >+ > const struct sio_device nct67xx_devices[] = { > { .ldn = 0x8, .type = SUPERIO_DEV_WDT }, > { .ldn = 0x9, .type = SUPERIO_DEV_GPIO }, > { .ldn = 0xb, .type = SUPERIO_DEV_HWM }, > { .type = SUPERIO_DEV_NONE }, > }; > > const struct sio_device fintek_devices[] = { > { .ldn = 6, .type = SUPERIO_DEV_GPIO }, > { .ldn = 7, .type = SUPERIO_DEV_WDT }, > { .type = SUPERIO_DEV_NONE }, > }; > > static const struct { > superio_vendor_t vendor; > uint16_t devid; > uint16_t mask; > int extid; /* Extra ID: used to handle conflicting devid. */ > 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, > }, > { > .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8716, > .devices = ite_devices, > }, > { > .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8718, > .devices = ite_devices, > }, > { > .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8720, > .devices = ite_devices, > }, > { > .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8721, > .devices = ite_devices, > }, > { > .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8726, > .devices = ite_devices, > }, > { > .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8728, > .devices = ite_devices, > }, > { > .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8771, > .devices = ite_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x1061, .mask = 0x00, > .descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. A)", > .devices = nct5104_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5200, .mask = 0xff, > .descr = "Winbond 83627HF/F/HG/G", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5900, .mask = 0xff, > .descr = "Winbond 83627S", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6000, .mask = 0xff, > .descr = "Winbond 83697HF", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6800, .mask = 0xff, > .descr = "Winbond 83697UG", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x7000, .mask = 0xff, > .descr = "Winbond 83637HF", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8200, .mask = 0xff, > .descr = "Winbond 83627THF", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8500, .mask = 0xff, > .descr = "Winbond 83687THF", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8800, .mask = 0xff, > .descr = "Winbond 83627EHF", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa000, .mask = 0xff, > .descr = "Winbond 83627DHG", > .devices = w83627_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa200, .mask = 0xff, > .descr = "Winbond 83627UHG", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa500, .mask = 0xff, > .descr = "Winbond 83667HG", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb000, .mask = 0xff, > .descr = "Winbond 83627DHG-P", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb300, .mask = 0xff, > .descr = "Winbond 83667HG-B", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb400, .mask = 0xff, > .descr = "Nuvoton NCT6775", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc300, .mask = 0xff, > .descr = "Nuvoton NCT6776", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc400, .mask = 0xff, > .descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. B+)", > .devices = nct5104_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc500, .mask = 0xff, > .descr = "Nuvoton NCT6779D", > .devices = nct67xx_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd42a, .extid = 1, > .descr = "Nuvoton NCT6796D-E", > .devices = nct67xx_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd42a, .extid = 2, > .descr = "Nuvoton NCT5585D", > .devices = nct5585_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc800, .mask = 0xff, > .descr = "Nuvoton NCT6791", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc900, .mask = 0xff, > .descr = "Nuvoton NCT6792", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd100, .mask = 0xff, > .descr = "Nuvoton NCT6793", > .devices = nvt_devices, > }, > { >- .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd200, .mask = 0xff, >- .descr = "Nuvoton NCT6112D/NCT6114D/NCT6116D", >+ .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd281, >+ .descr = "Nuvoton NCT6112D", // 2 UART > .devices = nct611x_devices, > }, >+ { >+ .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd282, >+ .descr = "Nuvoton NCT6114D", // 4 UART >+ .devices = nct611x_devices, >+ }, >+ { >+ .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd283, >+ .descr = "Nuvoton NCT6116D", // 6 UART >+ .devices = nct611x_devices, >+ }, >+ { >+ .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd2A4, >+ .descr = "Nuvoton NCT6122D", // 2 UART >+ .devices = nct612x_devices, >+ }, >+ { >+ .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd284, >+ .descr = "Nuvoton NCT6126D", // 6 UART >+ .devices = nct612x_devices, >+ }, > { > .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd300, .mask = 0xff, > .descr = "Nuvoton NCT6795", > .devices = nvt_devices, > }, > { > .vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x1210, .mask = 0xff, > .descr = "Fintek F81803", > .devices = fintek_devices, > }, > { > .vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x0704, > .descr = "Fintek F81865", > .devices = fintek_devices, > }, > { 0, 0 } > }; > > static const char * > devtype_to_str(superio_dev_type_t type) > { > switch (type) { > case SUPERIO_DEV_NONE: > return ("none"); > case SUPERIO_DEV_HWM: > return ("HWM"); > case SUPERIO_DEV_WDT: > return ("WDT"); > case SUPERIO_DEV_GPIO: > return ("GPIO"); > case SUPERIO_DEV_MAX: > return ("invalid"); > } > return ("invalid"); > } > > static int > superio_detect(device_t dev, bool claim, struct siosc *sc) > { > struct resource *res; > rman_res_t port; > rman_res_t count; > uint16_t devid; > uint8_t revid; > int error; > int rid; > int i, m; > int prefer; > > error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, &count); > if (error != 0) > return (error); > if (port > UINT16_MAX || count < NUMPORTS) { > device_printf(dev, "unexpected I/O range size\n"); > return (ENXIO); > } > > /* > * Make a temporary resource reservation for hardware probing. > * If we can't get the resources we need then > * we need to abort. Possibly this indicates > * the resources were used by another device > * in which case the probe would have failed anyhow. > */ > rid = 0; > res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); > if (res == NULL) { > if (claim) > device_printf(dev, "failed to allocate I/O resource\n"); > return (ENXIO); > } > > prefer = 0; > resource_int_value(device_get_name(dev), device_get_unit(dev), "prefer", &prefer); > if (bootverbose && prefer > 0) > device_printf(dev, "prefer extid %d\n", prefer); > > for (m = 0; methods_table[m] != NULL; m++) { > methods_table[m]->enter(res, port); > if (methods_table[m]->vendor == SUPERIO_VENDOR_ITE) { > devid = sio_readw(res, 0x20); > revid = sio_read(res, 0x22); > } else if (methods_table[m]->vendor == SUPERIO_VENDOR_NUVOTON) { > devid = sio_read(res, 0x20); > revid = sio_read(res, 0x21); > devid = (devid << 8) | revid; > } else if (methods_table[m]->vendor == SUPERIO_VENDOR_FINTEK) { > devid = sio_read(res, 0x20); > revid = sio_read(res, 0x21); > devid = (devid << 8) | revid; > } else { > continue; > } > methods_table[m]->exit(res, port); > for (i = 0; superio_table[i].vendor != 0; i++) { > uint16_t mask; > > mask = superio_table[i].mask; > if (superio_table[i].vendor !=
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 282738
:
255149
|
255458
|
255497