From 608e11c703c2a5a4f13ad5b1e4661e9be4c8dc0f Mon Sep 17 00:00:00 2001 From: jmcneill Date: Mon, 25 Jan 2021 12:18:18 +0000 Subject: [PATCH] Add support for ACPI-based I2C mux attachment. --- sys/dev/fdt/i2cmux_fdt.c | 26 +++---- sys/dev/i2c/i2c.c | 9 ++- sys/dev/i2c/i2cmux.c | 148 +++++++++++++++++++++++++++++++-------- sys/dev/i2c/i2cmuxvar.h | 8 ++- sys/dev/i2c/pcai2cmux.c | 71 ++++++++++++++----- 5 files changed, 195 insertions(+), 67 deletions(-) diff --git a/sys/dev/fdt/i2cmux_fdt.c b/sys/dev/fdt/i2cmux_fdt.c index 48d654bd7131..59a8d9242474 100644 --- a/sys/dev/fdt/i2cmux_fdt.c +++ b/sys/dev/fdt/i2cmux_fdt.c @@ -1,4 +1,4 @@ -/* $NetBSD: i2cmux_fdt.c,v 1.6 2021/01/18 02:35:49 thorpej Exp $ */ +/* $NetBSD: i2cmux_fdt.c,v 1.7 2021/01/25 12:18:18 jmcneill Exp $ */ /*- * Copyright (c) 2020 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: i2cmux_fdt.c,v 1.6 2021/01/18 02:35:49 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: i2cmux_fdt.c,v 1.7 2021/01/25 12:18:18 jmcneill Exp $"); #include #include @@ -63,7 +63,7 @@ iicmux_gpio_get_mux_info(struct iicmux_softc * const sc) mux_data = kmem_zalloc(sizeof(*mux_data), KM_SLEEP); - mux_data->npins = fdtbus_gpio_count(sc->sc_phandle, "mux-gpios"); + mux_data->npins = fdtbus_gpio_count(sc->sc_handle, "mux-gpios"); if (mux_data->npins == 0) { aprint_error_dev(sc->sc_dev, "unable to get mux-gpios property\n"); @@ -73,7 +73,7 @@ iicmux_gpio_get_mux_info(struct iicmux_softc * const sc) mux_data->pins = kmem_zalloc(sizeof(*mux_data->pins) * mux_data->npins, KM_SLEEP); for (i = 0; i < mux_data->npins; i++) { - mux_data->pins[i] = fdtbus_gpio_acquire_index(sc->sc_phandle, + mux_data->pins[i] = fdtbus_gpio_acquire_index(sc->sc_handle, "mux-gpios", i, GPIO_PIN_OUTPUT); if (mux_data->pins[i] == NULL) { aprint_error_dev(sc->sc_dev, @@ -83,7 +83,7 @@ iicmux_gpio_get_mux_info(struct iicmux_softc * const sc) } mux_data->has_idle_value = - of_getprop_uint32(sc->sc_phandle, "idle-state", + of_getprop_uint32(sc->sc_handle, "idle-state", &mux_data->idle_value) == 0; return mux_data; @@ -107,7 +107,7 @@ iicmux_gpio_get_bus_info(struct iicmux_bus * const bus) bus_info = kmem_zalloc(sizeof(*bus_info), KM_SLEEP); - error = fdtbus_get_reg(bus->phandle, 0, &bus_info->value, NULL); + error = fdtbus_get_reg(bus->handle, 0, &bus_info->value, NULL); if (error) { aprint_error_dev(sc->sc_dev, "unable to get reg property for bus %d\n", bus->busidx); @@ -177,7 +177,7 @@ iicmux_pinctrl_get_mux_info(struct iicmux_softc * const sc) mux_info = kmem_alloc(sizeof(*mux_info), KM_SLEEP); mux_info->has_idle_idx = - fdtbus_get_index(sc->sc_phandle, "pinctrl-names", "idle", + fdtbus_get_index(sc->sc_handle, "pinctrl-names", "idle", &mux_info->idle_idx) == 0; return mux_info; @@ -192,7 +192,7 @@ iicmux_pinctrl_get_bus_info(struct iicmux_bus * const bus) bus_info = kmem_alloc(sizeof(*bus_info), KM_SLEEP); - error = fdtbus_get_reg(bus->phandle, 0, &bus_info->idx, NULL); + error = fdtbus_get_reg(bus->handle, 0, &bus_info->idx, NULL); if (error) { aprint_error_dev(sc->sc_dev, "unable to get reg property for bus %d\n", bus->busidx); @@ -210,7 +210,7 @@ iicmux_pinctrl_acquire_bus(struct iicmux_bus * const bus, struct iicmux_softc * const sc = bus->mux; struct bus_info_pinctrl * const bus_info = bus->bus_data; - return fdtbus_pinctrl_set_config_index(sc->sc_phandle, bus_info->idx); + return fdtbus_pinctrl_set_config_index(sc->sc_handle, bus_info->idx); } static void @@ -221,7 +221,7 @@ iicmux_pinctrl_release_bus(struct iicmux_bus * const bus, struct mux_info_pinctrl * const mux_info = sc->sc_mux_data; if (mux_info->has_idle_idx) { - (void) fdtbus_pinctrl_set_config_index(sc->sc_phandle, + (void) fdtbus_pinctrl_set_config_index(sc->sc_handle, mux_info->idle_idx); } } @@ -261,13 +261,13 @@ iicmux_fdt_attach(device_t const parent, device_t const self, void * const aux) struct fdt_attach_args * const faa = aux; sc->sc_dev = self; - sc->sc_phandle = faa->faa_phandle; - sc->sc_config = of_search_compatible(sc->sc_phandle, compat_data)->data; + sc->sc_handle = faa->faa_phandle; + sc->sc_config = of_search_compatible(sc->sc_handle, compat_data)->data; aprint_naive("\n"); aprint_normal(": %s I2C mux\n", sc->sc_config->desc); - sc->sc_i2c_parent = fdtbus_i2c_acquire(sc->sc_phandle, "i2c-parent"); + sc->sc_i2c_parent = fdtbus_i2c_acquire(sc->sc_handle, "i2c-parent"); if (sc->sc_i2c_parent == NULL) { aprint_error_dev(sc->sc_dev, "unable to acquire i2c-parent\n"); return; diff --git a/sys/dev/i2c/i2c.c b/sys/dev/i2c/i2c.c index 079a95c338c5..956759d9a721 100644 --- a/sys/dev/i2c/i2c.c +++ b/sys/dev/i2c/i2c.c @@ -1,4 +1,4 @@ -/* $NetBSD: i2c.c,v 1.76 2021/01/18 15:28:21 thorpej Exp $ */ +/* $NetBSD: i2c.c,v 1.77 2021/01/25 12:18:18 jmcneill Exp $ */ /* * Copyright (c) 2003 Wasabi Systems, Inc. @@ -40,7 +40,7 @@ #endif #include -__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.76 2021/01/18 15:28:21 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.77 2021/01/25 12:18:18 jmcneill Exp $"); #include #include @@ -439,6 +439,7 @@ iic_attach(device_t parent, device_t self, void *aux) prop_data_t cdata; uint32_t addr; uint64_t cookie; + uint32_t cookietype; const char *name; struct i2c_attach_args ia; int loc[IICCF_NLOCS]; @@ -457,6 +458,9 @@ iic_attach(device_t parent, device_t self, void *aux) continue; if (!prop_dictionary_get_uint64(dev, "cookie", &cookie)) cookie = 0; + if (!prop_dictionary_get_uint32(dev, "cookietype", + &cookietype)) + cookietype = I2C_COOKIE_NONE; loc[IICCF_ADDR] = addr; memset(&ia, 0, sizeof ia); @@ -464,6 +468,7 @@ iic_attach(device_t parent, device_t self, void *aux) ia.ia_tag = ic; ia.ia_name = name; ia.ia_cookie = cookie; + ia.ia_cookietype = cookietype; ia.ia_prop = dev; buf = NULL; diff --git a/sys/dev/i2c/i2cmux.c b/sys/dev/i2c/i2cmux.c index 00fc88c5a637..bfb7fb7bdd96 100644 --- a/sys/dev/i2c/i2cmux.c +++ b/sys/dev/i2c/i2cmux.c @@ -1,4 +1,4 @@ -/* $NetBSD: i2cmux.c,v 1.2 2021/01/24 19:35:21 jmcneill Exp $ */ +/* $NetBSD: i2cmux.c,v 1.3 2021/01/25 12:18:18 jmcneill Exp $ */ /*- * Copyright (c) 2020 The NetBSD Foundation, Inc. @@ -29,8 +29,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__) +#include "acpica.h" +#endif + #include -__KERNEL_RCSID(0, "$NetBSD: i2cmux.c,v 1.2 2021/01/24 19:35:21 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: i2cmux.c,v 1.3 2021/01/25 12:18:18 jmcneill Exp $"); #include #include @@ -41,6 +45,11 @@ __KERNEL_RCSID(0, "$NetBSD: i2cmux.c,v 1.2 2021/01/24 19:35:21 jmcneill Exp $"); #include #include +#if NACPICA > 0 +#include +#include +#endif + /* * i2c mux * @@ -154,13 +163,14 @@ iicmux_print(void * const aux, const char * const pnp) static void iicmux_attach_bus(struct iicmux_softc * const sc, - int const phandle, int const busidx) + uintptr_t const handle, enum i2c_cookie_type handletype, int const busidx) { struct iicmux_bus * const bus = &sc->sc_busses[busidx]; bus->mux = sc; bus->busidx = busidx; - bus->phandle = phandle; + bus->handle = handle; + bus->handletype = handletype; bus->bus_data = sc->sc_config->get_bus_info(bus); if (bus->bus_data == NULL) { @@ -175,41 +185,41 @@ iicmux_attach_bus(struct iicmux_softc * const sc, bus->controller.ic_release_bus = iicmux_release_bus; bus->controller.ic_exec = iicmux_exec; - fdtbus_register_i2c_controller(&bus->controller, bus->phandle); + switch (handletype) { + case I2C_COOKIE_OF: + fdtbus_register_i2c_controller(&bus->controller, + (int)bus->handle); - fdtbus_attach_i2cbus(sc->sc_dev, bus->phandle, &bus->controller, - iicmux_print); + fdtbus_attach_i2cbus(sc->sc_dev, (int)bus->handle, + &bus->controller, iicmux_print); + break; +#if NACPICA > 0 + case I2C_COOKIE_ACPI: { + struct acpi_devnode *ad = acpi_match_node((ACPI_HANDLE)handle); + KASSERT(ad != NULL); + struct i2cbus_attach_args iba = { + .iba_tag = &bus->controller, + .iba_child_devices = acpi_enter_i2c_devs(ad) + }; + config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print); + } break; +#endif + default: + aprint_error_dev(sc->sc_dev, "unknown handle type\n"); + break; + } } -void -iicmux_attach(struct iicmux_softc * const sc) +static void +iicmux_attach_fdt(struct iicmux_softc * const sc) { - - /* - * We expect sc->sc_phandle, sc->sc_config, and sc->sc_i2c_parent - * to be initialized by the front-end. - */ - KASSERT(sc->sc_phandle > 0); - KASSERT(sc->sc_config != NULL); - KASSERT(sc->sc_i2c_parent != NULL); - /* * We start out assuming that the i2c bus nodes are children of * our own node. We'll adjust later if we encounter an "i2c-mux" * node when counting our children. If we encounter such a node, * then it's that node that is the parent of the i2c bus children. */ - sc->sc_i2c_mux_phandle = sc->sc_phandle; - - /* - * Gather up all of the various bits of information needed - * for this particular type of i2c mux. - */ - sc->sc_mux_data = sc->sc_config->get_mux_info(sc); - if (sc->sc_mux_data == NULL) { - aprint_error_dev(sc->sc_dev, "unable to get info for mux\n"); - return; - } + sc->sc_i2c_mux_phandle = (int)sc->sc_handle; sc->sc_nbusses = iicmux_count_children(sc); if (sc->sc_nbusses == 0) { @@ -223,6 +233,84 @@ iicmux_attach(struct iicmux_softc * const sc) for (child = OF_child(sc->sc_i2c_mux_phandle), idx = 0; child; child = OF_peer(child), idx++) { KASSERT(idx < sc->sc_nbusses); - iicmux_attach_bus(sc, child, idx); + iicmux_attach_bus(sc, child, I2C_COOKIE_OF, idx); + } +} + +#if NACPICA > 0 +static void +iicmux_attach_acpi(struct iicmux_softc * const sc) +{ + ACPI_HANDLE hdl = (ACPI_HANDLE)sc->sc_handle; + struct acpi_devnode *devnode, *ad; + int idx; + + devnode = acpi_match_node(hdl); + KASSERT(devnode != NULL); + + /* Count child busses */ + sc->sc_nbusses = 0; + SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) { + if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE || + !acpi_device_present(ad->ad_handle)) { + continue; + } + sc->sc_nbusses++; + } + + sc->sc_busses = kmem_zalloc(sizeof(*sc->sc_busses) * sc->sc_nbusses, + KM_SLEEP); + + /* Attach child busses */ + idx = 0; + SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) { + if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE || + !acpi_device_present(ad->ad_handle)) { + continue; + } + iicmux_attach_bus(sc, (uintptr_t)ad->ad_handle, + I2C_COOKIE_ACPI, idx); + idx++; + } +} +#endif + +void +iicmux_attach(struct iicmux_softc * const sc) +{ + /* + * We expect sc->sc_handle, sc->sc_config, and sc->sc_i2c_parent + * to be initialized by the front-end. + */ + KASSERT(sc->sc_handle > 0); + KASSERT(sc->sc_config != NULL); + KASSERT(sc->sc_i2c_parent != NULL); + + /* + * Gather up all of the various bits of information needed + * for this particular type of i2c mux. + */ + sc->sc_mux_data = sc->sc_config->get_mux_info(sc); + if (sc->sc_mux_data == NULL) { + aprint_error_dev(sc->sc_dev, "unable to get info for mux\n"); + return; + } + + /* + * Do configuration method (OF, ACPI) specific setup. + */ + switch (sc->sc_handletype) { + case I2C_COOKIE_OF: + iicmux_attach_fdt(sc); + break; +#if NACPICA > 0 + case I2C_COOKIE_ACPI: + iicmux_attach_acpi(sc); + break; +#endif + default: + aprint_error_dev(sc->sc_dev, "could not configure mux: " + "handle type %u not supported\n", sc->sc_handletype); + break; } } diff --git a/sys/dev/i2c/i2cmuxvar.h b/sys/dev/i2c/i2cmuxvar.h index 6f1e608028f8..b0cbc3032b5b 100644 --- a/sys/dev/i2c/i2cmuxvar.h +++ b/sys/dev/i2c/i2cmuxvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: i2cmuxvar.h,v 1.2 2021/01/24 19:35:45 jmcneill Exp $ */ +/* $NetBSD: i2cmuxvar.h,v 1.3 2021/01/25 12:18:18 jmcneill Exp $ */ /*- * Copyright (c) 2020 The NetBSD Foundation, Inc. @@ -48,14 +48,16 @@ struct iicmux_config { struct iicmux_bus { struct i2c_controller controller; struct iicmux_softc *mux; - int phandle; + uintptr_t handle; + enum i2c_cookie_type handletype; int busidx; void *bus_data; }; struct iicmux_softc { device_t sc_dev; - int sc_phandle; + enum i2c_cookie_type sc_handletype; + uintptr_t sc_handle; int sc_i2c_mux_phandle; const struct iicmux_config * sc_config; i2c_tag_t sc_i2c_parent; diff --git a/sys/dev/i2c/pcai2cmux.c b/sys/dev/i2c/pcai2cmux.c index ee94749f6a75..abe7253c7932 100644 --- a/sys/dev/i2c/pcai2cmux.c +++ b/sys/dev/i2c/pcai2cmux.c @@ -1,4 +1,4 @@ -/* $NetBSD: pcai2cmux.c,v 1.5 2021/01/24 19:38:49 jmcneill Exp $ */ +/* $NetBSD: pcai2cmux.c,v 1.6 2021/01/25 12:18:18 jmcneill Exp $ */ /*- * Copyright (c) 2020 The NetBSD Foundation, Inc. @@ -29,8 +29,12 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__) +#include "acpica.h" +#endif + #include -__KERNEL_RCSID(0, "$NetBSD: pcai2cmux.c,v 1.5 2021/01/24 19:38:49 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pcai2cmux.c,v 1.6 2021/01/25 12:18:18 jmcneill Exp $"); /* * Driver for NXP PCA954x / PCA984x I2C switches and multiplexers. @@ -59,6 +63,10 @@ __KERNEL_RCSID(0, "$NetBSD: pcai2cmux.c,v 1.5 2021/01/24 19:38:49 jmcneill Exp $ #include #include +#if NACPICA > 0 +#include +#endif + /* There are a maximum of 8 busses supported. */ #define PCAIICMUX_MAX_BUSSES 8 @@ -210,10 +218,32 @@ pcaiicmux_get_bus_info(struct iicmux_bus * const bus) struct pcaiicmux_bus_info * const bus_info = &sc->sc_bus_info[bus->busidx]; - error = fdtbus_get_reg(bus->phandle, 0, &addr, NULL); - if (error) { - aprint_error_dev(iicmux->sc_dev, - "unable to get reg property for bus %d\n", bus->busidx); + switch (bus->handletype) { + case I2C_COOKIE_OF: + error = fdtbus_get_reg(bus->handle, 0, &addr, NULL); + if (error) { + aprint_error_dev(iicmux->sc_dev, + "unable to get reg property for bus %d\n", + bus->busidx); + return NULL; + } + break; +#if NACPICA > 0 + case I2C_COOKIE_ACPI: { + ACPI_INTEGER val; + ACPI_STATUS rv; + rv = acpi_eval_integer((ACPI_HANDLE)bus->handle, "_ADR", &val); + if (ACPI_FAILURE(rv)) { + aprint_error_dev(iicmux->sc_dev, + "unable to evaluate _ADR for bus %d: %s\n", + bus->busidx, AcpiFormatException(rv)); + return NULL; + } + addr = (bus_addr_t)val; + } break; +#endif + default: + aprint_error_dev(iicmux->sc_dev, "unsupported handle type\n"); return NULL; } @@ -302,11 +332,11 @@ pcaiicmux_attach(device_t parent, device_t self, void *aux) { struct pcaiicmux_softc * const sc = device_private(self); struct i2c_attach_args * const ia = aux; - const int phandle = (int)ia->ia_cookie; int error; sc->sc_iicmux.sc_dev = self; - sc->sc_iicmux.sc_phandle = phandle; + sc->sc_iicmux.sc_handle = ia->ia_cookie; + sc->sc_iicmux.sc_handletype = ia->ia_cookietype; sc->sc_iicmux.sc_config = &pcaiicmux_config; sc->sc_iicmux.sc_i2c_parent = ia->ia_tag; sc->sc_addr = ia->ia_addr; @@ -318,18 +348,21 @@ pcaiicmux_attach(device_t parent, device_t self, void *aux) aprint_normal(": PCA954x I2C %s\n", sc->sc_type->enable_bit ? "mux" : "switch"); - if (of_hasprop(phandle, "i2c-mux-idle-disconnect")) { - sc->sc_idle_disconnect = true; - } + if (ia->ia_cookietype == I2C_COOKIE_OF) { + const int phandle = (int)ia->ia_cookie; + if (of_hasprop(phandle, "i2c-mux-idle-disconnect")) { + sc->sc_idle_disconnect = true; + } - /* Reset the mux if a reset GPIO is specified. */ - sc->sc_reset_gpio = - fdtbus_gpio_acquire(phandle, "reset-gpios", GPIO_PIN_OUTPUT); - if (sc->sc_reset_gpio) { - fdtbus_gpio_write(sc->sc_reset_gpio, 1); - delay(10); - fdtbus_gpio_write(sc->sc_reset_gpio, 0); - delay(10); + /* Reset the mux if a reset GPIO is specified. */ + sc->sc_reset_gpio = fdtbus_gpio_acquire(phandle, "reset-gpios", + GPIO_PIN_OUTPUT); + if (sc->sc_reset_gpio) { + fdtbus_gpio_write(sc->sc_reset_gpio, 1); + delay(10); + fdtbus_gpio_write(sc->sc_reset_gpio, 0); + delay(10); + } } /* Force the mux into a disconnected state. */