All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH v1 0/4] drivers: Add a framework for MUX drivers
@ 2019-10-02 12:47 Jean-Jacques Hiblot
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices Jean-Jacques Hiblot
                   ` (3 more replies)
  0 siblings, 4 replies; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-10-02 12:47 UTC (permalink / raw)
  To: u-boot


Add a new minimalistic subsystem that handles multiplexer controllers.
It provides the same API as Linux and mux drivers should be portable with
a minimum effort.
This series also includes a port of the Linux's mmio-mux driver.

This series relies on 2 other series [1] and [2] posted earlier.

[1] : https://patchwork.ozlabs.org/project/uboot/list/?series=132923
[2] : https://patchwork.ozlabs.org/project/uboot/list/?series=133713


Jean-Jacques Hiblot (4):
  drivers: Add a new framework for multiplexer devices
  dm: board: complete the initialization of the muxes in initr_dm()
  drivers: mux: mmio-based syscon mux controller
  test: Add tests for the multiplexer framework

 arch/sandbox/dts/test.dts     |  26 +++
 common/board_r.c              |   2 +
 configs/sandbox_defconfig     |   2 +
 drivers/Kconfig               |   2 +
 drivers/Makefile              |   1 +
 drivers/mux/Kconfig           |  22 +++
 drivers/mux/Makefile          |   7 +
 drivers/mux/mmio.c            | 155 ++++++++++++++++++
 drivers/mux/mux-uclass.c      | 296 ++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h        |   1 +
 include/dt-bindings/mux/mux.h |  17 ++
 include/mux-internal.h        |  80 +++++++++
 include/mux.h                 | 114 +++++++++++++
 test/dm/Makefile              |   1 +
 test/dm/mux-mmio.c            | 143 ++++++++++++++++
 15 files changed, 869 insertions(+)
 create mode 100644 drivers/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mmio.c
 create mode 100644 drivers/mux/mux-uclass.c
 create mode 100644 include/dt-bindings/mux/mux.h
 create mode 100644 include/mux-internal.h
 create mode 100644 include/mux.h
 create mode 100644 test/dm/mux-mmio.c

-- 
2.17.1

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices
  2019-10-02 12:47 [U-Boot] [PATCH v1 0/4] drivers: Add a framework for MUX drivers Jean-Jacques Hiblot
@ 2019-10-02 12:47 ` Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
  2019-11-05  1:37   ` Bin Meng
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 2/4] dm: board: complete the initialization of the muxes in initr_dm() Jean-Jacques Hiblot
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-10-02 12:47 UTC (permalink / raw)
  To: u-boot

Add a new subsystem that handles multiplexer controllers. The API is the
same as in Linux.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---

 drivers/Kconfig               |   2 +
 drivers/Makefile              |   1 +
 drivers/mux/Kconfig           |   7 +
 drivers/mux/Makefile          |   6 +
 drivers/mux/mux-uclass.c      | 296 ++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h        |   1 +
 include/dt-bindings/mux/mux.h |  17 ++
 include/mux-internal.h        |  80 +++++++++
 include/mux.h                 | 114 +++++++++++++
 9 files changed, 524 insertions(+)
 create mode 100644 drivers/mux/Kconfig
 create mode 100644 drivers/mux/Makefile
 create mode 100644 drivers/mux/mux-uclass.c
 create mode 100644 include/dt-bindings/mux/mux.h
 create mode 100644 include/mux-internal.h
 create mode 100644 include/mux.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 350acf81f3..5334974ad4 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -60,6 +60,8 @@ source "drivers/mmc/Kconfig"
 
 source "drivers/mtd/Kconfig"
 
+source "drivers/mux/Kconfig"
+
 source "drivers/net/Kconfig"
 
 source "drivers/nvme/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index a4bb5e4975..f4d71f3b3c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_TPL_)INPUT) += input/
 obj-$(CONFIG_$(SPL_TPL_)LED) += led/
 obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += mmc/
 obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += mtd/nand/raw/
+obj-$(CONFIG_$(SPl_)MULTIPLEXER) += mux/
 obj-$(CONFIG_$(SPL_TPL_)PCH_SUPPORT) += pch/
 obj-$(CONFIG_$(SPL_TPL_)PCI) += pci/
 obj-$(CONFIG_$(SPL_TPL_)PHY) += phy/
diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
new file mode 100644
index 0000000000..ad0199c058
--- /dev/null
+++ b/drivers/mux/Kconfig
@@ -0,0 +1,7 @@
+menu "Multiplexer drivers"
+
+config MULTIPLEXER
+	bool "Multiplexer Support"
+	depends on DM
+
+endmenu
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
new file mode 100644
index 0000000000..351e4363d3
--- /dev/null
+++ b/drivers/mux/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2019
+# Jean-Jacques Hiblot <jjhiblot@ti.com>
+
+obj-$(CONFIG_$(SPL_)MULTIPLEXER) += mux-uclass.o
diff --git a/drivers/mux/mux-uclass.c b/drivers/mux/mux-uclass.c
new file mode 100644
index 0000000000..58998af29c
--- /dev/null
+++ b/drivers/mux/mux-uclass.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Multiplexer subsystem
+ *
+ * Based on the linux multiplexer framework
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <mux-internal.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <errno.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/read.h>
+#include <dt-bindings/mux/mux.h>
+
+/*
+ * The idle-as-is "state" is not an actual state that may be selected, it
+ * only implies that the state should not be changed. So, use that state
+ * as indication that the cached state of the multiplexer is unknown.
+ */
+#define MUX_CACHE_UNKNOWN MUX_IDLE_AS_IS
+
+static inline const struct mux_control_ops *mux_dev_ops(struct udevice *dev)
+{
+	return (const struct mux_control_ops *)dev->driver->ops;
+}
+
+static int mux_control_set(struct mux_control *mux, int state)
+{
+	int ret = mux_dev_ops(mux->dev)->set(mux, state);
+
+	mux->cached_state = ret < 0 ? MUX_CACHE_UNKNOWN : state;
+
+	return ret;
+}
+
+unsigned int mux_control_states(struct mux_control *mux)
+{
+	return mux->states;
+}
+
+static int __mux_control_select(struct mux_control *mux, int state)
+{
+	int ret;
+
+	if (WARN_ON(state < 0 || state >= mux->states))
+		return -EINVAL;
+
+	if (mux->cached_state == state)
+		return 0;
+
+	ret = mux_control_set(mux, state);
+	if (ret >= 0)
+		return 0;
+
+	/* The mux update failed, try to revert if appropriate... */
+	if (mux->idle_state != MUX_IDLE_AS_IS)
+		mux_control_set(mux, mux->idle_state);
+
+	return ret;
+}
+
+int mux_control_select(struct mux_control *mux, unsigned int state)
+{
+	int ret;
+
+	if (mux->in_use)
+		return -EBUSY;
+
+	ret = __mux_control_select(mux, state);
+
+	if (ret < 0)
+		return ret;
+
+	mux->in_use = true;
+
+	return 0;
+}
+
+int mux_control_deselect(struct mux_control *mux)
+{
+	int ret = 0;
+
+	if (mux->idle_state != MUX_IDLE_AS_IS &&
+	    mux->idle_state != mux->cached_state)
+		ret = mux_control_set(mux, mux->idle_state);
+
+	mux->in_use = false;
+
+	return ret;
+}
+
+static int mux_of_xlate_default(struct mux_chip *mux_chip,
+				struct ofnode_phandle_args *args,
+				struct mux_control **muxp)
+{
+	struct mux_control *mux;
+	int id;
+
+	debug("%s(mux=%p)\n", __func__, mux);
+
+	if (args->args_count > 1) {
+		debug("Invaild args_count: %d\n", args->args_count);
+		return -EINVAL;
+	}
+
+	if (args->args_count)
+		id = args->args[0];
+	else
+		id = 0;
+
+	if (id >= mux_chip->controllers) {
+		dev_err(dev, "bad mux controller %u specified in %s\n",
+			id, ofnode_get_name(args->node));
+		return -ERANGE;
+	}
+
+	mux = &mux_chip->mux[id];
+	mux->id = id;
+	*muxp = mux;
+	return 0;
+}
+
+static int mux_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
+				   int index, struct mux_control **mux)
+{
+	int ret;
+	struct ofnode_phandle_args args;
+	struct udevice *dev_mux;
+	const struct mux_control_ops *ops;
+	struct mux_chip *mux_chip;
+
+	debug("%s(dev=%p, index=%d, mux=%p)\n", __func__, dev, index, mux);
+
+	ret = dev_read_phandle_with_args(dev, prop_name, "#mux-control-cells",
+					 0, index, &args);
+	if (ret) {
+		debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
+		      __func__, ret);
+		return ret;
+	}
+
+	ret = uclass_get_device_by_ofnode(UCLASS_MUX, args.node, &dev_mux);
+	if (ret) {
+		debug("%s: uclass_get_device_by_ofnode failed: err=%d\n",
+		      __func__, ret);
+		return ret;
+	}
+
+	mux_chip = dev_get_uclass_priv(dev_mux);
+
+	ops = mux_dev_ops(dev_mux);
+	if (ops->of_xlate)
+		ret = ops->of_xlate(mux_chip, &args, mux);
+	else
+		ret = mux_of_xlate_default(mux_chip, &args, mux);
+	if (ret) {
+		debug("of_xlate() failed: %d\n", ret);
+		return ret;
+	}
+	(*mux)->dev = dev_mux;
+
+	return 0;
+}
+
+int mux_get_by_index(struct udevice *dev, int index, struct mux_control **mux)
+{
+	return mux_get_by_indexed_prop(dev, "mux-controls", index, mux);
+}
+
+int mux_control_get(struct udevice *dev, const char *name,
+		    struct mux_control **mux)
+{
+	int index;
+
+	debug("%s(dev=%p, name=%s, mux=%p)\n", __func__, dev, name, mux);
+
+	index = dev_read_stringlist_search(dev, "mux-control-names", name);
+	if (index < 0) {
+		debug("fdt_stringlist_search() failed: %d\n", index);
+		return index;
+	}
+
+	return mux_get_by_index(dev, index, mux);
+}
+
+void mux_control_put(struct mux_control *mux)
+{
+	mux_control_deselect(mux);
+}
+
+static void devm_mux_control_release(struct udevice *dev, void *res)
+{
+	mux_control_put(*(struct mux_control **)res);
+}
+
+struct mux_control *devm_mux_control_get(struct udevice *dev, const char *id)
+{
+	int rc;
+	struct mux_control **mux;
+
+	mux = devres_alloc(devm_mux_control_release,
+			   sizeof(struct mux_control *), __GFP_ZERO);
+	if (unlikely(!mux))
+		return ERR_PTR(-ENOMEM);
+
+	rc = mux_control_get(dev, id, mux);
+	if (rc)
+		return ERR_PTR(rc);
+
+	devres_add(dev, mux);
+	return *mux;
+}
+
+int mux_alloc_controllers(struct udevice *dev, unsigned int controllers)
+{
+	int i;
+	struct mux_chip *mux_chip = dev_get_uclass_priv(dev);
+
+	mux_chip->mux = devm_kmalloc(dev,
+				     sizeof(struct mux_control) * controllers,
+				     __GFP_ZERO);
+	if (!mux_chip->mux)
+		return -ENOMEM;
+
+	mux_chip->controllers = controllers;
+
+	for (i = 0; i < mux_chip->controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		mux->dev = dev;
+		mux->cached_state = MUX_CACHE_UNKNOWN;
+		mux->idle_state = MUX_IDLE_AS_IS;
+		mux->in_use = false;
+		mux->id = i;
+	}
+
+	return 0;
+}
+
+int mux_uclass_post_probe(struct udevice *dev)
+{
+	int i, ret;
+	struct mux_chip *mux_chip = dev_get_uclass_priv(dev);
+
+	for (i = 0; i < mux_chip->controllers; ++i) {
+		struct mux_control *mux = &mux_chip->mux[i];
+
+		if (mux->idle_state == mux->cached_state)
+			continue;
+
+		ret = mux_control_set(mux, mux->idle_state);
+		if (ret < 0) {
+			dev_err(&mux_chip->dev, "unable to set idle state\n");
+			return ret;
+		}
+	}
+	return 0;
+}
+
+void dm_mux_init(void)
+{
+	struct uclass *uc;
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get(UCLASS_MUX, &uc);
+	if (ret < 0) {
+		debug("unable to get MUX uclass\n");
+		return;
+	}
+	uclass_foreach_dev(dev, uc) {
+		if (dev_read_bool(dev, "u-boot,mux-autoprobe")) {
+			ret = device_probe(dev);
+			if (ret)
+				debug("unable to probe device %s\n", dev->name);
+		} else {
+			printf("not found for dev %s\n", dev->name);
+		}
+	}
+}
+
+UCLASS_DRIVER(mux) = {
+	.id		= UCLASS_MUX,
+	.name		= "mux",
+	.post_probe	= mux_uclass_post_probe,
+	.per_device_auto_alloc_size = sizeof(struct mux_chip),
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index d4d96106b3..869c0616bd 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -64,6 +64,7 @@ enum uclass_id {
 	UCLASS_MMC,		/* SD / MMC card or chip */
 	UCLASS_MOD_EXP,		/* RSA Mod Exp device */
 	UCLASS_MTD,		/* Memory Technology Device (MTD) device */
+	UCLASS_MUX,		/* Multiplexer device */
 	UCLASS_NOP,		/* No-op devices */
 	UCLASS_NORTHBRIDGE,	/* Intel Northbridge / SDRAM controller */
 	UCLASS_NVME,		/* NVM Express device */
diff --git a/include/dt-bindings/mux/mux.h b/include/dt-bindings/mux/mux.h
new file mode 100644
index 0000000000..042719218d
--- /dev/null
+++ b/include/dt-bindings/mux/mux.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides constants for most Multiplexer bindings.
+ *
+ * Most Multiplexer bindings specify an idle state. In most cases, the
+ * the multiplexer can be left as is when idle, and in some cases it can
+ * disconnect the input/output and leave the multiplexer in a high
+ * impedance state.
+ */
+
+#ifndef _DT_BINDINGS_MUX_MUX_H
+#define _DT_BINDINGS_MUX_MUX_H
+
+#define MUX_IDLE_AS_IS      (-1)
+#define MUX_IDLE_DISCONNECT (-2)
+
+#endif
diff --git a/include/mux-internal.h b/include/mux-internal.h
new file mode 100644
index 0000000000..63444f4c3d
--- /dev/null
+++ b/include/mux-internal.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Based on the linux multiplexer framework
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#ifndef _MUX_UCLASS_H
+#define _MUX_UCLASS_H
+
+/* See mux.h for background documentation. */
+
+#include <mux.h>
+
+struct ofnode_phandle_args;
+
+/**
+ * struct mux_chip -	Represents a chip holding mux controllers.
+ * @controllers:	Number of mux controllers handled by the chip.
+ * @mux:		Array of mux controllers that are handled.
+ * @dev:		Device structure.
+ * @ops:		Mux controller operations.
+ */
+struct mux_chip {
+	unsigned int controllers;
+	struct mux_control *mux;
+};
+
+/**
+ * struct mux_control_ops -	Mux controller operations for a mux chip.
+ * @set:			Set the state of the given mux controller.
+ */
+struct mux_control_ops {
+	int (*set)(struct mux_control *mux, int state);
+	int (*of_xlate)(struct mux_chip *dev_mux,
+			struct ofnode_phandle_args *args,
+			struct mux_control **mux);
+};
+
+/**
+ * struct mux_control -	Represents a mux controller.
+ * @chip:		The mux chip that is handling this mux controller.
+ * @cached_state:	The current mux controller state, or -1 if none.
+ * @states:		The number of mux controller states.
+ * @idle_state:		The mux controller state to use when inactive, or one
+ *			of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
+ *
+ * Mux drivers may only change @states and @idle_state, and may only do so
+ * between allocation and registration of the mux controller. Specifically,
+ * @cached_state is internal to the mux core and should never be written by
+ * mux drivers.
+ */
+struct mux_control {
+	bool	in_use;
+	struct udevice *dev;
+	int cached_state;
+	unsigned int states;
+	int idle_state;
+	int id;
+};
+
+/**
+ * mux_control_get_index() - Get the index of the given mux controller
+ * @mux: The mux-control to get the index for.
+ *
+ * Return: The index of the mux controller within the mux chip the mux
+ * controller is a part of.
+ */
+static inline unsigned int mux_control_get_index(struct mux_control *mux)
+{
+	return mux->id;
+}
+
+int mux_alloc_controllers(struct udevice *dev, unsigned int controllers);
+
+#endif
diff --git a/include/mux.h b/include/mux.h
new file mode 100644
index 0000000000..d9d7728fea
--- /dev/null
+++ b/include/mux.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Based on the linux multiplexer framework
+ *
+ * Copyright (C) 2017 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#ifndef _MUX_H_
+#define _MUX_H_
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+struct udevice;
+struct mux_control;
+
+#if CONFIG_IS_ENABLED(MULTIPLEXER)
+/**
+ * mux_control_states() - Query the number of multiplexer states.
+ * @mux: The mux-control to query.
+ *
+ * Return: The number of multiplexer states.
+ */
+unsigned int mux_control_states(struct mux_control *mux);
+
+/**
+ * mux_control_select() - Select the given multiplexer state.
+ * @mux: The mux-control to request a change of state from.
+ * @state: The new requested state.
+ *
+ * On successfully selecting the mux-control state, it will be locked until
+ * there is a call to mux_control_deselect(). If the mux-control is already
+ * selected when mux_control_select() is called, the function will indicate
+ * -EBUSY
+ *
+ * Therefore, make sure to call mux_control_deselect() when the operation is
+ * complete and the mux-control is free for others to use, but do not call
+ * mux_control_deselect() if mux_control_select() fails.
+ *
+ * Return: 0 when the mux-control state has the requested state or a negative
+ * errno on error.
+ */
+int __must_check mux_control_select(struct mux_control *mux,
+				    unsigned int state);
+#define mux_control_try_select(mux) mux_control_select(mux)
+
+/**
+ * mux_control_deselect() - Deselect the previously selected multiplexer state.
+ * @mux: The mux-control to deselect.
+ *
+ * It is required that a single call is made to mux_control_deselect() for
+ * each and every successful call made to either of mux_control_select() or
+ * mux_control_try_select().
+ *
+ * Return: 0 on success and a negative errno on error. An error can only
+ * occur if the mux has an idle state. Note that even if an error occurs, the
+ * mux-control is unlocked and is thus free for the next access.
+ */
+int mux_control_deselect(struct mux_control *mux);
+
+int mux_get_by_index(struct udevice *dev, int index, struct mux_control **mux);
+int mux_control_get(struct udevice *dev, const char *name,
+		    struct mux_control **mux);
+
+void mux_control_put(struct mux_control *mux);
+
+struct mux_control *devm_mux_control_get(struct udevice *dev,
+					 const char *mux_name);
+
+void dm_mux_init(void);
+#else
+unsigned int mux_control_states(struct mux_control *mux)
+{
+	return -ENOSYS;
+}
+
+int __must_check mux_control_select(struct mux_control *mux,
+				    unsigned int state)
+{
+	return -ENOSYS;
+}
+
+#define mux_control_try_select(mux) mux_control_select(mux)
+
+int mux_control_deselect(struct mux_control *mux)
+{
+	return -ENOSYS;
+}
+
+struct mux_control *mux_control_get(struct udevice *dev, const char *mux_name)
+{
+	return NULL;
+}
+
+void mux_control_put(struct mux_control *mux)
+{
+}
+
+struct mux_control *devm_mux_control_get(struct udevice *dev,
+					 const char *mux_name)
+{
+	return NULL;
+}
+
+void dm_mux_init(void)
+{
+}
+#endif
+
+#endif
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 2/4] dm: board: complete the initialization of the muxes in initr_dm()
  2019-10-02 12:47 [U-Boot] [PATCH v1 0/4] drivers: Add a framework for MUX drivers Jean-Jacques Hiblot
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices Jean-Jacques Hiblot
@ 2019-10-02 12:47 ` Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 3/4] drivers: mux: mmio-based syscon mux controller Jean-Jacques Hiblot
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 4/4] test: Add tests for the multiplexer framework Jean-Jacques Hiblot
  3 siblings, 1 reply; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-10-02 12:47 UTC (permalink / raw)
  To: u-boot

