This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/...
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
TODO:
- Proper device tree bindings for the connector, for now look at the example.
- Discuss whether to actually do this or just take it all and flush it down the drain because the community doesn't like it. I'm not one of those especially infatuated with my own code, I always stay by the old programming project management mantra to calculate to make one version and throw it away as stepping stone to a good final design.
- Placement: putting this in drivers/bus is just an example. drivers/platform/96boards-mezzanines is fine too, maybe better?
- I am especially curious about input from Andy and Mika from the Intel/ACPI camp on what they have seen for non-discoverable plug-in boards. Does this problem even exist in the Intel world, or not...
Background:
- These boards connect on a custom connector on this family of boards. The relationship is many-to-many with the connector as nexus. The electronic standard for the connector is specified: https://github.com/96boards/documentation/blob/master/Specifications/96Board... Example mezzanines: https://www.96boards.org/documentation/mezzanine/
- These boards have siblings on other platforms, the problem scope is similar with BeagleBone "capes": https://beagleboard.org/capes Raspberry Pi expansion boards: https://www.abelectronics.co.uk/products/18/raspberry-pi-expansion-boards Intel Edison, Galileo, Joule also have expansion boards.
Idea: add a driver for the connector itself and tie it in to the device tree with a compatible string. Since the boards are non-discoverable two mechanisms are provided to discover them:
- Add a very simple device tree node with just a compatible string for the board in the node. This will be simple to add from e.g. a boot loader or as an overlay from userspace.
board { compatible = "96boards,secure96"; };
- Echo 1 > boardname into a sysfs file to populate the board and echo 0 > boardname to depopulate it. This makes it easy to even switch out expansion boards at runtime, if allowed by the electronics.
cd /sys/devices/platform/connector echo 1 > secure96
lscon connector: called mezzanine_store on secure96 lscon connector: populate secure96 at24 1-0050: 2048 byte 24c128 EEPROM, writable, 128 bytes/write atmel-ecc 1-0060: configuration zone is unlocked tpm_tis_spi spi0.0: 2.0 TPM (device-id 0x1B, rev-id 16) (...)
What this patch set does not do:
- It does not use device tree or ACPI DSDT or any other hardware decription language to model the contents of the board per se. Instead the boards buses are populated directly with platform devices.
Predictable complaints about this design:
Q: This is not device tree overlays. Why is it not device tree overlays?
A1: Right tool for the job, overlays are complex and the plan to get it in place seems to be spanning years, this is a few devices on simple busses and it works today. Using this approach I can already work on shaping up drivers for the mezzanine board devices as proved by: https://marc.info/?l=linux-crypto-vger&m=152820660120590&w=2 https://marc.info/?l=linux-crypto-vger&m=152820662820595&w=2 (...)
I can work on drivers for the chips on the Secure96 mezzanine board. It's just an example of what the mezzanine community can do. Now they are hacking around in userspace instead of doing/reusing kernel drivers for their stuff: https://github.com/jbech-linaro/secure96
This way we can bring developers for these components into the kernel community instead of telling them to wait for some big infrastructure that comes later before they can contribute their stuff.
A2: Overlays does not solve the problem if the system runs ACPI, and what about if the same connector[s] appear on a server board, servers use ACPI. Also notice that Intel have development boards with non-discoverable expansion boards as well. They just will not use device tree.
A3: Overlays is Big Upfront Design. https://en.wikipedia.org/wiki/Big_Design_Up_Front This way of designing things is associated with the (pejorative term) "waterfall model" which is out of fashion as a way of doing development. I think I am not the only one slightly annoyed by the fact that device tree overlays is now starting to look like a very big very upfront design. It's just not possible to get something up and running in small iterative steps with device tree overlays. Instead huge efforts are required and it involves major possible showstoppers and uncertain outcome as indicated by Frank's TODO: https://elinux.org/Frank%27s_Evolving_Overlay_Thoughts
This appears also in our work process documents: Documentation/process/4.Coding.rst "experience has shown that excessive or premature abstraction can be just as harmful as premature optimization. Abstraction should be used to the level required and no further."
So for that reason, or other predictable statements such as "you're reinventing board files", I'd like to have an open discussion on how to actually support these boards with the mainline kernel and work on device drivers common with other systems now, and not in 2020 when they are already obsolete.
Yeah it is a bit controversial, but what we are doing right now for non-discoverable expansion boards isn't working in my opinion, so I have to throw something out there, and this is it.
Linus Walleij (5): RFC: gpio: Add API to explicitly name a consumer RFC: eeprom: at24: Allow passing gpiodesc from pdata RFC: spi: Make of_find_spi_device_by_node() available RFC: bus: 96boards Low-Speed Connector RFC: ARM64: dts: Add Low-Speed Connector to ZCU100
.../boot/dts/xilinx/zynqmp-zcu100-revC.dts | 27 +- .../96boards-ls-connector.c | 307 ++++++++++++++++++ .../96boards-mezzanines/96boards-mezzanines.h | 46 +++ .../96boards-mezzanines/96boards-secure96.c | 249 ++++++++++++++ drivers/bus/96boards-mezzanines/Kconfig | 36 ++ drivers/bus/96boards-mezzanines/Makefile | 6 + drivers/bus/Kconfig | 2 + drivers/bus/Makefile | 4 +- drivers/gpio/gpiolib.c | 13 + drivers/misc/eeprom/at24.c | 6 +- drivers/spi/spi.c | 33 +- include/linux/gpio/consumer.h | 7 + include/linux/platform_data/at24.h | 2 + include/linux/spi/spi.h | 4 + 14 files changed, 723 insertions(+), 19 deletions(-) create mode 100644 drivers/bus/96boards-mezzanines/96boards-ls-connector.c create mode 100644 drivers/bus/96boards-mezzanines/96boards-mezzanines.h create mode 100644 drivers/bus/96boards-mezzanines/96boards-secure96.c create mode 100644 drivers/bus/96boards-mezzanines/Kconfig create mode 100644 drivers/bus/96boards-mezzanines/Makefile
The GPIO (descriptor) API registers a "label" naming what is currently using the GPIO line. Typically this is taken from things like the device tree node, so "reset-gpios" will result in he line being labeled "reset".
The technical effect is pretty much zero: the use is for debug and introspection, such as "lsgpio" and debugfs files.
However sometimes the user want this cuddly feeling of listing all GPIO lines and seeing exactly what they are for and it gives a very fulfilling sense of control. Especially in the cases when the device tree node doesn't provide a good name, or anonymous GPIO lines assigned just to "gpios" in the device tree because the usage is implicit.
For these cases it may be nice to be able to label the line directly and explicitly.
Signed-off-by: Linus Walleij linus.walleij@linaro.org --- drivers/gpio/gpiolib.c | 13 +++++++++++++ include/linux/gpio/consumer.h | 7 +++++++ 2 files changed, 20 insertions(+)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e11a3bb03820..c6f77e806cb8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3193,6 +3193,19 @@ int gpiod_cansleep(const struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_cansleep);
+/** + * gpiod_set_consumer_name() - set the consumer name for the descriptor + * @desc: gpio to set the consumer name on + * @name: the new consumer name + */ +void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name) +{ + VALIDATE_DESC_VOID(desc); + /* Just overwrite whatever the previous name was */ + desc->label = name; +} +EXPORT_SYMBOL_GPL(gpiod_set_consumer_name); + /** * gpiod_to_irq() - return the IRQ corresponding to a GPIO * @desc: gpio whose IRQ will be returned (already requested) diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 243112c7fa7d..e8aaf34dd65d 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -145,6 +145,7 @@ int gpiod_is_active_low(const struct gpio_desc *desc); int gpiod_cansleep(const struct gpio_desc *desc);
int gpiod_to_irq(const struct gpio_desc *desc); +void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name);
/* Convert between the old gpio_ and new gpiod_ interfaces */ struct gpio_desc *gpio_to_desc(unsigned gpio); @@ -467,6 +468,12 @@ static inline int gpiod_to_irq(const struct gpio_desc *desc) return -EINVAL; }
+static inline void gpiod_set_consumer_name(struct gpio_desc *desc, const char *name) +{ + /* GPIO can never have been requested */ + WARN_ON(1); +} + static inline struct gpio_desc *gpio_to_desc(unsigned gpio) { return ERR_PTR(-EINVAL);
This makes it possible to pass an initialized GPIO descriptor to the driver through platform data.
This is useful when we are dealing with EEPROMs on expansion boards where the GPIO has to be looked up indirectly using a connector abstraction (several systems using the same connector) so the machine descriptor tables cannot be used to associate the descriptor with the device and we then want to pass this descriptor on to the EEPROM driver this way instead.
Signed-off-by: Linus Walleij linus.walleij@linaro.org --- drivers/misc/eeprom/at24.c | 6 +++++- include/linux/platform_data/at24.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index f5cc517d1131..d577cdbe221e 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -662,7 +662,11 @@ static int at24_probe(struct i2c_client *client) at24->client[0].client = client; at24->client[0].regmap = regmap;
- at24->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH); + if (pdata.wp_gpiod) + at24->wp_gpio = pdata.wp_gpiod; + else + at24->wp_gpio = + devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH); if (IS_ERR(at24->wp_gpio)) return PTR_ERR(at24->wp_gpio);
diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h index 63507ff464ee..5606fb2ef76c 100644 --- a/include/linux/platform_data/at24.h +++ b/include/linux/platform_data/at24.h @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/nvmem-consumer.h> #include <linux/bitops.h> +#include <linux/gpio/consumer.h>
/** * struct at24_platform_data - data to set up at24 (generic eeprom) driver @@ -55,6 +56,7 @@ struct at24_platform_data {
void (*setup)(struct nvmem_device *nvmem, void *context); void *context; + struct gpio_desc *wp_gpiod; };
#endif /* _LINUX_AT24_H */
On Mon, Jun 18, 2018 at 10:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This makes it possible to pass an initialized GPIO descriptor to the driver through platform data.
This is useful when we are dealing with EEPROMs on expansion boards where the GPIO has to be looked up indirectly using a connector abstraction (several systems using the same connector) so the machine descriptor tables cannot be used to associate the descriptor with the device and we then want to pass this descriptor on to the EEPROM driver this way instead.
How this descriptor is supposed to be created? Whenever we probe the device we might add properties to it (consider how MFD does instansiate them), I guess same way GPIO lookup tables work. No?
P.S. I really would like to hear a _strong_ argument why it can't be done using other means like built-in device properties or GPIO lookup tables (which on my opinion have to work in the similar way at run time).
This externalizes and exports the symbol of_find_spi_device_by_node() from the SPI core akin to how of_find_i2c_adapter_by_node() is already available. As we will need this also for non-dynamic OF setups, we move it under a CONFIG_OF check.
Signed-off-by: Linus Walleij linus.walleij@linaro.org --- drivers/spi/spi.c | 33 ++++++++++++++++++--------------- include/linux/spi/spi.h | 4 ++++ 2 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ec395a6baf9c..6a1085077317 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3314,27 +3314,14 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
/*-------------------------------------------------------------------------*/
-#if IS_ENABLED(CONFIG_OF_DYNAMIC) -static int __spi_of_device_match(struct device *dev, void *data) -{ - return dev->of_node == data; -} - -/* must call put_device() when done with returned spi_device device */ -static struct spi_device *of_find_spi_device_by_node(struct device_node *node) -{ - struct device *dev = bus_find_device(&spi_bus_type, NULL, node, - __spi_of_device_match); - return dev ? to_spi_device(dev) : NULL; -} - +#if IS_ENABLED(CONFIG_OF) static int __spi_of_controller_match(struct device *dev, const void *data) { return dev->of_node == data; }
/* the spi controllers are not using spi_bus, so we find it with another way */ -static struct spi_controller *of_find_spi_controller_by_node(struct device_node *node) +struct spi_controller *of_find_spi_controller_by_node(struct device_node *node) { struct device *dev;
@@ -3349,6 +3336,22 @@ static struct spi_controller *of_find_spi_controller_by_node(struct device_node /* reference got in class_find_device */ return container_of(dev, struct spi_controller, dev); } +EXPORT_SYMBOL_GPL(of_find_spi_controller_by_node); +#endif + +#if IS_ENABLED(CONFIG_OF_DYNAMIC) +static int __spi_of_device_match(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +/* must call put_device() when done with returned spi_device device */ +static struct spi_device *of_find_spi_device_by_node(struct device_node *node) +{ + struct device *dev = bus_find_device(&spi_bus_type, NULL, node, + __spi_of_device_match); + return dev ? to_spi_device(dev) : NULL; +}
static int of_spi_notify(struct notifier_block *nb, unsigned long action, void *arg) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index a64235e05321..c2be93224bd1 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -639,6 +639,10 @@ extern int devm_spi_register_controller(struct device *dev, struct spi_controller *ctlr); extern void spi_unregister_controller(struct spi_controller *ctlr);
+#if IS_ENABLED(CONFIG_OF) +struct spi_controller *of_find_spi_controller_by_node(struct device_node *node); +#endif + extern struct spi_controller *spi_busnum_to_master(u16 busnum);
/*
This illustrates my idea for using a small connector driver to plug in "mezzanine boards" on the 96boards low-speed connector.
These "mezzanine boards" are no different than "capes", "logic modules", etc. This thing, a non-discoverable connector where a user can plug in a few peripherals has been reinvented a few times.
As a proof-of-concept we add the Secure96, a quite minimal mezzanine board.
Users can register their boards in a simple way. Either just add their compatible-string in the device tree:
board { compatible = "96boards,secure96"; };
And if they can't even change three lines in their device tree, or if they at runtime decide to plug in some board and test it, they can use sysfs, as exemplified by plugging in the secure96 security board at runtime:
cd /sys/devices/platform/connector echo 1 > secure96
[ 61.014629] lscon connector: called mezzanine_store on secure96 [ 61.020530] lscon connector: populate secure96 [ 61.027081] at24 1-0050: 2048 byte 24c128 EEPROM, writable, 128 bytes/write [ 61.053569] atmel-ecc 1-0060: configuration zone is unlocked [ 61.502535] tpm_tis_spi spi0.0: 2.0 TPM (device-id 0x1B, rev-id 16) (...)
The plug-in board can be removed from sysfs and added back again multiple times like this with the devices being runtime added and removed by two writes to sysfs.
echo 0 > secure96 echo 1 > secure96 echo 0 > secure96
(...)
I certainly see some scalability problems with this particular code for example, but the fact is: it pretty much works. The devices need hooks in I2C and SPI, and need to be able to accept initialized GPIO descriptors passed in as platform data.
Any discussions related to the concept compared to doing device tree overlays/fragments etc: please discuss in patch 0 (the cover letter).
Signed-off-by: Linus Walleij linus.walleij@linaro.org --- .../96boards-ls-connector.c | 307 ++++++++++++++++++ .../96boards-mezzanines/96boards-mezzanines.h | 46 +++ .../96boards-mezzanines/96boards-secure96.c | 249 ++++++++++++++ drivers/bus/96boards-mezzanines/Kconfig | 36 ++ drivers/bus/96boards-mezzanines/Makefile | 6 + drivers/bus/Kconfig | 2 + drivers/bus/Makefile | 4 +- 7 files changed, 649 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/96boards-mezzanines/96boards-ls-connector.c create mode 100644 drivers/bus/96boards-mezzanines/96boards-mezzanines.h create mode 100644 drivers/bus/96boards-mezzanines/96boards-secure96.c create mode 100644 drivers/bus/96boards-mezzanines/Kconfig create mode 100644 drivers/bus/96boards-mezzanines/Makefile
diff --git a/drivers/bus/96boards-mezzanines/96boards-ls-connector.c b/drivers/bus/96boards-mezzanines/96boards-ls-connector.c new file mode 100644 index 000000000000..1a012b0cd457 --- /dev/null +++ b/drivers/bus/96boards-mezzanines/96boards-ls-connector.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 96boards Low-speed Connector driver + * (C) 2018 Linus Walleij linus.walleij@linaro.org + */ + +#include <linux/init.h> +#include <linux/sysfs.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include "96boards-mezzanines.h" + +/** + * struct mezzanine - daughter boards (mezzanines) data + * Having dynamic data here means that we can only plug ONE board + * of each type. Stacking two different boards is fine. This + * should be fixed using a linked list of mezzanines if we + * go for this solution. + */ +struct mezzanine { + const char *compatible; + const char *sysfs_name; + struct dev_ext_attribute ext_attr; + void * (*populate) (struct lscon *ls); + void (*depopulate) (void *data); + void *data; +}; + +static struct mezzanine mezzanines[] = { +#if IS_ENABLED(96BOARDS_SECURE96) + { + .compatible = "96boards,secure96", + .sysfs_name = "secure96", + .populate = secure96_populate, + .depopulate = secure96_depopulate, + }, +#endif + /* Add any other mezzanines here */ +}; + +struct gpio_desc *mezzanine_ls_get_gpiod(struct lscon *ls, + enum mezzanine_ls_gpio pin, + const char *consumer_name, + enum gpiod_flags flags) +{ + struct gpio_desc *retdesc; + + /* + * TODO: get all the LS GPIOs as an array on probe() then + * the consumers can skip error handling of IS_ERR() descriptors + * and this need only set the consumer name. + */ + retdesc = devm_gpiod_get_index(ls->dev, NULL, pin, flags); + if (!IS_ERR(retdesc) && consumer_name) + gpiod_set_consumer_name(retdesc, consumer_name); + + return retdesc; +} +EXPORT_SYMBOL_GPL(mezzanine_ls_get_gpiod); + +/* + * Mezzanine boards will call this to orderly remove their claimed + * gpio descriptors, since we acquired them all with devm_gpiod_get() + * they will eventually be released once this connector device + * disappears if the board do not release them in order. + */ +void mezzanine_ls_put_gpiod(struct lscon *ls, struct gpio_desc *gpiod) +{ + devm_gpiod_put(ls->dev, gpiod); +} +EXPORT_SYMBOL_GPL(mezzanine_ls_put_gpiod); + +static ssize_t mezzanine_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct lscon *ls = dev_get_drvdata(dev); + struct dev_ext_attribute *d = container_of(attr, + struct dev_ext_attribute, + attr); + struct mezzanine *mez = d->var; + + dev_info(ls->dev, "called %s on %s\n", __func__, mez->sysfs_name); + return 0; +} + +static ssize_t mezzanine_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lscon *ls = dev_get_drvdata(dev); + struct dev_ext_attribute *d = container_of(attr, + struct dev_ext_attribute, + attr); + struct mezzanine *mez = d->var; + unsigned long state; + int ret; + + dev_info(ls->dev, "called %s on %s\n", __func__, mez->sysfs_name); + + ret = kstrtoul(buf, 0, &state); + if (ret) + return ret; + + if (state == 1) { + void *data; + + /* Already populated */ + if (mez->data) + return count; + + data = mez->populate(ls); + if (IS_ERR(data)) + return PTR_ERR(data); + mez->data = data; + return count; + } + + if (state == 0) { + /* Not populated so nothing to do here */ + if (!mez->data) + return count; + mez->depopulate(mez->data); + mez->data = NULL; + return count; + } + + return -EINVAL; +} + +/** + * This adds one sysfs file per mezzanine board that we support, so they + * can be probed and added from userspace. + */ +static int lscon_add_sysfs_mezzanines(struct lscon *ls) +{ + struct mezzanine *mez; + struct dev_ext_attribute *ext_attr; + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(mezzanines); i++) { + mez = &mezzanines[i]; + ext_attr = &mez->ext_attr; + + ext_attr->var = mez; + ext_attr->attr.attr.name = mez->sysfs_name; + ext_attr->attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0644); + ext_attr->attr.show = mezzanine_show; + ext_attr->attr.store = mezzanine_store; + ret = device_create_file(ls->dev, &ext_attr->attr); + if (ret) + dev_err(ls->dev, "unable to create sysfs entries\n"); + + } + + return 0; +} + +static int lscon_probe_of_mezzanine(struct lscon *ls, struct device_node *np) +{ + struct mezzanine *mez; + void *data; + int i; + + for (i = 0; i < ARRAY_SIZE(mezzanines); i++) { + mez = &mezzanines[i]; + if (of_device_is_compatible(np, mez->compatible)) { + dev_info(ls->dev, "found %s\n", mez->compatible); + data = mez->populate(ls); + if (IS_ERR(data)) + return PTR_ERR(data); + mez->data = data; + return 0; + } + } + + return 0; +} + +static int lscon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child; + struct spi_controller *spi; + struct mezzanine *mez; + struct lscon *ls; + int ret; + int i; + + ls = devm_kzalloc(dev, sizeof(*ls), GFP_KERNEL); + if (!ls) + return -ENOMEM; + ls->dev = dev; + + /* Bridge I2C busses */ + child = of_parse_phandle(np, "i2c0", 0); + if (!child) { + dev_err(dev, "no i2c0 phandle\n"); + return -ENODEV; + } + ls->i2c0 = of_get_i2c_adapter_by_node(child); + if (!ls->i2c0) { + dev_err(dev, "no i2c0 adapter, deferring\n"); + return -EPROBE_DEFER; + } + + child = of_parse_phandle(np, "i2c1", 0); + if (!child) { + dev_err(dev, "no i2c1 phandle\n"); + ret = -ENODEV; + goto out_put_i2c0; + } + ls->i2c1 = of_get_i2c_adapter_by_node(child); + if (!ls->i2c1) { + dev_err(dev, "no i2c0 adapter, deferring\n"); + ret = -EPROBE_DEFER; + goto out_put_i2c0; + } + + /* Bride SPI bus */ + child = of_parse_phandle(np, "spi", 0); + if (!child) { + dev_err(dev, "no spi phandle\n"); + ret = -ENODEV; + goto out_put_i2c1; + } + spi = of_find_spi_controller_by_node(child); + if (!spi) { + dev_err(dev, "no spi controller, deferring\n"); + ret = -EPROBE_DEFER; + goto out_put_i2c1; + } + ls->spi = spi_controller_get(spi); + if (!ls->spi) { + dev_err(dev, "no spi reference\n"); + ret = -ENODEV; + goto out_put_i2c1; + } + + platform_set_drvdata(pdev, ls); + + /* Get the mezzanine boards, stacking possible */ + for_each_available_child_of_node(np, child) + lscon_probe_of_mezzanine(ls, child); + + ret = lscon_add_sysfs_mezzanines(ls); + if (ret) + goto out_remove_mezzanines; + + return 0; + +out_remove_mezzanines: + /* Depopulate any populated boards */ + for (i = 0; i < ARRAY_SIZE(mezzanines); i++) { + mez = &mezzanines[i]; + if (mez->data) + mez->depopulate(mez->data); + mez->data = NULL; + } +out_put_i2c1: + i2c_put_adapter(ls->i2c1); +out_put_i2c0: + i2c_put_adapter(ls->i2c0); + return ret; +} + +static int lscon_remove(struct platform_device *pdev) +{ + struct lscon *ls = platform_get_drvdata(pdev); + struct mezzanine *mez; + int i; + + /* Depopulate any populated boards */ + for (i = 0; i < ARRAY_SIZE(mezzanines); i++) { + mez = &mezzanines[i]; + if (mez->data) + mez->depopulate(mez->data); + mez->data = NULL; + } + + spi_controller_put(ls->spi); + i2c_put_adapter(ls->i2c1); + i2c_put_adapter(ls->i2c0); + + return 0; +} + +static const struct of_device_id lscon_of_match[] = { + { + .compatible = "96boards,low-speed-connector", + }, +}; + +static struct platform_driver lscon_driver = { + .driver = { + .name = "lscon", + .of_match_table = of_match_ptr(lscon_of_match), + }, + .probe = lscon_probe, + .remove = lscon_remove, +}; +builtin_platform_driver(lscon_driver); diff --git a/drivers/bus/96boards-mezzanines/96boards-mezzanines.h b/drivers/bus/96boards-mezzanines/96boards-mezzanines.h new file mode 100644 index 000000000000..f6a460766ff3 --- /dev/null +++ b/drivers/bus/96boards-mezzanines/96boards-mezzanines.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/of.h> +#include <linux/i2c.h> +#include <linux/gpio/consumer.h> + +/** + * enum mezzanine_ls_gpio - the GPIO lines on the low-speed connector + */ +enum mezzanine_ls_gpio { + MEZZANINE_LS_GPIO_A = 0, + MEZZANINE_LS_GPIO_B, + MEZZANINE_LS_GPIO_C, + MEZZANINE_LS_GPIO_D, + MEZZANINE_LS_GPIO_E, + MEZZANINE_LS_GPIO_F, + MEZZANINE_LS_GPIO_G, + MEZZANINE_LS_GPIO_H, + MEZZANINE_LS_GPIO_I, + MEZZANINE_LS_GPIO_J, + MEZZANINE_LS_GPIO_K, + MEZZANINE_LS_GPIO_L, +}; + +/** + * struct lscon - low speed connector state container + * @dev: containing device for this instance + */ +struct lscon { + struct device *dev; + struct i2c_adapter *i2c0; + struct i2c_adapter *i2c1; + struct spi_controller *spi; +}; + +struct gpio_desc *mezzanine_ls_get_gpiod(struct lscon *ls, + enum mezzanine_ls_gpio pin, + const char *consumer_name, + enum gpiod_flags flags); +void mezzanine_ls_put_gpiod(struct lscon *ls, struct gpio_desc *gpiod); + +#if IS_ENABLED(96BOARDS_SECURE96) +void *secure96_populate(struct lscon *ls); +void secure96_depopulate(void *data); +#endif +/* Add any other mezzanine population calls here */ diff --git a/drivers/bus/96boards-mezzanines/96boards-secure96.c b/drivers/bus/96boards-mezzanines/96boards-secure96.c new file mode 100644 index 000000000000..6c44a699d2e0 --- /dev/null +++ b/drivers/bus/96boards-mezzanines/96boards-secure96.c @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 96boards Secure96 mezzanine board driver + * (C) 2018 Linus Walleij linus.walleij@linaro.org + */ +#include <linux/gpio/consumer.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/sizes.h> +#include <linux/platform_data/at24.h> +#include <linux/delay.h> + +#include "96boards-mezzanines.h" + +struct secure96 { + struct device *dev; + struct lscon *ls; + struct platform_device *leds_device; + struct gpio_led *secure96_leds; + struct i2c_client *eeprom; + struct i2c_client *crypto; + struct i2c_client *hash; + struct gpio_desc *tpm_reset; + struct gpio_desc *tpm_irq; + struct spi_device *tpm; +}; + +struct secure96_ledinfo { + enum mezzanine_ls_gpio pin; + const char *ledname; +}; + +/* + * GPIO-F, G, H and I are connected to LEDs, two red and two green + */ +static const struct secure96_ledinfo ledinfos[] = { + { + .pin = MEZZANINE_LS_GPIO_F, + .ledname = "secure96:red:0", + }, + { + .pin = MEZZANINE_LS_GPIO_G, + .ledname = "secure96:red:1", + }, + { + .pin = MEZZANINE_LS_GPIO_H, + .ledname = "secure96:green:0", + }, + { + .pin = MEZZANINE_LS_GPIO_I, + .ledname = "secure96:green:1", + }, +}; + +/* + * The On Semiconductor CAT21M01 is 131072bits i.e. 16KB. This should be + * mostly compatible to 24c128 so we register that with special pdata so + * that we can fill in the GPIO descriptor for write protect. + */ +static struct at24_platform_data secure96_eeprom_pdata = { + .byte_len = SZ_16K / 8, + .page_size = 256, + .flags = AT24_FLAG_ADDR16, +}; + +static const struct i2c_board_info secure96_eeprom = { + I2C_BOARD_INFO("24c128", 0x50), + .platform_data = &secure96_eeprom_pdata, +}; + +/* Crypto chip */ +static const struct i2c_board_info secure96_crypto = { + I2C_BOARD_INFO("atecc508a", 0x60), +}; + +/* SHA hash chip */ +static const struct i2c_board_info secure96_hash = { + I2C_BOARD_INFO("atsha204a", 0x64), +}; + +/* Infineon SLB9670 TPM 2.0 chip */ +static struct spi_board_info secure96_tpm = { + .modalias = "tpm_tis_spi", + /* The manual says 22.5MHz for 1.8V supply */ + .max_speed_hz = 22500000, + .chip_select = 0, +}; + +void *secure96_populate(struct lscon *ls) +{ + struct device *dev = ls->dev; + struct secure96 *sec; + struct gpio_desc *gpiod; + struct gpio_led_platform_data secure96_leds_pdata; + int ret; + int i; + + /* TODO: create a struct device for secure96? */ + + sec = devm_kzalloc(dev, sizeof(*sec), GFP_KERNEL); + if (!sec) + return ERR_PTR(-ENOMEM); + sec->dev = dev; + sec->ls = ls; + + sec->secure96_leds = devm_kzalloc(dev, + ARRAY_SIZE(ledinfos) * sizeof(*sec->secure96_leds), + GFP_KERNEL); + if (!sec->secure96_leds) + return ERR_PTR(-ENOMEM); + + dev_info(ls->dev, "populate secure96\n"); + + /* Populate the four LEDs */ + for (i = 0; i < ARRAY_SIZE(ledinfos); i++) { + const struct secure96_ledinfo *linfo; + + linfo = &ledinfos[i]; + + gpiod = mezzanine_ls_get_gpiod(ls, linfo->pin, linfo->ledname, + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + dev_err(dev, "failed to get GPIO line %d\n", + linfo->pin); + return ERR_PTR(-ENODEV); + } + sec->secure96_leds[i].gpiod = gpiod; + sec->secure96_leds[i].name = linfo->ledname; + /* Heartbeat on first LED */ + if (i == 0) + sec->secure96_leds[i].default_trigger = "heartbeat"; + } + + secure96_leds_pdata.num_leds = ARRAY_SIZE(ledinfos); + secure96_leds_pdata.leds = sec->secure96_leds; + + sec->leds_device = platform_device_register_data(dev, + "leds-gpio", + PLATFORM_DEVID_AUTO, + &secure96_leds_pdata, + sizeof(secure96_leds_pdata)); + if (IS_ERR(sec->leds_device)) { + dev_err(dev, "failed to populate LEDs device\n"); + return ERR_PTR(-ENODEV); + } + + /* Populate the three I2C0 devices */ + gpiod = mezzanine_ls_get_gpiod(ls, MEZZANINE_LS_GPIO_B, "cat21m01-wp", + GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) + dev_err(dev, "no CAT21M01 write-protect GPIO\n"); + else + secure96_eeprom_pdata.wp_gpiod = gpiod; + sec->eeprom = i2c_new_device(ls->i2c0, &secure96_eeprom); + if (!sec->eeprom) { + dev_err(dev, "failed to populate EEPROM\n"); + ret = -ENODEV; + goto out_unreg_leds; + } + + sec->crypto = i2c_new_device(ls->i2c0, &secure96_crypto); + if (!sec->eeprom) { + dev_err(dev, "failed to populate crypto device\n"); + ret = -ENODEV; + goto out_remove_eeprom; + } + + sec->hash = i2c_new_device(ls->i2c0, &secure96_hash); + if (!sec->eeprom) { + dev_err(dev, "failed to populate hash device\n"); + ret = -ENODEV; + goto out_remove_crypto; + } + + /* Populate the SPI TPM device */ + gpiod = mezzanine_ls_get_gpiod(ls, MEZZANINE_LS_GPIO_D, + "tpm-slb9670-rst", + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + dev_err(dev, "failed to get TPM RESET\n"); + ret = -ENODEV; + goto out_remove_hash; + } + udelay(80); + /* Deassert RST */ + gpiod_set_value(gpiod, 1); + sec->tpm_reset = gpiod; + + gpiod = mezzanine_ls_get_gpiod(ls, MEZZANINE_LS_GPIO_C, + "tpm-slb9670-irq", + GPIOD_IN); + if (IS_ERR(gpiod)) { + dev_err(dev, "failed to get TPM IRQ GPIO\n"); + ret = -ENODEV; + goto out_remove_tpm_reset; + } + sec->tpm_irq = gpiod; + secure96_tpm.irq = gpiod_to_irq(gpiod); + sec->tpm = spi_new_device(ls->spi, &secure96_tpm); + if (!sec->tpm) { + dev_err(dev, "failed to populate TPM device\n"); + ret = -ENODEV; + goto out_remove_tpm_irq; + } + + return sec; + +out_remove_tpm_irq: + mezzanine_ls_put_gpiod(ls, sec->tpm_irq); +out_remove_tpm_reset: + mezzanine_ls_put_gpiod(ls, sec->tpm_reset); +out_remove_hash: + i2c_unregister_device(sec->hash); +out_remove_crypto: + i2c_unregister_device(sec->crypto); +out_remove_eeprom: + i2c_unregister_device(sec->eeprom); + if (secure96_eeprom_pdata.wp_gpiod) + mezzanine_ls_put_gpiod(ls, secure96_eeprom_pdata.wp_gpiod); +out_unreg_leds: + platform_device_unregister(sec->leds_device); + for (i = 0; i < ARRAY_SIZE(ledinfos); i++) { + mezzanine_ls_put_gpiod(ls, sec->secure96_leds[i].gpiod); + }; + return ERR_PTR(ret); +} +EXPORT_SYMBOL_GPL(secure96_populate); + +void secure96_depopulate(void *data) +{ + struct secure96 *sec = data; + int i; + + spi_unregister_device(sec->tpm); + mezzanine_ls_put_gpiod(sec->ls, sec->tpm_irq); + mezzanine_ls_put_gpiod(sec->ls, sec->tpm_reset); + i2c_unregister_device(sec->hash); + i2c_unregister_device(sec->crypto); + i2c_unregister_device(sec->eeprom); + if (secure96_eeprom_pdata.wp_gpiod) + mezzanine_ls_put_gpiod(sec->ls, secure96_eeprom_pdata.wp_gpiod); + platform_device_unregister(sec->leds_device); + for (i = 0; i < ARRAY_SIZE(ledinfos); i++) { + mezzanine_ls_put_gpiod(sec->ls, sec->secure96_leds[i].gpiod); + }; +} +EXPORT_SYMBOL_GPL(secure96_depopulate); diff --git a/drivers/bus/96boards-mezzanines/Kconfig b/drivers/bus/96boards-mezzanines/Kconfig new file mode 100644 index 000000000000..18f94e9ec0f8 --- /dev/null +++ b/drivers/bus/96boards-mezzanines/Kconfig @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# 96boards mezzanine connectors and drivers + +menuconfig 96BOARDS_MEZZANINES + bool "96boards mezzanine boards" + +if 96BOARDS_MEZZANINES + +config 96BOARDS_LS_CONNECTOR + bool "96boards low speed connector driver" + depends on OF + depends on I2C + depends on SPI_MASTER + depends on GPIOLIB + help + Driver for the 96boards low speed connector + +config 96BOARDS_SECURE96 + bool "96boards Secure96 board driver" + depends on 96BOARDS_LS_CONNECTOR + select NEW_LEDS + select LEDS_CLASS + select LEDS_GPIO + select EEPROM_AT24 + select CRYPTO_HW + select CRYPTO_DEV_ATMEL_ECC + select HW_RANDOM + select TCG_TPM + select HW_RANDOM_TPM + select TCG_TIS + select TCG_TIS_SPI + help + Driver for the 96boards Secure96 mezzanine + +endif diff --git a/drivers/bus/96boards-mezzanines/Makefile b/drivers/bus/96boards-mezzanines/Makefile new file mode 100644 index 000000000000..a6e1f3507672 --- /dev/null +++ b/drivers/bus/96boards-mezzanines/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the 96boards mezzanines +# +obj-$(CONFIG_96BOARDS_LS_CONNECTOR) += 96boards-ls-connector.o +obj-$(CONFIG_96BOARDS_SECURE96) += 96boards-secure96.o diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index d1c0b60e9326..46f7785f27e9 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -173,4 +173,6 @@ config DA8XX_MSTPRI
source "drivers/bus/fsl-mc/Kconfig"
+source "drivers/bus/96boards-mezzanines/Kconfig" + endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index b8f036cca7ff..f6d080a63bd7 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -29,5 +29,7 @@ obj-$(CONFIG_TI_SYSC) += ti-sysc.o obj-$(CONFIG_TS_NBUS) += ts-nbus.o obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o - obj-$(CONFIG_DA8XX_MSTPRI) += da8xx-mstpri.o + +# 96boards mezzanines +obj-$(CONFIG_96BOARDS_MEZZANINES) += 96boards-mezzanines/
On Mon, Jun 18, 2018 at 09:45:55AM +0200, Linus Walleij wrote:
This illustrates my idea for using a small connector driver to plug in "mezzanine boards" on the 96boards low-speed connector.
These "mezzanine boards" are no different than "capes", "logic modules", etc. This thing, a non-discoverable connector where a user can plug in a few peripherals has been reinvented a few times.
As a proof-of-concept we add the Secure96, a quite minimal mezzanine board.
Users can register their boards in a simple way. Either just add their compatible-string in the device tree:
board { compatible = "96boards,secure96"; };
And if they can't even change three lines in their device tree, or if they at runtime decide to plug in some board and test it, they can use sysfs, as exemplified by plugging in the secure96 security board at runtime:
cd /sys/devices/platform/connector echo 1 > secure96
[ 61.014629] lscon connector: called mezzanine_store on secure96 [ 61.020530] lscon connector: populate secure96 [ 61.027081] at24 1-0050: 2048 byte 24c128 EEPROM, writable, 128 bytes/write [ 61.053569] atmel-ecc 1-0060: configuration zone is unlocked [ 61.502535] tpm_tis_spi spi0.0: 2.0 TPM (device-id 0x1B, rev-id 16) (...)
The plug-in board can be removed from sysfs and added back again multiple times like this with the devices being runtime added and removed by two writes to sysfs.
echo 0 > secure96 echo 1 > secure96 echo 0 > secure96
(...)
Having a sysfs interface is useful (I certainly love being able to use sysfs to manage ad-hoc I2C chains).
However it feels like the current blurring between connector device and mezzanine device is shining through in this interface if only because the look and feel is very different to instantiating an I2C device from user-space.
Daniel.
This adds the low-speed connector to the ZCU100 rev C device tree (also known as the Ultra96 board).
This is a proof-of-concept only, showing how it is possible to populate a Secure96 board using the other patches in the series.
If you comment out or delete the board {} node, you can populate/depopulate the board from sysfs instead.
Signed-off-by: Linus Walleij linus.walleij@linaro.org --- .../boot/dts/xilinx/zynqmp-zcu100-revC.dts | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts index d62276e0e0a9..fc30497f248d 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts @@ -110,6 +110,28 @@ compatible = "mmc-pwrseq-simple"; reset-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; /* WIFI_EN */ }; + + lscon: connector { + compatible = "96boards,low-speed-connector"; + i2c0 = <&i2csw_0>; + i2c1 = <&i2csw_1>; + spi = <&spi0>; + gpios = <&gpio 36 GPIO_ACTIVE_HIGH>, /* GPIO-A */ + <&gpio 37 GPIO_ACTIVE_HIGH>, /* GPIO-B */ + <&gpio 39 GPIO_ACTIVE_HIGH>, /* GPIO-C */ + <&gpio 40 GPIO_ACTIVE_HIGH>, /* GPIO-D */ + <&gpio 44 GPIO_ACTIVE_HIGH>, /* GPIO-E */ + <&gpio 45 GPIO_ACTIVE_HIGH>, /* GPIO-F */ + <&gpio 78 GPIO_ACTIVE_HIGH>, /* GPIO-G */ + <&gpio 79 GPIO_ACTIVE_HIGH>, /* GPIO-H */ + <&gpio 80 GPIO_ACTIVE_HIGH>, /* GPIO-I */ + <&gpio 81 GPIO_ACTIVE_HIGH>, /* GPIO-J */ + <&gpio 82 GPIO_ACTIVE_HIGH>, /* GPIO-K */ + <&gpio 83 GPIO_ACTIVE_HIGH>; /* GPIO-L */ + board { + compatible = "96boards,secure96"; + }; + }; };
&dcc { @@ -134,8 +156,9 @@ "USB1_DIR", "USB1_DATA2", "USB1_NXT", "USB1_DATA0", "USB1_DATA1", "USB1_STP", "USB1_DATA3", "USB1_DATA4", "USB1_DATA5", "USB1_DATA6", "USB_DATA7", "WLAN_IRQ", "PMIC_IRQ", /* MIO end and EMIO start */ - "", "", - "", "", "", "", "", "", "", "", "", "", + "GPIO-G", "GPIO-H", + "GPIO-I", "GPIO-J", "GPIO-K", "GPIO-L", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+David G
On Mon, Jun 18, 2018 at 1:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This adds the low-speed connector to the ZCU100 rev C device tree (also known as the Ultra96 board).
This is a proof-of-concept only, showing how it is possible to populate a Secure96 board using the other patches in the series.
If you comment out or delete the board {} node, you can populate/depopulate the board from sysfs instead.
Signed-off-by: Linus Walleij linus.walleij@linaro.org
.../boot/dts/xilinx/zynqmp-zcu100-revC.dts | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts index d62276e0e0a9..fc30497f248d 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts @@ -110,6 +110,28 @@ compatible = "mmc-pwrseq-simple"; reset-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; /* WIFI_EN */ };
lscon: connector {
compatible = "96boards,low-speed-connector";
i2c0 = <&i2csw_0>;
i2c1 = <&i2csw_1>;
spi = <&spi0>;
David had suggested having an aliases node here for mapping things like SPI and I2C. That actually seems like a good use for aliases compared to the usual abuse to make Linux provide fixed numbering.
gpios = <&gpio 36 GPIO_ACTIVE_HIGH>, /* GPIO-A */
Why aren't you using gpio-map? This is what it was defined for.
<&gpio 37 GPIO_ACTIVE_HIGH>, /* GPIO-B */
<&gpio 39 GPIO_ACTIVE_HIGH>, /* GPIO-C */
<&gpio 40 GPIO_ACTIVE_HIGH>, /* GPIO-D */
<&gpio 44 GPIO_ACTIVE_HIGH>, /* GPIO-E */
<&gpio 45 GPIO_ACTIVE_HIGH>, /* GPIO-F */
<&gpio 78 GPIO_ACTIVE_HIGH>, /* GPIO-G */
<&gpio 79 GPIO_ACTIVE_HIGH>, /* GPIO-H */
<&gpio 80 GPIO_ACTIVE_HIGH>, /* GPIO-I */
<&gpio 81 GPIO_ACTIVE_HIGH>, /* GPIO-J */
<&gpio 82 GPIO_ACTIVE_HIGH>, /* GPIO-K */
<&gpio 83 GPIO_ACTIVE_HIGH>; /* GPIO-L */
board {
compatible = "96boards,secure96";
I'm all for putting things in the kernel/drivers for things we can't nail down bindings for, but it really seems like you are punting all the problems. Plus if we fully define how to handle the different bindings, we'll likely end up with something different and incompatible with what you have here.
Rob
On 18.6.2018 09:45, Linus Walleij wrote:
This adds the low-speed connector to the ZCU100 rev C device tree (also known as the Ultra96 board).
This is a proof-of-concept only, showing how it is possible to populate a Secure96 board using the other patches in the series.
If you comment out or delete the board {} node, you can populate/depopulate the board from sysfs instead.
Signed-off-by: Linus Walleij linus.walleij@linaro.org
.../boot/dts/xilinx/zynqmp-zcu100-revC.dts | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts index d62276e0e0a9..fc30497f248d 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts @@ -110,6 +110,28 @@ compatible = "mmc-pwrseq-simple"; reset-gpios = <&gpio 7 GPIO_ACTIVE_LOW>; /* WIFI_EN */ };
- lscon: connector {
compatible = "96boards,low-speed-connector";
i2c0 = <&i2csw_0>;
i2c1 = <&i2csw_1>;
spi = <&spi0>;
gpios = <&gpio 36 GPIO_ACTIVE_HIGH>, /* GPIO-A */
<&gpio 37 GPIO_ACTIVE_HIGH>, /* GPIO-B */
<&gpio 39 GPIO_ACTIVE_HIGH>, /* GPIO-C */
<&gpio 40 GPIO_ACTIVE_HIGH>, /* GPIO-D */
<&gpio 44 GPIO_ACTIVE_HIGH>, /* GPIO-E */
<&gpio 45 GPIO_ACTIVE_HIGH>, /* GPIO-F */
<&gpio 78 GPIO_ACTIVE_HIGH>, /* GPIO-G */
<&gpio 79 GPIO_ACTIVE_HIGH>, /* GPIO-H */
<&gpio 80 GPIO_ACTIVE_HIGH>, /* GPIO-I */
<&gpio 81 GPIO_ACTIVE_HIGH>, /* GPIO-J */
<&gpio 82 GPIO_ACTIVE_HIGH>, /* GPIO-K */
<&gpio 83 GPIO_ACTIVE_HIGH>; /* GPIO-L */
This connector has also 2 uarts which you should have here too.
Thanks, Michal
board {
compatible = "96boards,secure96";
};
- };
}; &dcc { @@ -134,8 +156,9 @@ "USB1_DIR", "USB1_DATA2", "USB1_NXT", "USB1_DATA0", "USB1_DATA1", "USB1_STP", "USB1_DATA3", "USB1_DATA4", "USB1_DATA5", "USB1_DATA6", "USB_DATA7", "WLAN_IRQ", "PMIC_IRQ", /* MIO end and EMIO start */
"", "",
"", "", "", "", "", "", "", "", "", "",
"GPIO-G", "GPIO-H",
"GPIO-I", "GPIO-J", "GPIO-K", "GPIO-L",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/...
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
Hi Linus,
Thanks for your work on solving this long-standing problem. I've just read through your patches briefly and have a few thoughts:
- I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
- I don't like the idea of having the bus driver contain a list of possible add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable modules, and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures etc, which could all be described as mezzanines. One open question is how we structure the commonality between the various connectors, but we can defer that until we have more than one or two of them.
Arnd
On 18 June 2018 at 14:21, Arnd Bergmann arnd@arndb.de wrote:
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/...
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
Hi Linus,
Thanks for your work on solving this long-standing problem. I've just read through your patches briefly and have a few thoughts:
I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
I don't like the idea of having the bus driver contain a list of possible add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable modules, and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures etc, which could all be described as mezzanines. One open question is how we structure the commonality between the various connectors, but we can defer that until we have more than one or two of them.
Hello all,
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use of it.
Also, given that we can (and do) already describe topologies involving mezzanines by ignoring the connector altogether (which is not entirely unreasonable given the fact that we [as Linaro/96boards] dropped the ball on this one and did not mandate discoverability for mezzanines). So ideally, DTs can be expressed such that older kernels can still use those peripherals.
On Mon, Jun 18, 2018 at 3:22 PM, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 18 June 2018 at 14:21, Arnd Bergmann arnd@arndb.de wrote:
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
Also, given that we can (and do) already describe topologies involving mezzanines by ignoring the connector altogether (which is not entirely unreasonable given the fact that we [as Linaro/96boards] dropped the ball on this one and did not mandate discoverability for mezzanines). So ideally, DTs can be expressed such that older kernels can still use those peripherals.
Not sure. Modeling the connector as a device with its own driver does seem like a significant advantage, which to me weighs more than backward compatibility with old kernels. We can clearly always describe the devices behind the connector individually and ignore the connector on old kernels and we should still allow running DT files that work with the old kernels on new kernels, but I don't see running new DT files on old kernels as essential in this case. Many platforms don't actually care about that case at all today (but some do of course).
Arnd
On 18.6.2018 16:15, Arnd Bergmann wrote:
On Mon, Jun 18, 2018 at 3:22 PM, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 18 June 2018 at 14:21, Arnd Bergmann arnd@arndb.de wrote:
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
Also, given that we can (and do) already describe topologies involving mezzanines by ignoring the connector altogether (which is not entirely unreasonable given the fact that we [as Linaro/96boards] dropped the ball on this one and did not mandate discoverability for mezzanines). So ideally, DTs can be expressed such that older kernels can still use those peripherals.
Not sure. Modeling the connector as a device with its own driver does seem like a significant advantage, which to me weighs more than backward compatibility with old kernels. We can clearly always describe the devices behind the connector individually and ignore the connector on old kernels and we should still allow running DT files that work with the old kernels on new kernels, but I don't see running new DT files on old kernels as essential in this case. Many platforms don't actually care about that case at all today (but some do of course).
Linus choose Ultra96 board which is showing that "standard" 96boards connector doesn't need to be standard in all cases. If you look at board schematics that you will see that loaded bitstream/configuration is making these connector compatible with 96boards spec. Almost the whole HS connector is connected to programmable logic and low speed connector is pretty much flexible too.
Also resource/power saving case should be considered. I will take uart mezzanine as an example which requires only 6 uart pins and one gpio. In Ultra96 that means that doesn't make sense to waste your fpga resources for something what you don't need. (Truth is that for low speed it is just about wires but with High speed connector MIPI is in PL part which consume a logic). And both connectors should also be handled together because some mezzanine cards require both of them.
Thanks, Michal
On 18 June 2018 at 14:22, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 18 June 2018 at 14:21, Arnd Bergmann arnd@arndb.de wrote:
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org
wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux
-integrator.git/log/?h=ultra96
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
Hi Linus,
Thanks for your work on solving this long-standing problem. I've just read through your patches briefly and have a few thoughts:
I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
I don't like the idea of having the bus driver contain a list of
possible
add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable modules, and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures etc, which could all be described as mezzanines. One open question is how we structure the commonality between the various connectors, but we can defer that until we have more than one or two of them.
Hello all,
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use of it.
Also, given that we can (and do) already describe topologies involving mezzanines by ignoring the connector altogether (which is not entirely unreasonable given the fact that we [as Linaro/96boards] dropped the ball on this one and did not mandate discoverability for mezzanines).
The design guideline has been reviewed by many inside/outside linaro through the mezzanine@lists.96boards.org and 96b-spec-sig < 96b-spec-sig@96boards.org> published as recommended/strongly recommended item from day one. 'dropping the ball' is a strong conclusion.
https://www.96boards.org/documentation/mezzanine/
So ideally, DTs can be expressed such that older kernels can still use those peripherals. _______________________________________________ Dev mailing list Dev@lists.96boards.org https://lists.96boards.org/mailman/listinfo/dev
On 19 June 2018 at 17:14, Yang Zhang yang.zhang@96boards.org wrote:
On 18 June 2018 at 14:22, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 18 June 2018 at 14:21, Arnd Bergmann arnd@arndb.de wrote:
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here:
https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/...
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
Hi Linus,
Thanks for your work on solving this long-standing problem. I've just read through your patches briefly and have a few thoughts:
I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
I don't like the idea of having the bus driver contain a list of
possible add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable modules, and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures etc, which could all be described as mezzanines. One open question is how we structure the commonality between the various connectors, but we can defer that until we have more than one or two of them.
Hello all,
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use of it.
Also, given that we can (and do) already describe topologies involving mezzanines by ignoring the connector altogether (which is not entirely unreasonable given the fact that we [as Linaro/96boards] dropped the ball on this one and did not mandate discoverability for mezzanines).
The design guideline has been reviewed by many inside/outside linaro through the mezzanine@lists.96boards.org and 96b-spec-sig 96b-spec-sig@96boards.org published as recommended/strongly recommended item from day one. 'dropping the ball' is a strong conclusion.
Apologies for using a term that you seem to take issue with. Are you saying the spec currently recommends it?
Yes.
https://github.com/96boards/documentation/blob/master/mezzanine/files/mezzan...
Under Configuration data section
On 19 June 2018 at 16:25, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 19 June 2018 at 17:14, Yang Zhang yang.zhang@96boards.org wrote:
On 18 June 2018 at 14:22, Ard Biesheuvel ard.biesheuvel@linaro.org
wrote:
On 18 June 2018 at 14:21, Arnd Bergmann arnd@arndb.de wrote:
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here:
linux-integrator.git/log/?h=ultra96
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
Hi Linus,
Thanks for your work on solving this long-standing problem. I've just read through your patches briefly and have a few thoughts:
I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
I don't like the idea of having the bus driver contain a list of
possible add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable
modules,
and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures
etc,
which could all be described as mezzanines. One open question is how we structure the commonality between the various connectors, but we can defer that until we have more than one or two of them.
Hello all,
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use of it.
Also, given that we can (and do) already describe topologies involving mezzanines by ignoring the connector altogether (which is not entirely unreasonable given the fact that we [as Linaro/96boards] dropped the ball on this one and did not mandate discoverability for mezzanines).
The design guideline has been reviewed by many inside/outside linaro
through
the mezzanine@lists.96boards.org and 96b-spec-sig 96b-spec-sig@96boards.org published as recommended/strongly
recommended
item from day one. 'dropping the ball' is a strong conclusion.
Apologies for using a term that you seem to take issue with. Are you saying the spec currently recommends it?
On 19 June 2018 at 17:26, Yang Zhang yang.zhang@96boards.org wrote:
Yes.
https://github.com/96boards/documentation/blob/master/mezzanine/files/mezzan...
Under Configuration data section
OK, fair enough. Do any such mezzanines exist yet? Should we offer more guidance on how exactly this discovery should be implemented?
On 19 June 2018 at 16:25, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 19 June 2018 at 17:14, Yang Zhang yang.zhang@96boards.org wrote:
On 18 June 2018 at 14:22, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 18 June 2018 at 14:21, Arnd Bergmann arnd@arndb.de wrote:
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here:
https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/...
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
Hi Linus,
Thanks for your work on solving this long-standing problem. I've just read through your patches briefly and have a few thoughts:
I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
I don't like the idea of having the bus driver contain a list of
possible add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable modules, and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures
etc, which could all be described as mezzanines. One open question is how we structure the commonality between the various connectors, but we can defer that until we have more than one or two of them.
Hello all,
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use of it.
Also, given that we can (and do) already describe topologies involving mezzanines by ignoring the connector altogether (which is not entirely unreasonable given the fact that we [as Linaro/96boards] dropped the ball on this one and did not mandate discoverability for mezzanines).
The design guideline has been reviewed by many inside/outside linaro through the mezzanine@lists.96boards.org and 96b-spec-sig 96b-spec-sig@96boards.org published as recommended/strongly recommended item from day one. 'dropping the ball' is a strong conclusion.
Apologies for using a term that you seem to take issue with. Are you saying the spec currently recommends it?
On 19 June 2018 at 16:30, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 19 June 2018 at 17:26, Yang Zhang yang.zhang@96boards.org wrote:
Yes.
mezzanine/files/mezzanine-design-guidelines.pdf
Under Configuration data section
OK, fair enough. Do any such mezzanines exist yet? Should we offer more guidance on how exactly this discovery should be implemented?
I can't be sure, could look into it - I know there were couple of from Arrow and ST were supporting this.
Yes, more details guidance of "How to" is always welcome :-).
On 19 June 2018 at 16:25, Ard Biesheuvel ard.biesheuvel@linaro.org
wrote:
On 19 June 2018 at 17:14, Yang Zhang yang.zhang@96boards.org wrote:
On 18 June 2018 at 14:22, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 18 June 2018 at 14:21, Arnd Bergmann arnd@arndb.de wrote:
On Mon, Jun 18, 2018 at 9:45 AM, Linus Walleij linus.walleij@linaro.org wrote: > This is a proposal for how to handle the non-discoverable > 96boards plug-in expansion boards called "mezzanines" in the > Linux kernel. It is a working RFC series meant for discussion > at the moment. > > The RFC was done on the brand new Ultra96 board from Xilinx > with a Secure96 mezzanine expansion board. The main part > is in patch 4, the rest is enabling and examples. > > The code can be obtained from here: > > > https://git.kernel.org/pub/scm/linux/kernel/git/linusw/
linux-integrator.git/log/?h=ultra96
> > You can for example probably augment the DTS file for any > upstream-supported 96board and get the Secure96 going with > it with minor efforts.
Hi Linus,
Thanks for your work on solving this long-standing problem. I've
just
read through your patches briefly and have a few thoughts:
I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
I don't like the idea of having the bus driver contain a list of
possible add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable modules, and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something
related
to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures etc, which could all be described as mezzanines. One open question is how we structure the commonality between the various connectors, but we can defer that until we have more than one or two of them.
Hello all,
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use
of
it.
Also, given that we can (and do) already describe topologies
involving
mezzanines by ignoring the connector altogether (which is not
entirely
unreasonable given the fact that we [as Linaro/96boards] dropped the ball on this one and did not mandate discoverability for mezzanines).
The design guideline has been reviewed by many inside/outside linaro through the mezzanine@lists.96boards.org and 96b-spec-sig 96b-spec-sig@96boards.org published as recommended/strongly recommended item from day one. 'dropping the ball' is a strong conclusion.
Apologies for using a term that you seem to take issue with. Are you saying the spec currently recommends it?
On 19.6.2018 17:32, Yang Zhang wrote:
On 19 June 2018 at 16:30, Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 19 June 2018 at 17:26, Yang Zhang yang.zhang@96boards.org wrote:
Yes.
mezzanine/files/mezzanine-design-guidelines.pdf
Under Configuration data section
OK, fair enough. Do any such mezzanines exist yet? Should we offer more guidance on how exactly this discovery should be implemented?
I can't be sure, could look into it - I know there were couple of from Arrow and ST were supporting this.
Yes, more details guidance of "How to" is always welcome :-).
Unfortunately this is not saying i2c address and also how to handle stacked solution.
I have told to Linus what Xilinx is using for FMC connector present on the most of xilinx development boards. These on board FMC eeproms contain information in FRU format. Also there incomplete support fmc support in the kernel in drivers/fmc which was added by Alessandro Rubini in 2013.
At least these eeprom could reuse FRU data format.
Thanks, Michal
On Fri, Jun 22, 2018 at 3:09 PM Michal Simek michal.simek@xilinx.com wrote:
I have told to Linus what Xilinx is using for FMC connector present on the most of xilinx development boards. These on board FMC eeproms contain information in FRU format. Also there incomplete support fmc support in the kernel in drivers/fmc which was added by Alessandro Rubini in 2013.
At least these eeprom could reuse FRU data format.
The FRU is a very tasteful design IMO and since it is a discoverable (plug and play!) bus I think we should have a clean FRU bus driver along Alessandro's suggestion to support them and spawn devices much like I do, as long as there is interest and some person who spends time writing the bus driver for it.
Yours, Linus Walleij
On Mon, Jun 18, 2018 at 3:22 PM Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use of it.
This problem: sharing or dedicating a piece of hardware to UEFI or the TrustZone secure world is a generic problem not related to mezzanines or plug-in boards specifically.
c.f. arch/arm64/boot/dts/arm/juno-motherboard.dtsi:
flash@0,00000000 { /* 2 * 32MiB NOR Flash memory mounted on CS0 */ compatible = "arm,vexpress-flash", "cfi-flash"; linux,part-probe = "afs"; reg = <0 0x00000000 0x04000000>; bank-width = <4>; /* * Unfortunately, accessing the flash disturbs * the CPU idle states (suspend) and CPU * hotplug of the platform. For this reason, * flash hardware access is disabled by default. */ status = "disabled"; };
What we need for this is something like
status = "secure-world-exclusive"; status = "UEFI-exclusive";
Or something like the same when using device tree.
If people probe this from sysfs (as in my example) they are obviously not novice users and they know what they are doing. For a simple user experience, I suspect device tree is what we want to use to populate defaults.
So ideally, DTs can be expressed such that older kernels can still use those peripherals.
That kind of expressions are possible already, such as putting the TPM DT node inside a SoC-specific I2C bus node. The boot loader can do that for example.
Then they can't also probe the same board from userspace, obviously. No matter whether they use the idea I present here or device tree overlays or anything else.
Yours, Linus Walleij
On 26 June 2018 at 10:09, Linus Walleij linus.walleij@linaro.org wrote:
On Mon, Jun 18, 2018 at 3:22 PM Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use of it.
This problem: sharing or dedicating a piece of hardware to UEFI or the TrustZone secure world is a generic problem not related to mezzanines or plug-in boards specifically.
c.f. arch/arm64/boot/dts/arm/juno-motherboard.dtsi:
flash@0,00000000 { /* 2 * 32MiB NOR Flash memory mounted on CS0 */ compatible = "arm,vexpress-flash", "cfi-flash"; linux,part-probe = "afs"; reg = <0 0x00000000 0x04000000>; bank-width = <4>; /* * Unfortunately, accessing the flash disturbs * the CPU idle states (suspend) and CPU * hotplug of the platform. For this reason, * flash hardware access is disabled by default. */ status = "disabled"; };
What we need for this is something like
status = "secure-world-exclusive"; status = "UEFI-exclusive";
Or something like the same when using device tree.
I agree that this is *also* a problem. But it is not what I was talking about.
My example is about peripherals that firmware and OS should both drive natively, and in the TPM case, the OS should be mindful of the fact that the measured state should be preserved. Also, it means that we may be duplicating functionality between the OS and firmware [as usual] so it might make sense to come up with something that takes both use cases into account.
If people probe this from sysfs (as in my example) they are obviously not novice users and they know what they are doing. For a simple user experience, I suspect device tree is what we want to use to populate defaults.
So ideally, DTs can be expressed such that older kernels can still use those peripherals.
That kind of expressions are possible already, such as putting the TPM DT node inside a SoC-specific I2C bus node. The boot loader can do that for example.
Then they can't also probe the same board from userspace, obviously. No matter whether they use the idea I present here or device tree overlays or anything else.
OK.
On Tue, Jun 26, 2018 at 10:19 AM Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
On 26 June 2018 at 10:09, Linus Walleij linus.walleij@linaro.org wrote:
On Mon, Jun 18, 2018 at 3:22 PM Ard Biesheuvel ard.biesheuvel@linaro.org wrote:
We should also consider firmware use of the mezzanines. For instance, the Secure96 has a RNG which UEFI may want to use so the early boot code can access is for KASLR. It also has a TPM, which should not be reset/reinitialized/etc by the OS if we want to make meaningful use of it.
This problem: sharing or dedicating a piece of hardware to UEFI or the TrustZone secure world is a generic problem not related to mezzanines or plug-in boards specifically.
(...)
I agree that this is *also* a problem. But it is not what I was talking about.
My example is about peripherals that firmware and OS should both drive natively, and in the TPM case, the OS should be mindful of the fact that the measured state should be preserved.
Ah I see.
In that case this is something the TPM driver should be doing I guess? I mean it is a "firmware plus OS TPM driver"-specific problem.
I guess that would be hard to duct-tape on if the peripheral is context-unaware and easy to do if the designer of the peripheral HW took multiple call-context into account. Whether TPM does this I don't know...
Also, it means that we may be duplicating functionality between the OS and firmware [as usual] so it might make sense to come up with something that takes both use cases into account.
What we are doing now with Atmel's ECC chip is even worse: duplicating functionality between OS and userspace. So I'm trying to solve that first.
Yours, Linus Walleij
On Mon, Jun 18, 2018 at 2:21 PM Arnd Bergmann arnd@arndb.de wrote:
- I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
This is my point of view as well.
- I don't like the idea of having the bus driver contain a list of possible add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable modules, and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
OK I think I can do that. It will take some thinking and I would guess I should also move it to drivers/platform/*
My idea here would be to have a connector bus that some random add-on (such as a 96board mezzanine) would probe to, so we make it generic for any connector plug.
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures etc, which could all be described as mezzanines.
Michal also brings up the (discoverable!) FMC connectors Xilinx are using. So the idea would be to create something generic to help probe and populate them all whether partly discoverable or not.
One open question is how we structure the commonality between the various connectors, but we can defer that until we have more than one or two of them.
I can clean up the namespace at least so it gets clear where to add them. I will try to be more generic in the next iteration.
Yours, Linus Walleij
On Tue, Jun 26, 2018 at 10:02 AM, Linus Walleij linus.walleij@linaro.org wrote:
On Mon, Jun 18, 2018 at 2:21 PM Arnd Bergmann arnd@arndb.de wrote:
- I really like the idea of having C code deal with the mezzanine connector itself, acting as an intermediate to tie a number of boards to a number of add-on cards, this seems much simpler than trying to do everything with overlays or one of the other more generic mechanisms.
This is my point of view as well.
- I don't like the idea of having the bus driver contain a list of possible add-ons, this seems to go against our usual driver model. What I think we want instead is to make the connector itself a proper bus_type, to allow drivers to register against it as loadable modules, and devices (maybe limited to one device) being created as probed from DT or some other method as you describe.
OK I think I can do that. It will take some thinking and I would guess I should also move it to drivers/platform/*
I'd probably leave it in drivers/bus/, though this might be one of the rare cases that drivers/platform makes sense for as well.
My idea here would be to have a connector bus that some random add-on (such as a 96board mezzanine) would probe to, so we make it generic for any connector plug.
The question here is whether we want one 'struct bus_type' instance shared by all connector types, or one for each type. I was actually leaning towards the latter here.
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures etc, which could all be described as mezzanines.
Michal also brings up the (discoverable!) FMC connectors Xilinx are using. So the idea would be to create something generic to help probe and populate them all whether partly discoverable or not.
If a bus is fully discoverable, I think it's better to use a separate bus_type that does not use DT based probing for its children. However, many buses (even USB and PCI) turn out to be only mostly discoverable, so we end up having to come up with a way to represent child devices in DT as well.
Arnd
On Tue, Jun 26, 2018 at 10:02:20AM +0200, Linus Walleij wrote:
On Mon, Jun 18, 2018 at 2:21 PM Arnd Bergmann arnd@arndb.de wrote:
- You export symbols in the mezzanine_* namespace, which I think is a bit too generic and should perhaps contain something related to 96boards in its name to make it less ambiguous. I suspect we would add a number of further connectors for hats, capes, lures etc, which could all be described as mezzanines.
Michal also brings up the (discoverable!) FMC connectors Xilinx are using. So the idea would be to create something generic to help probe and populate them all whether partly discoverable or not.
There's also the plug in modules in the Wolfson Cragganmore, there's enumeration support for that in mainline.
On Mon, Jun 18, 2018 at 09:45:51AM +0200, Linus Walleij wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/...
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
Like other commenters I'm rather like using C to solve this, and your comments Big Upfront Design are good backup in term of convincing me.
TODO:
Proper device tree bindings for the connector, for now look at the example.
Discuss whether to actually do this or just take it all and flush it down the drain because the community doesn't like it. I'm not one of those especially infatuated with my own code, I always stay by the old programming project management mantra to calculate to make one version and throw it away as stepping stone to a good final design.
Placement: putting this in drivers/bus is just an example. drivers/platform/96boards-mezzanines is fine too, maybe better?
I am especially curious about input from Andy and Mika from the Intel/ACPI camp on what they have seen for non-discoverable plug-in boards. Does this problem even exist in the Intel world, or not...
I'm also interested in the "what about ACPI" question?
Using C makes describing a board in ACPI fairly easy. AFAICT allocating IDs to a board rather than its included components is fairly natural for ACPI.
However I'm too ignorant to be able to figure out if the expansion connector itself could/should be described in the tables (e.g. if connector is a bus and the board is[1] a device, could the bus driver be instantiated in a reasonable way).
Daniel.
[1] ... or becomes a device, based on feedback in this thread ;-)
On Tue, Jun 19, 2018 at 12:10:18PM +0100, Daniel Thompson wrote:
On Mon, Jun 18, 2018 at 09:45:51AM +0200, Linus Walleij wrote:
- I am especially curious about input from Andy and Mika from the Intel/ACPI camp on what they have seen for non-discoverable plug-in boards. Does this problem even exist in the Intel world, or not...
I'm also interested in the "what about ACPI" question?
Using C makes describing a board in ACPI fairly easy. AFAICT allocating IDs to a board rather than its included components is fairly natural for ACPI.
Yes, they have this problem - they have plug in modules on for example the minnowboard and some of their other reference platforms. They have overlays working for ACPI, these have their own problems in that they don't appear to have the equivalent of DMI data (at least the patches people are sending indicates that they don't) which is unfortuate as the idiomatic thing for ACPI is as you say to key huge chunks of data of quirk tables based on the DMI information for their boards.
They don't to my knowledge have generic connectors or anything like that, it's just patches to the base ACPI.
On Mon, Jun 18, 2018 at 1:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/...
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
TODO:
Proper device tree bindings for the connector, for now look at the example.
Discuss whether to actually do this or just take it all and flush it down the drain because the community doesn't like it. I'm not one of those especially infatuated with my own code, I always stay by the old programming project management mantra to calculate to make one version and throw it away as stepping stone to a good final design.
Placement: putting this in drivers/bus is just an example. drivers/platform/96boards-mezzanines is fine too, maybe better?
I am especially curious about input from Andy and Mika from the Intel/ACPI camp on what they have seen for non-discoverable plug-in boards. Does this problem even exist in the Intel world, or not...
Background:
These boards connect on a custom connector on this family of boards. The relationship is many-to-many with the connector as nexus. The electronic standard for the connector is specified: https://github.com/96boards/documentation/blob/master/Specifications/96Board... Example mezzanines: https://www.96boards.org/documentation/mezzanine/
These boards have siblings on other platforms, the problem scope is similar with BeagleBone "capes": https://beagleboard.org/capes Raspberry Pi expansion boards: https://www.abelectronics.co.uk/products/18/raspberry-pi-expansion-boards Intel Edison, Galileo, Joule also have expansion boards.
Idea: add a driver for the connector itself and tie it in to the device tree with a compatible string. Since the boards are non-discoverable two mechanisms are provided to discover them:
Add a very simple device tree node with just a compatible string for the board in the node. This will be simple to add from e.g. a boot loader or as an overlay from userspace.
board { compatible = "96boards,secure96"; };
Echo 1 > boardname into a sysfs file to populate the board and echo 0 > boardname to depopulate it. This makes it easy to even switch out expansion boards at runtime, if allowed by the electronics.
cd /sys/devices/platform/connector echo 1 > secure96
lscon connector: called mezzanine_store on secure96 lscon connector: populate secure96 at24 1-0050: 2048 byte 24c128 EEPROM, writable, 128 bytes/write atmel-ecc 1-0060: configuration zone is unlocked tpm_tis_spi spi0.0: 2.0 TPM (device-id 0x1B, rev-id 16) (...)
What this patch set does not do:
- It does not use device tree or ACPI DSDT or any other hardware decription language to model the contents of the board per se. Instead the boards buses are populated directly with platform devices.
Predictable complaints about this design:
Q: This is not device tree overlays. Why is it not device tree overlays?
A1: Right tool for the job, overlays are complex and the plan to get it in place seems to be spanning years, this is a few devices on simple busses and it works today. Using this approach I can already work on shaping up drivers for the mezzanine board devices as proved by: https://marc.info/?l=linux-crypto-vger&m=152820660120590&w=2 https://marc.info/?l=linux-crypto-vger&m=152820662820595&w=2 (...)
I can work on drivers for the chips on the Secure96 mezzanine board. It's just an example of what the mezzanine community can do. Now they are hacking around in userspace instead of doing/reusing kernel drivers for their stuff: https://github.com/jbech-linaro/secure96 This way we can bring developers for these components into the kernel community instead of telling them to wait for some big infrastructure that comes later before they can contribute their stuff.
A2: Overlays does not solve the problem if the system runs ACPI, and what about if the same connector[s] appear on a server board, servers use ACPI. Also notice that Intel have development boards with non-discoverable expansion boards as well. They just will not use device tree.
A3: Overlays is Big Upfront Design. https://en.wikipedia.org/wiki/Big_Design_Up_Front This way of designing things is associated with the (pejorative term) "waterfall model" which is out of fashion as a way of doing development. I think I am not the only one slightly annoyed by the fact that device tree overlays is now starting to look like a very big very upfront design. It's just not possible to get something up and running in small iterative steps with device tree overlays. Instead huge efforts are required and it involves major possible showstoppers and uncertain outcome as indicated by Frank's TODO: https://elinux.org/Frank%27s_Evolving_Overlay_Thoughts
I don't agree. This can be broken down into various smaller mostly independent problems. Overlay handling is mostly an orthogonal problem. The exception is that we need to ensure bindings allow a decoupling of upstream of the connector and downstream of the connector so the downstream part can be a reusable overlay. Defining anything while ignoring this known criteria would be a mistake.
The list is roughly like this:
- Connector node binding and probing infrastructure - GPIO (already done w/ gpio-map binding) - I2C - SPI - Pinmux - clocks - OF graph (displays, cameras, etc.) - USB (re-use the USB connector binding for non-standard connectors) - Userspace interface
We don't have to support every interface from the start. The bindings and corresponding kernel support can be designed 1-by-1 for the most part. Start with something simple like a GPIO LED on a mezzanine. Once the base is functionality is there, the other parts can be worked on incrementally. We can punt any overlay handling to the bootloader initially. That punts all the issues around overlays like designing a userspace interface, where overlays are located (filesystem, passed from bootloader, built into the kernel), when they are loaded, and how to specify which overlays to load. Most of Frank's list is related to these issues.
Rob
On 06/19/18 08:52, Rob Herring wrote:
On Mon, Jun 18, 2018 at 1:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
The RFC was done on the brand new Ultra96 board from Xilinx with a Secure96 mezzanine expansion board. The main part is in patch 4, the rest is enabling and examples.
The code can be obtained from here: https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-integrator.git/...
You can for example probably augment the DTS file for any upstream-supported 96board and get the Secure96 going with it with minor efforts.
TODO:
Proper device tree bindings for the connector, for now look at the example.
Discuss whether to actually do this or just take it all and flush it down the drain because the community doesn't like it. I'm not one of those especially infatuated with my own code, I always stay by the old programming project management mantra to calculate to make one version and throw it away as stepping stone to a good final design.
Placement: putting this in drivers/bus is just an example. drivers/platform/96boards-mezzanines is fine too, maybe better?
I am especially curious about input from Andy and Mika from the Intel/ACPI camp on what they have seen for non-discoverable plug-in boards. Does this problem even exist in the Intel world, or not...
Background:
These boards connect on a custom connector on this family of boards. The relationship is many-to-many with the connector as nexus. The electronic standard for the connector is specified: https://github.com/96boards/documentation/blob/master/Specifications/96Board... Example mezzanines: https://www.96boards.org/documentation/mezzanine/
These boards have siblings on other platforms, the problem scope is similar with BeagleBone "capes": https://beagleboard.org/capes Raspberry Pi expansion boards: https://www.abelectronics.co.uk/products/18/raspberry-pi-expansion-boards Intel Edison, Galileo, Joule also have expansion boards.
Idea: add a driver for the connector itself and tie it in to the device tree with a compatible string. Since the boards are non-discoverable two mechanisms are provided to discover them:
Add a very simple device tree node with just a compatible string for the board in the node. This will be simple to add from e.g. a boot loader or as an overlay from userspace.
board { compatible = "96boards,secure96"; };
Echo 1 > boardname into a sysfs file to populate the board and echo 0 > boardname to depopulate it. This makes it easy to even switch out expansion boards at runtime, if allowed by the electronics.
cd /sys/devices/platform/connector echo 1 > secure96
lscon connector: called mezzanine_store on secure96 lscon connector: populate secure96 at24 1-0050: 2048 byte 24c128 EEPROM, writable, 128 bytes/write atmel-ecc 1-0060: configuration zone is unlocked tpm_tis_spi spi0.0: 2.0 TPM (device-id 0x1B, rev-id 16) (...)
What this patch set does not do:
- It does not use device tree or ACPI DSDT or any other hardware decription language to model the contents of the board per se. Instead the boards buses are populated directly with platform devices.
Predictable complaints about this design:
Q: This is not device tree overlays. Why is it not device tree overlays?
A1: Right tool for the job, overlays are complex and the plan to get it in place seems to be spanning years, this is a few devices on simple busses and it works today. Using this approach I can already work on shaping up drivers for the mezzanine board devices as proved by: https://marc.info/?l=linux-crypto-vger&m=152820660120590&w=2 https://marc.info/?l=linux-crypto-vger&m=152820662820595&w=2 (...)
I can work on drivers for the chips on the Secure96 mezzanine board. It's just an example of what the mezzanine community can do. Now they are hacking around in userspace instead of doing/reusing kernel drivers for their stuff: https://github.com/jbech-linaro/secure96 This way we can bring developers for these components into the kernel community instead of telling them to wait for some big infrastructure that comes later before they can contribute their stuff.
A2: Overlays does not solve the problem if the system runs ACPI, and what about if the same connector[s] appear on a server board, servers use ACPI. Also notice that Intel have development boards with non-discoverable expansion boards as well. They just will not use device tree.
A3: Overlays is Big Upfront Design. https://en.wikipedia.org/wiki/Big_Design_Up_Front This way of designing things is associated with the (pejorative term) "waterfall model" which is out of fashion as a way of doing development. I think I am not the only one slightly annoyed by the fact that device tree overlays is now starting to look like a very big very upfront design. It's just not possible to get something up and running in small iterative steps with device tree overlays. Instead huge efforts are required and it involves major possible showstoppers and uncertain outcome as indicated by Frank's TODO: https://elinux.org/Frank%27s_Evolving_Overlay_Thoughts
I don't agree. This can be broken down into various smaller mostly independent problems. Overlay handling is mostly an orthogonal problem. The exception is that we need to ensure bindings allow a decoupling of upstream of the connector and downstream of the connector so the downstream part can be a reusable overlay. Defining anything while ignoring this known criteria would be a mistake.
The list is roughly like this:
- Connector node binding and probing infrastructure
- GPIO (already done w/ gpio-map binding)
- I2C
- SPI
- Pinmux
- clocks
- OF graph (displays, cameras, etc.)
- USB (re-use the USB connector binding for non-standard connectors)
- Userspace interface
We don't have to support every interface from the start. The bindings and corresponding kernel support can be designed 1-by-1 for the most part. Start with something simple like a GPIO LED on a mezzanine. Once the base is functionality is there, the other parts can be worked on incrementally. We can punt any overlay handling to the bootloader initially. That punts all the issues around overlays like designing a userspace interface, where overlays are located (filesystem, passed from bootloader, built into the kernel), when they are loaded, and how to specify which overlays to load. Most of Frank's list is related to these issues.
Rob
Agreeing with Rob (despite my other reply asking why the current devicetree mechanisms can't be used) that we do have a desire to have the ability to create bindings for connectors - this has been discussed before.
-Frank
On Thu, Jun 21, 2018 at 3:02 PM Frank Rowand frowand.list@gmail.com wrote:
Agreeing with Rob (despite my other reply asking why the current devicetree mechanisms can't be used)
I think I answer also your comments in my reply to Rob, please check!
that we do have a desire to have the ability to create bindings for connectors - this has been discussed before.
Let's create bindings for connectors.
But I have this caveat: let's create a binding for connectors that does not stipulate that its children must be populated using overlays, but could optionally be bound to driver that populate the children any way the OS want to do this.
Yours, Linus Walleij
On Tue, Jun 19, 2018 at 5:52 PM Rob Herring robh+dt@kernel.org wrote:
On Mon, Jun 18, 2018 at 1:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
A3: Overlays is Big Upfront Design.
(...)
I don't agree. This can be broken down into various smaller mostly independent problems. Overlay handling is mostly an orthogonal problem. The exception is that we need to ensure bindings allow a decoupling of upstream of the connector and downstream of the connector so the downstream part can be a reusable overlay. Defining anything while ignoring this known criteria would be a mistake.
Hopefully we can make a connector binding that can be used in any way by the OS: either probe a board populating driver (such as in this patch set) or allow an overlay to be inserted (the aforementioned driver compiled out or inactive) further down the road. I would like to believe the board population problem is a both/and thing, not an either/or thing here.
Could be a simple as a compatible-string for the connector(s). We just keep it dirt simple.
The list is roughly like this:
- Connector node binding and probing infrastructure
- GPIO (already done w/ gpio-map binding)
I tested that actually, using the connector as nexus. It works fine. The problem I ran into was more practical (see below).
- I2C
- SPI
- Pinmux
- clocks
- OF graph (displays, cameras, etc.)
- USB (re-use the USB connector binding for non-standard connectors)
- Userspace interface
We don't have to support every interface from the start. The bindings and corresponding kernel support can be designed 1-by-1 for the most part. Start with something simple like a GPIO LED on a mezzanine.
I have that working today, I just didn't go beyond that.
It's because of usability issues. (Described below.)
Once the base is functionality is there, the other parts can be worked on incrementally. We can punt any overlay handling to the bootloader initially.
I didn't even do that. I just patched the DTS with a connector and booted it.
From a user point of view whether having a
patched up DTS or a boot loader modifying the DTB at run-time does not really matter as these boards are non-discoverable anyway. The boot loader will now know if they are there or not. What should the user do? Should they send command line arguments to U-Boot to say that we have the secure96 board? Flash different boot loaders depending on what board(s) are connected? That is even more awkward (IMO) than just modifying and redeploying the DTB.
The bright side of this patch set is that the user boots and the kernel is aware of there being a connector and presents sysfs files to populate the boards.
User goes "hm OK I have a secure96": cd /sys/bus/platform/devices/connector echo 1 > secure96
And there it populates.
No special boot loaders. No special tools.
That punts all the issues around overlays like designing a userspace interface, where overlays are located (filesystem, passed from bootloader, built into the kernel), when they are loaded, and how to specify which overlays to load. Most of Frank's list is related to these issues.
And that is where the user (also me) stops short.
Now I want to plug this board. OK download device tree compiler, author a fragment, compile it, compile a special userspace for inserting it into the right node, flash filesystem with that new userpace tool, also do not forget the DTB fragment, parameterize that tool to load the fragment into the connector node. Maybe the user need to change stuff on the fly? Hm then they need a text editor and a DT compiler on the target too, OK things like that can be done.
Admittedly the above is more versatile. Probably awesome when you need to populate a device forest on an FPGA.
But is that even a realistic usecase? And what about the average plug-in board user? If they can do the population by compiling a kernel driver for their board and say it's there and populate it with a simple echo into a sysfs file they will be happy.
It doesn't exclude (IMHO if done right) the possibility for a more complex device tree fragment approach to be substituted for this later, if it is better for the user. They just stop to compile in that kernel module for populating the board, or do not use the sysfs file.
IMO it is way better than "stop everything and fix fragments first". It's a stopgap thing, if overlays materialize later.
Yours, Linus Walleij
On Tue, Jun 26, 2018 at 8:36 AM Linus Walleij linus.walleij@linaro.org wrote:
On Tue, Jun 19, 2018 at 5:52 PM Rob Herring robh+dt@kernel.org wrote:
On Mon, Jun 18, 2018 at 1:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
A3: Overlays is Big Upfront Design.
(...)
I don't agree. This can be broken down into various smaller mostly independent problems. Overlay handling is mostly an orthogonal problem. The exception is that we need to ensure bindings allow a decoupling of upstream of the connector and downstream of the connector so the downstream part can be a reusable overlay. Defining anything while ignoring this known criteria would be a mistake.
Hopefully we can make a connector binding that can be used in any way by the OS: either probe a board populating driver (such as in this patch set) or allow an overlay to be inserted (the aforementioned driver compiled out or inactive) further down the road. I would like to believe the board population problem is a both/and thing, not an either/or thing here.
Certainly both can be supported. The base DT should be the same. I don't think populating via DT needs to be a further down the road thing. We're already further down the road...
Could be a simple as a compatible-string for the connector(s). We just keep it dirt simple.
Yes, that would be the most simple case. Not really any work to do there, so what's the point? Soon enough, we'll need to support all the things listed below and what we certainly don't need is each connector doing things their own way.
The list is roughly like this:
- Connector node binding and probing infrastructure
- GPIO (already done w/ gpio-map binding)
I tested that actually, using the connector as nexus. It works fine. The problem I ran into was more practical (see below).
- I2C
- SPI
- Pinmux
- clocks
- OF graph (displays, cameras, etc.)
- USB (re-use the USB connector binding for non-standard connectors)
- Userspace interface
We don't have to support every interface from the start. The bindings and corresponding kernel support can be designed 1-by-1 for the most part. Start with something simple like a GPIO LED on a mezzanine.
I have that working today, I just didn't go beyond that.
It's because of usability issues. (Described below.)
Once the base is functionality is there, the other parts can be worked on incrementally. We can punt any overlay handling to the bootloader initially.
I didn't even do that. I just patched the DTS with a connector and booted it.
Yes, or just do that. In any case, don't blame overlays for avoiding more fully defining connector bindings.
From a user point of view whether having a patched up DTS or a boot loader modifying the DTB at run-time does not really matter as these boards are non-discoverable anyway. The boot loader will now know if they are there or not. What should the user do? Should they send command line arguments to U-Boot to say that we have the secure96 board? Flash different boot loaders depending on what board(s) are connected? That is even more awkward (IMO) than just modifying and redeploying the DTB.
Ideally, it would be as simple as editing a syslinux style menu text file or setting an EFI variable. But yes, we do need to define exactly how that is done. It's something on the todo list for EBBR, but not going to happen until after the 1st release.
The bright side of this patch set is that the user boots and the kernel is aware of there being a connector and presents sysfs files to populate the boards.
User goes "hm OK I have a secure96": cd /sys/bus/platform/devices/connector echo 1 > secure96
And there it populates.
No special boot loaders. No special tools.
That punts all the issues around overlays like designing a userspace interface, where overlays are located (filesystem, passed from bootloader, built into the kernel), when they are loaded, and how to specify which overlays to load. Most of Frank's list is related to these issues.
And that is where the user (also me) stops short.
Now I want to plug this board. OK download device tree compiler, author a fragment, compile it, compile a special userspace for inserting it into the right node, flash filesystem with that new userpace tool, also do not forget the DTB fragment, parameterize that tool to load the fragment into the connector node. Maybe the user need to change stuff on the fly? Hm then they need a text editor and a DT compiler on the target too, OK things like that can be done.
With your series, they'd just have to edit and rebuild the kernel...
Admittedly the above is more versatile. Probably awesome when you need to populate a device forest on an FPGA.
But is that even a realistic usecase? And what about the average plug-in board user? If they can do the population by compiling a kernel driver for their board and say it's there and populate it with a simple echo into a sysfs file they will be happy.
Only a kernel developer would think compiling a kernel driver makes for a good usecase.
For users, I think all the board dtbs have to be on the filesystem and the user only has to set which ones to apply (when there is no eeprom to allow doing that automatically). That's essentially what you have on RPi today (though I've got issues with some of their overlays, but that's a whole other can of worms).
The other user usecase I think is custom or prototyping boards. For those cases, we probably do want some run-time interface which could be a kernel driver (as you have) or configfs overlay interface. But I'd start with the first usecase and worry about this one later.
Rob
+Pantelis
On 27.6.2018 17:23, Rob Herring wrote:
On Tue, Jun 26, 2018 at 8:36 AM Linus Walleij linus.walleij@linaro.org wrote:
On Tue, Jun 19, 2018 at 5:52 PM Rob Herring robh+dt@kernel.org wrote:
On Mon, Jun 18, 2018 at 1:45 AM, Linus Walleij linus.walleij@linaro.org wrote:
A3: Overlays is Big Upfront Design.
(...)
I don't agree. This can be broken down into various smaller mostly independent problems. Overlay handling is mostly an orthogonal problem. The exception is that we need to ensure bindings allow a decoupling of upstream of the connector and downstream of the connector so the downstream part can be a reusable overlay. Defining anything while ignoring this known criteria would be a mistake.
Hopefully we can make a connector binding that can be used in any way by the OS: either probe a board populating driver (such as in this patch set) or allow an overlay to be inserted (the aforementioned driver compiled out or inactive) further down the road. I would like to believe the board population problem is a both/and thing, not an either/or thing here.
Certainly both can be supported. The base DT should be the same. I don't think populating via DT needs to be a further down the road thing. We're already further down the road...
Could be a simple as a compatible-string for the connector(s). We just keep it dirt simple.
Yes, that would be the most simple case. Not really any work to do there, so what's the point? Soon enough, we'll need to support all the things listed below and what we certainly don't need is each connector doing things their own way.
The list is roughly like this:
- Connector node binding and probing infrastructure
- GPIO (already done w/ gpio-map binding)
I tested that actually, using the connector as nexus. It works fine. The problem I ran into was more practical (see below).
- I2C
- SPI
- Pinmux
- clocks
- OF graph (displays, cameras, etc.)
- USB (re-use the USB connector binding for non-standard connectors)
- Userspace interface
We don't have to support every interface from the start. The bindings and corresponding kernel support can be designed 1-by-1 for the most part. Start with something simple like a GPIO LED on a mezzanine.
I have that working today, I just didn't go beyond that.
It's because of usability issues. (Described below.)
Once the base is functionality is there, the other parts can be worked on incrementally. We can punt any overlay handling to the bootloader initially.
I didn't even do that. I just patched the DTS with a connector and booted it.
Yes, or just do that. In any case, don't blame overlays for avoiding more fully defining connector bindings.
From a user point of view whether having a patched up DTS or a boot loader modifying the DTB at run-time does not really matter as these boards are non-discoverable anyway. The boot loader will now know if they are there or not. What should the user do? Should they send command line arguments to U-Boot to say that we have the secure96 board? Flash different boot loaders depending on what board(s) are connected? That is even more awkward (IMO) than just modifying and redeploying the DTB.
Ideally, it would be as simple as editing a syslinux style menu text file or setting an EFI variable. But yes, we do need to define exactly how that is done. It's something on the todo list for EBBR, but not going to happen until after the 1st release.
The bright side of this patch set is that the user boots and the kernel is aware of there being a connector and presents sysfs files to populate the boards.
User goes "hm OK I have a secure96": cd /sys/bus/platform/devices/connector echo 1 > secure96
And there it populates.
No special boot loaders. No special tools.
That punts all the issues around overlays like designing a userspace interface, where overlays are located (filesystem, passed from bootloader, built into the kernel), when they are loaded, and how to specify which overlays to load. Most of Frank's list is related to these issues.
And that is where the user (also me) stops short.
Now I want to plug this board. OK download device tree compiler, author a fragment, compile it, compile a special userspace for inserting it into the right node, flash filesystem with that new userpace tool, also do not forget the DTB fragment, parameterize that tool to load the fragment into the connector node. Maybe the user need to change stuff on the fly? Hm then they need a text editor and a DT compiler on the target too, OK things like that can be done.
With your series, they'd just have to edit and rebuild the kernel...
Admittedly the above is more versatile. Probably awesome when you need to populate a device forest on an FPGA.
But is that even a realistic usecase? And what about the average plug-in board user? If they can do the population by compiling a kernel driver for their board and say it's there and populate it with a simple echo into a sysfs file they will be happy.
Only a kernel developer would think compiling a kernel driver makes for a good usecase.
For users, I think all the board dtbs have to be on the filesystem and the user only has to set which ones to apply (when there is no eeprom to allow doing that automatically). That's essentially what you have on RPi today (though I've got issues with some of their overlays, but that's a whole other can of worms).
The other user usecase I think is custom or prototyping boards. For those cases, we probably do want some run-time interface which could be a kernel driver (as you have) or configfs overlay interface. But I'd start with the first usecase and worry about this one later.
Pantelis had (I believe still have) configs overlay interface already. At least we are keep having it in xilinx soc tree.
Thanks, Michal
On 06/18/18 00:45, Linus Walleij wrote:
This is a proposal for how to handle the non-discoverable 96boards plug-in expansion boards called "mezzanines" in the Linux kernel. It is a working RFC series meant for discussion at the moment.
< snip >
So for that reason, or other predictable statements such as "you're reinventing board files", I'd like to have an open discussion on how to actually support these boards with the mainline kernel and work on device drivers common with other systems now, and not in 2020 when they are already obsolete.
Yeah it is a bit controversial, but what we are doing right now for non-discoverable expansion boards isn't working in my opinion, so I have to throw something out there, and this is it.
< snip >
why can't a devicetree description of the devices on the mezzanine board be used?
I do understand the desire to describe interchangeable mezzanine boards separately from the base devicetree, such as in an overlay. Overlays can be applied today by U-boot before the Linux kernel is booted, so lack of being able to apply an overlay after Linux boot completes is not a blocker.
-Frank