This will probe the multiplexer devices that have a "u-boot,mux-autoprobe"
property. As a consequence they will be put in their idle state.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---

 common/board_r.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/common/board_r.c b/common/board_r.c
index d6fb5047a2..92a4e2c150 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -32,6 +32,7 @@
 #include <miiphy.h>
 #endif
 #include <mmc.h>
+#include <mux.h>
 #include <nand.h>
 #include <of_live.h>
 #include <onenand_uboot.h>
@@ -310,6 +311,7 @@ static int initr_dm(void)
 	if (ret)
 		return ret;
 #endif
+	dm_mux_init();
 
 	return 0;
 }
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 3/4] drivers: mux: mmio-based syscon mux controller
  2019-10-02 12:47 [U-Boot] [PATCH v1 0/4] drivers: Add a framework for MUX drivers Jean-Jacques Hiblot
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices Jean-Jacques Hiblot
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 2/4] dm: board: complete the initialization of the muxes in initr_dm() Jean-Jacques Hiblot
@ 2019-10-02 12:47 ` Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 4/4] test: Add tests for the multiplexer framework Jean-Jacques Hiblot
  3 siblings, 1 reply; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-10-02 12:47 UTC (permalink / raw)
  To: u-boot

This adds a driver for mmio-based syscon multiplexers controlled by
bitfields in a syscon register range.
This is heavily based on the linux mmio-mux driver.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
---

 drivers/mux/Kconfig  |  15 +++++
 drivers/mux/Makefile |   1 +
 drivers/mux/mmio.c   | 155 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 171 insertions(+)
 create mode 100644 drivers/mux/mmio.c

diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
index ad0199c058..bda6a2d9f5 100644
--- a/drivers/mux/Kconfig
+++ b/drivers/mux/Kconfig
@@ -4,4 +4,19 @@ config MULTIPLEXER
 	bool "Multiplexer Support"
 	depends on DM
 
+
+if MULTIPLEXER
+
+config MUX_MMIO
+	bool "MMIO register bitfield-controlled Multiplexer"
+	depends on MULTIPLEXER && SYSCON
+	help
+	  MMIO register bitfield-controlled Multiplexer controller.
+
+	  The driver builds multiplexer controllers for bitfields in a syscon
+	  register. For N bit wide bitfields, there will be 2^N possible
+	  multiplexer states.
+
+endif
+
 endmenu
diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
index 351e4363d3..78ebf04c7a 100644
--- a/drivers/mux/Makefile
+++ b/drivers/mux/Makefile
@@ -4,3 +4,4 @@
 # Jean-Jacques Hiblot <jjhiblot@ti.com>
 
 obj-$(CONFIG_$(SPL_)MULTIPLEXER) += mux-uclass.o
+obj-$(CONFIG_$(SPL_)MUX_MMIO) += mmio.o
diff --git a/drivers/mux/mmio.c b/drivers/mux/mmio.c
new file mode 100644
index 0000000000..a9faaeb9fd
--- /dev/null
+++ b/drivers/mux/mmio.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * MMIO register bitfield-controlled multiplexer driver
+ * Based on the linux mmio multiplexer driver
+ *
+ * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de>
+ * Copyright (C) 2019 Texas Instrument, Jean-jacques Hiblot <jjhiblot@ti.com>
+ */
+#include <common.h>
+#include <dm.h>
+#include <mux-internal.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <dt-bindings/mux/mux.h>
+
+static int mux_mmio_set(struct mux_control *mux, int state)
+{
+	struct regmap_field **fields = dev_get_priv(mux->dev);
+
+	return regmap_field_write(fields[mux_control_get_index(mux)], state);
+}
+
+static const struct mux_control_ops mux_mmio_ops = {
+	.set = mux_mmio_set,
+};
+
+static const struct udevice_id mmio_mux_of_match[] = {
+	{ .compatible = "mmio-mux" },
+	{ /* sentinel */ },
+};
+
+static int mmio_mux_probe(struct udevice *dev)
+{
+	struct regmap_field **fields;
+	struct mux_chip *mux_chip = dev_get_uclass_priv(dev);
+	struct regmap *regmap;
+	u32 *mux_reg_masks;
+	u32 *idle_states;
+	int num_fields;
+	int ret;
+	int i;
+
+	regmap = syscon_node_to_regmap(dev_ofnode(dev->parent));
+	if (IS_ERR(regmap)) {
+		ret = PTR_ERR(regmap);
+		dev_err(dev, "failed to get regmap: %d\n", ret);
+		return ret;
+	}
+
+	num_fields = dev_read_size(dev, "mux-reg-masks");
+	if (num_fields < 0) {
+		dev_err(dev, "mux-reg-masks property missing or invalid: %d\n",
+			num_fields);
+		return num_fields;
+	}
+	num_fields /= sizeof(u32);
+	if (num_fields == 0 || num_fields % 2)
+		ret = -EINVAL;
+	num_fields = num_fields / 2;
+
+	ret = mux_alloc_controllers(dev, num_fields);
+	if (ret < 0) {
+		dev_err(dev, "failed to allocate mux controllers: %d\n",
+			ret);
+		return ret;
+	}
+
+	fields = devm_kmalloc(dev, num_fields * sizeof(*fields), __GFP_ZERO);
+	if (!fields)
+		return -ENOMEM;
+	dev->priv = fields;
+
+	mux_reg_masks = devm_kmalloc(dev, num_fields * 2 * sizeof(u32),
+				     __GFP_ZERO);
+	if (!mux_reg_masks)
+		return -ENOMEM;
+
+	ret = dev_read_u32_array(dev, "mux-reg-masks", mux_reg_masks,
+				 num_fields * 2);
+	if (ret < 0) {
+		dev_err(dev, "failed to read mux-reg-masks property: %d\n",
+			ret);
+		return ret;
+	}
+
+	idle_states = devm_kmalloc(dev, num_fields * sizeof(u32), __GFP_ZERO);
+	if (!idle_states)
+		return -ENOMEM;
+
+	ret = dev_read_u32_array(dev, "idle-states", idle_states, num_fields);
+	if (ret < 0) {
+		dev_err(dev, "failed to read idle-states property: %d\n",
+			ret);
+		devm_kfree(dev, idle_states);
+		idle_states = NULL;
+	}
+
+	for (i = 0; i < num_fields; i++) {
+		struct mux_control *mux = &mux_chip->mux[i];
+		struct reg_field field;
+		u32 reg, mask;
+		int bits;
+
+		reg = mux_reg_masks[2 * i];
+		mask = mux_reg_masks[2 * i + 1];
+
+		field.reg = reg;
+		field.msb = fls(mask) - 1;
+		field.lsb = ffs(mask) - 1;
+
+		if (mask != GENMASK(field.msb, field.lsb)) {
+			dev_err(dev, "bitfield %d: invalid mask 0x%x\n",
+				i, mask);
+			return -EINVAL;
+		}
+
+		fields[i] = devm_regmap_field_alloc(dev, regmap, field);
+		if (IS_ERR(fields[i])) {
+			ret = PTR_ERR(fields[i]);
+			dev_err(dev, "bitfield %d: failed allocate: %d\n",
+				i, ret);
+			return ret;
+		}
+
+		bits = 1 + field.msb - field.lsb;
+		mux->states = 1 << bits;
+
+		if (!idle_states)
+			continue;
+
+		if (idle_states[i] != MUX_IDLE_AS_IS &&
+		    idle_states[i] >= mux->states) {
+			dev_err(dev, "bitfield: %d: out of range idle state %d\n",
+				i, idle_states[i]);
+			return -EINVAL;
+		}
+		mux->idle_state = idle_states[i];
+	}
+
+	devm_kfree(dev, mux_reg_masks);
+	if (idle_states)
+		devm_kfree(dev, idle_states);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(mmio_mux) = {
+	.name = "mmio-mux",
+	.id = UCLASS_MUX,
+	.of_match = mmio_mux_of_match,
+	.probe = mmio_mux_probe,
+	.ops = &mux_mmio_ops,
+};
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 4/4] test: Add tests for the multiplexer framework
  2019-10-02 12:47 [U-Boot] [PATCH v1 0/4] drivers: Add a framework for MUX drivers Jean-Jacques Hiblot
                   ` (2 preceding siblings ...)
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 3/4] drivers: mux: mmio-based syscon mux controller Jean-Jacques Hiblot
@ 2019-10-02 12:47 ` Jean-Jacques Hiblot
  2019-10-24 23:45   ` Tom Rini
  3 siblings, 1 reply; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-10-02 12:47 UTC (permalink / raw)
  To: u-boot

Provide tests to check the behavior of the multiplexer framework.
The test uses a mmio-based multiplexer.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>

---

 arch/sandbox/dts/test.dts |  26 +++++++
 configs/sandbox_defconfig |   2 +
 test/dm/Makefile          |   1 +
 test/dm/mux-mmio.c        | 143 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 172 insertions(+)
 create mode 100644 test/dm/mux-mmio.c

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 044895586a..a502dc8bd7 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1,3 +1,5 @@
+#include <dt-bindings/mux/mux.h>
+
 /dts-v1/;
 
 / {
@@ -89,6 +91,11 @@
 			<&gpio_b 9 0xc 3 2 1>;
 		int-value = <1234>;
 		uint-value = <(-1234)>;
+
+		mux-controls = <&muxcontroller0 0>, <&muxcontroller0 1>,
+			       <&muxcontroller0 2>, <&muxcontroller0 3>;
+		mux-control-names = "mux0", "mux1", "mux2", "mux3";
+		mux-syscon = <&syscon3>;
 	};
 
 	junk {
@@ -125,6 +132,9 @@
 		compatible = "denx,u-boot-fdt-test";
 		ping-expect = <3>;
 		ping-add = <3>;
+
+		mux-controls = <&muxcontroller0 0>;
+		mux-control-names = "mux0";
 	};
 
 	phy_provider0: gen_phy at 0 {
@@ -640,6 +650,22 @@
 			0x58 8>;
 	};
 
+	syscon3: syscon at 3 {
+		compatible = "simple-mfd", "syscon";
+		reg = <0x000100 0x10>;
+
+		muxcontroller0: a-mux-controller {
+			compatible = "mmio-mux";
+			#mux-control-cells = <1>;
+
+			mux-reg-masks = <0x0 0x30>, /* 0: reg 0x0, bits 5:4 */
+					<0x3 0x1E>, /* 1: reg 0x3, bits 4:1 */
+					<0x1 0xFF>; /* 2: reg 0x1, bits 7:0 */
+			idle-states = <MUX_IDLE_AS_IS>, <0x02>, <0x73>;
+			u-boot,mux-autoprobe;
+		};
+	};
+
 	timer {
 		compatible = "sandbox,timer";
 		clock-frequency = <1000000>;
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index f77b9e8a7d..aa5d89dfc2 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -143,6 +143,8 @@ CONFIG_SPI_FLASH_SPANSION=y
 CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_SST=y
 CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_MULTIPLEXER=y
+CONFIG_MUX_MMIO=y
 CONFIG_DM_ETH=y
 CONFIG_NVME=y
 CONFIG_PCI=y
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 55a7940053..5fedcb8a7a 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_SMEM) += smem.o
 obj-$(CONFIG_DM_SPI) += spi.o
 obj-y += syscon.o
+obj-$(CONFIG_MUX_MMIO) += mux-mmio.o
 obj-$(CONFIG_DM_USB) += usb.o
 obj-$(CONFIG_DM_PMIC) += pmic.o
 obj-$(CONFIG_DM_REGULATOR) += regulator.o
diff --git a/test/dm/mux-mmio.c b/test/dm/mux-mmio.c
new file mode 100644
index 0000000000..8a19281614
--- /dev/null
+++ b/test/dm/mux-mmio.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
+ * Jean-Jacques Hiblot <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <dm.h>
+#include <mux.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/test.h>
+#include <dm/root.h>
+#include <dm/test.h>
+#include <dm/util.h>
+#include <test/ut.h>
+
+/* Test that mmio mux work correctly */
+static int dm_test_mux_mmio(struct unit_test_state *uts)
+{
+	struct udevice *dev, *dev_b;
+	struct regmap *map;
+	struct mux_control *ctl0_a, *ctl0_b;
+	struct mux_control *ctl1;
+	struct mux_control *ctl_err;
+	u32 val;
+	int i;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 1, &dev_b));
+	ut_asserteq_str("a-test", dev->name);
+	ut_asserteq_str("b-test", dev_b->name);
+	map = syscon_regmap_lookup_by_phandle(dev, "mux-syscon");
+	ut_assert(!IS_ERR(map));
+	ut_assert(map);
+
+	/* check default states */
+	ut_assertok(regmap_read(map, 3, &val));
+	ut_asserteq(0x02, (val & 0x1E) >> 1);
+	ut_assertok(regmap_read(map, 1, &val));
+	ut_asserteq(0x73, (val & 0xFF) >> 0);
+
+	ut_assertok(mux_control_get(dev, "mux0", &ctl0_a));
+	ut_assertok(mux_control_get(dev, "mux1", &ctl1));
+	ut_asserteq(-ERANGE, mux_control_get(dev, "mux3", &ctl_err));
+	ut_asserteq(-ENODATA, mux_control_get(dev, "dummy", &ctl_err));
+	ut_assertok(mux_control_get(dev_b, "mux0", &ctl0_b));
+
+	for (i = 0; i < mux_control_states(ctl0_a); i++) {
+		/* select a new state and verify the value in the regmap */
+		ut_assertok(mux_control_select(ctl0_a, i));
+		ut_assertok(regmap_read(map, 0, &val));
+		ut_asserteq(i, (val & 0x30) >> 4);
+		/*
+		 * deselect the mux and verify that the value in the regmap
+		 * reflects the idle state (fixed to MUX_IDLE_AS_IS)
+		 */
+		ut_assertok(mux_control_deselect(ctl0_a));
+		ut_assertok(regmap_read(map, 0, &val));
+		ut_asserteq(i, (val & 0x30) >> 4);
+	}
+
+	for (i = 0; i < mux_control_states(ctl1); i++) {
+		/* select a new state and verify the value in the regmap */
+		ut_assertok(mux_control_select(ctl1, i));
+		ut_assertok(regmap_read(map, 3, &val));
+		ut_asserteq(i, (val & 0x1E) >> 1);
+		/*
+		 * deselect the mux and verify that the value in the regmap
+		 * reflects the idle state (fixed to 2)
+		 */
+		ut_assertok(mux_control_deselect(ctl1));
+		ut_assertok(regmap_read(map, 3, &val));
+		ut_asserteq(2, (val & 0x1E) >> 1);
+	}
+
+	// try unbalanced selection/deselection
+	ut_assertok(mux_control_select(ctl0_a, 0));
+	ut_asserteq(-EBUSY, mux_control_select(ctl0_a, 1));
+	ut_asserteq(-EBUSY, mux_control_select(ctl0_a, 0));
+	ut_assertok(mux_control_deselect(ctl0_a));
+
+	// try concurent selection
+	ut_assertok(mux_control_select(ctl0_a, 0));
+	ut_assert(mux_control_select(ctl0_b, 0));
+	ut_assertok(mux_control_deselect(ctl0_a));
+	ut_assertok(mux_control_select(ctl0_b, 0));
+	ut_assert(mux_control_select(ctl0_a, 0));
+	ut_assertok(mux_control_deselect(ctl0_b));
+	ut_assertok(mux_control_select(ctl0_a, 0));
+	ut_assertok(mux_control_deselect(ctl0_a));
+
+	return 0;
+}
+DM_TEST(dm_test_mux_mmio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that managed API for mux work correctly */
+static int dm_test_devm_mux_mmio(struct unit_test_state *uts)
+{
+	struct udevice *dev, *dev_b;
+	struct mux_control *ctl0_a, *ctl0_b;
+	struct mux_control *ctl1;
+	struct mux_control *ctl_err;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 1, &dev_b));
+	ut_asserteq_str("a-test", dev->name);
+	ut_asserteq_str("b-test", dev_b->name);
+
+	ctl0_a = devm_mux_control_get(dev, "mux0");
+	ut_assertok(IS_ERR(ctl0_a));
+	ut_assert(ctl0_a);
+	ctl1 = devm_mux_control_get(dev, "mux1");
+	ut_assertok(IS_ERR(ctl1));
+	ut_assert(ctl1);
+	ctl_err = devm_mux_control_get(dev, "mux3");
+	ut_asserteq(-ERANGE, PTR_ERR(ctl_err));
+	ctl_err = devm_mux_control_get(dev, "dummy");
+	ut_asserteq(-ENODATA, PTR_ERR(ctl_err));
+
+	ctl0_b = devm_mux_control_get(dev_b, "mux0");
+	ut_assertok(IS_ERR(ctl0_b));
+	ut_assert(ctl0_b);
+
+	/* try concurent selection */
+	ut_assertok(mux_control_select(ctl0_a, 0));
+	ut_assert(mux_control_select(ctl0_b, 0));
+	ut_assertok(mux_control_deselect(ctl0_a));
+	ut_assertok(mux_control_select(ctl0_b, 0));
+	ut_assert(mux_control_select(ctl0_a, 0));
+	ut_assertok(mux_control_deselect(ctl0_b));
+
+	/* removed one device and check that the mux is released */
+	ut_assertok(mux_control_select(ctl0_a, 0));
+	ut_assert(mux_control_select(ctl0_b, 0));
+	device_remove(dev, DM_REMOVE_NORMAL);
+	ut_assertok(mux_control_select(ctl0_b, 0));
+
+	device_remove(dev_b, DM_REMOVE_NORMAL);
+	return 0;
+}
+DM_TEST(dm_test_devm_mux_mmio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 4/4] test: Add tests for the multiplexer framework
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 4/4] test: Add tests for the multiplexer framework Jean-Jacques Hiblot
@ 2019-10-24 23:45   ` Tom Rini
  2019-10-25  9:32     ` Jean-Jacques Hiblot
  0 siblings, 1 reply; 15+ messages in thread
From: Tom Rini @ 2019-10-24 23:45 UTC (permalink / raw)
  To: u-boot

On Wed, Oct 02, 2019 at 02:47:49PM +0200, Jean-Jacques Hiblot wrote:

> Provide tests to check the behavior of the multiplexer framework.
> The test uses a mmio-based multiplexer.
> 
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>

These tests don't pass (with all of the other series applied as well,
and some warnings fixed up):
_________________________ test_ut[ut_dm_devm_mux_mmio] _________________________

u_boot_console = <u_boot_console_sandbox.ConsoleSandbox object@0x7f2550b89890>
ut_subtest = 'dm devm_mux_mmio'

    def test_ut(u_boot_console, ut_subtest):
        """Execute a "ut" subtest."""
    
        output = u_boot_console.run_command('ut ' + ut_subtest)
>       assert output.endswith('Failures: 0')
E       assert False
E        +  where False = <built-in method endswith of str object@0x7f2550567030>('Failures: 0')
E        +    where <built-in method endswith of str object@0x7f2550567030> = 'Test: dm_test_devm_mux_mmio: mux-mmio.c\r\r\n/builds/u-boot/u-boot/test/dm/mux-mmio.c:110, dm_test_devm_mux_mmio(): "...ux-mmio.c:110, dm_test_devm_mux_mmio(): "b-test" = dev_b->name: Expected "b-test", got "another-test"\r\r\nFailures: 2'.endswith

test/py/tests/test_ut.py:28: AssertionError
----------------------------- Captured stdout call -----------------------------
=> ut dm devm_mux_mmio

Test: dm_test_devm_mux_mmio: mux-mmio.c

/builds/u-boot/u-boot/test/dm/mux-mmio.c:110, dm_test_devm_mux_mmio(): "b-test" = dev_b->name: Expected "b-test", got "another-test"

Test: dm_test_devm_mux_mmio: mux-mmio.c (flat tree)

/builds/u-boot/u-boot/test/dm/mux-mmio.c:110, dm_test_devm_mux_mmio(): "b-test" = dev_b->name: Expected "b-test", got "another-test"

Failures: 2

=> 

Finally, clang-7 reports:
/home/trini/u-boot/u-boot/drivers/mux/mux-uclass.c:108:34: warning: variable 'mux' is uninitialized when used here [-Wuninitialized]
        debug("%s(mux=%p)\n", __func__, mux);
                                        ^~~
/home/trini/u-boot/u-boot/include/log.h:188:28: note: expanded from macro 'debug'
        debug_cond(_DEBUG, fmt, ##args)
                                  ^~~~
/home/trini/u-boot/u-boot/include/log.h:168:41: note: expanded from macro 'debug_cond'
                        log(LOG_CATEGORY, LOGL_DEBUG, fmt, ##args); \
                                                             ^~~~
/home/trini/u-boot/u-boot/include/log.h:139:25: note: expanded from macro 'log'
                      pr_fmt(_fmt), ##_args); \
                                      ^~~~~
/home/trini/u-boot/u-boot/drivers/mux/mux-uclass.c:105:25: note: initialize the variable 'mux' to silence this warning
        struct mux_control *mux;
                               ^
                                = NULL

Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20191024/e4df6e06/attachment.sig>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 4/4] test: Add tests for the multiplexer framework
  2019-10-24 23:45   ` Tom Rini
@ 2019-10-25  9:32     ` Jean-Jacques Hiblot
  0 siblings, 0 replies; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-10-25  9:32 UTC (permalink / raw)
  To: u-boot

Hi Tom,

On 25/10/2019 01:45, Tom Rini wrote:
> On Wed, Oct 02, 2019 at 02:47:49PM +0200, Jean-Jacques Hiblot wrote:
>
>> Provide tests to check the behavior of the multiplexer framework.
>> The test uses a mmio-based multiplexer.
>>
>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> These tests don't pass (with all of the other series applied as well,
> and some warnings fixed up):
> _________________________ test_ut[ut_dm_devm_mux_mmio] _________________________
>
> u_boot_console = <u_boot_console_sandbox.ConsoleSandbox object@0x7f2550b89890>
> ut_subtest = 'dm devm_mux_mmio'
>
>      def test_ut(u_boot_console, ut_subtest):
>          """Execute a "ut" subtest."""
>      
>          output = u_boot_console.run_command('ut ' + ut_subtest)
>>        assert output.endswith('Failures: 0')
> E       assert False
> E        +  where False = <built-in method endswith of str object@0x7f2550567030>('Failures: 0')
> E        +    where <built-in method endswith of str object@0x7f2550567030> = 'Test: dm_test_devm_mux_mmio: mux-mmio.c\r\r\n/builds/u-boot/u-boot/test/dm/mux-mmio.c:110, dm_test_devm_mux_mmio(): "...ux-mmio.c:110, dm_test_devm_mux_mmio(): "b-test" = dev_b->name: Expected "b-test", got "another-test"\r\r\nFailures: 2'.endswith

There has been some changes in the regmap support for sandbox. I'll 
rebase on top of master and send an updated version.

Thanks

JJ

>
> test/py/tests/test_ut.py:28: AssertionError
> ----------------------------- Captured stdout call -----------------------------
> => ut dm devm_mux_mmio
>
> Test: dm_test_devm_mux_mmio: mux-mmio.c
>
> /builds/u-boot/u-boot/test/dm/mux-mmio.c:110, dm_test_devm_mux_mmio(): "b-test" = dev_b->name: Expected "b-test", got "another-test"
>
> Test: dm_test_devm_mux_mmio: mux-mmio.c (flat tree)
>
> /builds/u-boot/u-boot/test/dm/mux-mmio.c:110, dm_test_devm_mux_mmio(): "b-test" = dev_b->name: Expected "b-test", got "another-test"
>
> Failures: 2
>
> =>
>
> Finally, clang-7 reports:
> /home/trini/u-boot/u-boot/drivers/mux/mux-uclass.c:108:34: warning: variable 'mux' is uninitialized when used here [-Wuninitialized]
>          debug("%s(mux=%p)\n", __func__, mux);
>                                          ^~~
> /home/trini/u-boot/u-boot/include/log.h:188:28: note: expanded from macro 'debug'
>          debug_cond(_DEBUG, fmt, ##args)
>                                    ^~~~
> /home/trini/u-boot/u-boot/include/log.h:168:41: note: expanded from macro 'debug_cond'
>                          log(LOG_CATEGORY, LOGL_DEBUG, fmt, ##args); \
>                                                               ^~~~
> /home/trini/u-boot/u-boot/include/log.h:139:25: note: expanded from macro 'log'
>                        pr_fmt(_fmt), ##_args); \
>                                        ^~~~~
> /home/trini/u-boot/u-boot/drivers/mux/mux-uclass.c:105:25: note: initialize the variable 'mux' to silence this warning
>          struct mux_control *mux;
>                                 ^
>                                  = NULL
>
> Thanks!

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices Jean-Jacques Hiblot
@ 2019-10-30  1:48   ` Simon Glass
  2019-11-04 17:53     ` Jean-Jacques Hiblot
  2019-11-05  1:37   ` Bin Meng
  1 sibling, 1 reply; 15+ messages in thread
From: Simon Glass @ 2019-10-30  1:48 UTC (permalink / raw)
  To: u-boot

Hi Jean-Jacques,

On Wed, 2 Oct 2019 at 06:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> Add a new subsystem that handles multiplexer controllers. The API is the
> same as in Linux.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>
>  drivers/Kconfig               |   2 +
>  drivers/Makefile              |   1 +
>  drivers/mux/Kconfig           |   7 +
>  drivers/mux/Makefile          |   6 +
>  drivers/mux/mux-uclass.c      | 296 ++++++++++++++++++++++++++++++++++
>  include/dm/uclass-id.h        |   1 +
>  include/dt-bindings/mux/mux.h |  17 ++
>  include/mux-internal.h        |  80 +++++++++
>  include/mux.h                 | 114 +++++++++++++
>  9 files changed, 524 insertions(+)
>  create mode 100644 drivers/mux/Kconfig
>  create mode 100644 drivers/mux/Makefile
>  create mode 100644 drivers/mux/mux-uclass.c
>  create mode 100644 include/dt-bindings/mux/mux.h
>  create mode 100644 include/mux-internal.h
>  create mode 100644 include/mux.h
>

I feel this needs more documentation. What is a multiplexer?

> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index 350acf81f3..5334974ad4 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -60,6 +60,8 @@ source "drivers/mmc/Kconfig"
>
>  source "drivers/mtd/Kconfig"
>
> +source "drivers/mux/Kconfig"
> +
>  source "drivers/net/Kconfig"
>
>  source "drivers/nvme/Kconfig"
> diff --git a/drivers/Makefile b/drivers/Makefile
> index a4bb5e4975..f4d71f3b3c 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_TPL_)INPUT) += input/
>  obj-$(CONFIG_$(SPL_TPL_)LED) += led/
>  obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += mmc/
>  obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += mtd/nand/raw/
> +obj-$(CONFIG_$(SPl_)MULTIPLEXER) += mux/

SPL?

>  obj-$(CONFIG_$(SPL_TPL_)PCH_SUPPORT) += pch/
>  obj-$(CONFIG_$(SPL_TPL_)PCI) += pci/
>  obj-$(CONFIG_$(SPL_TPL_)PHY) += phy/
> diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
> new file mode 100644
> index 0000000000..ad0199c058
> --- /dev/null
> +++ b/drivers/mux/Kconfig
> @@ -0,0 +1,7 @@
> +menu "Multiplexer drivers"
> +
> +config MULTIPLEXER
> +       bool "Multiplexer Support"
> +       depends on DM
> +
> +endmenu
> diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
> new file mode 100644
> index 0000000000..351e4363d3
> --- /dev/null
> +++ b/drivers/mux/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# (C) Copyright 2019
> +# Jean-Jacques Hiblot <jjhiblot@ti.com>
> +
> +obj-$(CONFIG_$(SPL_)MULTIPLEXER) += mux-uclass.o
> diff --git a/drivers/mux/mux-uclass.c b/drivers/mux/mux-uclass.c
> new file mode 100644
> index 0000000000..58998af29c
> --- /dev/null
> +++ b/drivers/mux/mux-uclass.c
> @@ -0,0 +1,296 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Multiplexer subsystem
> + *
> + * Based on the linux multiplexer framework
> + *
> + * Copyright (C) 2017 Axentia Technologies AB
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
> + * Jean-Jacques Hiblot <jjhiblot@ti.com>
> + */
> +
> +#include <common.h>
> +#include <mux-internal.h>

should go above the dm/device-internal

> +#include <dm.h>
> +#include <dt-structs.h>

Shouldn't need this
> +#include <errno.h>

Shouldn't need this

> +#include <dm/device-internal.h>
> +#include <dm/lists.h>
> +#include <dm/read.h>

Shouldn't need this

> +#include <dt-bindings/mux/mux.h>
> +
> +/*
> + * The idle-as-is "state" is not an actual state that may be selected, it
> + * only implies that the state should not be changed. So, use that state
> + * as indication that the cached state of the multiplexer is unknown.
> + */
> +#define MUX_CACHE_UNKNOWN MUX_IDLE_AS_IS
> +
> +static inline const struct mux_control_ops *mux_dev_ops(struct udevice *dev)
> +{
> +       return (const struct mux_control_ops *)dev->driver->ops;
> +}
> +
> +static int mux_control_set(struct mux_control *mux, int state)
> +{
> +       int ret = mux_dev_ops(mux->dev)->set(mux, state);
> +
> +       mux->cached_state = ret < 0 ? MUX_CACHE_UNKNOWN : state;
> +
> +       return ret;
> +}
> +
> +unsigned int mux_control_states(struct mux_control *mux)
> +{
> +       return mux->states;
> +}
> +
> +static int __mux_control_select(struct mux_control *mux, int state)
> +{
> +       int ret;
> +
> +       if (WARN_ON(state < 0 || state >= mux->states))
> +               return -EINVAL;
> +
> +       if (mux->cached_state == state)
> +               return 0;
> +
> +       ret = mux_control_set(mux, state);
> +       if (ret >= 0)
> +               return 0;
> +
> +       /* The mux update failed, try to revert if appropriate... */
> +       if (mux->idle_state != MUX_IDLE_AS_IS)
> +               mux_control_set(mux, mux->idle_state);
> +
> +       return ret;
> +}
> +
> +int mux_control_select(struct mux_control *mux, unsigned int state)
> +{
> +       int ret;
> +
> +       if (mux->in_use)
> +               return -EBUSY;
> +
> +       ret = __mux_control_select(mux, state);
> +
> +       if (ret < 0)
> +               return ret;
> +
> +       mux->in_use = true;
> +
> +       return 0;
> +}
> +
> +int mux_control_deselect(struct mux_control *mux)
> +{
> +       int ret = 0;
> +
> +       if (mux->idle_state != MUX_IDLE_AS_IS &&
> +           mux->idle_state != mux->cached_state)
> +               ret = mux_control_set(mux, mux->idle_state);
> +
> +       mux->in_use = false;
> +
> +       return ret;
> +}
> +
> +static int mux_of_xlate_default(struct mux_chip *mux_chip,
> +                               struct ofnode_phandle_args *args,
> +                               struct mux_control **muxp)
> +{
> +       struct mux_control *mux;
> +       int id;
> +
> +       debug("%s(mux=%p)\n", __func__, mux);
> +
> +       if (args->args_count > 1) {
> +               debug("Invaild args_count: %d\n", args->args_count);
> +               return -EINVAL;
> +       }
> +
> +       if (args->args_count)
> +               id = args->args[0];
> +       else
> +               id = 0;
> +
> +       if (id >= mux_chip->controllers) {
> +               dev_err(dev, "bad mux controller %u specified in %s\n",
> +                       id, ofnode_get_name(args->node));
> +               return -ERANGE;
> +       }
> +
> +       mux = &mux_chip->mux[id];
> +       mux->id = id;
> +       *muxp = mux;
> +       return 0;
> +}
> +
> +static int mux_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
> +                                  int index, struct mux_control **mux)
> +{
> +       int ret;
> +       struct ofnode_phandle_args args;
> +       struct udevice *dev_mux;
> +       const struct mux_control_ops *ops;
> +       struct mux_chip *mux_chip;
> +
> +       debug("%s(dev=%p, index=%d, mux=%p)\n", __func__, dev, index, mux);
> +
> +       ret = dev_read_phandle_with_args(dev, prop_name, "#mux-control-cells",
> +                                        0, index, &args);
> +       if (ret) {
> +               debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
> +                     __func__, ret);
> +               return ret;
> +       }
> +
> +       ret = uclass_get_device_by_ofnode(UCLASS_MUX, args.node, &dev_mux);
> +       if (ret) {
> +               debug("%s: uclass_get_device_by_ofnode failed: err=%d\n",
> +                     __func__, ret);
> +               return ret;
> +       }
> +
> +       mux_chip = dev_get_uclass_priv(dev_mux);
> +
> +       ops = mux_dev_ops(dev_mux);
> +       if (ops->of_xlate)
> +               ret = ops->of_xlate(mux_chip, &args, mux);
> +       else
> +               ret = mux_of_xlate_default(mux_chip, &args, mux);
> +       if (ret) {
> +               debug("of_xlate() failed: %d\n", ret);
> +               return ret;
> +       }
> +       (*mux)->dev = dev_mux;
> +
> +       return 0;
> +}
> +
> +int mux_get_by_index(struct udevice *dev, int index, struct mux_control **mux)
> +{
> +       return mux_get_by_indexed_prop(dev, "mux-controls", index, mux);
> +}
> +
> +int mux_control_get(struct udevice *dev, const char *name,
> +                   struct mux_control **mux)
> +{
> +       int index;
> +
> +       debug("%s(dev=%p, name=%s, mux=%p)\n", __func__, dev, name, mux);
> +
> +       index = dev_read_stringlist_search(dev, "mux-control-names", name);
> +       if (index < 0) {
> +               debug("fdt_stringlist_search() failed: %d\n", index);
> +               return index;
> +       }
> +
> +       return mux_get_by_index(dev, index, mux);
> +}
> +
> +void mux_control_put(struct mux_control *mux)
> +{
> +       mux_control_deselect(mux);
> +}
> +
> +static void devm_mux_control_release(struct udevice *dev, void *res)
> +{
> +       mux_control_put(*(struct mux_control **)res);
> +}
> +
> +struct mux_control *devm_mux_control_get(struct udevice *dev, const char *id)
> +{
> +       int rc;
> +       struct mux_control **mux;
> +
> +       mux = devres_alloc(devm_mux_control_release,
> +                          sizeof(struct mux_control *), __GFP_ZERO);
> +       if (unlikely(!mux))
> +               return ERR_PTR(-ENOMEM);
> +
> +       rc = mux_control_get(dev, id, mux);
> +       if (rc)
> +               return ERR_PTR(rc);
> +
> +       devres_add(dev, mux);
> +       return *mux;
> +}
> +
> +int mux_alloc_controllers(struct udevice *dev, unsigned int controllers)
> +{
> +       int i;
> +       struct mux_chip *mux_chip = dev_get_uclass_priv(dev);
> +
> +       mux_chip->mux = devm_kmalloc(dev,
> +                                    sizeof(struct mux_control) * controllers,
> +                                    __GFP_ZERO);
> +       if (!mux_chip->mux)
> +               return -ENOMEM;
> +
> +       mux_chip->controllers = controllers;
> +
> +       for (i = 0; i < mux_chip->controllers; ++i) {
> +               struct mux_control *mux = &mux_chip->mux[i];
> +
> +               mux->dev = dev;
> +               mux->cached_state = MUX_CACHE_UNKNOWN;
> +               mux->idle_state = MUX_IDLE_AS_IS;
> +               mux->in_use = false;
> +               mux->id = i;
> +       }
> +
> +       return 0;
> +}
> +
> +int mux_uclass_post_probe(struct udevice *dev)
> +{
> +       int i, ret;
> +       struct mux_chip *mux_chip = dev_get_uclass_priv(dev);
> +
> +       for (i = 0; i < mux_chip->controllers; ++i) {
> +               struct mux_control *mux = &mux_chip->mux[i];
> +
> +               if (mux->idle_state == mux->cached_state)
> +                       continue;
> +
> +               ret = mux_control_set(mux, mux->idle_state);
> +               if (ret < 0) {
> +                       dev_err(&mux_chip->dev, "unable to set idle state\n");
> +                       return ret;
> +               }
> +       }
> +       return 0;
> +}
> +
> +void dm_mux_init(void)
> +{
> +       struct uclass *uc;
> +       struct udevice *dev;
> +       int ret;
> +
> +       ret = uclass_get(UCLASS_MUX, &uc);
> +       if (ret < 0) {
> +               debug("unable to get MUX uclass\n");
> +               return;
> +       }
> +       uclass_foreach_dev(dev, uc) {
> +               if (dev_read_bool(dev, "u-boot,mux-autoprobe")) {
> +                       ret = device_probe(dev);
> +                       if (ret)
> +                               debug("unable to probe device %s\n", dev->name);
> +               } else {
> +                       printf("not found for dev %s\n", dev->name);
> +               }
> +       }
> +}
> +
> +UCLASS_DRIVER(mux) = {
> +       .id             = UCLASS_MUX,
> +       .name           = "mux",
> +       .post_probe     = mux_uclass_post_probe,
> +       .per_device_auto_alloc_size = sizeof(struct mux_chip),
> +};
> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
> index d4d96106b3..869c0616bd 100644
> --- a/include/dm/uclass-id.h
> +++ b/include/dm/uclass-id.h
> @@ -64,6 +64,7 @@ enum uclass_id {
>         UCLASS_MMC,             /* SD / MMC card or chip */
>         UCLASS_MOD_EXP,         /* RSA Mod Exp device */
>         UCLASS_MTD,             /* Memory Technology Device (MTD) device */
> +       UCLASS_MUX,             /* Multiplexer device */
>         UCLASS_NOP,             /* No-op devices */
>         UCLASS_NORTHBRIDGE,     /* Intel Northbridge / SDRAM controller */
>         UCLASS_NVME,            /* NVM Express device */
> diff --git a/include/dt-bindings/mux/mux.h b/include/dt-bindings/mux/mux.h
> new file mode 100644
> index 0000000000..042719218d
> --- /dev/null
> +++ b/include/dt-bindings/mux/mux.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * This header provides constants for most Multiplexer bindings.
> + *
> + * Most Multiplexer bindings specify an idle state. In most cases, the
> + * the multiplexer can be left as is when idle, and in some cases it can
> + * disconnect the input/output and leave the multiplexer in a high
> + * impedance state.

<add more details...what is a mux?>

How do I use this API?

> + */
> +
> +#ifndef _DT_BINDINGS_MUX_MUX_H
> +#define _DT_BINDINGS_MUX_MUX_H
> +
> +#define MUX_IDLE_AS_IS      (-1)
> +#define MUX_IDLE_DISCONNECT (-2)
> +
> +#endif
> diff --git a/include/mux-internal.h b/include/mux-internal.h
> new file mode 100644
> index 0000000000..63444f4c3d
> --- /dev/null
> +++ b/include/mux-internal.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Based on the linux multiplexer framework
> + *
> + * Copyright (C) 2017 Axentia Technologies AB
> + * Author: Peter Rosin <peda@axentia.se>
> + *
> + * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
> + * Jean-Jacques Hiblot <jjhiblot@ti.com>
> + */
> +
> +#ifndef _MUX_UCLASS_H
> +#define _MUX_UCLASS_H
> +
> +/* See mux.h for background documentation. */
> +
> +#include <mux.h>
> +
> +struct ofnode_phandle_args;
> +
> +/**
> + * struct mux_chip -   Represents a chip holding mux controllers.
> + * @controllers:       Number of mux controllers handled by the chip.
> + * @mux:               Array of mux controllers that are handled.
> + * @dev:               Device structure.
> + * @ops:               Mux controller operations.

Mention that this is per-device uclass-private data.

> + */
> +struct mux_chip {
> +       unsigned int controllers;
> +       struct mux_control *mux;
> +};
> +
> +/**
> + * struct mux_control_ops -    Mux controller operations for a mux chip.
> + * @set:                       Set the state of the given mux controller.
> + */
> +struct mux_control_ops {
> +       int (*set)(struct mux_control *mux, int state);
> +       int (*of_xlate)(struct mux_chip *dev_mux,
> +                       struct ofnode_phandle_args *args,
> +                       struct mux_control **mux);

Function comments

> +};
> +
> +/**
> + * struct mux_control -        Represents a mux controller.
> + * @chip:              The mux chip that is handling this mux controller.
> + * @cached_state:      The current mux controller state, or -1 if none.
> + * @states:            The number of mux controller states.
> + * @idle_state:                The mux controller state to use when inactive, or one
> + *                     of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
> + *
> + * Mux drivers may only change @states and @idle_state, and may only do so
> + * between allocation and registration of the mux controller. Specifically,
> + * @cached_state is internal to the mux core and should never be written by
> + * mux drivers.

How do I get from a struct udevice * to this struct? Is it private data?

> + */
> +struct mux_control {
> +       bool    in_use;
> +       struct udevice *dev;
> +       int cached_state;
> +       unsigned int states;
> +       int idle_state;
> +       int id;
> +};
> +
> +/**
> + * mux_control_get_index() - Get the index of the given mux controller
> + * @mux: The mux-control to get the index for.
> + *
> + * Return: The index of the mux controller within the mux chip the mux
> + * controller is a part of.
> + */
> +static inline unsigned int mux_control_get_index(struct mux_control *mux)
> +{
> +       return mux->id;
> +}
> +
> +int mux_alloc_controllers(struct udevice *dev, unsigned int controllers);
> +
> +#endif

[..]

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 2/4] dm: board: complete the initialization of the muxes in initr_dm()
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 2/4] dm: board: complete the initialization of the muxes in initr_dm() Jean-Jacques Hiblot
@ 2019-10-30  1:48   ` Simon Glass
  2019-11-04 18:07     ` Jean-Jacques Hiblot
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2019-10-30  1:48 UTC (permalink / raw)
  To: u-boot

Hi Jean-Jacques,

On Wed, 2 Oct 2019 at 06:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> This will probe the multiplexer devices that have a "u-boot,mux-autoprobe"
> property. As a consequence they will be put in their idle state.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>
>  common/board_r.c | 2 ++
>  1 file changed, 2 insertions(+)

I worry this should happen later, or lazily, since at present we don't
actually probe any devices at this point, right?

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 3/4] drivers: mux: mmio-based syscon mux controller
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 3/4] drivers: mux: mmio-based syscon mux controller Jean-Jacques Hiblot
@ 2019-10-30  1:48   ` Simon Glass
  2019-11-04 18:15     ` Jean-Jacques Hiblot
  0 siblings, 1 reply; 15+ messages in thread
From: Simon Glass @ 2019-10-30  1:48 UTC (permalink / raw)
  To: u-boot

On Wed, 2 Oct 2019 at 06:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> This adds a driver for mmio-based syscon multiplexers controlled by
> bitfields in a syscon register range.
> This is heavily based on the linux mmio-mux driver.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>
>  drivers/mux/Kconfig  |  15 +++++
>  drivers/mux/Makefile |   1 +
>  drivers/mux/mmio.c   | 155 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 171 insertions(+)
>  create mode 100644 drivers/mux/mmio.c

Reviewed-by: Simon Glass <sjg@chromium.org>

So much memory allocation! But I suppose it is unavoidable. No way to
use DM's auto-alloc?

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices
  2019-10-30  1:48   ` Simon Glass
@ 2019-11-04 17:53     ` Jean-Jacques Hiblot
  0 siblings, 0 replies; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-11-04 17:53 UTC (permalink / raw)
  To: u-boot

Hi Simon,

Thank for the review.

On 30/10/2019 02:48, Simon Glass wrote:
> Hi Jean-Jacques,
>
> On Wed, 2 Oct 2019 at 06:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>> Add a new subsystem that handles multiplexer controllers. The API is the
>> same as in Linux.
>>
>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>> ---
>>
>>   drivers/Kconfig               |   2 +
>>   drivers/Makefile              |   1 +
>>   drivers/mux/Kconfig           |   7 +
>>   drivers/mux/Makefile          |   6 +
>>   drivers/mux/mux-uclass.c      | 296 ++++++++++++++++++++++++++++++++++
>>   include/dm/uclass-id.h        |   1 +
>>   include/dt-bindings/mux/mux.h |  17 ++
>>   include/mux-internal.h        |  80 +++++++++
>>   include/mux.h                 | 114 +++++++++++++
>>   9 files changed, 524 insertions(+)
>>   create mode 100644 drivers/mux/Kconfig
>>   create mode 100644 drivers/mux/Makefile
>>   create mode 100644 drivers/mux/mux-uclass.c
>>   create mode 100644 include/dt-bindings/mux/mux.h
>>   create mode 100644 include/mux-internal.h
>>   create mode 100644 include/mux.h
>>
> I feel this needs more documentation. What is a multiplexer?

I'll add a description of what a mux is in include/mux.h

>
>> diff --git a/drivers/Kconfig b/drivers/Kconfig
>> index 350acf81f3..5334974ad4 100644
>> --- a/drivers/Kconfig
>> +++ b/drivers/Kconfig
>> @@ -60,6 +60,8 @@ source "drivers/mmc/Kconfig"
>>
>>   source "drivers/mtd/Kconfig"
>>
>> +source "drivers/mux/Kconfig"
>> +
>>   source "drivers/net/Kconfig"
>>
>>   source "drivers/nvme/Kconfig"
>> diff --git a/drivers/Makefile b/drivers/Makefile
>> index a4bb5e4975..f4d71f3b3c 100644
>> --- a/drivers/Makefile
>> +++ b/drivers/Makefile
>> @@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_TPL_)INPUT) += input/
>>   obj-$(CONFIG_$(SPL_TPL_)LED) += led/
>>   obj-$(CONFIG_$(SPL_TPL_)MMC_SUPPORT) += mmc/
>>   obj-$(CONFIG_$(SPL_TPL_)NAND_SUPPORT) += mtd/nand/raw/
>> +obj-$(CONFIG_$(SPl_)MULTIPLEXER) += mux/
> SPL?
good catch
>
>>   obj-$(CONFIG_$(SPL_TPL_)PCH_SUPPORT) += pch/
>>   obj-$(CONFIG_$(SPL_TPL_)PCI) += pci/
>>   obj-$(CONFIG_$(SPL_TPL_)PHY) += phy/
>> diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig
>> new file mode 100644
>> index 0000000000..ad0199c058
>> --- /dev/null
>> +++ b/drivers/mux/Kconfig
>> @@ -0,0 +1,7 @@
>> +menu "Multiplexer drivers"
>> +
>> +config MULTIPLEXER
>> +       bool "Multiplexer Support"
>> +       depends on DM
>> +
>> +endmenu
>> diff --git a/drivers/mux/Makefile b/drivers/mux/Makefile
>> new file mode 100644
>> index 0000000000..351e4363d3
>> --- /dev/null
>> +++ b/drivers/mux/Makefile
>> @@ -0,0 +1,6 @@
>> +# SPDX-License-Identifier: GPL-2.0+
>> +#
>> +# (C) Copyright 2019
>> +# Jean-Jacques Hiblot <jjhiblot@ti.com>
>> +
>> +obj-$(CONFIG_$(SPL_)MULTIPLEXER) += mux-uclass.o
>> diff --git a/drivers/mux/mux-uclass.c b/drivers/mux/mux-uclass.c
>> new file mode 100644
>> index 0000000000..58998af29c
>> --- /dev/null
>> +++ b/drivers/mux/mux-uclass.c
>> @@ -0,0 +1,296 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Multiplexer subsystem
>> + *
>> + * Based on the linux multiplexer framework
>> + *
>> + * Copyright (C) 2017 Axentia Technologies AB
>> + * Author: Peter Rosin <peda@axentia.se>
>> + *
>> + * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
>> + * Jean-Jacques Hiblot <jjhiblot@ti.com>
>> + */
>> +
>> +#include <common.h>
>> +#include <mux-internal.h>
> should go above the dm/device-internal
>
>> +#include <dm.h>
>> +#include <dt-structs.h>
> Shouldn't need this
>> +#include <errno.h>
> Shouldn't need this
>
>> +#include <dm/device-internal.h>
>> +#include <dm/lists.h>
>> +#include <dm/read.h>
> Shouldn't need this
I'll cleanup the headers in v2.
>
>> +#include <dt-bindings/mux/mux.h>
>> +
>> +/*
>> + * The idle-as-is "state" is not an actual state that may be selected, it
>> + * only implies that the state should not be changed. So, use that state
>> + * as indication that the cached state of the multiplexer is unknown.
>> + */
>> +#define MUX_CACHE_UNKNOWN MUX_IDLE_AS_IS
>> +
>> +static inline const struct mux_control_ops *mux_dev_ops(struct udevice *dev)
>> +{
>> +       return (const struct mux_control_ops *)dev->driver->ops;
>> +}
>> +
>> +static int mux_control_set(struct mux_control *mux, int state)
>> +{
>> +       int ret = mux_dev_ops(mux->dev)->set(mux, state);
>> +
>> +       mux->cached_state = ret < 0 ? MUX_CACHE_UNKNOWN : state;
>> +
>> +       return ret;
>> +}
>> +
>> +unsigned int mux_control_states(struct mux_control *mux)
>> +{
>> +       return mux->states;
>> +}
>> +
>> +static int __mux_control_select(struct mux_control *mux, int state)
>> +{
>> +       int ret;
>> +
>> +       if (WARN_ON(state < 0 || state >= mux->states))
>> +               return -EINVAL;
>> +
>> +       if (mux->cached_state == state)
>> +               return 0;
>> +
>> +       ret = mux_control_set(mux, state);
>> +       if (ret >= 0)
>> +               return 0;
>> +
>> +       /* The mux update failed, try to revert if appropriate... */
>> +       if (mux->idle_state != MUX_IDLE_AS_IS)
>> +               mux_control_set(mux, mux->idle_state);
>> +
>> +       return ret;
>> +}
>> +
>> +int mux_control_select(struct mux_control *mux, unsigned int state)
>> +{
>> +       int ret;
>> +
>> +       if (mux->in_use)
>> +               return -EBUSY;
>> +
>> +       ret = __mux_control_select(mux, state);
>> +
>> +       if (ret < 0)
>> +               return ret;
>> +
>> +       mux->in_use = true;
>> +
>> +       return 0;
>> +}
>> +
>> +int mux_control_deselect(struct mux_control *mux)
>> +{
>> +       int ret = 0;
>> +
>> +       if (mux->idle_state != MUX_IDLE_AS_IS &&
>> +           mux->idle_state != mux->cached_state)
>> +               ret = mux_control_set(mux, mux->idle_state);
>> +
>> +       mux->in_use = false;
>> +
>> +       return ret;
>> +}
>> +
>> +static int mux_of_xlate_default(struct mux_chip *mux_chip,
>> +                               struct ofnode_phandle_args *args,
>> +                               struct mux_control **muxp)
>> +{
>> +       struct mux_control *mux;
>> +       int id;
>> +
>> +       debug("%s(mux=%p)\n", __func__, mux);
>> +
>> +       if (args->args_count > 1) {
>> +               debug("Invaild args_count: %d\n", args->args_count);
>> +               return -EINVAL;
>> +       }
>> +
>> +       if (args->args_count)
>> +               id = args->args[0];
>> +       else
>> +               id = 0;
>> +
>> +       if (id >= mux_chip->controllers) {
>> +               dev_err(dev, "bad mux controller %u specified in %s\n",
>> +                       id, ofnode_get_name(args->node));
>> +               return -ERANGE;
>> +       }
>> +
>> +       mux = &mux_chip->mux[id];
>> +       mux->id = id;
>> +       *muxp = mux;
>> +       return 0;
>> +}
>> +
>> +static int mux_get_by_indexed_prop(struct udevice *dev, const char *prop_name,
>> +                                  int index, struct mux_control **mux)
>> +{
>> +       int ret;
>> +       struct ofnode_phandle_args args;
>> +       struct udevice *dev_mux;
>> +       const struct mux_control_ops *ops;
>> +       struct mux_chip *mux_chip;
>> +
>> +       debug("%s(dev=%p, index=%d, mux=%p)\n", __func__, dev, index, mux);
>> +
>> +       ret = dev_read_phandle_with_args(dev, prop_name, "#mux-control-cells",
>> +                                        0, index, &args);
>> +       if (ret) {
>> +               debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
>> +                     __func__, ret);
>> +               return ret;
>> +       }
>> +
>> +       ret = uclass_get_device_by_ofnode(UCLASS_MUX, args.node, &dev_mux);
>> +       if (ret) {
>> +               debug("%s: uclass_get_device_by_ofnode failed: err=%d\n",
>> +                     __func__, ret);
>> +               return ret;
>> +       }
>> +
>> +       mux_chip = dev_get_uclass_priv(dev_mux);
>> +
>> +       ops = mux_dev_ops(dev_mux);
>> +       if (ops->of_xlate)
>> +               ret = ops->of_xlate(mux_chip, &args, mux);
>> +       else
>> +               ret = mux_of_xlate_default(mux_chip, &args, mux);
>> +       if (ret) {
>> +               debug("of_xlate() failed: %d\n", ret);
>> +               return ret;
>> +       }
>> +       (*mux)->dev = dev_mux;
>> +
>> +       return 0;
>> +}
>> +
>> +int mux_get_by_index(struct udevice *dev, int index, struct mux_control **mux)
>> +{
>> +       return mux_get_by_indexed_prop(dev, "mux-controls", index, mux);
>> +}
>> +
>> +int mux_control_get(struct udevice *dev, const char *name,
>> +                   struct mux_control **mux)
>> +{
>> +       int index;
>> +
>> +       debug("%s(dev=%p, name=%s, mux=%p)\n", __func__, dev, name, mux);
>> +
>> +       index = dev_read_stringlist_search(dev, "mux-control-names", name);
>> +       if (index < 0) {
>> +               debug("fdt_stringlist_search() failed: %d\n", index);
>> +               return index;
>> +       }
>> +
>> +       return mux_get_by_index(dev, index, mux);
>> +}
>> +
>> +void mux_control_put(struct mux_control *mux)
>> +{
>> +       mux_control_deselect(mux);
>> +}
>> +
>> +static void devm_mux_control_release(struct udevice *dev, void *res)
>> +{
>> +       mux_control_put(*(struct mux_control **)res);
>> +}
>> +
>> +struct mux_control *devm_mux_control_get(struct udevice *dev, const char *id)
>> +{
>> +       int rc;
>> +       struct mux_control **mux;
>> +
>> +       mux = devres_alloc(devm_mux_control_release,
>> +                          sizeof(struct mux_control *), __GFP_ZERO);
>> +       if (unlikely(!mux))
>> +               return ERR_PTR(-ENOMEM);
>> +
>> +       rc = mux_control_get(dev, id, mux);
>> +       if (rc)
>> +               return ERR_PTR(rc);
>> +
>> +       devres_add(dev, mux);
>> +       return *mux;
>> +}
>> +
>> +int mux_alloc_controllers(struct udevice *dev, unsigned int controllers)
>> +{
>> +       int i;
>> +       struct mux_chip *mux_chip = dev_get_uclass_priv(dev);
>> +
>> +       mux_chip->mux = devm_kmalloc(dev,
>> +                                    sizeof(struct mux_control) * controllers,
>> +                                    __GFP_ZERO);
>> +       if (!mux_chip->mux)
>> +               return -ENOMEM;
>> +
>> +       mux_chip->controllers = controllers;
>> +
>> +       for (i = 0; i < mux_chip->controllers; ++i) {
>> +               struct mux_control *mux = &mux_chip->mux[i];
>> +
>> +               mux->dev = dev;
>> +               mux->cached_state = MUX_CACHE_UNKNOWN;
>> +               mux->idle_state = MUX_IDLE_AS_IS;
>> +               mux->in_use = false;
>> +               mux->id = i;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +int mux_uclass_post_probe(struct udevice *dev)
>> +{
>> +       int i, ret;
>> +       struct mux_chip *mux_chip = dev_get_uclass_priv(dev);
>> +
>> +       for (i = 0; i < mux_chip->controllers; ++i) {
>> +               struct mux_control *mux = &mux_chip->mux[i];
>> +
>> +               if (mux->idle_state == mux->cached_state)
>> +                       continue;
>> +
>> +               ret = mux_control_set(mux, mux->idle_state);
>> +               if (ret < 0) {
>> +                       dev_err(&mux_chip->dev, "unable to set idle state\n");
>> +                       return ret;
>> +               }
>> +       }
>> +       return 0;
>> +}
>> +
>> +void dm_mux_init(void)
>> +{
>> +       struct uclass *uc;
>> +       struct udevice *dev;
>> +       int ret;
>> +
>> +       ret = uclass_get(UCLASS_MUX, &uc);
>> +       if (ret < 0) {
>> +               debug("unable to get MUX uclass\n");
>> +               return;
>> +       }
>> +       uclass_foreach_dev(dev, uc) {
>> +               if (dev_read_bool(dev, "u-boot,mux-autoprobe")) {
>> +                       ret = device_probe(dev);
>> +                       if (ret)
>> +                               debug("unable to probe device %s\n", dev->name);
>> +               } else {
>> +                       printf("not found for dev %s\n", dev->name);
>> +               }
>> +       }
>> +}
>> +
>> +UCLASS_DRIVER(mux) = {
>> +       .id             = UCLASS_MUX,
>> +       .name           = "mux",
>> +       .post_probe     = mux_uclass_post_probe,
>> +       .per_device_auto_alloc_size = sizeof(struct mux_chip),
>> +};
>> diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
>> index d4d96106b3..869c0616bd 100644
>> --- a/include/dm/uclass-id.h
>> +++ b/include/dm/uclass-id.h
>> @@ -64,6 +64,7 @@ enum uclass_id {
>>          UCLASS_MMC,             /* SD / MMC card or chip */
>>          UCLASS_MOD_EXP,         /* RSA Mod Exp device */
>>          UCLASS_MTD,             /* Memory Technology Device (MTD) device */
>> +       UCLASS_MUX,             /* Multiplexer device */
>>          UCLASS_NOP,             /* No-op devices */
>>          UCLASS_NORTHBRIDGE,     /* Intel Northbridge / SDRAM controller */
>>          UCLASS_NVME,            /* NVM Express device */
>> diff --git a/include/dt-bindings/mux/mux.h b/include/dt-bindings/mux/mux.h
>> new file mode 100644
>> index 0000000000..042719218d
>> --- /dev/null
>> +++ b/include/dt-bindings/mux/mux.h
>> @@ -0,0 +1,17 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * This header provides constants for most Multiplexer bindings.
>> + *
>> + * Most Multiplexer bindings specify an idle state. In most cases, the
>> + * the multiplexer can be left as is when idle, and in some cases it can
>> + * disconnect the input/output and leave the multiplexer in a high
>> + * impedance state.
> <add more details...what is a mux?>
>
> How do I use this API?
The API is described by the comments in include/mux.h
>
>> + */
>> +
>> +#ifndef _DT_BINDINGS_MUX_MUX_H
>> +#define _DT_BINDINGS_MUX_MUX_H
>> +
>> +#define MUX_IDLE_AS_IS      (-1)
>> +#define MUX_IDLE_DISCONNECT (-2)
>> +
>> +#endif
>> diff --git a/include/mux-internal.h b/include/mux-internal.h
>> new file mode 100644
>> index 0000000000..63444f4c3d
>> --- /dev/null
>> +++ b/include/mux-internal.h
>> @@ -0,0 +1,80 @@
>> +/* SPDX-License-Identifier: GPL-2.0+ */
>> +/*
>> + * Based on the linux multiplexer framework
>> + *
>> + * Copyright (C) 2017 Axentia Technologies AB
>> + * Author: Peter Rosin <peda@axentia.se>
>> + *
>> + * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
>> + * Jean-Jacques Hiblot <jjhiblot@ti.com>
>> + */
>> +
>> +#ifndef _MUX_UCLASS_H
>> +#define _MUX_UCLASS_H
>> +
>> +/* See mux.h for background documentation. */
>> +
>> +#include <mux.h>
>> +
>> +struct ofnode_phandle_args;
>> +
>> +/**
>> + * struct mux_chip -   Represents a chip holding mux controllers.
>> + * @controllers:       Number of mux controllers handled by the chip.
>> + * @mux:               Array of mux controllers that are handled.
>> + * @dev:               Device structure.
>> + * @ops:               Mux controller operations.
> Mention that this is per-device uclass-private data.
>
>> + */
>> +struct mux_chip {
>> +       unsigned int controllers;
>> +       struct mux_control *mux;
>> +};
>> +
>> +/**
>> + * struct mux_control_ops -    Mux controller operations for a mux chip.
>> + * @set:                       Set the state of the given mux controller.
>> + */
>> +struct mux_control_ops {
>> +       int (*set)(struct mux_control *mux, int state);
>> +       int (*of_xlate)(struct mux_chip *dev_mux,
>> +                       struct ofnode_phandle_args *args,
>> +                       struct mux_control **mux);
> Function comments
>
>> +};
>> +
>> +/**
>> + * struct mux_control -        Represents a mux controller.
>> + * @chip:              The mux chip that is handling this mux controller.
>> + * @cached_state:      The current mux controller state, or -1 if none.
>> + * @states:            The number of mux controller states.
>> + * @idle_state:                The mux controller state to use when inactive, or one
>> + *                     of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
>> + *
>> + * Mux drivers may only change @states and @idle_state, and may only do so
>> + * between allocation and registration of the mux controller. Specifically,
>> + * @cached_state is internal to the mux core and should never be written by
>> + * mux drivers.
> How do I get from a struct udevice * to this struct? Is it private data?

This is not private data per-se. It is intended to be used by a client 
device.

You get a mux_control* with mux_control_get() and devm_mux_control_get().


JJ

>
>> + */
>> +struct mux_control {
>> +       bool    in_use;
>> +       struct udevice *dev;
>> +       int cached_state;
>> +       unsigned int states;
>> +       int idle_state;
>> +       int id;
>> +};
>> +
>> +/**
>> + * mux_control_get_index() - Get the index of the given mux controller
>> + * @mux: The mux-control to get the index for.
>> + *
>> + * Return: The index of the mux controller within the mux chip the mux
>> + * controller is a part of.
>> + */
>> +static inline unsigned int mux_control_get_index(struct mux_control *mux)
>> +{
>> +       return mux->id;
>> +}
>> +
>> +int mux_alloc_controllers(struct udevice *dev, unsigned int controllers);
>> +
>> +#endif
> [..]
>
> Regards,
> Simon
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 2/4] dm: board: complete the initialization of the muxes in initr_dm()
  2019-10-30  1:48   ` Simon Glass
@ 2019-11-04 18:07     ` Jean-Jacques Hiblot
  2019-11-04 20:01       ` Simon Glass
  0 siblings, 1 reply; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-11-04 18:07 UTC (permalink / raw)
  To: u-boot


On 30/10/2019 02:48, Simon Glass wrote:
> Hi Jean-Jacques,
>
> On Wed, 2 Oct 2019 at 06:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>> This will probe the multiplexer devices that have a "u-boot,mux-autoprobe"
>> property. As a consequence they will be put in their idle state.
>>
>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>> ---
>>
>>   common/board_r.c | 2 ++
>>   1 file changed, 2 insertions(+)
> I worry this should happen later, or lazily, since at present we don't
> actually probe any devices at this point, right?

It has to be done early to make sure that the platform is in the right 
state before most of the drivers are initialized. Some devices may rely 
on it without knowing it. In this way, it is similar to the gpio-hog 
mechanism.

Now, I have no strong opinion on when this should really take place. 
Only it has to be after dm is initialized. Maybe it could be inserted in 
init_sequence_r, after board_init() ?

It should probably be before the serial port is used, just in case 
someone multiplexed the serial port of the console.


JJ


>
> Regards,
> Simon
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 3/4] drivers: mux: mmio-based syscon mux controller
  2019-10-30  1:48   ` Simon Glass
@ 2019-11-04 18:15     ` Jean-Jacques Hiblot
  0 siblings, 0 replies; 15+ messages in thread
From: Jean-Jacques Hiblot @ 2019-11-04 18:15 UTC (permalink / raw)
  To: u-boot

Simon,

On 30/10/2019 02:48, Simon Glass wrote:
> On Wed, 2 Oct 2019 at 06:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>> This adds a driver for mmio-based syscon multiplexers controlled by
>> bitfields in a syscon register range.
>> This is heavily based on the linux mmio-mux driver.
>>
>> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
>> ---
>>
>>   drivers/mux/Kconfig  |  15 +++++
>>   drivers/mux/Makefile |   1 +
>>   drivers/mux/mmio.c   | 155 +++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 171 insertions(+)
>>   create mode 100644 drivers/mux/mmio.c
> Reviewed-by: Simon Glass <sjg@chromium.org>
>
> So much memory allocation! But I suppose it is unavoidable. No way to
> use DM's auto-alloc?

I didn't try very hard to reduce the number of allocations to keep the 
code simple.

Part of the trouble comes from the fact that the number of mux_controls 
is read from the DT making it not possible to use the auto-alloc.

With other type of multiplexers (like a I2C or analog-lines multiplexer) 
the number of controls will be fixed and using auto-alloc will be possible.

JJ

>
> Regards,
> Simon
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 2/4] dm: board: complete the initialization of the muxes in initr_dm()
  2019-11-04 18:07     ` Jean-Jacques Hiblot
@ 2019-11-04 20:01       ` Simon Glass
  0 siblings, 0 replies; 15+ messages in thread
From: Simon Glass @ 2019-11-04 20:01 UTC (permalink / raw)
  To: u-boot

Hi Jean-Jacques,

On Mon, 4 Nov 2019 at 11:07, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
>
> On 30/10/2019 02:48, Simon Glass wrote:
> > Hi Jean-Jacques,
> >
> > On Wed, 2 Oct 2019 at 06:47, Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
> >> This will probe the multiplexer devices that have a "u-boot,mux-autoprobe"
> >> property. As a consequence they will be put in their idle state.
> >>
> >> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> >> ---
> >>
> >>   common/board_r.c | 2 ++
> >>   1 file changed, 2 insertions(+)
> > I worry this should happen later, or lazily, since at present we don't
> > actually probe any devices at this point, right?
>
> It has to be done early to make sure that the platform is in the right
> state before most of the drivers are initialized. Some devices may rely
> on it without knowing it. In this way, it is similar to the gpio-hog
> mechanism.
>
> Now, I have no strong opinion on when this should really take place.
> Only it has to be after dm is initialized. Maybe it could be inserted in
> init_sequence_r, after board_init() ?
>
> It should probably be before the serial port is used, just in case
> someone multiplexed the serial port of the console.

I hit a similar issue and created this patch, which I'll send soon.

https://gitlab.denx.de/u-boot/custodians/u-boot-dm/commit/087f241416bf7a1b65575840e02a3d270d4fa440

(actually it looks a bit broken, but hopefully you get the idea)

Regards,
Simon

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices
  2019-10-02 12:47 ` [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices Jean-Jacques Hiblot
  2019-10-30  1:48   ` Simon Glass
@ 2019-11-05  1:37   ` Bin Meng
  1 sibling, 0 replies; 15+ messages in thread
From: Bin Meng @ 2019-11-05  1:37 UTC (permalink / raw)
  To: u-boot

+Alex who once worked in MUX on LS1028 IIRC.

On Wed, Oct 2, 2019 at 8:47 PM Jean-Jacques Hiblot <jjhiblot@ti.com> wrote:
>
> Add a new subsystem that handles multiplexer controllers. The API is the
> same as in Linux.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
> ---
>
>  drivers/Kconfig               |   2 +
>  drivers/Makefile              |   1 +
>  drivers/mux/Kconfig           |   7 +
>  drivers/mux/Makefile          |   6 +
>  drivers/mux/mux-uclass.c      | 296 ++++++++++++++++++++++++++++++++++
>  include/dm/uclass-id.h        |   1 +
>  include/dt-bindings/mux/mux.h |  17 ++
>  include/mux-internal.h        |  80 +++++++++
>  include/mux.h                 | 114 +++++++++++++
>  9 files changed, 524 insertions(+)
>  create mode 100644 drivers/mux/Kconfig
>  create mode 100644 drivers/mux/Makefile
>  create mode 100644 drivers/mux/mux-uclass.c
>  create mode 100644 include/dt-bindings/mux/mux.h
>  create mode 100644 include/mux-internal.h
>  create mode 100644 include/mux.h
>

Regards,
Bin

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2019-11-05  1:37 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-02 12:47 [U-Boot] [PATCH v1 0/4] drivers: Add a framework for MUX drivers Jean-Jacques Hiblot
2019-10-02 12:47 ` [U-Boot] [PATCH v1 1/4] drivers: Add a new framework for multiplexer devices Jean-Jacques Hiblot
2019-10-30  1:48   ` Simon Glass
2019-11-04 17:53     ` Jean-Jacques Hiblot
2019-11-05  1:37   ` Bin Meng
2019-10-02 12:47 ` [U-Boot] [PATCH v1 2/4] dm: board: complete the initialization of the muxes in initr_dm() Jean-Jacques Hiblot
2019-10-30  1:48   ` Simon Glass
2019-11-04 18:07     ` Jean-Jacques Hiblot
2019-11-04 20:01       ` Simon Glass
2019-10-02 12:47 ` [U-Boot] [PATCH v1 3/4] drivers: mux: mmio-based syscon mux controller Jean-Jacques Hiblot
2019-10-30  1:48   ` Simon Glass
2019-11-04 18:15     ` Jean-Jacques Hiblot
2019-10-02 12:47 ` [U-Boot] [PATCH v1 4/4] test: Add tests for the multiplexer framework Jean-Jacques Hiblot
2019-10-24 23:45   ` Tom Rini
2019-10-25  9:32     ` Jean-Jacques Hiblot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.