* [PATCH 2/2] pinctrl: add ZTE ZX pinctrl driver support
From: Shawn Guo @ 2017-04-24 13:01 UTC (permalink / raw)
To: Linus Walleij
Cc: Rob Herring, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Baoyou Xie,
Xin Zhou, Jun Nie, Shawn Guo
In-Reply-To: <1493038873-18354-1-git-send-email-shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
From: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
The pin controller on ZTE ZX platforms is kinda of hybrid. It consists
of a main controller and an auxiliary one. For example, on ZX296718 SoC,
the main controller is TOP_PMM and the auxiliary one is AON_IOCFG. Both
controllers work together to control pin multiplexing and configuration.
For most of pins, the pinmux function is controlled by main controller
only, and this type of pins are meant by term 'TOP pins'. For other
pins, the pinmux is controlled by both main and auxiliary controllers,
as the available multiplexing functions for the pin spread in both
controllers. This type of pins are called 'AON pins'. Though pinmux
implementation is quite different, pinconf is same for both types of
pins. Both are controlled by auxiliary controller, i.e. AON_IOCFG on
ZX296718.
The patch adds the ZTE ZX core pinctrl driver to support this hybrid
pin controller as well as ZX296718 SoC specific pin data.
Signed-off-by: Shawn Guo <shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/pinctrl/Kconfig | 1 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/zte/Kconfig | 13 +
drivers/pinctrl/zte/Makefile | 2 +
drivers/pinctrl/zte/pinctrl-zx.c | 445 ++++++++++++++
drivers/pinctrl/zte/pinctrl-zx.h | 105 ++++
drivers/pinctrl/zte/pinctrl-zx296718.c | 1027 ++++++++++++++++++++++++++++++++
7 files changed, 1594 insertions(+)
create mode 100644 drivers/pinctrl/zte/Kconfig
create mode 100644 drivers/pinctrl/zte/Makefile
create mode 100644 drivers/pinctrl/zte/pinctrl-zx.c
create mode 100644 drivers/pinctrl/zte/pinctrl-zx.h
create mode 100644 drivers/pinctrl/zte/pinctrl-zx296718.c
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af45781..97c202ba9a7a 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -304,6 +304,7 @@ source "drivers/pinctrl/ti/Kconfig"
source "drivers/pinctrl/uniphier/Kconfig"
source "drivers/pinctrl/vt8500/Kconfig"
source "drivers/pinctrl/mediatek/Kconfig"
+source "drivers/pinctrl/zte/Kconfig"
config PINCTRL_XWAY
bool
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f439626f..dce8ff892b23 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -57,3 +57,4 @@ obj-y += ti/
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
obj-$(CONFIG_ARCH_VT8500) += vt8500/
obj-$(CONFIG_PINCTRL_MTK) += mediatek/
+obj-$(CONFIG_PINCTRL_ZX) += zte/
diff --git a/drivers/pinctrl/zte/Kconfig b/drivers/pinctrl/zte/Kconfig
new file mode 100644
index 000000000000..0d97352a24ec
--- /dev/null
+++ b/drivers/pinctrl/zte/Kconfig
@@ -0,0 +1,13 @@
+config PINCTRL_ZX
+ bool
+ select PINMUX
+ select GENERIC_PINCONF
+ select GENERIC_PINCTRL_GROUPS
+ select GENERIC_PINMUX_FUNCTIONS
+
+config PINCTRL_ZX296718
+ bool "ZTE ZX296718 pinctrl driver"
+ depends on OF && ARCH_ZX
+ select PINCTRL_ZX
+ help
+ Say Y here to enable the ZX296718 pinctrl driver
diff --git a/drivers/pinctrl/zte/Makefile b/drivers/pinctrl/zte/Makefile
new file mode 100644
index 000000000000..c42e651d7a73
--- /dev/null
+++ b/drivers/pinctrl/zte/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PINCTRL_ZX) += pinctrl-zx.o
+obj-$(CONFIG_PINCTRL_ZX296718) += pinctrl-zx296718.o
diff --git a/drivers/pinctrl/zte/pinctrl-zx.c b/drivers/pinctrl/zte/pinctrl-zx.c
new file mode 100644
index 000000000000..2aca4e4b3f1c
--- /dev/null
+++ b/drivers/pinctrl/zte/pinctrl-zx.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2017 Sanechips Technology Co., Ltd.
+ * Copyright 2017 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+#include "../pinmux.h"
+#include "pinctrl-zx.h"
+
+#define ZX_PULL_DOWN BIT(0)
+#define ZX_PULL_UP BIT(1)
+#define ZX_INPUT_ENABLE BIT(3)
+#define ZX_DS_SHIFT 4
+#define ZX_DS_MASK (0x7 << ZX_DS_SHIFT)
+#define ZX_DS_VALUE(x) (((x) << ZX_DS_SHIFT) & ZX_DS_MASK)
+#define ZX_SLEW BIT(8)
+
+struct zx_pinctrl {
+ struct pinctrl_dev *pctldev;
+ struct device *dev;
+ void __iomem *base;
+ void __iomem *aux_base;
+ spinlock_t lock;
+ struct zx_pinctrl_soc_info *info;
+};
+
+static int zx_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, u32 *num_maps)
+{
+ return pinconf_generic_dt_node_to_map(pctldev, np_config, map,
+ num_maps, PIN_MAP_TYPE_INVALID);
+}
+
+static const struct pinctrl_ops zx_pinctrl_ops = {
+ .dt_node_to_map = zx_dt_node_to_map,
+ .dt_free_map = pinctrl_utils_free_map,
+ .get_groups_count = pinctrl_generic_get_group_count,
+ .get_group_name = pinctrl_generic_get_group_name,
+ .get_group_pins = pinctrl_generic_get_group_pins,
+};
+
+#define NONAON_MVAL 2
+
+static int zx_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
+ unsigned int group_selector)
+{
+ struct zx_pinctrl *zpctl = pinctrl_dev_get_drvdata(pctldev);
+ struct zx_pinctrl_soc_info *info = zpctl->info;
+ const struct pinctrl_pin_desc *pindesc = info->pins + group_selector;
+ struct zx_pin_data *data = pindesc->drv_data;
+ struct zx_mux_desc *mux = data->muxes;
+ u32 mask = (1 << data->width) - 1;
+ u32 offset = data->offset;
+ u32 bitpos = data->bitpos;
+ struct function_desc *func;
+ unsigned long flags;
+ u32 val, mval;
+
+ /* Skip reserved pin */
+ if (!data)
+ return -EINVAL;
+
+ func = pinmux_generic_get_function(pctldev, func_selector);
+ if (!func)
+ return -EINVAL;
+
+ while (mux->name) {
+ if (strcmp(mux->name, func->name) == 0)
+ break;
+ mux++;
+ }
+
+ /* Found mux value to be written */
+ mval = mux->muxval;
+
+ spin_lock_irqsave(&zpctl->lock, flags);
+
+ if (data->aon_pin) {
+ /*
+ * It's an AON pin, whose mux register offset and bit position
+ * can be caluculated from pin number. Each register covers 16
+ * pins, and each pin occupies 2 bits.
+ */
+ u16 aoffset = pindesc->number / 16 * 4;
+ u16 abitpos = (pindesc->number % 16) * 2;
+
+ if (mval & AON_MUX_FLAG) {
+ /*
+ * This is a mux value that needs to be written into
+ * AON pinmux register. Write it and then we're done.
+ */
+ val = readl(zpctl->aux_base + aoffset);
+ val &= ~(0x3 << abitpos);
+ val |= (mval & 0x3) << abitpos;
+ writel(val, zpctl->aux_base + aoffset);
+ } else {
+ /*
+ * It's a mux value that needs to be written into TOP
+ * pinmux register.
+ */
+ val = readl(zpctl->base + offset);
+ val &= ~(mask << bitpos);
+ val |= (mval & mask) << bitpos;
+ writel(val, zpctl->base + offset);
+
+ /*
+ * In this case, the AON pinmux register needs to be
+ * set up to select non-AON function.
+ */
+ val = readl(zpctl->aux_base + aoffset);
+ val &= ~(0x3 << abitpos);
+ val |= NONAON_MVAL << abitpos;
+ writel(val, zpctl->aux_base + aoffset);
+ }
+
+ } else {
+ /*
+ * This is a TOP pin, and we only need to set up TOP pinmux
+ * register and then we're done with it.
+ */
+ val = readl(zpctl->base + offset);
+ val &= ~(mask << bitpos);
+ val |= (mval & mask) << bitpos;
+ writel(val, zpctl->base + offset);
+ }
+
+ spin_unlock_irqrestore(&zpctl->lock, flags);
+
+ return 0;
+}
+
+static const struct pinmux_ops zx_pinmux_ops = {
+ .get_functions_count = pinmux_generic_get_function_count,
+ .get_function_name = pinmux_generic_get_function_name,
+ .get_function_groups = pinmux_generic_get_function_groups,
+ .set_mux = zx_set_mux,
+};
+
+static int zx_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *config)
+{
+ struct zx_pinctrl *zpctl = pinctrl_dev_get_drvdata(pctldev);
+ struct zx_pinctrl_soc_info *info = zpctl->info;
+ const struct pinctrl_pin_desc *pindesc = info->pins + pin;
+ struct zx_pin_data *data = pindesc->drv_data;
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u32 val;
+
+ /* Skip reserved pin */
+ if (!data)
+ return -EINVAL;
+
+ val = readl(zpctl->aux_base + data->coffset);
+ val = val >> data->cbitpos;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ val &= ZX_PULL_DOWN;
+ val = !!val;
+ if (val == 0)
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ val &= ZX_PULL_UP;
+ val = !!val;
+ if (val == 0)
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ val &= ZX_INPUT_ENABLE;
+ val = !!val;
+ if (val == 0)
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ val &= ZX_DS_MASK;
+ val = val >> ZX_DS_SHIFT;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ val &= ZX_SLEW;
+ val = !!val;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, val);
+
+ return 0;
+}
+
+static int zx_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int num_configs)
+{
+ struct zx_pinctrl *zpctl = pinctrl_dev_get_drvdata(pctldev);
+ struct zx_pinctrl_soc_info *info = zpctl->info;
+ const struct pinctrl_pin_desc *pindesc = info->pins + pin;
+ struct zx_pin_data *data = pindesc->drv_data;
+ enum pin_config_param param;
+ u32 val, arg;
+ int i;
+
+ /* Skip reserved pin */
+ if (!data)
+ return -EINVAL;
+
+ val = readl(zpctl->aux_base + data->coffset);
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ val |= ZX_PULL_DOWN << data->cbitpos;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ val |= ZX_PULL_UP << data->cbitpos;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ val |= ZX_INPUT_ENABLE << data->cbitpos;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ val &= ~(ZX_DS_MASK << data->cbitpos);
+ val |= ZX_DS_VALUE(arg) << data->cbitpos;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ if (arg)
+ val |= ZX_SLEW << data->cbitpos;
+ else
+ val &= ~ZX_SLEW << data->cbitpos;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ }
+
+ writel(val, zpctl->aux_base + data->coffset);
+ return 0;
+}
+
+static const struct pinconf_ops zx_pinconf_ops = {
+ .pin_config_set = zx_pin_config_set,
+ .pin_config_get = zx_pin_config_get,
+ .is_generic = true,
+};
+
+static int zx_pinctrl_build_state(struct platform_device *pdev)
+{
+ struct zx_pinctrl *zpctl = platform_get_drvdata(pdev);
+ struct zx_pinctrl_soc_info *info = zpctl->info;
+ struct pinctrl_dev *pctldev = zpctl->pctldev;
+ struct function_desc *functions;
+ int nfunctions;
+ struct group_desc *groups;
+ int ngroups;
+ int i;
+
+ /* Every single pin composes a group */
+ ngroups = info->npins;
+ groups = devm_kzalloc(&pdev->dev, ngroups * sizeof(*groups),
+ GFP_KERNEL);
+ if (!groups)
+ return -ENOMEM;
+
+ for (i = 0; i < ngroups; i++) {
+ const struct pinctrl_pin_desc *pindesc = info->pins + i;
+ struct group_desc *group = groups + i;
+ int id = pindesc->number;
+
+ group->name = pindesc->name;
+ group->pins = &id;
+ radix_tree_insert(&pctldev->pin_group_tree, i, group);
+ }
+
+ pctldev->num_groups = ngroups;
+
+ /* Build function list from pin mux functions */
+ functions = devm_kzalloc(&pdev->dev, info->npins * sizeof(*functions),
+ GFP_KERNEL);
+ if (!functions)
+ return -ENOMEM;
+
+ nfunctions = 0;
+ for (i = 0; i < info->npins; i++) {
+ const struct pinctrl_pin_desc *pindesc = info->pins + i;
+ struct zx_pin_data *data = pindesc->drv_data;
+ struct zx_mux_desc *mux;
+
+ /* Reserved pins do not have a drv_data at all */
+ if (!data)
+ continue;
+
+ /* Loop over all muxes for the pin */
+ mux = data->muxes;
+ while (mux->name) {
+ struct function_desc *func = functions;
+
+ /* Search function list for given mux */
+ while (func->name) {
+ if (strcmp(mux->name, func->name) == 0) {
+ /* Function exists */
+ func->num_group_names++;
+ break;
+ }
+ func++;
+ }
+
+ if (!func->name) {
+ /* New function */
+ func->name = mux->name;
+ func->num_group_names = 1;
+ radix_tree_insert(&pctldev->pin_function_tree,
+ nfunctions++, func);
+ }
+
+ mux++;
+ }
+ }
+
+ pctldev->num_functions = nfunctions;
+ functions = krealloc(functions, nfunctions * sizeof(*functions),
+ GFP_KERNEL);
+
+ /* Find pin groups for every single function */
+ for (i = 0; i < info->npins; i++) {
+ const struct pinctrl_pin_desc *pindesc = info->pins + i;
+ struct zx_pin_data *data = pindesc->drv_data;
+ struct zx_mux_desc *mux;
+
+ if (!data)
+ continue;
+
+ mux = data->muxes;
+ while (mux->name) {
+ struct function_desc *func;
+ const char **group;
+ int j;
+
+ /* Find function for given mux */
+ for (j = 0; j < nfunctions; j++)
+ if (strcmp(functions[j].name, mux->name) == 0)
+ break;
+
+ func = functions + j;
+ if (!func->group_names) {
+ func->group_names = devm_kzalloc(&pdev->dev,
+ func->num_group_names *
+ sizeof(*func->group_names),
+ GFP_KERNEL);
+ if (!func->group_names)
+ return -ENOMEM;
+ }
+
+ group = func->group_names;
+ while (*group)
+ group++;
+ *group = pindesc->name;
+
+ mux++;
+ }
+ }
+
+ return 0;
+}
+
+int zx_pinctrl_init(struct platform_device *pdev,
+ struct zx_pinctrl_soc_info *info)
+{
+ struct pinctrl_desc *pctldesc;
+ struct zx_pinctrl *zpctl;
+ struct device_node *np;
+ struct resource *res;
+ int ret;
+
+ zpctl = devm_kzalloc(&pdev->dev, sizeof(*zpctl), GFP_KERNEL);
+ if (!zpctl)
+ return -ENOMEM;
+
+ spin_lock_init(&zpctl->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ zpctl->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(zpctl->base))
+ return PTR_ERR(zpctl->base);
+
+ np = of_parse_phandle(pdev->dev.of_node, "zte,auxiliary-controller", 0);
+ if (!np) {
+ dev_err(&pdev->dev, "failed to find auxiliary controller\n");
+ return -ENODEV;
+ }
+
+ zpctl->aux_base = of_iomap(np, 0);
+ if (!zpctl->aux_base)
+ return -ENOMEM;
+
+ zpctl->dev = &pdev->dev;
+ zpctl->info = info;
+
+ pctldesc = devm_kzalloc(&pdev->dev, sizeof(*pctldesc), GFP_KERNEL);
+ if (!pctldesc)
+ return -ENOMEM;
+
+ pctldesc->name = dev_name(&pdev->dev);
+ pctldesc->owner = THIS_MODULE;
+ pctldesc->pins = info->pins;
+ pctldesc->npins = info->npins;
+ pctldesc->pctlops = &zx_pinctrl_ops;
+ pctldesc->pmxops = &zx_pinmux_ops;
+ pctldesc->confops = &zx_pinconf_ops;
+
+ zpctl->pctldev = devm_pinctrl_register(&pdev->dev, pctldesc, zpctl);
+ if (IS_ERR(zpctl->pctldev)) {
+ ret = PTR_ERR(zpctl->pctldev);
+ dev_err(&pdev->dev, "failed to register pinctrl: %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, zpctl);
+
+ ret = zx_pinctrl_build_state(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to build state: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "initialized pinctrl driver\n");
+ return 0;
+}
diff --git a/drivers/pinctrl/zte/pinctrl-zx.h b/drivers/pinctrl/zte/pinctrl-zx.h
new file mode 100644
index 000000000000..bc67e2be0503
--- /dev/null
+++ b/drivers/pinctrl/zte/pinctrl-zx.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 Sanechips Technology Co., Ltd.
+ * Copyright 2017 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PINCTRL_ZX_H
+#define __PINCTRL_ZX_H
+
+/**
+ * struct zx_mux_desc - hardware mux descriptor
+ * @name: mux function name
+ * @muxval: mux register bit value
+ */
+struct zx_mux_desc {
+ const char *name;
+ u8 muxval;
+};
+
+/**
+ * struct zx_pin_data - hardware per-pin data
+ * @aon_pin: whether it's an AON pin
+ * @offset: register offset within TOP pinmux controller
+ * @bitpos: bit position within TOP pinmux register
+ * @width: bit width within TOP pinmux register
+ * @coffset: pinconf register offset within AON controller
+ * @cbitpos: pinconf bit position within AON register
+ * @muxes: available mux function names and corresponding register values
+ *
+ * Unlike TOP pinmux and AON pinconf registers which are arranged pretty
+ * arbitrarily, AON pinmux register bits are well organized per pin id, and
+ * each pin occupies two bits, so that we can calculate the AON register offset
+ * and bit position from pin id. Thus, we only need to define TOP pinmux and
+ * AON pinconf register data for the pin.
+ */
+struct zx_pin_data {
+ bool aon_pin;
+ u16 offset;
+ u16 bitpos;
+ u16 width;
+ u16 coffset;
+ u16 cbitpos;
+ struct zx_mux_desc *muxes;
+};
+
+struct zx_pinctrl_soc_info {
+ const struct pinctrl_pin_desc *pins;
+ unsigned int npins;
+};
+
+#define TOP_PIN(pin, off, bp, wd, coff, cbp, ...) { \
+ .number = pin, \
+ .name = #pin, \
+ .drv_data = &(struct zx_pin_data) { \
+ .aon_pin = false, \
+ .offset = off, \
+ .bitpos = bp, \
+ .width = wd, \
+ .coffset = coff, \
+ .cbitpos = cbp, \
+ .muxes = (struct zx_mux_desc[]) { \
+ __VA_ARGS__, { } }, \
+ }, \
+}
+
+#define AON_PIN(pin, off, bp, wd, coff, cbp, ...) { \
+ .number = pin, \
+ .name = #pin, \
+ .drv_data = &(struct zx_pin_data) { \
+ .aon_pin = true, \
+ .offset = off, \
+ .bitpos = bp, \
+ .width = wd, \
+ .coffset = coff, \
+ .cbitpos = cbp, \
+ .muxes = (struct zx_mux_desc[]) { \
+ __VA_ARGS__, { } }, \
+ }, \
+}
+
+#define ZX_RESERVED(pin) PINCTRL_PIN(pin, #pin)
+
+#define TOP_MUX(_val, _name) { \
+ .name = _name, \
+ .muxval = _val, \
+}
+
+/*
+ * When the flag is set, it's a mux configuration for an AON pin that sits in
+ * AON register. Otherwise, it's one for AON pin but sitting in TOP register.
+ */
+#define AON_MUX_FLAG BIT(7)
+
+#define AON_MUX(_val, _name) { \
+ .name = _name, \
+ .muxval = _val | AON_MUX_FLAG, \
+}
+
+int zx_pinctrl_init(struct platform_device *pdev,
+ struct zx_pinctrl_soc_info *info);
+
+#endif /* __PINCTRL_ZX_H */
diff --git a/drivers/pinctrl/zte/pinctrl-zx296718.c b/drivers/pinctrl/zte/pinctrl-zx296718.c
new file mode 100644
index 000000000000..71efec17ee7e
--- /dev/null
+++ b/drivers/pinctrl/zte/pinctrl-zx296718.c
@@ -0,0 +1,1027 @@
+/*
+ * Copyright (C) 2017 Sanechips Technology Co., Ltd.
+ * Copyright 2017 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-zx.h"
+
+#define TOP_REG0 0x00
+#define TOP_REG1 0x04
+#define TOP_REG2 0x08
+#define TOP_REG3 0x0c
+#define TOP_REG4 0x10
+#define TOP_REG5 0x14
+#define TOP_REG6 0x18
+#define TOP_REG7 0x1c
+#define TOP_REG8 0x20
+
+/*
+ * The pin numbering starts from AON pins with reserved ones included,
+ * so that register data like offset and bit position for AON pins can
+ * be calculated from pin number.
+ */
+enum zx296718_pin {
+ /* aon_pmm_reg_0 */
+ I2C3_SCL = 0,
+ I2C3_SDA = 1,
+ AON_RESERVED0 = 2,
+ AON_RESERVED1 = 3,
+ SEC_EN = 4,
+ UART0_RXD = 5,
+ UART0_TXD = 6,
+ IR_IN = 7,
+ SPI0_CLK = 8,
+ SPI0_CS = 9,
+ SPI0_TXD = 10,
+ SPI0_RXD = 11,
+ KEY_COL0 = 12,
+ KEY_COL1 = 13,
+ KEY_COL2 = 14,
+ KEY_ROW0 = 15,
+
+ /* aon_pmm_reg_1 */
+ KEY_ROW1 = 16,
+ KEY_ROW2 = 17,
+ HDMI_SCL = 18,
+ HDMI_SDA = 19,
+ JTAG_TCK = 20,
+ JTAG_TRSTN = 21,
+ JTAG_TMS = 22,
+ JTAG_TDI = 23,
+ JTAG_TDO = 24,
+ I2C0_SCL = 25,
+ I2C0_SDA = 26,
+ I2C1_SCL = 27,
+ I2C1_SDA = 28,
+ AON_RESERVED2 = 29,
+ AON_RESERVED3 = 30,
+ AON_RESERVED4 = 31,
+
+ /* aon_pmm_reg_2 */
+ SPI1_CLK = 32,
+ SPI1_CS = 33,
+ SPI1_TXD = 34,
+ SPI1_RXD = 35,
+ AON_RESERVED5 = 36,
+ AON_RESERVED6 = 37,
+ AUDIO_DET = 38,
+ SPDIF_OUT = 39,
+ HDMI_CEC = 40,
+ HDMI_HPD = 41,
+ GMAC_25M_OUT = 42,
+ BOOT_SEL0 = 43,
+ BOOT_SEL1 = 44,
+ BOOT_SEL2 = 45,
+ DEEP_SLEEP_OUT_N = 46,
+ AON_RESERVED7 = 47,
+
+ /* top_pmm_reg_0 */
+ GMII_GTX_CLK = 48,
+ GMII_TX_CLK = 49,
+ GMII_TXD0 = 50,
+ GMII_TXD1 = 51,
+ GMII_TXD2 = 52,
+ GMII_TXD3 = 53,
+ GMII_TXD4 = 54,
+ GMII_TXD5 = 55,
+ GMII_TXD6 = 56,
+ GMII_TXD7 = 57,
+ GMII_TX_ER = 58,
+ GMII_TX_EN = 59,
+ GMII_RX_CLK = 60,
+ GMII_RXD0 = 61,
+ GMII_RXD1 = 62,
+ GMII_RXD2 = 63,
+
+ /* top_pmm_reg_1 */
+ GMII_RXD3 = 64,
+ GMII_RXD4 = 65,
+ GMII_RXD5 = 66,
+ GMII_RXD6 = 67,
+ GMII_RXD7 = 68,
+ GMII_RX_ER = 69,
+ GMII_RX_DV = 70,
+ GMII_COL = 71,
+ GMII_CRS = 72,
+ GMII_MDC = 73,
+ GMII_MDIO = 74,
+ SDIO1_CLK = 75,
+ SDIO1_CMD = 76,
+ SDIO1_DATA0 = 77,
+ SDIO1_DATA1 = 78,
+ SDIO1_DATA2 = 79,
+
+ /* top_pmm_reg_2 */
+ SDIO1_DATA3 = 80,
+ SDIO1_CD = 81,
+ SDIO1_WP = 82,
+ USIM1_CD = 83,
+ USIM1_CLK = 84,
+ USIM1_RST = 85,
+
+ /* top_pmm_reg_3 */
+ USIM1_DATA = 86,
+ SDIO0_CLK = 87,
+ SDIO0_CMD = 88,
+ SDIO0_DATA0 = 89,
+ SDIO0_DATA1 = 90,
+ SDIO0_DATA2 = 91,
+ SDIO0_DATA3 = 92,
+ SDIO0_CD = 93,
+ SDIO0_WP = 94,
+
+ /* top_pmm_reg_4 */
+ TSI0_DATA0 = 95,
+ SPINOR_CLK = 96,
+ TSI2_DATA = 97,
+ TSI2_CLK = 98,
+ TSI2_SYNC = 99,
+ TSI2_VALID = 100,
+ SPINOR_CS = 101,
+ SPINOR_DQ0 = 102,
+ SPINOR_DQ1 = 103,
+ SPINOR_DQ2 = 104,
+ SPINOR_DQ3 = 105,
+ VGA_HS = 106,
+ VGA_VS = 107,
+ TSI3_DATA = 108,
+
+ /* top_pmm_reg_5 */
+ TSI3_CLK = 109,
+ TSI3_SYNC = 110,
+ TSI3_VALID = 111,
+ I2S1_WS = 112,
+ I2S1_BCLK = 113,
+ I2S1_MCLK = 114,
+ I2S1_DIN0 = 115,
+ I2S1_DOUT0 = 116,
+ SPI3_CLK = 117,
+ SPI3_CS = 118,
+ SPI3_TXD = 119,
+ NAND_LDO_MS18_SEL = 120,
+
+ /* top_pmm_reg_6 */
+ SPI3_RXD = 121,
+ I2S0_MCLK = 122,
+ I2S0_BCLK = 123,
+ I2S0_WS = 124,
+ I2S0_DIN0 = 125,
+ I2S0_DOUT0 = 126,
+ I2C5_SCL = 127,
+ I2C5_SDA = 128,
+ SPI2_CLK = 129,
+ SPI2_CS = 130,
+ SPI2_TXD = 131,
+
+ /* top_pmm_reg_7 */
+ SPI2_RXD = 132,
+ NAND_WP_N = 133,
+ NAND_PAGE_SIZE0 = 134,
+ NAND_PAGE_SIZE1 = 135,
+ NAND_ADDR_CYCLE = 136,
+ NAND_RB0 = 137,
+ NAND_RB1 = 138,
+ NAND_RB2 = 139,
+ NAND_RB3 = 140,
+
+ /* top_pmm_reg_8 */
+ GMAC_125M_IN = 141,
+ GMAC_50M_OUT = 142,
+ SPINOR_SSCLK_LOOPBACK = 143,
+ SPINOR_SDIO1CLK_LOOPBACK = 144,
+};
+
+static const struct pinctrl_pin_desc zx296718_pins[] = {
+ /* aon_pmm_reg_0 */
+ AON_PIN(I2C3_SCL, TOP_REG2, 18, 2, 0x48, 0,
+ AON_MUX(0x0, "ANMI"), /* anmi */
+ AON_MUX(0x1, "AGPIO"), /* agpio29 */
+ AON_MUX(0x2, "nonAON"), /* pin0 */
+ AON_MUX(0x3, "EXT_INT"), /* int4 */
+ TOP_MUX(0x0, "I2C3"), /* scl */
+ TOP_MUX(0x1, "SPI2"), /* txd */
+ TOP_MUX(0x2, "I2S1")), /* din0 */
+ AON_PIN(I2C3_SDA, TOP_REG2, 20, 2, 0x48, 9,
+ AON_MUX(0x0, "WD"), /* rst_b */
+ AON_MUX(0x1, "AGPIO"), /* agpio30 */
+ AON_MUX(0x2, "nonAON"), /* pin1 */
+ AON_MUX(0x3, "EXT_INT"), /* int5 */
+ TOP_MUX(0x0, "I2C3"), /* sda */
+ TOP_MUX(0x1, "SPI2"), /* rxd */
+ TOP_MUX(0x2, "I2S0")), /* mclk */
+ ZX_RESERVED(AON_RESERVED0),
+ ZX_RESERVED(AON_RESERVED1),
+ AON_PIN(SEC_EN, TOP_REG3, 5, 1, 0x50, 0,
+ AON_MUX(0x0, "SEC"), /* en */
+ AON_MUX(0x1, "AGPIO"), /* agpio28 */
+ AON_MUX(0x2, "nonAON"), /* pin3 */
+ AON_MUX(0x3, "EXT_INT"), /* int7 */
+ TOP_MUX(0x0, "I2C2"), /* sda */
+ TOP_MUX(0x1, "SPI2")), /* cs */
+ AON_PIN(UART0_RXD, 0, 0, 0, 0x50, 9,
+ AON_MUX(0x0, "UART0"), /* rxd */
+ AON_MUX(0x1, "AGPIO"), /* agpio20 */
+ AON_MUX(0x2, "nonAON")), /* pin34 */
+ AON_PIN(UART0_TXD, 0, 0, 0, 0x50, 18,
+ AON_MUX(0x0, "UART0"), /* txd */
+ AON_MUX(0x1, "AGPIO"), /* agpio21 */
+ AON_MUX(0x2, "nonAON")), /* pin32 */
+ AON_PIN(IR_IN, 0, 0, 0, 0x64, 0,
+ AON_MUX(0x0, "IR"), /* in */
+ AON_MUX(0x1, "AGPIO"), /* agpio0 */
+ AON_MUX(0x2, "nonAON")), /* pin27 */
+ AON_PIN(SPI0_CLK, TOP_REG3, 16, 1, 0x64, 9,
+ AON_MUX(0x0, "EXT_INT"), /* int0 */
+ AON_MUX(0x1, "AGPIO"), /* agpio23 */
+ AON_MUX(0x2, "nonAON"), /* pin5 */
+ AON_MUX(0x3, "PCU"), /* test6 */
+ TOP_MUX(0x0, "SPI0"), /* clk */
+ TOP_MUX(0x1, "ISP")), /* flash_trig */
+ AON_PIN(SPI0_CS, TOP_REG3, 17, 1, 0x64, 18,
+ AON_MUX(0x0, "EXT_INT"), /* int1 */
+ AON_MUX(0x1, "AGPIO"), /* agpio24 */
+ AON_MUX(0x2, "nonAON"), /* pin6 */
+ AON_MUX(0x3, "PCU"), /* test0 */
+ TOP_MUX(0x0, "SPI0"), /* cs */
+ TOP_MUX(0x1, "ISP")), /* prelight_trig */
+ AON_PIN(SPI0_TXD, TOP_REG3, 18, 1, 0x68, 0,
+ AON_MUX(0x0, "EXT_INT"), /* int2 */
+ AON_MUX(0x1, "AGPIO"), /* agpio25 */
+ AON_MUX(0x2, "nonAON"), /* pin7 */
+ AON_MUX(0x3, "PCU"), /* test1 */
+ TOP_MUX(0x0, "SPI0"), /* txd */
+ TOP_MUX(0x1, "ISP")), /* shutter_trig */
+ AON_PIN(SPI0_RXD, TOP_REG3, 19, 1, 0x68, 9,
+ AON_MUX(0x0, "EXT_INT"), /* int3 */
+ AON_MUX(0x1, "AGPIO"), /* agpio26 */
+ AON_MUX(0x2, "nonAON"), /* pin8 */
+ AON_MUX(0x3, "PCU"), /* test2 */
+ TOP_MUX(0x0, "SPI0"), /* rxd */
+ TOP_MUX(0x1, "ISP")), /* shutter_open */
+ AON_PIN(KEY_COL0, TOP_REG3, 20, 1, 0x68, 18,
+ AON_MUX(0x0, "KEY"), /* col0 */
+ AON_MUX(0x1, "AGPIO"), /* agpio5 */
+ AON_MUX(0x2, "nonAON"), /* pin9 */
+ AON_MUX(0x3, "PCU"), /* test3 */
+ TOP_MUX(0x0, "UART3"), /* rxd */
+ TOP_MUX(0x1, "I2S0")), /* din1 */
+ AON_PIN(KEY_COL1, TOP_REG3, 21, 2, 0x6c, 0,
+ AON_MUX(0x0, "KEY"), /* col1 */
+ AON_MUX(0x1, "AGPIO"), /* agpio6 */
+ AON_MUX(0x2, "nonAON"), /* pin10 */
+ TOP_MUX(0x0, "UART3"), /* txd */
+ TOP_MUX(0x1, "I2S0"), /* din2 */
+ TOP_MUX(0x2, "VGA")), /* scl */
+ AON_PIN(KEY_COL2, TOP_REG3, 23, 2, 0x6c, 9,
+ AON_MUX(0x0, "KEY"), /* col2 */
+ AON_MUX(0x1, "AGPIO"), /* agpio7 */
+ AON_MUX(0x2, "nonAON"), /* pin11 */
+ TOP_MUX(0x0, "PWM"), /* out1 */
+ TOP_MUX(0x1, "I2S0"), /* din3 */
+ TOP_MUX(0x2, "VGA")), /* sda */
+ AON_PIN(KEY_ROW0, 0, 0, 0, 0x6c, 18,
+ AON_MUX(0x0, "KEY"), /* row0 */
+ AON_MUX(0x1, "AGPIO"), /* agpio8 */
+ AON_MUX(0x2, "nonAON"), /* pin33 */
+ AON_MUX(0x3, "WD")), /* rst_b */
+
+ /* aon_pmm_reg_1 */
+ AON_PIN(KEY_ROW1, TOP_REG3, 25, 2, 0x70, 0,
+ AON_MUX(0x0, "KEY"), /* row1 */
+ AON_MUX(0x1, "AGPIO"), /* agpio9 */
+ AON_MUX(0x2, "nonAON"), /* pin12 */
+ TOP_MUX(0x0, "LCD"), /* port0 lcd_te */
+ TOP_MUX(0x1, "I2S0"), /* dout2 */
+ TOP_MUX(0x2, "PWM"), /* out2 */
+ TOP_MUX(0x3, "VGA")), /* hs1 */
+ AON_PIN(KEY_ROW2, TOP_REG3, 27, 2, 0x70, 9,
+ AON_MUX(0x0, "KEY"), /* row2 */
+ AON_MUX(0x1, "AGPIO"), /* agpio10 */
+ AON_MUX(0x2, "nonAON"), /* pin13 */
+ TOP_MUX(0x0, "LCD"), /* port1 lcd_te */
+ TOP_MUX(0x1, "I2S0"), /* dout3 */
+ TOP_MUX(0x2, "PWM"), /* out3 */
+ TOP_MUX(0x3, "VGA")), /* vs1 */
+ AON_PIN(HDMI_SCL, TOP_REG3, 29, 1, 0x70, 18,
+ AON_MUX(0x0, "PCU"), /* test7 */
+ AON_MUX(0x1, "AGPIO"), /* agpio3 */
+ AON_MUX(0x2, "nonAON"), /* pin14 */
+ TOP_MUX(0x0, "HDMI"), /* scl */
+ TOP_MUX(0x1, "UART3")), /* rxd */
+ AON_PIN(HDMI_SDA, TOP_REG3, 30, 1, 0x74, 0,
+ AON_MUX(0x0, "PCU"), /* test8 */
+ AON_MUX(0x1, "AGPIO"), /* agpio4 */
+ AON_MUX(0x2, "nonAON"), /* pin15 */
+ TOP_MUX(0x0, "HDMI"), /* sda */
+ TOP_MUX(0x1, "UART3")), /* txd */
+ AON_PIN(JTAG_TCK, TOP_REG7, 3, 1, 0x78, 18,
+ AON_MUX(0x0, "JTAG"), /* tck */
+ AON_MUX(0x1, "AGPIO"), /* agpio11 */
+ AON_MUX(0x2, "nonAON"), /* pin22 */
+ AON_MUX(0x3, "EXT_INT"), /* int4 */
+ TOP_MUX(0x0, "SPI4"), /* clk */
+ TOP_MUX(0x1, "UART1")), /* rxd */
+ AON_PIN(JTAG_TRSTN, TOP_REG7, 4, 1, 0xac, 0,
+ AON_MUX(0x0, "JTAG"), /* trstn */
+ AON_MUX(0x1, "AGPIO"), /* agpio12 */
+ AON_MUX(0x2, "nonAON"), /* pin23 */
+ AON_MUX(0x3, "EXT_INT"), /* int5 */
+ TOP_MUX(0x0, "SPI4"), /* cs */
+ TOP_MUX(0x1, "UART1")), /* txd */
+ AON_PIN(JTAG_TMS, TOP_REG7, 5, 1, 0xac, 9,
+ AON_MUX(0x0, "JTAG"), /* tms */
+ AON_MUX(0x1, "AGPIO"), /* agpio13 */
+ AON_MUX(0x2, "nonAON"), /* pin24 */
+ AON_MUX(0x3, "EXT_INT"), /* int6 */
+ TOP_MUX(0x0, "SPI4"), /* txd */
+ TOP_MUX(0x1, "UART2")), /* rxd */
+ AON_PIN(JTAG_TDI, TOP_REG7, 6, 1, 0xac, 18,
+ AON_MUX(0x0, "JTAG"), /* tdi */
+ AON_MUX(0x1, "AGPIO"), /* agpio14 */
+ AON_MUX(0x2, "nonAON"), /* pin25 */
+ AON_MUX(0x3, "EXT_INT"), /* int7 */
+ TOP_MUX(0x0, "SPI4"), /* rxd */
+ TOP_MUX(0x1, "UART2")), /* txd */
+ AON_PIN(JTAG_TDO, 0, 0, 0, 0xb0, 0,
+ AON_MUX(0x0, "JTAG"), /* tdo */
+ AON_MUX(0x1, "AGPIO"), /* agpio15 */
+ AON_MUX(0x2, "nonAON")), /* pin26 */
+ AON_PIN(I2C0_SCL, 0, 0, 0, 0xb0, 9,
+ AON_MUX(0x0, "I2C0"), /* scl */
+ AON_MUX(0x1, "AGPIO"), /* agpio16 */
+ AON_MUX(0x2, "nonAON")), /* pin28 */
+ AON_PIN(I2C0_SDA, 0, 0, 0, 0xb0, 18,
+ AON_MUX(0x0, "I2C0"), /* sda */
+ AON_MUX(0x1, "AGPIO"), /* agpio17 */
+ AON_MUX(0x2, "nonAON")), /* pin29 */
+ AON_PIN(I2C1_SCL, TOP_REG8, 4, 1, 0xb4, 0,
+ AON_MUX(0x0, "I2C1"), /* scl */
+ AON_MUX(0x1, "AGPIO"), /* agpio18 */
+ AON_MUX(0x2, "nonAON"), /* pin30 */
+ TOP_MUX(0x0, "LCD")), /* port0 lcd_te */
+ AON_PIN(I2C1_SDA, TOP_REG8, 5, 1, 0xb4, 9,
+ AON_MUX(0x0, "I2C1"), /* sda */
+ AON_MUX(0x1, "AGPIO"), /* agpio19 */
+ AON_MUX(0x2, "nonAON"), /* pin31 */
+ TOP_MUX(0x0, "LCD")), /* port1 lcd_te */
+ ZX_RESERVED(AON_RESERVED2),
+ ZX_RESERVED(AON_RESERVED3),
+ ZX_RESERVED(AON_RESERVED4),
+
+ /* aon_pmm_reg_2 */
+ AON_PIN(SPI1_CLK, TOP_REG2, 6, 3, 0x40, 9,
+ AON_MUX(0x0, "EXT_INT"), /* int0 */
+ AON_MUX(0x1, "PCU"), /* test12 */
+ AON_MUX(0x2, "nonAON"), /* pin39 */
+ TOP_MUX(0x0, "SPI1"), /* clk */
+ TOP_MUX(0x1, "PCM"), /* clk */
+ TOP_MUX(0x2, "BGPIO"), /* gpio35 */
+ TOP_MUX(0x3, "I2C4"), /* scl */
+ TOP_MUX(0x4, "I2S1"), /* mclk */
+ TOP_MUX(0x5, "ISP")), /* flash_trig */
+ AON_PIN(SPI1_CS, TOP_REG2, 9, 3, 0x40, 18,
+ AON_MUX(0x0, "EXT_INT"), /* int1 */
+ AON_MUX(0x1, "PCU"), /* test13 */
+ AON_MUX(0x2, "nonAON"), /* pin40 */
+ TOP_MUX(0x0, "SPI1"), /* cs */
+ TOP_MUX(0x1, "PCM"), /* fs */
+ TOP_MUX(0x2, "BGPIO"), /* gpio36 */
+ TOP_MUX(0x3, "I2C4"), /* sda */
+ TOP_MUX(0x4, "I2S1"), /* bclk */
+ TOP_MUX(0x5, "ISP")), /* prelight_trig */
+ AON_PIN(SPI1_TXD, TOP_REG2, 12, 3, 0x44, 0,
+ AON_MUX(0x0, "EXT_INT"), /* int2 */
+ AON_MUX(0x1, "PCU"), /* test14 */
+ AON_MUX(0x2, "nonAON"), /* pin41 */
+ TOP_MUX(0x0, "SPI1"), /* txd */
+ TOP_MUX(0x1, "PCM"), /* txd */
+ TOP_MUX(0x2, "BGPIO"), /* gpio37 */
+ TOP_MUX(0x3, "UART5"), /* rxd */
+ TOP_MUX(0x4, "I2S1"), /* ws */
+ TOP_MUX(0x5, "ISP")), /* shutter_trig */
+ AON_PIN(SPI1_RXD, TOP_REG2, 15, 3, 0x44, 9,
+ AON_MUX(0x0, "EXT_INT"), /* int3 */
+ AON_MUX(0x1, "PCU"), /* test15 */
+ AON_MUX(0x2, "nonAON"), /* pin42 */
+ TOP_MUX(0x0, "SPI1"), /* rxd */
+ TOP_MUX(0x1, "PCM"), /* rxd */
+ TOP_MUX(0x2, "BGPIO"), /* gpio38 */
+ TOP_MUX(0x3, "UART5"), /* txd */
+ TOP_MUX(0x4, "I2S1"), /* dout0 */
+ TOP_MUX(0x5, "ISP")), /* shutter_open */
+ ZX_RESERVED(AON_RESERVED5),
+ ZX_RESERVED(AON_RESERVED6),
+ AON_PIN(AUDIO_DET, TOP_REG3, 3, 2, 0x48, 18,
+ AON_MUX(0x0, "PCU"), /* test4 */
+ AON_MUX(0x1, "AGPIO"), /* agpio27 */
+ AON_MUX(0x2, "nonAON"), /* pin2 */
+ AON_MUX(0x3, "EXT_INT"), /* int16 */
+ TOP_MUX(0x0, "AUDIO"), /* detect */
+ TOP_MUX(0x1, "I2C2"), /* scl */
+ TOP_MUX(0x2, "SPI2")), /* clk */
+ AON_PIN(SPDIF_OUT, TOP_REG3, 14, 2, 0x78, 9,
+ AON_MUX(0x0, "PCU"), /* test5 */
+ AON_MUX(0x1, "AGPIO"), /* agpio22 */
+ AON_MUX(0x2, "nonAON"), /* pin4 */
+ TOP_MUX(0x0, "SPDIF"), /* out */
+ TOP_MUX(0x1, "PWM"), /* out0 */
+ TOP_MUX(0x2, "ISP")), /* fl_trig */
+ AON_PIN(HDMI_CEC, 0, 0, 0, 0x74, 9,
+ AON_MUX(0x0, "PCU"), /* test9 */
+ AON_MUX(0x1, "AGPIO"), /* agpio1 */
+ AON_MUX(0x2, "nonAON")), /* pin16 */
+ AON_PIN(HDMI_HPD, 0, 0, 0, 0x74, 18,
+ AON_MUX(0x0, "PCU"), /* test10 */
+ AON_MUX(0x1, "AGPIO"), /* agpio2 */
+ AON_MUX(0x2, "nonAON")), /* pin17 */
+ AON_PIN(GMAC_25M_OUT, 0, 0, 0, 0x78, 0,
+ AON_MUX(0x0, "PCU"), /* test11 */
+ AON_MUX(0x1, "AGPIO"), /* agpio31 */
+ AON_MUX(0x2, "nonAON")), /* pin43 */
+ AON_PIN(BOOT_SEL0, 0, 0, 0, 0xc0, 9,
+ AON_MUX(0x0, "BOOT"), /* sel0 */
+ AON_MUX(0x1, "AGPIO"), /* agpio18 */
+ AON_MUX(0x2, "nonAON")), /* pin18 */
+ AON_PIN(BOOT_SEL1, 0, 0, 0, 0xc0, 18,
+ AON_MUX(0x0, "BOOT"), /* sel1 */
+ AON_MUX(0x1, "AGPIO"), /* agpio19 */
+ AON_MUX(0x2, "nonAON")), /* pin19 */
+ AON_PIN(BOOT_SEL2, 0, 0, 0, 0xc4, 0,
+ AON_MUX(0x0, "BOOT"), /* sel2 */
+ AON_MUX(0x1, "AGPIO"), /* agpio20 */
+ AON_MUX(0x2, "nonAON")), /* pin20 */
+ AON_PIN(DEEP_SLEEP_OUT_N, 0, 0, 0, 0xc4, 9,
+ AON_MUX(0x0, "DEEPSLP"), /* deep sleep out_n */
+ AON_MUX(0x1, "AGPIO"), /* agpio21 */
+ AON_MUX(0x2, "nonAON")), /* pin21 */
+ ZX_RESERVED(AON_RESERVED7),
+
+ /* top_pmm_reg_0 */
+ TOP_PIN(GMII_GTX_CLK, TOP_REG0, 0, 2, 0x10, 0,
+ TOP_MUX(0x0, "GMII"), /* gtx_clk */
+ TOP_MUX(0x1, "DVI0"), /* clk */
+ TOP_MUX(0x2, "BGPIO")), /* gpio0 */
+ TOP_PIN(GMII_TX_CLK, TOP_REG0, 2, 2, 0x10, 9,
+ TOP_MUX(0x0, "GMII"), /* tx_clk */
+ TOP_MUX(0x1, "DVI0"), /* vs */
+ TOP_MUX(0x2, "BGPIO")), /* gpio1 */
+ TOP_PIN(GMII_TXD0, TOP_REG0, 4, 2, 0x10, 18,
+ TOP_MUX(0x0, "GMII"), /* txd0 */
+ TOP_MUX(0x1, "DVI0"), /* hs */
+ TOP_MUX(0x2, "BGPIO")), /* gpio2 */
+ TOP_PIN(GMII_TXD1, TOP_REG0, 6, 2, 0x14, 0,
+ TOP_MUX(0x0, "GMII"), /* txd1 */
+ TOP_MUX(0x1, "DVI0"), /* d0 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio3 */
+ TOP_PIN(GMII_TXD2, TOP_REG0, 8, 2, 0x14, 9,
+ TOP_MUX(0x0, "GMII"), /* txd2 */
+ TOP_MUX(0x1, "DVI0"), /* d1 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio4 */
+ TOP_PIN(GMII_TXD3, TOP_REG0, 10, 2, 0x14, 18,
+ TOP_MUX(0x0, "GMII"), /* txd3 */
+ TOP_MUX(0x1, "DVI0"), /* d2 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio5 */
+ TOP_PIN(GMII_TXD4, TOP_REG0, 12, 2, 0x18, 0,
+ TOP_MUX(0x0, "GMII"), /* txd4 */
+ TOP_MUX(0x1, "DVI0"), /* d3 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio6 */
+ TOP_PIN(GMII_TXD5, TOP_REG0, 14, 2, 0x18, 9,
+ TOP_MUX(0x0, "GMII"), /* txd5 */
+ TOP_MUX(0x1, "DVI0"), /* d4 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio7 */
+ TOP_PIN(GMII_TXD6, TOP_REG0, 16, 2, 0x18, 18,
+ TOP_MUX(0x0, "GMII"), /* txd6 */
+ TOP_MUX(0x1, "DVI0"), /* d5 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio8 */
+ TOP_PIN(GMII_TXD7, TOP_REG0, 18, 2, 0x1c, 0,
+ TOP_MUX(0x0, "GMII"), /* txd7 */
+ TOP_MUX(0x1, "DVI0"), /* d6 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio9 */
+ TOP_PIN(GMII_TX_ER, TOP_REG0, 20, 2, 0x1c, 9,
+ TOP_MUX(0x0, "GMII"), /* tx_er */
+ TOP_MUX(0x1, "DVI0"), /* d7 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio10 */
+ TOP_PIN(GMII_TX_EN, TOP_REG0, 22, 2, 0x1c, 18,
+ TOP_MUX(0x0, "GMII"), /* tx_en */
+ TOP_MUX(0x1, "DVI0"), /* d8 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio11 */
+ TOP_PIN(GMII_RX_CLK, TOP_REG0, 24, 2, 0x20, 0,
+ TOP_MUX(0x0, "GMII"), /* rx_clk */
+ TOP_MUX(0x1, "DVI0"), /* d9 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio12 */
+ TOP_PIN(GMII_RXD0, TOP_REG0, 26, 2, 0x20, 9,
+ TOP_MUX(0x0, "GMII"), /* rxd0 */
+ TOP_MUX(0x1, "DVI0"), /* d10 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio13 */
+ TOP_PIN(GMII_RXD1, TOP_REG0, 28, 2, 0x20, 18,
+ TOP_MUX(0x0, "GMII"), /* rxd1 */
+ TOP_MUX(0x1, "DVI0"), /* d11 */
+ TOP_MUX(0x2, "BGPIO")), /* gpio14 */
+ TOP_PIN(GMII_RXD2, TOP_REG0, 30, 2, 0x24, 0,
+ TOP_MUX(0x0, "GMII"), /* rxd2 */
+ TOP_MUX(0x1, "DVI1"), /* clk */
+ TOP_MUX(0x2, "BGPIO")), /* gpio15 */
+
+ /* top_pmm_reg_1 */
+ TOP_PIN(GMII_RXD3, TOP_REG1, 0, 2, 0x24, 9,
+ TOP_MUX(0x0, "GMII"), /* rxd3 */
+ TOP_MUX(0x1, "DVI1"), /* hs */
+ TOP_MUX(0x2, "BGPIO")), /* gpio16 */
+ TOP_PIN(GMII_RXD4, TOP_REG1, 2, 2, 0x24, 18,
+ TOP_MUX(0x0, "GMII"), /* rxd4 */
+ TOP_MUX(0x1, "DVI1"), /* vs */
+ TOP_MUX(0x2, "BGPIO")), /* gpio17 */
+ TOP_PIN(GMII_RXD5, TOP_REG1, 4, 2, 0x28, 0,
+ TOP_MUX(0x0, "GMII"), /* rxd5 */
+ TOP_MUX(0x1, "DVI1"), /* d0 */
+ TOP_MUX(0x2, "BGPIO"), /* gpio18 */
+ TOP_MUX(0x3, "TSI0")), /* dat0 */
+ TOP_PIN(GMII_RXD6, TOP_REG1, 6, 2, 0x28, 9,
+ TOP_MUX(0x0, "GMII"), /* rxd6 */
+ TOP_MUX(0x1, "DVI1"), /* d1 */
+ TOP_MUX(0x2, "BGPIO"), /* gpio19 */
+ TOP_MUX(0x3, "TSI0")), /* clk */
+ TOP_PIN(GMII_RXD7, TOP_REG1, 8, 2, 0x28, 18,
+ TOP_MUX(0x0, "GMII"), /* rxd7 */
+ TOP_MUX(0x1, "DVI1"), /* d2 */
+ TOP_MUX(0x2, "BGPIO"), /* gpio20 */
+ TOP_MUX(0x3, "TSI0")), /* sync */
+ TOP_PIN(GMII_RX_ER, TOP_REG1, 10, 2, 0x2c, 0,
+ TOP_MUX(0x0, "GMII"), /* rx_er */
+ TOP_MUX(0x1, "DVI1"), /* d3 */
+ TOP_MUX(0x2, "BGPIO"), /* gpio21 */
+ TOP_MUX(0x3, "TSI0")), /* valid */
+ TOP_PIN(GMII_RX_DV, TOP_REG1, 12, 2, 0x2c, 9,
+ TOP_MUX(0x0, "GMII"), /* rx_dv */
+ TOP_MUX(0x1, "DVI1"), /* d4 */
+ TOP_MUX(0x2, "BGPIO"), /* gpio22 */
+ TOP_MUX(0x3, "TSI1")), /* dat0 */
+ TOP_PIN(GMII_COL, TOP_REG1, 14, 2, 0x2c, 18,
+ TOP_MUX(0x0, "GMII"), /* col */
+ TOP_MUX(0x1, "DVI1"), /* d5 */
+ TOP_MUX(0x2, "BGPIO"), /* gpio23 */
+ TOP_MUX(0x3, "TSI1")), /* clk */
+ TOP_PIN(GMII_CRS, TOP_REG1, 16, 2, 0x30, 0,
+ TOP_MUX(0x0, "GMII"), /* crs */
+ TOP_MUX(0x1, "DVI1"), /* d6 */
+ TOP_MUX(0x2, "BGPIO"), /* gpio24 */
+ TOP_MUX(0x3, "TSI1")), /* sync */
+ TOP_PIN(GMII_MDC, TOP_REG1, 18, 2, 0x30, 9,
+ TOP_MUX(0x0, "GMII"), /* mdc */
+ TOP_MUX(0x1, "DVI1"), /* d7 */
+ TOP_MUX(0x2, "BGPIO"), /* gpio25 */
+ TOP_MUX(0x3, "TSI1")), /* valid */
+ TOP_PIN(GMII_MDIO, TOP_REG1, 20, 1, 0x30, 18,
+ TOP_MUX(0x0, "GMII"), /* mdio */
+ TOP_MUX(0x2, "BGPIO")), /* gpio26 */
+ TOP_PIN(SDIO1_CLK, TOP_REG1, 21, 2, 0x34, 18,
+ TOP_MUX(0x0, "SDIO1"), /* clk */
+ TOP_MUX(0x1, "USIM0"), /* clk */
+ TOP_MUX(0x2, "BGPIO"), /* gpio27 */
+ TOP_MUX(0x3, "SPINOR")), /* clk */
+ TOP_PIN(SDIO1_CMD, TOP_REG1, 23, 2, 0x38, 0,
+ TOP_MUX(0x0, "SDIO1"), /* cmd */
+ TOP_MUX(0x1, "USIM0"), /* cd */
+ TOP_MUX(0x2, "BGPIO"), /* gpio28 */
+ TOP_MUX(0x3, "SPINOR")), /* cs */
+ TOP_PIN(SDIO1_DATA0, TOP_REG1, 25, 2, 0x38, 9,
+ TOP_MUX(0x0, "SDIO1"), /* dat0 */
+ TOP_MUX(0x1, "USIM0"), /* rst */
+ TOP_MUX(0x2, "BGPIO"), /* gpio29 */
+ TOP_MUX(0x3, "SPINOR")), /* dq0 */
+ TOP_PIN(SDIO1_DATA1, TOP_REG1, 27, 2, 0x38, 18,
+ TOP_MUX(0x0, "SDIO1"), /* dat1 */
+ TOP_MUX(0x1, "USIM0"), /* data */
+ TOP_MUX(0x2, "BGPIO"), /* gpio30 */
+ TOP_MUX(0x3, "SPINOR")), /* dq1 */
+ TOP_PIN(SDIO1_DATA2, TOP_REG1, 29, 2, 0x3c, 0,
+ TOP_MUX(0x0, "SDIO1"), /* dat2 */
+ TOP_MUX(0x1, "BGPIO"), /* gpio31 */
+ TOP_MUX(0x2, "SPINOR")), /* dq2 */
+
+ /* top_pmm_reg_2 */
+ TOP_PIN(SDIO1_DATA3, TOP_REG2, 0, 2, 0x3c, 9,
+ TOP_MUX(0x0, "SDIO1"), /* dat3 */
+ TOP_MUX(0x1, "BGPIO"), /* gpio32 */
+ TOP_MUX(0x2, "SPINOR")), /* dq3 */
+ TOP_PIN(SDIO1_CD, TOP_REG2, 2, 2, 0x3c, 18,
+ TOP_MUX(0x0, "SDIO1"), /* cd */
+ TOP_MUX(0x1, "BGPIO"), /* gpio33 */
+ TOP_MUX(0x2, "ISP")), /* fl_trig */
+ TOP_PIN(SDIO1_WP, TOP_REG2, 4, 2, 0x40, 0,
+ TOP_MUX(0x0, "SDIO1"), /* wp */
+ TOP_MUX(0x1, "BGPIO"), /* gpio34 */
+ TOP_MUX(0x2, "ISP")), /* ref_clk */
+ TOP_PIN(USIM1_CD, TOP_REG2, 22, 3, 0x44, 18,
+ TOP_MUX(0x0, "USIM1"), /* cd */
+ TOP_MUX(0x1, "UART4"), /* rxd */
+ TOP_MUX(0x2, "BGPIO"), /* gpio39 */
+ TOP_MUX(0x3, "SPI3"), /* clk */
+ TOP_MUX(0x4, "I2S0"), /* bclk */
+ TOP_MUX(0x5, "B_DVI0")), /* d8 */
+ TOP_PIN(USIM1_CLK, TOP_REG2, 25, 3, 0x4c, 18,
+ TOP_MUX(0x0, "USIM1"), /* clk */
+ TOP_MUX(0x1, "UART4"), /* txd */
+ TOP_MUX(0x2, "BGPIO"), /* gpio40 */
+ TOP_MUX(0x3, "SPI3"), /* cs */
+ TOP_MUX(0x4, "I2S0"), /* ws */
+ TOP_MUX(0x5, "B_DVI0")), /* d9 */
+ TOP_PIN(USIM1_RST, TOP_REG2, 28, 3, 0x4c, 0,
+ TOP_MUX(0x0, "USIM1"), /* rst */
+ TOP_MUX(0x1, "UART4"), /* cts */
+ TOP_MUX(0x2, "BGPIO"), /* gpio41 */
+ TOP_MUX(0x3, "SPI3"), /* txd */
+ TOP_MUX(0x4, "I2S0"), /* dout0 */
+ TOP_MUX(0x5, "B_DVI0")), /* d10 */
+
+ /* top_pmm_reg_3 */
+ TOP_PIN(USIM1_DATA, TOP_REG3, 0, 3, 0x4c, 9,
+ TOP_MUX(0x0, "USIM1"), /* dat */
+ TOP_MUX(0x1, "UART4"), /* rst */
+ TOP_MUX(0x2, "BGPIO"), /* gpio42 */
+ TOP_MUX(0x3, "SPI3"), /* rxd */
+ TOP_MUX(0x4, "I2S0"), /* din0 */
+ TOP_MUX(0x5, "B_DVI0")), /* d11 */
+ TOP_PIN(SDIO0_CLK, TOP_REG3, 6, 1, 0x58, 0,
+ TOP_MUX(0x0, "SDIO0"), /* clk */
+ TOP_MUX(0x1, "GPIO")), /* gpio43 */
+ TOP_PIN(SDIO0_CMD, TOP_REG3, 7, 1, 0x58, 9,
+ TOP_MUX(0x0, "SDIO0"), /* cmd */
+ TOP_MUX(0x1, "GPIO")), /* gpio44 */
+ TOP_PIN(SDIO0_DATA0, TOP_REG3, 8, 1, 0x58, 18,
+ TOP_MUX(0x0, "SDIO0"), /* dat0 */
+ TOP_MUX(0x1, "GPIO")), /* gpio45 */
+ TOP_PIN(SDIO0_DATA1, TOP_REG3, 9, 1, 0x5c, 0,
+ TOP_MUX(0x0, "SDIO0"), /* dat1 */
+ TOP_MUX(0x1, "GPIO")), /* gpio46 */
+ TOP_PIN(SDIO0_DATA2, TOP_REG3, 10, 1, 0x5c, 9,
+ TOP_MUX(0x0, "SDIO0"), /* dat2 */
+ TOP_MUX(0x1, "GPIO")), /* gpio47 */
+ TOP_PIN(SDIO0_DATA3, TOP_REG3, 11, 1, 0x5c, 18,
+ TOP_MUX(0x0, "SDIO0"), /* dat3 */
+ TOP_MUX(0x1, "GPIO")), /* gpio48 */
+ TOP_PIN(SDIO0_CD, TOP_REG3, 12, 1, 0x60, 0,
+ TOP_MUX(0x0, "SDIO0"), /* cd */
+ TOP_MUX(0x1, "GPIO")), /* gpio49 */
+ TOP_PIN(SDIO0_WP, TOP_REG3, 13, 1, 0x60, 9,
+ TOP_MUX(0x0, "SDIO0"), /* wp */
+ TOP_MUX(0x1, "GPIO")), /* gpio50 */
+
+ /* top_pmm_reg_4 */
+ TOP_PIN(TSI0_DATA0, TOP_REG4, 0, 2, 0x60, 18,
+ TOP_MUX(0x0, "TSI0"), /* dat0 */
+ TOP_MUX(0x1, "LCD"), /* clk */
+ TOP_MUX(0x2, "BGPIO")), /* gpio51 */
+ TOP_PIN(SPINOR_CLK, TOP_REG4, 2, 2, 0xa8, 18,
+ TOP_MUX(0x0, "SPINOR"), /* clk */
+ TOP_MUX(0x1, "TSI0"), /* dat1 */
+ TOP_MUX(0x2, "LCD"), /* dat0 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio52 */
+ TOP_PIN(TSI2_DATA, TOP_REG4, 4, 2, 0x7c, 0,
+ TOP_MUX(0x0, "TSI2"), /* dat */
+ TOP_MUX(0x1, "TSI0"), /* dat2 */
+ TOP_MUX(0x2, "LCD"), /* dat1 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio53 */
+ TOP_PIN(TSI2_CLK, TOP_REG4, 6, 2, 0x7c, 9,
+ TOP_MUX(0x0, "TSI2"), /* clk */
+ TOP_MUX(0x1, "TSI0"), /* dat3 */
+ TOP_MUX(0x2, "LCD"), /* dat2 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio54 */
+ TOP_PIN(TSI2_SYNC, TOP_REG4, 8, 2, 0x7c, 18,
+ TOP_MUX(0x0, "TSI2"), /* sync */
+ TOP_MUX(0x1, "TSI0"), /* dat4 */
+ TOP_MUX(0x2, "LCD"), /* dat3 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio55 */
+ TOP_PIN(TSI2_VALID, TOP_REG4, 10, 2, 0x80, 0,
+ TOP_MUX(0x0, "TSI2"), /* valid */
+ TOP_MUX(0x1, "TSI0"), /* dat5 */
+ TOP_MUX(0x2, "LCD"), /* dat4 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio56 */
+ TOP_PIN(SPINOR_CS, TOP_REG4, 12, 2, 0x80, 9,
+ TOP_MUX(0x0, "SPINOR"), /* cs */
+ TOP_MUX(0x1, "TSI0"), /* dat6 */
+ TOP_MUX(0x2, "LCD"), /* dat5 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio57 */
+ TOP_PIN(SPINOR_DQ0, TOP_REG4, 14, 2, 0x80, 18,
+ TOP_MUX(0x0, "SPINOR"), /* dq0 */
+ TOP_MUX(0x1, "TSI0"), /* dat7 */
+ TOP_MUX(0x2, "LCD"), /* dat6 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio58 */
+ TOP_PIN(SPINOR_DQ1, TOP_REG4, 16, 2, 0x84, 0,
+ TOP_MUX(0x0, "SPINOR"), /* dq1 */
+ TOP_MUX(0x1, "TSI0"), /* clk */
+ TOP_MUX(0x2, "LCD"), /* dat7 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio59 */
+ TOP_PIN(SPINOR_DQ2, TOP_REG4, 18, 2, 0x84, 9,
+ TOP_MUX(0x0, "SPINOR"), /* dq2 */
+ TOP_MUX(0x1, "TSI0"), /* sync */
+ TOP_MUX(0x2, "LCD"), /* dat8 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio60 */
+ TOP_PIN(SPINOR_DQ3, TOP_REG4, 20, 2, 0x84, 18,
+ TOP_MUX(0x0, "SPINOR"), /* dq3 */
+ TOP_MUX(0x1, "TSI0"), /* valid */
+ TOP_MUX(0x2, "LCD"), /* dat9 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio61 */
+ TOP_PIN(VGA_HS, TOP_REG4, 22, 3, 0x88, 0,
+ TOP_MUX(0x0, "VGA"), /* hs */
+ TOP_MUX(0x1, "TSI1"), /* dat0 */
+ TOP_MUX(0x2, "LCD"), /* dat10 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio62 */
+ TOP_MUX(0x4, "I2S1"), /* din1 */
+ TOP_MUX(0x5, "B_DVI0")), /* clk */
+ TOP_PIN(VGA_VS, TOP_REG4, 25, 3, 0x88, 9,
+ TOP_MUX(0x0, "VGA"), /* vs0 */
+ TOP_MUX(0x1, "TSI1"), /* dat1 */
+ TOP_MUX(0x2, "LCD"), /* dat11 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio63 */
+ TOP_MUX(0x4, "I2S1"), /* din2 */
+ TOP_MUX(0x5, "B_DVI0")), /* vs */
+ TOP_PIN(TSI3_DATA, TOP_REG4, 28, 3, 0x88, 18,
+ TOP_MUX(0x0, "TSI3"), /* dat */
+ TOP_MUX(0x1, "TSI1"), /* dat2 */
+ TOP_MUX(0x2, "LCD"), /* dat12 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio64 */
+ TOP_MUX(0x4, "I2S1"), /* din3 */
+ TOP_MUX(0x5, "B_DVI0")), /* hs */
+
+ /* top_pmm_reg_5 */
+ TOP_PIN(TSI3_CLK, TOP_REG5, 0, 3, 0x8c, 0,
+ TOP_MUX(0x0, "TSI3"), /* clk */
+ TOP_MUX(0x1, "TSI1"), /* dat3 */
+ TOP_MUX(0x2, "LCD"), /* dat13 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio65 */
+ TOP_MUX(0x4, "I2S1"), /* dout1 */
+ TOP_MUX(0x5, "B_DVI0")), /* d0 */
+ TOP_PIN(TSI3_SYNC, TOP_REG5, 3, 3, 0x8c, 9,
+ TOP_MUX(0x0, "TSI3"), /* sync */
+ TOP_MUX(0x1, "TSI1"), /* dat4 */
+ TOP_MUX(0x2, "LCD"), /* dat14 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio66 */
+ TOP_MUX(0x4, "I2S1"), /* dout2 */
+ TOP_MUX(0x5, "B_DVI0")), /* d1 */
+ TOP_PIN(TSI3_VALID, TOP_REG5, 6, 3, 0x8c, 18,
+ TOP_MUX(0x0, "TSI3"), /* valid */
+ TOP_MUX(0x1, "TSI1"), /* dat5 */
+ TOP_MUX(0x2, "LCD"), /* dat15 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio67 */
+ TOP_MUX(0x4, "I2S1"), /* dout3 */
+ TOP_MUX(0x5, "B_DVI0")), /* d2 */
+ TOP_PIN(I2S1_WS, TOP_REG5, 9, 3, 0x90, 0,
+ TOP_MUX(0x0, "I2S1"), /* ws */
+ TOP_MUX(0x1, "TSI1"), /* dat6 */
+ TOP_MUX(0x2, "LCD"), /* dat16 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio68 */
+ TOP_MUX(0x4, "VGA"), /* scl */
+ TOP_MUX(0x5, "B_DVI0")), /* d3 */
+ TOP_PIN(I2S1_BCLK, TOP_REG5, 12, 3, 0x90, 9,
+ TOP_MUX(0x0, "I2S1"), /* bclk */
+ TOP_MUX(0x1, "TSI1"), /* dat7 */
+ TOP_MUX(0x2, "LCD"), /* dat17 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio69 */
+ TOP_MUX(0x4, "VGA"), /* sda */
+ TOP_MUX(0x5, "B_DVI0")), /* d4 */
+ TOP_PIN(I2S1_MCLK, TOP_REG5, 15, 2, 0x90, 18,
+ TOP_MUX(0x0, "I2S1"), /* mclk */
+ TOP_MUX(0x1, "TSI1"), /* clk */
+ TOP_MUX(0x2, "LCD"), /* dat18 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio70 */
+ TOP_PIN(I2S1_DIN0, TOP_REG5, 17, 2, 0x94, 0,
+ TOP_MUX(0x0, "I2S1"), /* din0 */
+ TOP_MUX(0x1, "TSI1"), /* sync */
+ TOP_MUX(0x2, "LCD"), /* dat19 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio71 */
+ TOP_PIN(I2S1_DOUT0, TOP_REG5, 19, 2, 0x94, 9,
+ TOP_MUX(0x0, "I2S1"), /* dout0 */
+ TOP_MUX(0x1, "TSI1"), /* valid */
+ TOP_MUX(0x2, "LCD"), /* dat20 */
+ TOP_MUX(0x3, "BGPIO")), /* gpio72 */
+ TOP_PIN(SPI3_CLK, TOP_REG5, 21, 3, 0x94, 18,
+ TOP_MUX(0x0, "SPI3"), /* clk */
+ TOP_MUX(0x1, "TSO1"), /* clk */
+ TOP_MUX(0x2, "LCD"), /* dat21 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio73 */
+ TOP_MUX(0x4, "UART5"), /* rxd */
+ TOP_MUX(0x5, "PCM"), /* fs */
+ TOP_MUX(0x6, "I2S0"), /* din1 */
+ TOP_MUX(0x7, "B_DVI0")), /* d5 */
+ TOP_PIN(SPI3_CS, TOP_REG5, 24, 3, 0x98, 0,
+ TOP_MUX(0x0, "SPI3"), /* cs */
+ TOP_MUX(0x1, "TSO1"), /* dat0 */
+ TOP_MUX(0x2, "LCD"), /* dat22 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio74 */
+ TOP_MUX(0x4, "UART5"), /* txd */
+ TOP_MUX(0x5, "PCM"), /* clk */
+ TOP_MUX(0x6, "I2S0"), /* din2 */
+ TOP_MUX(0x7, "B_DVI0")), /* d6 */
+ TOP_PIN(SPI3_TXD, TOP_REG5, 27, 3, 0x98, 9,
+ TOP_MUX(0x0, "SPI3"), /* txd */
+ TOP_MUX(0x1, "TSO1"), /* dat1 */
+ TOP_MUX(0x2, "LCD"), /* dat23 */
+ TOP_MUX(0x3, "BGPIO"), /* gpio75 */
+ TOP_MUX(0x4, "UART5"), /* cts */
+ TOP_MUX(0x5, "PCM"), /* txd */
+ TOP_MUX(0x6, "I2S0"), /* din3 */
+ TOP_MUX(0x7, "B_DVI0")), /* d7 */
+ TOP_PIN(NAND_LDO_MS18_SEL, TOP_REG5, 30, 1, 0xe4, 0,
+ TOP_MUX(0x0, "NAND"), /* ldo_ms18_sel */
+ TOP_MUX(0x1, "BGPIO")), /* gpio99 */
+
+ /* top_pmm_reg_6 */
+ TOP_PIN(SPI3_RXD, TOP_REG6, 0, 3, 0x98, 18,
+ TOP_MUX(0x0, "SPI3"), /* rxd */
+ TOP_MUX(0x1, "TSO1"), /* dat2 */
+ TOP_MUX(0x2, "LCD"), /* stvu_vsync */
+ TOP_MUX(0x3, "BGPIO"), /* gpio76 */
+ TOP_MUX(0x4, "UART5"), /* rts */
+ TOP_MUX(0x5, "PCM"), /* rxd */
+ TOP_MUX(0x6, "I2S0"), /* dout1 */
+ TOP_MUX(0x7, "B_DVI1")), /* clk */
+ TOP_PIN(I2S0_MCLK, TOP_REG6, 3, 3, 0x9c, 0,
+ TOP_MUX(0x0, "I2S0"), /* mclk */
+ TOP_MUX(0x1, "TSO1"), /* dat3 */
+ TOP_MUX(0x2, "LCD"), /* stvd */
+ TOP_MUX(0x3, "BGPIO"), /* gpio77 */
+ TOP_MUX(0x4, "USIM0"), /* cd */
+ TOP_MUX(0x5, "B_DVI1")), /* vs */
+ TOP_PIN(I2S0_BCLK, TOP_REG6, 6, 3, 0x9c, 9,
+ TOP_MUX(0x0, "I2S0"), /* bclk */
+ TOP_MUX(0x1, "TSO1"), /* dat4 */
+ TOP_MUX(0x2, "LCD"), /* sthl_hsync */
+ TOP_MUX(0x3, "BGPIO"), /* gpio78 */
+ TOP_MUX(0x4, "USIM0"), /* clk */
+ TOP_MUX(0x5, "B_DVI1")), /* hs */
+ TOP_PIN(I2S0_WS, TOP_REG6, 9, 3, 0x9c, 18,
+ TOP_MUX(0x0, "I2S0"), /* ws */
+ TOP_MUX(0x1, "TSO1"), /* dat5 */
+ TOP_MUX(0x2, "LCD"), /* sthr */
+ TOP_MUX(0x3, "BGPIO"), /* gpio79 */
+ TOP_MUX(0x4, "USIM0"), /* rst */
+ TOP_MUX(0x5, "B_DVI1")), /* d0 */
+ TOP_PIN(I2S0_DIN0, TOP_REG6, 12, 3, 0xa0, 0,
+ TOP_MUX(0x0, "I2S0"), /* din0 */
+ TOP_MUX(0x1, "TSO1"), /* dat6 */
+ TOP_MUX(0x2, "LCD"), /* oev_dataen */
+ TOP_MUX(0x3, "BGPIO"), /* gpio80 */
+ TOP_MUX(0x4, "USIM0"), /* dat */
+ TOP_MUX(0x5, "B_DVI1")), /* d1 */
+ TOP_PIN(I2S0_DOUT0, TOP_REG6, 15, 2, 0xa0, 9,
+ TOP_MUX(0x0, "I2S0"), /* dout0 */
+ TOP_MUX(0x1, "TSO1"), /* dat7 */
+ TOP_MUX(0x2, "LCD"), /* ckv */
+ TOP_MUX(0x3, "BGPIO")), /* gpio81 */
+ TOP_PIN(I2C5_SCL, TOP_REG6, 17, 3, 0xa0, 18,
+ TOP_MUX(0x0, "I2C5"), /* scl */
+ TOP_MUX(0x1, "TSO1"), /* sync */
+ TOP_MUX(0x2, "LCD"), /* ld */
+ TOP_MUX(0x3, "BGPIO"), /* gpio82 */
+ TOP_MUX(0x4, "PWM"), /* out2 */
+ TOP_MUX(0x5, "I2S0"), /* dout2 */
+ TOP_MUX(0x6, "B_DVI1")), /* d2 */
+ TOP_PIN(I2C5_SDA, TOP_REG6, 20, 3, 0xa4, 0,
+ TOP_MUX(0x0, "I2C5"), /* sda */
+ TOP_MUX(0x1, "TSO1"), /* vld */
+ TOP_MUX(0x2, "LCD"), /* pol */
+ TOP_MUX(0x3, "BGPIO"), /* gpio83 */
+ TOP_MUX(0x4, "PWM"), /* out3 */
+ TOP_MUX(0x5, "I2S0"), /* dout3 */
+ TOP_MUX(0x6, "B_DVI1")), /* d3 */
+ TOP_PIN(SPI2_CLK, TOP_REG6, 23, 3, 0xa4, 9,
+ TOP_MUX(0x0, "SPI2"), /* clk */
+ TOP_MUX(0x1, "TSO0"), /* clk */
+ TOP_MUX(0x2, "LCD"), /* degsl */
+ TOP_MUX(0x3, "BGPIO"), /* gpio84 */
+ TOP_MUX(0x4, "I2C4"), /* scl */
+ TOP_MUX(0x5, "B_DVI1")), /* d4 */
+ TOP_PIN(SPI2_CS, TOP_REG6, 26, 3, 0xa4, 18,
+ TOP_MUX(0x0, "SPI2"), /* cs */
+ TOP_MUX(0x1, "TSO0"), /* data */
+ TOP_MUX(0x2, "LCD"), /* rev */
+ TOP_MUX(0x3, "BGPIO"), /* gpio85 */
+ TOP_MUX(0x4, "I2C4"), /* sda */
+ TOP_MUX(0x5, "B_DVI1")), /* d5 */
+ TOP_PIN(SPI2_TXD, TOP_REG6, 29, 3, 0xa8, 0,
+ TOP_MUX(0x0, "SPI2"), /* txd */
+ TOP_MUX(0x1, "TSO0"), /* sync */
+ TOP_MUX(0x2, "LCD"), /* u_d */
+ TOP_MUX(0x3, "BGPIO"), /* gpio86 */
+ TOP_MUX(0x4, "I2C4"), /* scl */
+ TOP_MUX(0x5, "B_DVI1")), /* d6 */
+
+ /* top_pmm_reg_7 */
+ TOP_PIN(SPI2_RXD, TOP_REG7, 0, 3, 0xa8, 9,
+ TOP_MUX(0x0, "SPI2"), /* rxd */
+ TOP_MUX(0x1, "TSO0"), /* vld */
+ TOP_MUX(0x2, "LCD"), /* r_l */
+ TOP_MUX(0x3, "BGPIO"), /* gpio87 */
+ TOP_MUX(0x4, "I2C3"), /* sda */
+ TOP_MUX(0x5, "B_DVI1")), /* d7 */
+ TOP_PIN(NAND_WP_N, TOP_REG7, 7, 3, 0x54, 9,
+ TOP_MUX(0x0, "NAND"), /* wp */
+ TOP_MUX(0x1, "PWM"), /* out2 */
+ TOP_MUX(0x2, "SPI2"), /* clk */
+ TOP_MUX(0x3, "BGPIO"), /* gpio88 */
+ TOP_MUX(0x4, "TSI0"), /* dat0 */
+ TOP_MUX(0x5, "I2S1")), /* din1 */
+ TOP_PIN(NAND_PAGE_SIZE0, TOP_REG7, 10, 3, 0xb8, 0,
+ TOP_MUX(0x0, "NAND"), /* boot_pagesize0 */
+ TOP_MUX(0x1, "PWM"), /* out3 */
+ TOP_MUX(0x2, "SPI2"), /* cs */
+ TOP_MUX(0x3, "BGPIO"), /* gpio89 */
+ TOP_MUX(0x4, "TSI0"), /* clk */
+ TOP_MUX(0x5, "I2S1")), /* din2 */
+ TOP_PIN(NAND_PAGE_SIZE1, TOP_REG7, 13, 3, 0xb8, 9,
+ TOP_MUX(0x0, "NAND"), /* boot_pagesize1 */
+ TOP_MUX(0x1, "I2C4"), /* scl */
+ TOP_MUX(0x2, "SPI2"), /* txd */
+ TOP_MUX(0x3, "BGPIO"), /* gpio90 */
+ TOP_MUX(0x4, "TSI0"), /* sync */
+ TOP_MUX(0x5, "I2S1")), /* din3 */
+ TOP_PIN(NAND_ADDR_CYCLE, TOP_REG7, 16, 3, 0xb8, 18,
+ TOP_MUX(0x0, "NAND"), /* boot_addr_cycles */
+ TOP_MUX(0x1, "I2C4"), /* sda */
+ TOP_MUX(0x2, "SPI2"), /* rxd */
+ TOP_MUX(0x3, "BGPIO"), /* gpio91 */
+ TOP_MUX(0x4, "TSI0"), /* valid */
+ TOP_MUX(0x5, "I2S1")), /* dout1 */
+ TOP_PIN(NAND_RB0, TOP_REG7, 19, 3, 0xbc, 0,
+ TOP_MUX(0x0, "NAND"), /* rdy_busy0 */
+ TOP_MUX(0x1, "I2C2"), /* scl */
+ TOP_MUX(0x2, "USIM0"), /* cd */
+ TOP_MUX(0x3, "BGPIO"), /* gpio92 */
+ TOP_MUX(0x4, "TSI1")), /* data0 */
+ TOP_PIN(NAND_RB1, TOP_REG7, 22, 3, 0xbc, 9,
+ TOP_MUX(0x0, "NAND"), /* rdy_busy1 */
+ TOP_MUX(0x1, "I2C2"), /* sda */
+ TOP_MUX(0x2, "USIM0"), /* clk */
+ TOP_MUX(0x3, "BGPIO"), /* gpio93 */
+ TOP_MUX(0x4, "TSI1")), /* clk */
+ TOP_PIN(NAND_RB2, TOP_REG7, 25, 3, 0xbc, 18,
+ TOP_MUX(0x0, "NAND"), /* rdy_busy2 */
+ TOP_MUX(0x1, "UART5"), /* rxd */
+ TOP_MUX(0x2, "USIM0"), /* rst */
+ TOP_MUX(0x3, "BGPIO"), /* gpio94 */
+ TOP_MUX(0x4, "TSI1"), /* sync */
+ TOP_MUX(0x4, "I2S1")), /* dout2 */
+ TOP_PIN(NAND_RB3, TOP_REG7, 28, 3, 0x54, 18,
+ TOP_MUX(0x0, "NAND"), /* rdy_busy3 */
+ TOP_MUX(0x1, "UART5"), /* txd */
+ TOP_MUX(0x2, "USIM0"), /* dat */
+ TOP_MUX(0x3, "BGPIO"), /* gpio95 */
+ TOP_MUX(0x4, "TSI1"), /* valid */
+ TOP_MUX(0x4, "I2S1")), /* dout3 */
+
+ /* top_pmm_reg_8 */
+ TOP_PIN(GMAC_125M_IN, TOP_REG8, 0, 2, 0x34, 0,
+ TOP_MUX(0x0, "GMII"), /* 125m_in */
+ TOP_MUX(0x1, "USB2"), /* 0_drvvbus */
+ TOP_MUX(0x2, "ISP"), /* ref_clk */
+ TOP_MUX(0x3, "BGPIO")), /* gpio96 */
+ TOP_PIN(GMAC_50M_OUT, TOP_REG8, 2, 2, 0x34, 9,
+ TOP_MUX(0x0, "GMII"), /* 50m_out */
+ TOP_MUX(0x1, "USB2"), /* 1_drvvbus */
+ TOP_MUX(0x2, "BGPIO"), /* gpio97 */
+ TOP_MUX(0x3, "USB2")), /* 0_drvvbus */
+ TOP_PIN(SPINOR_SSCLK_LOOPBACK, TOP_REG8, 6, 1, 0xc8, 9,
+ TOP_MUX(0x0, "SPINOR")), /* sdio1_clk_i */
+ TOP_PIN(SPINOR_SDIO1CLK_LOOPBACK, TOP_REG8, 7, 1, 0xc8, 18,
+ TOP_MUX(0x0, "SPINOR")), /* ssclk_i */
+};
+
+static struct zx_pinctrl_soc_info zx296718_pinctrl_info = {
+ .pins = zx296718_pins,
+ .npins = ARRAY_SIZE(zx296718_pins),
+};
+
+static int zx296718_pinctrl_probe(struct platform_device *pdev)
+{
+ return zx_pinctrl_init(pdev, &zx296718_pinctrl_info);
+}
+
+static const struct of_device_id zx296718_pinctrl_match[] = {
+ { .compatible = "zte,zx296718-pmm", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, zx296718_pinctrl_match);
+
+static struct platform_driver zx296718_pinctrl_driver = {
+ .probe = zx296718_pinctrl_probe,
+ .driver = {
+ .name = "zx296718-pinctrl",
+ .of_match_table = zx296718_pinctrl_match,
+ },
+};
+builtin_platform_driver(zx296718_pinctrl_driver);
+
+MODULE_DESCRIPTION("ZTE ZX296718 pinctrl driver");
+MODULE_LICENSE("GPL");
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH V3 2/2] ARM64: dts: hi6220-hikey: Add clock binding for the pmic mfd
From: Lee Jones @ 2017-04-24 13:01 UTC (permalink / raw)
To: Daniel Lezcano
Cc: Stephen Boyd, mturquette-rdvid1DuHRBWk0Htik3J/w,
xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170424091609.GA2137@mai>
On Mon, 24 Apr 2017, Daniel Lezcano wrote:
> On Mon, Apr 24, 2017 at 09:59:44AM +0100, Lee Jones wrote:
> > On Sat, 22 Apr 2017, Daniel Lezcano wrote:
> >
> > > On 22/04/2017 04:02, Stephen Boyd wrote:
> > > > On 04/17, Daniel Lezcano wrote:
> > > >> Signed-off-by: Daniel Lezcano <daniel.lezcano-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > > >> ---
> > > >> Documentation/devicetree/bindings/mfd/hisilicon,hi655x.txt | 6 ++++++
> > > >> arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 1 +
> > > >> 2 files changed, 7 insertions(+)
> > > >>
> > > >
> > > > I take it this goes through arm-soc? Not sure why I'm on To:
> > > > line.
> > >
> > > Probably it should go through Lee's tree.
> >
> > Unlikely.
> >
> > The document and the DTS change should really have gone separately,
> > but to save you from having to mess around so close to the merge window:
> >
> > Acked-by: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>
> Thanks Lee.
>
> Usually, I take the DT changes (including doc) with the timers changes with the
> maintainer and Rob's blessing. So the DT and the driver changes are aligned in
> my tree and make the submission changes easier.
The binding docs go with the bindings, not the DTS changes.
> I agree mixing the patches for different destinations into a single patchset is
> fuzzy, I will take care next time to separate the patches.
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 1/5] dt-bindings: gpu: add bindings for the ARM Mali Midgard GPU
From: Rob Herring @ 2017-04-24 13:02 UTC (permalink / raw)
To: Guillaume Tucker
Cc: Neil Armstrong, Heiko Stübner, Mark Rutland,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Sjoerd Simons,
Wookey, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
open list:ARM/Rockchip SoC..., John Reitan,
Enric Balletbo i Serra,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
In-Reply-To: <92e0492a-bd17-0171-10a3-8af5044ba6cc-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
On Wed, Apr 12, 2017 at 4:36 AM, Guillaume Tucker
<guillaume.tucker-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org> wrote:
> Hi Neil,
>
>
> On 12/04/17 09:48, Neil Armstrong wrote:
>>
>> Hi Guillaume,
>>
>> On 04/12/2017 10:25 AM, Guillaume Tucker wrote:
>>>
>>> Hi Heiko,
>>>
>>> On 11/04/17 21:52, Heiko Stübner wrote:
>>>>
>>>> Hi Guillaume,
>>>>
>>>> Am Dienstag, 11. April 2017, 18:40:37 CEST schrieb Guillaume Tucker:
>>>>>
>>>>> On 03/04/17 09:12, Neil Armstrong wrote:
>>>>>>
>>>>>> On 04/02/2017 09:59 AM, Guillaume Tucker wrote:
>>>>>>>
>>>>>>> +Optional:
>>>>>>> +
>>>>>>> +- clocks : Phandle to clock for the Mali Midgard device.
>>>>>>> +- clock-names : Shall be "clk_mali".
>>>>>>> +- mali-supply : Phandle to regulator for the Mali device. Refer to
>>>>>>> + Documentation/devicetree/bindings/regulator/regulator.txt for
>>>>>>> details.
>>>>>>> +- operating-points : Refer to
>>>>>>> Documentation/devicetree/bindings/power/opp.txt + for details.
>>>>>>
>>>>>>
>>>>>> Please add :
>>>>>> * Must be one of the following:
>>>>>> "arm,mali-t820"
>>>>>>
>>>>>> * And, optionally, one of the vendor specific compatible:
>>>>>> "amlogic,meson-gxm-mali"
>>>>>>
>>>>>> with my Ack for the amlogic platform.
>>>>>
>>>>>
>>>>> It seems to me that as long as the GPU architecture hasn't been
>>>>> modified (I don't think I've ever encountered such a case) then
>>>>> it has to be a standard ARM Mali type regardless of the SoC
>>>>> vendor. So unless a Mali-T820 in the Amlogic S912 SoC is not the
>>>>> same as a T820 in a different SoC, please forgive me but I don't
>>>>> understand why a vendor compatible string is needed. My main
>>>>> concern is that it's going to be very hard to keep that list
>>>>> up-to-date with all existing Midgard SoC variants. If do we need
>>>>> to add vendor compatible strings to correctly describe the
>>>>> hardware then I'm happy to add the amlogic one in my patch v3; I
>>>>> would just like to understand why that's necessary.
>>>>
>>>>
>>>> SoC vendors in most cases hook ip blocks into their socs in different
>>>> and often strange ways. After all it's not some discrete ic you solder
>>>> onto a board, but instead a part of the soc itself.
>>>
>>>
>>> Thanks for your explanation. I see, it's really about special
>>> things that are not supported by the standard Midgard kernel
>>> driver.
>>>
>>>> So in most cases you will have some hooks outside the actual gpu iospace
>>>> that can be used to tune different things about how the gpu interacts
>>>> with
>>>> the system. Which is probably also the reason the midgard kernel driver
>>>> has this ugly "platform" subdirectory for compile-time platform
>>>> selection.
>>>
>>>
>>> I see the "platform" directory approach as an old and deprecated
>>> way of supporting platforms, upstreaming the dt bindings goes in
>>> the direction of using solely the device tree to describe the GPU
>>> hardware (i.e. CONFIG_MALI_PLATFORM_DEVICETREE). If something
>>> quirky is needed in the platform, it should be possible to
>>> support it outside the GPU driver (platform devfreq etc...).
>>
>>
>> If this was so simple...
>>
>> This is why the "vendor" compatible is optional.
>>
>> And on another side, the binding were written by ARM, are may not be
>> compatible with how the mainline Linux handles these uses-cases.
>>
>> ARM added some tweaks to handle some weird integration using DT
>> properties,
>> but this should definitely go in platform specific code instead.
>
>
> OK, sorry I was approaching the issue from a completely different
> and somewhat more idealistic angle. My impression is that if the
> driver was in mainline then it would be maintained in such a way
> that vendor compatible strings would not be required, but this is
> all hypothetical.
>
> So in practice, I think I now better understand why vendor
> compatible strings may still be needed. And they're optional, so
> harmless to other platforms, so it's all fine with me :)
SoC specific compatibles are required. They are only optional for a
driver to use.
Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v6 3/6] irqdomain: Add irq_domain_{push,pop}_irq() functions.
From: Linus Walleij @ 2017-04-24 13:05 UTC (permalink / raw)
To: David Daney, Bjorn Helgaas, linux-pci
Cc: Alexandre Courbot, Rob Herring, Mark Rutland, Marc Zyngier,
Thomas Gleixner, linux-gpio@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1491931269-15650-4-git-send-email-david.daney@cavium.com>
Sorry for top posting but we need to loop in Bjorn Helgass and the
linux-pci mailing list on this patch, at least so they see it, and can
recognize similar cases in the future.
(The patch set if very nice.)
Yours,
Linus Walleij
On Tue, Apr 11, 2017 at 7:21 PM, David Daney <david.daney@cavium.com> wrote:
> For an already existing irqdomain hierarchy, as might be obtained via
> a call to pci_enable_msix_range(), a PCI driver wishing to add an
> additional irqdomain to the hierarchy needs to be able to insert the
> irqdomain to that already initialized hierarchy. Calling
> irq_domain_create_hierarchy() allows the new irqdomain to be created,
> but no existing code allows for initializing the associated irq_data.
>
> Add a couple of helper functions (irq_domain_push_irq() and
> irq_domain_pop_irq()) to initialize the irq_data for the new
> irqdomain added to an existing hierarchy.
>
> Signed-off-by: David Daney <david.daney@cavium.com>
> ---
> include/linux/irqdomain.h | 3 +
> kernel/irq/irqdomain.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 181 insertions(+)
>
> diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
> index 9f36160..0316846 100644
> --- a/include/linux/irqdomain.h
> +++ b/include/linux/irqdomain.h
> @@ -425,6 +425,9 @@ extern void irq_domain_free_irqs_common(struct irq_domain *domain,
> extern void irq_domain_free_irqs_top(struct irq_domain *domain,
> unsigned int virq, unsigned int nr_irqs);
>
> +extern int irq_domain_push_irq(struct irq_domain *domain, int virq, void *arg);
> +extern int irq_domain_pop_irq(struct irq_domain *domain, int virq);
> +
> extern int irq_domain_alloc_irqs_parent(struct irq_domain *domain,
> unsigned int irq_base,
> unsigned int nr_irqs, void *arg);
> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
> index 31805f2..ea9d30d 100644
> --- a/kernel/irq/irqdomain.c
> +++ b/kernel/irq/irqdomain.c
> @@ -1304,6 +1304,184 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
> return ret;
> }
>
> +/* The irq_data was moved, fix the revmap to refer to the new location */
> +static void irq_domain_fix_revmap(struct irq_data *d)
> +{
> + void **slot;
> +
> + if (d->hwirq < d->domain->revmap_size)
> + return; /* Not using radix tree. */
> +
> + /* Fix up the revmap. */
> + mutex_lock(&revmap_trees_mutex);
> + slot = radix_tree_lookup_slot(&d->domain->revmap_tree, d->hwirq);
> + if (slot)
> + radix_tree_replace_slot(&d->domain->revmap_tree, slot, d);
> + mutex_unlock(&revmap_trees_mutex);
> +}
> +
> +/**
> + * irq_domain_push_irq() - Push a domain in to the top of a hierarchy.
> + * @domain: Domain to push.
> + * @virq: Irq to push the domain in to.
> + * @arg: Passed to the irq_domain_ops alloc() function.
> + *
> + * For an already existing irqdomain hierarchy, as might be obtained
> + * via a call to pci_enable_msix(), add an additional domain to the
> + * head of the processing chain. Must be called before request_irq()
> + * has been called.
> + */
> +int irq_domain_push_irq(struct irq_domain *domain, int virq, void *arg)
> +{
> + struct irq_data *child_irq_data;
> + struct irq_data *root_irq_data = irq_get_irq_data(virq);
> + struct irq_desc *desc;
> + int rv = 0;
> +
> + /*
> + * Check that no action has been set, which indicates the virq
> + * is in a state where this function doesn't have to deal with
> + * races between interrupt handling and maintaining the
> + * hierarchy. This will catch gross misuse. Attempting to
> + * make the check race free would require holding locks across
> + * calls to struct irq_domain_ops->alloc(), which could lead
> + * to deadlock, so we just do a simple check before starting.
> + */
> + desc = irq_to_desc(virq);
> + if (!desc)
> + return -EINVAL;
> + if (WARN_ON(desc->action))
> + return -EBUSY;
> +
> + if (domain == NULL)
> + return -EINVAL;
> +
> + if (WARN_ON(!domain->ops->alloc))
> + return -EINVAL;
> +
> + if (!root_irq_data)
> + return -EINVAL;
> +
> + child_irq_data = kzalloc_node(sizeof(*child_irq_data), GFP_KERNEL,
> + irq_data_get_node(root_irq_data));
> + if (!child_irq_data)
> + return -ENOMEM;
> +
> + mutex_lock(&irq_domain_mutex);
> +
> + /* Copy the original irq_data. */
> + *child_irq_data = *root_irq_data;
> +
> + irq_domain_fix_revmap(child_irq_data);
> +
> + /*
> + * Overwrite the root_irq_data, which is embedded in struct
> + * irq_desc, with values for this domain.
> + */
> + root_irq_data->parent_data = child_irq_data;
> + root_irq_data->domain = domain;
> + root_irq_data->mask = 0;
> + root_irq_data->hwirq = 0;
> + root_irq_data->chip = NULL;
> + root_irq_data->chip_data = NULL;
> + rv = domain->ops->alloc(domain, virq, 1, arg);
> + if (rv) {
> + /* Restore the original irq_data. */
> + *root_irq_data = *child_irq_data;
> + irq_domain_fix_revmap(root_irq_data);
> + goto error;
> + }
> +
> + if (root_irq_data->hwirq < domain->revmap_size) {
> + domain->linear_revmap[root_irq_data->hwirq] = virq;
> + } else {
> + mutex_lock(&revmap_trees_mutex);
> + radix_tree_insert(&domain->revmap_tree,
> + root_irq_data->hwirq, root_irq_data);
> + mutex_unlock(&revmap_trees_mutex);
> + }
> +error:
> + mutex_unlock(&irq_domain_mutex);
> +
> + return rv;
> +}
> +EXPORT_SYMBOL_GPL(irq_domain_push_irq);
> +
> +/**
> + * irq_domain_pop_irq() - Remove a domain from the top of a hierarchy.
> + * @domain: Domain to remove.
> + * @virq: Irq to remove the domain from.
> + *
> + * Undo the effects of a call to irq_domain_push_irq(). Must be
> + * called either before request_irq() or after free_irq().
> + */
> +int irq_domain_pop_irq(struct irq_domain *domain, int virq)
> +{
> + struct irq_data *root_irq_data = irq_get_irq_data(virq);
> + struct irq_data *child_irq_data;
> + struct irq_data *tmp_irq_data;
> + struct irq_desc *desc;
> +
> + /*
> + * Check that no action is set, which indicates the virq is in
> + * a state where this function doesn't have to deal with races
> + * between interrupt handling and maintaining the hierarchy.
> + * This will catch gross misuse. Attempting to make the check
> + * race free would require holding locks across calls to
> + * struct irq_domain_ops->free(), which could lead to
> + * deadlock, so we just do a simple check before starting.
> + */
> + desc = irq_to_desc(virq);
> + if (!desc)
> + return -EINVAL;
> + if (WARN_ON(desc->action))
> + return -EBUSY;
> +
> + if (domain == NULL)
> + return -EINVAL;
> +
> + if (!root_irq_data)
> + return -EINVAL;
> +
> + tmp_irq_data = irq_domain_get_irq_data(domain, virq);
> +
> + /* We can only "pop" if this domain is at the top of the list */
> + if (WARN_ON(root_irq_data != tmp_irq_data))
> + return -EINVAL;
> +
> + if (WARN_ON(root_irq_data->domain != domain))
> + return -EINVAL;
> +
> + child_irq_data = root_irq_data->parent_data;
> + if (WARN_ON(!child_irq_data))
> + return -EINVAL;
> +
> + mutex_lock(&irq_domain_mutex);
> +
> + root_irq_data->parent_data = NULL;
> +
> + if (root_irq_data->hwirq >= domain->revmap_size) {
> + mutex_lock(&revmap_trees_mutex);
> + radix_tree_delete(&domain->revmap_tree, root_irq_data->hwirq);
> + mutex_unlock(&revmap_trees_mutex);
> + }
> +
> + if (domain->ops->free)
> + domain->ops->free(domain, virq, 1);
> +
> + /* Restore the original irq_data. */
> + *root_irq_data = *child_irq_data;
> +
> + irq_domain_fix_revmap(root_irq_data);
> +
> + mutex_unlock(&irq_domain_mutex);
> +
> + kfree(child_irq_data);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(irq_domain_pop_irq);
> +
> /**
> * irq_domain_free_irqs - Free IRQ number and associated data structures
> * @virq: base IRQ number
> --
> 1.8.3.1
>
^ permalink raw reply
* Re: [PATCH v6 5/6] gpio: Add gpio driver support for ThunderX and OCTEON-TX
From: Linus Walleij @ 2017-04-24 13:08 UTC (permalink / raw)
To: David Daney
Cc: Alexandre Courbot, Rob Herring, Mark Rutland, Marc Zyngier,
Thomas Gleixner, linux-gpio@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1491931269-15650-6-git-send-email-david.daney@cavium.com>
On Tue, Apr 11, 2017 at 7:21 PM, David Daney <david.daney@cavium.com> wrote:
> Cavium ThunderX and OCTEON-TX are arm64 based SoCs. Add driver for
> the on-chip GPIO pins.
>
> Signed-off-by: David Daney <david.daney@cavium.com>
I'm already happy with this driver.
Just waiting for the IRQ people to merge the dependencies
of give their ACKs.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH RFC 0/5] *** SPI Slave mode support ***
From: Geert Uytterhoeven @ 2017-04-24 13:10 UTC (permalink / raw)
To: Jiada Wang
Cc: Mark Brown, Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer,
Fabio Estevam, linux-spi, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <58FDF430.5090306@mentor.com>
Hi Jiada,
On Mon, Apr 24, 2017 at 2:48 PM, Jiada Wang <jiada_wang@mentor.com> wrote:
> On 04/24/2017 03:55 AM, Geert Uytterhoeven wrote:
>> On Fri, Apr 14, 2017 at 7:39 AM, Jiada Wang<jiada_wang@mentor.com> wrote:
>>> On 04/13/2017 12:47 PM, Geert Uytterhoeven wrote:
>>>> On Thu, Apr 13, 2017 at 2:59 PM, Mark Brown<broonie@kernel.org> wrote:
>>>>> On Thu, Apr 13, 2017 at 05:13:59AM -0700, jiada_wang@mentor.com wrote:
>>>>>> From: Jiada Wang<jiada_wang@mentor.com>
>>>>>>
>>>>>> v1:
>>>>>> add Slave mode support in SPI core
>>>>>> spidev create slave device when SPI controller work in slave mode
>>>>>> spi-imx support to work in slave mode
>>>>>
>>>>> Adding Geert who also had a series doing this in progress that was
>>>>> getting very near to being merged.
>>>>
>>>> Thank you!
>>>>
>>>> Actually my plan is to fix the last remaining issues and resubmit for
>>>> v4.13.
>>>
>>> I noticed your patch set for SPI slave support,
>>> (I am sure you can find out some of the change
>>> in this patch set is based on your work).
>>> we have similar requirement to add slave mode support to ecspi IP on imx6
>>> Soc.
>>>
>>> Our use case is to use spidev as an interface to communicate with
>>> external
>>> SPI master devices.
>>> meanwhile the SPI bus controller can also act as master device to send
>>> data
>>> to other
>>> SPI slave devices on the board.
>>
>> That sounds a bit hackish to me. SPI was never meant to be a multi-master
>> bus.
>> While it can be done, you will need external synchronization (signals) to
>> avoid conflicts between the SPI masters.
>
> It doesn't need to be a multi-master bus,
> for example A is master device for slave device B.
> while B has its own slave device C
> for each SPI connection A <=> B, and B <=> C, there is only one master
> device.
>
> and I think from use case point of view, it's very normal,
> one CPU upon receives command from external SPI master device,
> it writes data to its own slave device (EEPROM) connected to it.
So "A <=> B" and "B <=> C" are two distinct SPI buses?
Or do they share some signals?
Your comment seems to suggest otherwise:
> > > I found in your implementation, SPI bus controller is limited to either work in master mode or
> > > slave mode, is there any reasoning to not configure SPI mode based on SPI devices use case?
If they are distinct, it should work. Then B has two SPI controllers: one slave
controller controlled by A, and one master controller to control C.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH v2 1/4] dt-bindings: gpio - add exar to vendor prefixes list
From: Linus Walleij @ 2017-04-24 13:19 UTC (permalink / raw)
To: Nandor Han
Cc: Greg KH, David S. Miller, Geert Uytterhoeven,
Mauro Carvalho Chehab, Daniel Vetter, Alexandre Courbot,
Rob Herring, Mark Rutland, linux-gpio@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <f02af49f4d72326c455c9137ffb2714e7236cbab.1492077070.git.nandor.han@ge.com>
On Thu, Apr 13, 2017 at 12:27 PM, Nandor Han <nandor.han@ge.com> wrote:
> Add Exar Corporation to vendors list.
>
> Signed-off-by: Nandor Han <nandor.han@ge.com>
This patch applied to the GPIO tree with Rob's ACK and
the suggested subject change.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH 2/2] drm/panel: simple: add support for NLT NL192108AC18-02D
From: Lucas Stach @ 2017-04-24 13:21 UTC (permalink / raw)
To: Rob Herring
Cc: Thierry Reding, Mark Rutland,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
devicetree-u79uwXL29TY76Z2rM5mHXA, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
patchwork-lst-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <20170419211518.uie37orpqwda3qaa@rob-hp-laptop>
Hi Rob,
Am Mittwoch, den 19.04.2017, 16:15 -0500 schrieb Rob Herring:
> On Wed, Apr 12, 2017 at 07:15:26PM +0200, Lucas Stach wrote:
> > This adds support for the NLT Technologies NL192108AC18-02D
> > 15.6" LVDS FullHD TFT LCD panel, which can be supported
> > by the simple panel driver.
> >
> > Timings are taken from the preliminary datasheet, as a final
> > one is not yet available.
> >
> > Signed-off-by: Lucas Stach <l.stach-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> > ---
> > .../display/panel/nlt,nl192108ac18-02d.txt | 7 ++++++
> > drivers/gpu/drm/panel/panel-simple.c | 29 ++++++++++++++++++++++
> > 2 files changed, 36 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/display/panel/nlt,nl192108ac18-02d.txt
> >
> > diff --git a/Documentation/devicetree/bindings/display/panel/nlt,nl192108ac18-02d.txt b/Documentation/devicetree/bindings/display/panel/nlt,nl192108ac18-02d.txt
> > new file mode 100644
> > index 000000000000..edc34fbd2131
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/panel/nlt,nl192108ac18-02d.txt
> > @@ -0,0 +1,7 @@
> > +NLT Technologies, Ltd. 15.6" FHD (1920x1080) LVDS TFT LCD panel
> > +
> > +Required properties:
> > +- compatible: should be "nlt,nl192108ac18-02d"
>
> Please define the power supply. Is power-supply used or are there
> multiple supplies?
How would you like to have that done? I thought that the sentence below
is clear enough that this panel uses the simple panel binding where the
power-supply property is non-optional. To me it feels a bit redundant to
say in this binding document that, yes this panel is compatible to the
binding it claims to be compatible with.
And yes, this panel has a single supply for the digital logic.
> > +
> > +This binding is compatible with the simple-panel binding, which is specified
> > +in simple-panel.txt in this directory.
Regards,
Lucas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 2/4] gpio - Add EXAR XRA1403 SPI GPIO expander driver
From: Linus Walleij @ 2017-04-24 13:47 UTC (permalink / raw)
To: Nandor Han
Cc: Greg KH, David S. Miller, Geert Uytterhoeven,
Mauro Carvalho Chehab, Daniel Vetter, Alexandre Courbot,
Rob Herring, Mark Rutland, linux-gpio@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
Semi Malinen
In-Reply-To: <f28eef264102786357ac5ed7205813619c508fb4.1492077070.git.nandor.han@ge.com>
On Thu, Apr 13, 2017 at 12:27 PM, Nandor Han <nandor.han@ge.com> wrote:
> This is a simple driver that provides a /sys/class/gpio
> interface for controlling and configuring the GPIO lines.
> It does not provide support for chip select or interrupts.
>
> Signed-off-by: Nandor Han <nandor.han@ge.com>
> Signed-off-by: Semi Malinen <semi.malinen@ge.com>
I almost want to make the driver depend on !GPIO_SYSFS because
of this commit message.
DO NOT USE OR ENCOURAGE THE USE OF THE GPIO SYSFS
INTERFACE.
Use the character device.
Use the example in tools/gpio/* as a guideline and testbed.
Use libgpiod as a rich userspace.
And the commit message should state that this is a driver
for such and such Exar hardware instead.
Thanks.
> +#include <linux/bitops.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of_device.h>
> +#include <linux/of_gpio.h>
> +#include <linux/spi/spi.h>
> +#include <linux/regmap.h>
You are missing
#include <linux/seq_file.h>
and that is why the build robot is complaining.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH v2 3/4] doc,dts - add XRA1403 DTS binding documentation
From: Linus Walleij @ 2017-04-24 13:49 UTC (permalink / raw)
To: Nandor Han
Cc: Greg KH, David S. Miller, Geert Uytterhoeven,
Mauro Carvalho Chehab, Daniel Vetter, Alexandre Courbot,
Rob Herring, Mark Rutland,
linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <0d970c6a929597804eae3577ed24f57ee23b820a.1492077070.git.nandor.han-JJi787mZWgc@public.gmane.org>
On Thu, Apr 13, 2017 at 12:27 PM, Nandor Han <nandor.han-JJi787mZWgc@public.gmane.org> wrote:
> Add the XRA1403 DTS binding documentation.
>
> Signed-off-by: Nandor Han <nandor.han-JJi787mZWgc@public.gmane.org>
Patch applied with altered subject and Rob's ACK.
Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 2/4] gpio - Add EXAR XRA1403 SPI GPIO expander driver
From: Han, Nandor (GE Healthcare) @ 2017-04-24 13:53 UTC (permalink / raw)
To: Linus Walleij
Cc: Greg KH, David S. Miller, Geert Uytterhoeven,
Mauro Carvalho Chehab, Daniel Vetter, Alexandre Courbot,
Rob Herring, Mark Rutland,
linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Malinen, Semi (GE Healthcare)
In-Reply-To: <CACRpkdZHMWH2W-i4MGZ7NKzPHUURRmC-5YwiK7cVLCHKDsb7sw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
> -----Original Message-----
> From: Linus Walleij [mailto:linus.walleij@linaro.org]
> Sent: 24 April 2017 16:47
> To: Han, Nandor (GE Healthcare) <nandor.han@ge.com>
> Cc: Greg KH <gregkh@linuxfoundation.org>; David S. Miller <davem@davemloft.net>; Geert Uytterhoeven <geert@linux-
> m68k.org>; Mauro Carvalho Chehab <mchehab@kernel.org>; Daniel Vetter <daniel.vetter@ffwll.ch>; Alexandre Courbot
> <gnurou@gmail.com>; Rob Herring <robh+dt@kernel.org>; Mark Rutland <mark.rutland@arm.com>; linux-
> gpio@vger.kernel.org; devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; Malinen, Semi (GE Healthcare)
> <semi.malinen@ge.com>
> Subject: EXT: Re: [PATCH v2 2/4] gpio - Add EXAR XRA1403 SPI GPIO expander driver
>
> On Thu, Apr 13, 2017 at 12:27 PM, Nandor Han <nandor.han@ge.com> wrote:
>
> > This is a simple driver that provides a /sys/class/gpio
> > interface for controlling and configuring the GPIO lines.
> > It does not provide support for chip select or interrupts.
> >
> > Signed-off-by: Nandor Han <nandor.han@ge.com>
> > Signed-off-by: Semi Malinen <semi.malinen@ge.com>
>
> I almost want to make the driver depend on !GPIO_SYSFS because
> of this commit message.
>
> DO NOT USE OR ENCOURAGE THE USE OF THE GPIO SYSFS
> INTERFACE.
>
Ahh.. I forgot to change this commit message. Sorry I will change it ASAP.
> Use the character device.
>
> Use the example in tools/gpio/* as a guideline and testbed.
>
> Use libgpiod as a rich userspace.
>
> And the commit message should state that this is a driver
> for such and such Exar hardware instead.
>
> Thanks.
>
> > +#include <linux/bitops.h>
> > +#include <linux/gpio/driver.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of_gpio.h>
> > +#include <linux/spi/spi.h>
> > +#include <linux/regmap.h>
>
> You are missing
> #include <linux/seq_file.h>
>
> and that is why the build robot is complaining.
>
I've noticed that. I will change it in the next rev.
> Yours,
> Linus Walleij
Thanks,
Nandy
^ permalink raw reply
* Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes
From: Philipp Zabel @ 2017-04-24 14:10 UTC (permalink / raw)
To: Peter Rosin
Cc: Jonathan Cameron, linux-kernel, Greg Kroah-Hartman, Wolfram Sang,
Rob Herring, Mark Rutland, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, linux-i2c, devicetree,
linux-iio, linux-doc, Andrew Morton, Colin Ian King,
Paul Gortmaker, kernel
In-Reply-To: <2d978956-d247-917d-4150-a6723917a733@axentia.se>
On Mon, 2017-04-24 at 13:37 +0200, Peter Rosin wrote:
> On 2017-04-24 12:52, Philipp Zabel wrote:
> > On Mon, 2017-04-24 at 10:36 +0200, Peter Rosin wrote:
> >> Hi!
> >>
> >> The big change since v13 is that the mux state is now locked with a mutex
> >> instead of an rwsem. Other that that, it is mostly restructuring and doc
> >> changes. There are a few other "real" changes as well, but those changes
> >> feel kind of minor. I guess what I'm trying to say is that although the
> >> list of changes for v14 is longish, it's still basically the same as last
> >> time.
> >
> > I have hooked this up to the video-multiplexer and now I trigger
> > the lockdep debug_check_no_locks_held error message when selecting the
> > mux input from userspace:
> >
> > $ media-ctl --links "'imx6-mipi-csi2':1->'ipu1_csi0_mux':0[1]"
> > [ 66.258368]
> > [ 66.259919] =====================================
> > [ 66.265369] [ BUG: media-ctl/258 still has locks held! ]
> > [ 66.270810] 4.11.0-rc8-20170424-1+ #1305 Not tainted
> > [ 66.275863] -------------------------------------
> > [ 66.282158] 1 lock held by media-ctl/258:
> > [ 66.286464] #0: (&mux->lock){+.+.+.}, at: [<8074a6c0>] mux_control_select+0x24/0x50
> > [ 66.294424]
> > [ 66.294424] stack backtrace:
> > [ 66.298980] CPU: 0 PID: 258 Comm: media-ctl Not tainted 4.11.0-rc8+ #1305
> > [ 66.306771] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
> > [ 66.313334] Backtrace:
> > [ 66.315858] [<8010e5a4>] (dump_backtrace) from [<8010e8ac>] (show_stack+0x20/0x24)
> > [ 66.323473] r7:80e518d0 r6:80e518d0 r5:600d0013 r4:00000000
> > [ 66.329190] [<8010e88c>] (show_stack) from [<80496cf4>] (dump_stack+0xb0/0xdc)
> > [ 66.336470] [<80496c44>] (dump_stack) from [<8017e404>] (debug_check_no_locks_held+0xb8/0xbc)
> > [ 66.345043] r9:ae8566b8 r8:ad88dc84 r7:ad88df58 r6:ad88dc84 r5:ad88df58 r4:ae856400
> > [ 66.352837] [<8017e34c>] (debug_check_no_locks_held) from [<8012b258>] (do_exit+0x79c/0xcc8)
> > [ 66.361321] [<8012aabc>] (do_exit) from [<8012d25c>] (do_group_exit+0x4c/0xcc)
> > [ 66.368581] r7:000000f8
> > [ 66.371161] [<8012d210>] (do_group_exit) from [<8012d2fc>] (__wake_up_parent+0x0/0x30)
> > [ 66.379120] r7:000000f8 r6:76f71798 r5:00000000 r4:00000001
> > [ 66.384837] [<8012d2dc>] (SyS_exit_group) from [<80109380>] (ret_fast_syscall+0x0/0x1c)
> >
> > That correctly warns that the media-ctl process caused the mux->lock to
> > be locked and still held when the process exited. Do we need a usage
> > counter based mechanism for muxes that are (indirectly) controlled from
> > userspace?
[...]
> The question then becomes how to best tell the mux core that you want
> an exclusive mux. I see two options. Either you declare a mux controller
> as exclusive up front somehow (in the device tree presumably), or you
> add a mux_control_get_exclusive call that makes further calls to
> mux_control_get{,_exclusive} fail with -EBUSY. I think I like the
> latter better, if that can be made to work...
How about an atomic use_count on the mux_control, a bool shared that is
only set by the first consumer, and controls whether selecting locks?
----------8<----------
diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index c02fa4dd2d099..1d18bb7f15e07 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -372,11 +372,12 @@ int mux_control_select(struct mux_control *mux, unsigned int state)
{
int ret;
- mutex_lock(&mux->lock);
+ if (mux->shared)
+ mutex_lock(&mux->lock);
ret = __mux_control_select(mux, state);
- if (ret < 0)
+ if (ret < 0 && mux->shared)
mutex_unlock(&mux->lock);
return ret;
@@ -399,12 +400,12 @@ int mux_control_try_select(struct mux_control *mux, unsigned int state)
{
int ret;
- if (!mutex_trylock(&mux->lock))
+ if (mux->shared && !mutex_trylock(&mux->lock))
return -EBUSY;
ret = __mux_control_select(mux, state);
- if (ret < 0)
+ if (ret < 0 && mux->shared)
mutex_unlock(&mux->lock);
return ret;
@@ -427,7 +428,8 @@ int mux_control_deselect(struct mux_control *mux)
mux->idle_state != mux->cached_state)
ret = mux_control_set(mux, mux->idle_state);
- mutex_unlock(&mux->lock);
+ if (mux->shared)
+ mutex_unlock(&mux->lock);
return ret;
}
@@ -447,18 +449,13 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
return dev ? to_mux_chip(dev) : NULL;
}
-/**
- * mux_control_get() - Get the mux-control for a device.
- * @dev: The device that needs a mux-control.
- * @mux_name: The name identifying the mux-control.
- *
- * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
- */
-struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+static struct mux_control *__mux_control_get(struct device *dev,
+ const char *mux_name, bool shared)
{
struct device_node *np = dev->of_node;
struct of_phandle_args args;
struct mux_chip *mux_chip;
+ struct mux_control *mux;
unsigned int controller;
int index = 0;
int ret;
@@ -505,9 +502,56 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
}
get_device(&mux_chip->dev);
- return &mux_chip->mux[controller];
+
+ mux = &mux_chip->mux[controller];
+
+ ret = atomic_inc_return(&mux->use_count);
+ if (ret == 1 && shared)
+ mux->shared = true;
+ if (ret > 1 && (!shared || !mux->shared)) {
+ atomic_dec(&mux->use_count);
+ put_device(&mux_chip->dev);
+ return ERR_PTR(-EBUSY);
+ }
+
+ return mux;
+}
+
+/**
+ * mux_control_get_shared() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * The returned mux control is in shared mode and can not be controlled from
+ * userspace. The mux control lock is taken when the mux is selected and
+ * released when the mux is deselected.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get_shared(struct device *dev,
+ const char *mux_name)
+{
+ return __mux_control_get(dev, mux_name, true);
+}
+EXPORT_SYMBOL_GPL(mux_control_get_shared);
+
+/**
+ * mux_control_get_exclusive() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * The returned mux control is in exclusive mode and does not lock the mux
+ * control lock when the mux is selected. The exclusive consumer has to take
+ * care of locking, if necessary.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get_exclusive(struct device *dev,
+ const char *mux_name)
+{
+ return __mux_control_get(dev, mux_name, false);
}
-EXPORT_SYMBOL_GPL(mux_control_get);
+EXPORT_SYMBOL_GPL(mux_control_get_exclusive);
/**
* mux_control_put() - Put away the mux-control for good.
@@ -517,6 +561,7 @@ EXPORT_SYMBOL_GPL(mux_control_get);
*/
void mux_control_put(struct mux_control *mux)
{
+ atomic_dec(&mux->use_count);
put_device(&mux->chip->dev);
}
EXPORT_SYMBOL_GPL(mux_control_put);
@@ -528,16 +573,9 @@ static void devm_mux_control_release(struct device *dev, void *res)
mux_control_put(mux);
}
-/**
- * devm_mux_control_get() - Get the mux-control for a device, with resource
- * management.
- * @dev: The device that needs a mux-control.
- * @mux_name: The name identifying the mux-control.
- *
- * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
- */
-struct mux_control *devm_mux_control_get(struct device *dev,
- const char *mux_name)
+static struct mux_control *__devm_mux_control_get(struct device *dev,
+ const char *mux_name,
+ bool shared)
{
struct mux_control **ptr, *mux;
@@ -545,7 +583,7 @@ struct mux_control *devm_mux_control_get(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
- mux = mux_control_get(dev, mux_name);
+ mux = __mux_control_get(dev, mux_name, shared);
if (IS_ERR(mux)) {
devres_free(ptr);
return mux;
@@ -556,7 +594,36 @@ struct mux_control *devm_mux_control_get(struct device *dev,
return mux;
}
-EXPORT_SYMBOL_GPL(devm_mux_control_get);
+
+/**
+ * devm_mux_control_get_shared() - Get the mux-control for a device, with
+ * resource management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get_shared(struct device *dev,
+ const char *mux_name)
+{
+ return __devm_mux_control_get(dev, mux_name, true);
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get_shared);
+
+/**
+ * devm_mux_control_get_exclusive() - Get the mux-control for a device, with
+ * resource management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *devm_mux_control_get_exclusive(struct device *dev,
+ const char *mux_name)
+{
+ return __devm_mux_control_get(dev, mux_name, false);
+}
+EXPORT_SYMBOL_GPL(devm_mux_control_get_exclusive);
static int devm_mux_control_match(struct device *dev, void *res, void *data)
{
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index a2a61834bd3ae..26634c3dda124 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -23,11 +23,16 @@ int __must_check mux_control_try_select(struct mux_control *mux,
unsigned int state);
int mux_control_deselect(struct mux_control *mux);
-struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
+struct mux_control *mux_control_get_exclusive(struct device *dev,
+ const char *mux_name);
+struct mux_control *mux_control_get_shared(struct device *dev,
+ const char *mux_name);
void mux_control_put(struct mux_control *mux);
-struct mux_control *devm_mux_control_get(struct device *dev,
- const char *mux_name);
+struct mux_control *devm_mux_control_get_exclusive(struct device *dev,
+ const char *mux_name);
+struct mux_control *devm_mux_control_get_shared(struct device *dev,
+ const char *mux_name);
void devm_mux_control_put(struct device *dev, struct mux_control *mux);
#endif /* _LINUX_MUX_CONSUMER_H */
diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
index 95269f40670a7..0ac5d3db9cd3e 100644
--- a/include/linux/mux/driver.h
+++ b/include/linux/mux/driver.h
@@ -31,17 +31,20 @@ struct mux_control_ops {
/**
* struct mux_control - Represents a mux controller.
- * @lock: Protects the mux controller state.
+ * @lock: Protects the mux controller state, if shared.
* @chip: The mux chip that is handling this mux controller.
* @cached_state: The current mux controller state, or -1 if none.
* @states: The number of mux controller states.
* @idle_state: The mux controller state to use when inactive, or one
* of MUX_IDLE_AS_IS and MUX_IDLE_DISCONNECT.
+ * @use_count: Number of consumers that have requested this mux.
+ * @shared: True if the mux control was requested as shared and
+ * must therefore be locked.
*
* Mux drivers may only change @states and @idle_state, and may only do so
* between allocation and registration of the mux controller. Specifically,
- * @cached_state is internal to the mux core and should never be written by
- * mux drivers.
+ * @cached_state, @use_count, and @shared are internal to the mux core and
+ * should never be written by mux drivers.
*/
struct mux_control {
struct mutex lock; /* protects the state of the mux */
@@ -51,6 +54,9 @@ struct mux_control {
unsigned int states;
int idle_state;
+
+ atomic_t use_count;
+ bool shared;
};
/**
---------->8----------
regards
Philipp
^ permalink raw reply related
* Re: [PATCH 08/13] OF/PCI: Add IORESOURCE_MEM_64 for 64-bit resource
From: Rob Herring @ 2017-04-24 14:12 UTC (permalink / raw)
To: Yinghai Lu
Cc: Bjorn Helgaas, David Miller, Benjamin Herrenschmidt, Wei Yang,
Khalid Aziz, linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Grant Likely, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <20170421050500.13957-9-yinghai-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On Fri, Apr 21, 2017 at 12:04 AM, Yinghai Lu <yinghai-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> For device resource PREF bit setting under bridge 64-bit pref resource,
> we need to make sure only set PREF for 64bit resource.
>
> This patch set IORESOUCE_MEM_64 for 64bit resource during OF device
> resource flags parsing.
>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=96261
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=96241
> Signed-off-by: Yinghai Lu <yinghai-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Grant Likely <grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Tested-by: Khalid Aziz <khalid.aziz-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
> ---
> drivers/of/address.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC PATH] of/pci/dma: fix DMA configruation for PCI masters
From: Rob Herring @ 2017-04-24 14:20 UTC (permalink / raw)
To: Oza Pawandeep
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Oza Pawandeep,
linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux IOMMU,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
In-Reply-To: <1492848487-11768-1-git-send-email-oza.oza-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
On Sat, Apr 22, 2017 at 3:08 AM, Oza Pawandeep <oza.oza-dY08KVG/lbpWk0Htik3J/w@public.gmane.org> wrote:
> current device frmework and of framework integration assumes dma-ranges
> in a way where memory-mapped devices define their dma-ranges.
> dma-ranges: (child-bus-address, parent-bus-address, length).
>
> but iproc based SOCs and other SOCs(suc as rcar) have PCI world dma-ranges.
> dma-ranges = <0x43000000 0x00 0x00 0x00 0x00 0x80 0x00>;
>
> of_dma_configure is specifically witten to take care of memory mapped devices.
> but no implementation exists for pci to take care of pcie based memory ranges.
> in fact pci world doesnt seem to define standard dma-ranges
>
> this patch served following purposes
>
> 1) exposes intrface to the pci host driver for thir inbound memory ranges
>
> 2) provide an interface to callers such as of_dma_get_ranges.
> so then the returned size get best possible (largest) dma_mask.
> for e.g.
> dma-ranges = <0x43000000 0x00 0x00 0x00 0x00 0x80 0x00>;
> we should get dev->coherent_dma_mask=0x7fffffffff.
>
> 3) this patch handles multiple inbound windows and dma-ranges.
> it is left to the caller, how it wants to use them.
> the new function returns the resources in a standard and unform way
>
> 4) this way the callers of of_dma_get_ranges does not need to change.
> and
>
> 5) leaves scope of adding PCI flag handling for inbound memory
> by the new function.
>
> Signed-off-by: Oza Pawandeep <oza.oza-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
>
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index 02b2903..ec21191 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -6,6 +6,7 @@
> #include <linux/ioport.h>
> #include <linux/module.h>
> #include <linux/of_address.h>
> +#include <linux/of_pci.h>
> #include <linux/pci.h>
> #include <linux/pci_regs.h>
> #include <linux/sizes.h>
> @@ -829,10 +830,30 @@ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *siz
> int len, naddr, nsize, pna;
> int ret = 0;
> u64 dmaaddr;
> + struct resource_entry *window;
> + LIST_HEAD(res);
>
> if (!node)
> return -EINVAL;
>
> + if (strcmp(np->name, "pci")) {
Using the name is not reliable though I did recently add a dtc check
for this. Of course, 'pcie' is valid too (and probably should be used
for what you are testing). type is what you want to use here. We
already have bus matching function and bus specific handlers in
address.c. Whatever solution you come up with should be integrated
with the existing bus specific handlers.
Rob
^ permalink raw reply
* Re: [PATCH 2/3] drm/vc4: Don't try to initialize FBDEV if we're only bound to V3D.
From: Alex Deucher @ 2017-04-24 14:26 UTC (permalink / raw)
To: Eric Anholt
Cc: Mark Rutland, devicetree@vger.kernel.org,
Linux Kernel Mailing List, dri-devel, Rob Herring
In-Reply-To: <87wpadtlsl.fsf@eliezer.anholt.net>
On Fri, Apr 21, 2017 at 6:53 PM, Eric Anholt <eric@anholt.net> wrote:
> Daniel Vetter <daniel@ffwll.ch> writes:
>
>> On Wed, Apr 19, 2017 at 7:55 PM, Eric Anholt <eric@anholt.net> wrote:
>>> Daniel Vetter <daniel@ffwll.ch> writes:
>>>> On Tue, Apr 18, 2017 at 9:11 PM, Eric Anholt <eric@anholt.net> wrote:
>>>>> The FBDEV initialization would throw an error in dmesg, when we just
>>>>> want to silently not initialize fbdev on a V3D-only VC4 instance.
>>>>>
>>>>> Signed-off-by: Eric Anholt <eric@anholt.net>
>>>>
>>>> Hm, this shouldn't be an error really, you might want to hotplug more
>>>> connectors later on. What exactly complains?
>>>
>>> drm_fb_helper_init() throws an error if the passed in connector count is
>>> 0, so drm_fb_cma_helper() printks an error.
>>
>> Oh, _that_ thing. The error in there is correct, but (almost) everyone
>> gets this parameter wrong. This isn't the max number of connectors the
>> fb helper will light up, but just the max number of connectors _per_
>> crtc when driving in hw clone mode. There's two problems with that:
>> - fb helpers don't support hw clone mode, we select 1:1 crtcs for each
>> active connector
>> - I mentioned that everyone gets this wrong?
>>
>> If you're moderately bored it'd be great to nuke the max_connector
>> argument from drm_fb_helper_init, and hard-code it to 1 (with a big
>> comment explaining that this needs to be changed, probably with
>> dynamic reallocation, once someone gets around to implementing hw
>> clone mode).
>>
>> If you're less bored, just hardcode this to 1 in vc4 and done. Plus a
>> TODO.rst entry would be great in that case.
>
> If I'm driving a GPU with no display subsystem at all, it seems like I
> shouldn't initialize fbdev for it, right?
That's what we do for radeon/amdgpu on hw without display blocks.
Alex
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes
From: Peter Rosin @ 2017-04-24 14:36 UTC (permalink / raw)
To: Philipp Zabel
Cc: Jonathan Cameron, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Greg Kroah-Hartman, Wolfram Sang, Rob Herring, Mark Rutland,
Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
Jonathan Corbet, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Colin Ian King,
Paul Gortmaker, kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <1493043046.2446.37.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On 2017-04-24 16:10, Philipp Zabel wrote:
> On Mon, 2017-04-24 at 13:37 +0200, Peter Rosin wrote:
>> On 2017-04-24 12:52, Philipp Zabel wrote:
>>> On Mon, 2017-04-24 at 10:36 +0200, Peter Rosin wrote:
>>>> Hi!
>>>>
>>>> The big change since v13 is that the mux state is now locked with a mutex
>>>> instead of an rwsem. Other that that, it is mostly restructuring and doc
>>>> changes. There are a few other "real" changes as well, but those changes
>>>> feel kind of minor. I guess what I'm trying to say is that although the
>>>> list of changes for v14 is longish, it's still basically the same as last
>>>> time.
>>>
>>> I have hooked this up to the video-multiplexer and now I trigger
>>> the lockdep debug_check_no_locks_held error message when selecting the
>>> mux input from userspace:
>>>
>>> $ media-ctl --links "'imx6-mipi-csi2':1->'ipu1_csi0_mux':0[1]"
>>> [ 66.258368]
>>> [ 66.259919] =====================================
>>> [ 66.265369] [ BUG: media-ctl/258 still has locks held! ]
>>> [ 66.270810] 4.11.0-rc8-20170424-1+ #1305 Not tainted
>>> [ 66.275863] -------------------------------------
>>> [ 66.282158] 1 lock held by media-ctl/258:
>>> [ 66.286464] #0: (&mux->lock){+.+.+.}, at: [<8074a6c0>] mux_control_select+0x24/0x50
>>> [ 66.294424]
>>> [ 66.294424] stack backtrace:
>>> [ 66.298980] CPU: 0 PID: 258 Comm: media-ctl Not tainted 4.11.0-rc8+ #1305
>>> [ 66.306771] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
>>> [ 66.313334] Backtrace:
>>> [ 66.315858] [<8010e5a4>] (dump_backtrace) from [<8010e8ac>] (show_stack+0x20/0x24)
>>> [ 66.323473] r7:80e518d0 r6:80e518d0 r5:600d0013 r4:00000000
>>> [ 66.329190] [<8010e88c>] (show_stack) from [<80496cf4>] (dump_stack+0xb0/0xdc)
>>> [ 66.336470] [<80496c44>] (dump_stack) from [<8017e404>] (debug_check_no_locks_held+0xb8/0xbc)
>>> [ 66.345043] r9:ae8566b8 r8:ad88dc84 r7:ad88df58 r6:ad88dc84 r5:ad88df58 r4:ae856400
>>> [ 66.352837] [<8017e34c>] (debug_check_no_locks_held) from [<8012b258>] (do_exit+0x79c/0xcc8)
>>> [ 66.361321] [<8012aabc>] (do_exit) from [<8012d25c>] (do_group_exit+0x4c/0xcc)
>>> [ 66.368581] r7:000000f8
>>> [ 66.371161] [<8012d210>] (do_group_exit) from [<8012d2fc>] (__wake_up_parent+0x0/0x30)
>>> [ 66.379120] r7:000000f8 r6:76f71798 r5:00000000 r4:00000001
>>> [ 66.384837] [<8012d2dc>] (SyS_exit_group) from [<80109380>] (ret_fast_syscall+0x0/0x1c)
>>>
>>> That correctly warns that the media-ctl process caused the mux->lock to
>>> be locked and still held when the process exited. Do we need a usage
>>> counter based mechanism for muxes that are (indirectly) controlled from
>>> userspace?
> [...]
>> The question then becomes how to best tell the mux core that you want
>> an exclusive mux. I see two options. Either you declare a mux controller
>> as exclusive up front somehow (in the device tree presumably), or you
>> add a mux_control_get_exclusive call that makes further calls to
>> mux_control_get{,_exclusive} fail with -EBUSY. I think I like the
>> latter better, if that can be made to work...
>
> How about an atomic use_count on the mux_control, a bool shared that is
> only set by the first consumer, and controls whether selecting locks?
That has the drawback that it is hard to restore the mux-control in a safe
way so that exclusive consumers are allowed after the last shared consumer
puts the mux away. Agreed, it's a corner case, but I had this very similar
patch going through the compiler when I got this mail. Does it work as well
as what you suggested?
Cheers,
peda
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index e2343d9cbec7..5a7352a83124 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -342,7 +342,8 @@ MUX
devm_mux_chip_free()
devm_mux_chip_register()
devm_mux_chip_unregister()
- devm_mux_control_get()
+ devm_mux_control_get_shared()
+ devm_mux_control_get_exclusive()
devm_mux_control_put()
PER-CPU MEM
diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c
index 92cf5f48afe6..135d6baaebe5 100644
--- a/drivers/i2c/muxes/i2c-mux-gpmux.c
+++ b/drivers/i2c/muxes/i2c-mux-gpmux.c
@@ -87,7 +87,7 @@ static int i2c_mux_probe(struct platform_device *pdev)
if (!mux)
return -ENOMEM;
- mux->control = devm_mux_control_get(dev, NULL);
+ mux->control = devm_mux_control_get_shared(dev, NULL);
if (IS_ERR(mux->control)) {
if (PTR_ERR(mux->control) != -EPROBE_DEFER)
dev_err(dev, "failed to get control-mux\n");
diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c
index 37ba007f8dca..fc41e9d10737 100644
--- a/drivers/iio/multiplexer/iio-mux.c
+++ b/drivers/iio/multiplexer/iio-mux.c
@@ -413,7 +413,7 @@ static int mux_probe(struct platform_device *pdev)
}
}
- mux->control = devm_mux_control_get(dev, NULL);
+ mux->control = devm_mux_control_get_shared(dev, NULL);
if (IS_ERR(mux->control)) {
if (PTR_ERR(mux->control) != -EPROBE_DEFER)
dev_err(dev, "failed to get control-mux\n");
diff --git a/drivers/mux/mux-core.c b/drivers/mux/mux-core.c
index c02fa4dd2d09..6055e7c3ad1c 100644
--- a/drivers/mux/mux-core.c
+++ b/drivers/mux/mux-core.c
@@ -37,6 +37,7 @@ static struct class mux_class = {
};
static DEFINE_IDA(mux_ida);
+static DEFINE_MUTEX(mux_lock);
static int __init mux_init(void)
{
@@ -333,7 +334,8 @@ unsigned int mux_control_states(struct mux_control *mux)
EXPORT_SYMBOL_GPL(mux_control_states);
/*
- * The mux->lock must be held when calling this function.
+ * The mux->lock must be held when calling this function if the
+ * mux-control is shared.
*/
static int __mux_control_select(struct mux_control *mux, int state)
{
@@ -372,11 +374,12 @@ int mux_control_select(struct mux_control *mux, unsigned int state)
{
int ret;
- mutex_lock(&mux->lock);
+ if (mux->shared >= 0)
+ mutex_lock(&mux->lock);
ret = __mux_control_select(mux, state);
- if (ret < 0)
+ if (ret < 0 && mux->shared >= 0)
mutex_unlock(&mux->lock);
return ret;
@@ -399,12 +402,12 @@ int mux_control_try_select(struct mux_control *mux, unsigned int state)
{
int ret;
- if (!mutex_trylock(&mux->lock))
+ if (mux->shared >= 0 && !mutex_trylock(&mux->lock))
return -EBUSY;
ret = __mux_control_select(mux, state);
- if (ret < 0)
+ if (ret < 0 && mux->shared >= 0)
mutex_unlock(&mux->lock);
return ret;
@@ -427,7 +430,8 @@ int mux_control_deselect(struct mux_control *mux)
mux->idle_state != mux->cached_state)
ret = mux_control_set(mux, mux->idle_state);
- mutex_unlock(&mux->lock);
+ if (mux->shared >= 0)
+ mutex_unlock(&mux->lock);
return ret;
}
@@ -447,18 +451,13 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
return dev ? to_mux_chip(dev) : NULL;
}
-/**
- * mux_control_get() - Get the mux-control for a device.
- * @dev: The device that needs a mux-control.
- * @mux_name: The name identifying the mux-control.
- *
- * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
- */
-struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+struct mux_control *__mux_control_get(struct device *dev, const char *mux_name,
+ bool shared)
{
struct device_node *np = dev->of_node;
struct of_phandle_args args;
struct mux_chip *mux_chip;
+ struct mux_control *mux;
unsigned int controller;
int index = 0;
int ret;
@@ -504,10 +503,20 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
return ERR_PTR(-EINVAL);
}
+ mux = &mux_chip->mux[controller];
+
+ mutex_lock(&mux_lock);
+ if (WARN_ON(mux->shared < 0 || (!shared && mux->shared))) {
+ mutex_unlock(&mux_lock);
+ return ERR_PTR(-EBUSY);
+ }
+ mux->shared = shared ? mux->shared + 1 : -1;
+ mutex_unlock(&mux_lock);
+
get_device(&mux_chip->dev);
- return &mux_chip->mux[controller];
+ return mux;
}
-EXPORT_SYMBOL_GPL(mux_control_get);
+EXPORT_SYMBOL_GPL(__mux_control_get);
/**
* mux_control_put() - Put away the mux-control for good.
@@ -517,6 +526,14 @@ EXPORT_SYMBOL_GPL(mux_control_get);
*/
void mux_control_put(struct mux_control *mux)
{
+ mutex_lock(&mux_lock);
+ WARN_ON(!mux->shared);
+ if (mux->shared > 0)
+ --mux->shared;
+ else
+ mux->shared = 0;
+ mutex_unlock(&mux_lock);
+
put_device(&mux->chip->dev);
}
EXPORT_SYMBOL_GPL(mux_control_put);
@@ -528,16 +545,9 @@ static void devm_mux_control_release(struct device *dev, void *res)
mux_control_put(mux);
}
-/**
- * devm_mux_control_get() - Get the mux-control for a device, with resource
- * management.
- * @dev: The device that needs a mux-control.
- * @mux_name: The name identifying the mux-control.
- *
- * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
- */
-struct mux_control *devm_mux_control_get(struct device *dev,
- const char *mux_name)
+struct mux_control *__devm_mux_control_get(struct device *dev,
+ const char *mux_name,
+ bool shared)
{
struct mux_control **ptr, *mux;
@@ -545,7 +555,7 @@ struct mux_control *devm_mux_control_get(struct device *dev,
if (!ptr)
return ERR_PTR(-ENOMEM);
- mux = mux_control_get(dev, mux_name);
+ mux = __mux_control_get(dev, mux_name, shared);
if (IS_ERR(mux)) {
devres_free(ptr);
return mux;
@@ -556,7 +566,7 @@ struct mux_control *devm_mux_control_get(struct device *dev,
return mux;
}
-EXPORT_SYMBOL_GPL(devm_mux_control_get);
+EXPORT_SYMBOL_GPL(__devm_mux_control_get);
static int devm_mux_control_match(struct device *dev, void *res, void *data)
{
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index a2a61834bd3a..611dcec7fa3a 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -23,11 +23,81 @@ int __must_check mux_control_try_select(struct mux_control *mux,
unsigned int state);
int mux_control_deselect(struct mux_control *mux);
-struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
+struct mux_control *__mux_control_get(struct device *dev,
+ const char *mux_name, bool shared);
void mux_control_put(struct mux_control *mux);
-
-struct mux_control *devm_mux_control_get(struct device *dev,
- const char *mux_name);
+struct mux_control *__devm_mux_control_get(struct device *dev,
+ const char *mux_name, bool shared);
void devm_mux_control_put(struct device *dev, struct mux_control *mux);
+/**
+ * mux_control_get_shared() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * A shared mux-control can be operated by several independent consumers.
+ * The mux core will coordinate access by grabbing a lock when the mux-control
+ * is selected and releasing it when it is deselected.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+static inline struct mux_control *mux_control_get_shared(
+ struct device *dev,
+ const char *mux_name)
+{
+ return __mux_control_get(dev, mux_name, true);
+}
+
+/**
+ * mux_control_get_exclusive() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * An exclusive mux-control can only be operated by a single consumer. The
+ * mux core will return EBUSY for any further attempts to get a mux-control
+ * that already has an exclusive consumer. The mux core will also not lock
+ * the mux-control on mux_control_select, and the consumer is free to call
+ * repeatedly call select without calling mux_control_deselect. The consumer
+ * may however still call mux_control_deselect in order to activate the idle
+ * state.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+static inline struct mux_control *mux_control_get_exclusive(
+ struct device *dev,
+ const char *mux_name)
+{
+ return __mux_control_get(dev, mux_name, false);
+}
+
+/**
+ * devm_mux_control_get_shared() - Get a shared mux-control for a device, with
+ * resource management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+static inline struct mux_control *devm_mux_control_get_shared(
+ struct device *dev,
+ const char *mux_name)
+{
+ return __devm_mux_control_get(dev, mux_name, true);
+}
+
+/**
+ * devm_mux_control_get_exclusive() - Get an exclusive mux-control for a
+ * device, with resource management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+static inline struct mux_control *devm_mux_control_get_exclusive(
+ struct device *dev,
+ const char *mux_name)
+{
+ return __devm_mux_control_get(dev, mux_name, false);
+}
+
#endif /* _LINUX_MUX_CONSUMER_H */
diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
index 95269f40670a..882e9be3d185 100644
--- a/include/linux/mux/driver.h
+++ b/include/linux/mux/driver.h
@@ -33,6 +33,8 @@ struct mux_control_ops {
* struct mux_control - Represents a mux controller.
* @lock: Protects the mux controller state.
* @chip: The mux chip that is handling this mux controller.
+ * @shared: The shared state, -1 if exclusive, 0 if no consumer
+ * and if positive the number of sharing consumers.
* @cached_state: The current mux controller state, or -1 if none.
* @states: The number of mux controller states.
* @idle_state: The mux controller state to use when inactive, or one
@@ -40,13 +42,14 @@ struct mux_control_ops {
*
* Mux drivers may only change @states and @idle_state, and may only do so
* between allocation and registration of the mux controller. Specifically,
- * @cached_state is internal to the mux core and should never be written by
- * mux drivers.
+ * @cached_state and @shared are internal to the mux core and should never be
+ * written by mux drivers.
*/
struct mux_control {
struct mutex lock; /* protects the state of the mux */
struct mux_chip *chip;
+ int shared;
int cached_state;
unsigned int states;
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH v14 00/11] mux controller abstraction and iio/i2c muxes
From: Philipp Zabel @ 2017-04-24 14:59 UTC (permalink / raw)
To: Peter Rosin
Cc: Jonathan Cameron, linux-kernel, Greg Kroah-Hartman, Wolfram Sang,
Rob Herring, Mark Rutland, Hartmut Knaack, Lars-Peter Clausen,
Peter Meerwald-Stadler, Jonathan Corbet, linux-i2c, devicetree,
linux-iio, linux-doc, Andrew Morton, Colin Ian King,
Paul Gortmaker, kernel
In-Reply-To: <6fb34ea5-edc8-c7aa-1d49-f6ce1d33a2d4@axentia.se>
On Mon, 2017-04-24 at 16:36 +0200, Peter Rosin wrote:
[...]
> > How about an atomic use_count on the mux_control, a bool shared that is
> > only set by the first consumer, and controls whether selecting locks?
>
> That has the drawback that it is hard to restore the mux-control in a safe
> way so that exclusive consumers are allowed after the last shared consumer
> puts the mux away.
True.
> Agreed, it's a corner case, but I had this very similar
> patch going through the compiler when I got this mail. Does it work as well
> as what you suggested?
Yes, this patch works just as well.
regards
Philipp
^ permalink raw reply
* Re: [PATCH v8 1/3] backlight arcxcnn add arc to vendor prefix
From: Rob Herring @ 2017-04-24 15:09 UTC (permalink / raw)
To: Olimpiu Dejeu
Cc: Lee Jones, linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Jingoo Han,
bdodge-eV7fy4qpoLhpLGFMi4vTTA, Joe Perches,
medasaro-eV7fy4qpoLhpLGFMi4vTTA, Daniel Thompson
In-Reply-To: <1489607133-7870-1-git-send-email-olimpiu-eV7fy4qpoLhpLGFMi4vTTA@public.gmane.org>
On Wed, Mar 15, 2017 at 2:45 PM, Olimpiu Dejeu <olimpiu-eV7fy4qpoLhpLGFMi4vTTA@public.gmane.org> wrote:
> backlight: Add arc to vendor prefixes
> Signed-off-by: Olimpiu Dejeu <olimpiu-eV7fy4qpoLhpLGFMi4vTTA@public.gmane.org>
> ---
> v8:
> - Version to match other patches in set
>
> Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index 16d3b5e..6f33a4b 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -28,6 +28,7 @@ andestech Andes Technology Corporation
> apm Applied Micro Circuits Corporation (APM)
> aptina Aptina Imaging
> arasan Arasan Chip Systems
> +arc Arctic Sand
arc is also a cpu arch. While not a vendor, it could be confusing. How
about "arctic" instead?
BTW, some reason your patches are not going to the DT list.
Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH V2 1/4] mfd: Add ROHM BD9571MWV-M PMIC DT bindings
From: Marek Vasut @ 2017-04-24 15:21 UTC (permalink / raw)
To: linux-renesas-soc
Cc: Marek Vasut, devicetree, Rob Herring, Geert Uytterhoeven
Add DT bindings for the ROHM BD9571MWV-M PMIC. This PMIC has
the following features:
- multiple voltage monitors for 1V8, 2V5, 3V3 voltage rail
- one voltage regulator for DVFS
- two GPIOs
Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: devicetree@vger.kernel.org
Cc: Rob Herring <robh@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: linux-renesas-soc@vger.kernel.org
---
V2: - Drop the compatible = "regulator-fixed" from the binding example,
it should not be there.
- List the VD09 regulator
---
.../devicetree/bindings/mfd/bd9571mwv.txt | 49 ++++++++++++++++++++++
1 file changed, 49 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/bd9571mwv.txt
diff --git a/Documentation/devicetree/bindings/mfd/bd9571mwv.txt b/Documentation/devicetree/bindings/mfd/bd9571mwv.txt
new file mode 100644
index 000000000000..ce24231edd7d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/bd9571mwv.txt
@@ -0,0 +1,49 @@
+* ROHM BD9571MWV Power Management Integrated Circuit (PMIC) bindings
+
+Required properties:
+ - compatible : Should be "rohm,bd9571mwv".
+ - reg : I2C slave address.
+ - interrupt-parent : Phandle to the parent interrupt controller.
+ - interrupts : The interrupt line the device is connected to.
+ - interrupt-controller : Marks the device node as an interrupt controller.
+ - #interrupt-cells : The number of cells to describe an IRQ, should be 2.
+ The first cell is the IRQ number.
+ The second cell is the flags, encoded as trigger
+ masks from ../interrupt-controller/interrupts.txt.
+ - gpio-controller : Marks the device node as a GPIO Controller.
+ - #gpio-cells : Should be two. The first cell is the pin number and
+ the second cell is used to specify flags.
+ See ../gpio/gpio.txt for more information.
+ - regulators: : List of child nodes that specify the regulator
+ initialization data. Child nodes must be named
+ after their hardware counterparts:
+ - vd09
+ - vd18
+ - vd25
+ - vd33
+ - dvfs
+ Each child node is defined using the standard
+ binding for regulators.
+
+Example:
+
+ pmic: bd9571mwv@30 {
+ compatible = "rohm,bd9571mwv";
+ reg = <0x30>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ regulators {
+ dvfs: dvfs {
+ regulator-name = "dvfs";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1030000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
--
2.11.0
^ permalink raw reply related
* Re: [PATCH V2 1/4] dt-bindings: mtd: make partitions doc a bit more generic
From: Jonas Gorski @ 2017-04-24 15:28 UTC (permalink / raw)
To: Rafał Miłecki
Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
Frank Rowand, Linus Walleij, MTD Maling List,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Geert Uytterhoeven, Rafał Miłecki
In-Reply-To: <20170424124120.31613-2-zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hi,
On 24 April 2017 at 14:41, Rafał Miłecki <zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> From: Brian Norris <computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>
> Currently the only documented partitioning is "fixed-partitions" but
> there are more methods in use that we may want to support in the future.
> Mention them and make it clear Fixed Partitions are just a single case.
>
> Signed-off-by: Brian Norris <computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Rafał Miłecki <rafal-g1n6cQUeyibVItvQsEIGlw@public.gmane.org>
> ---
> This is based on Brian's patch:
> [RFC PATCH 3/7] doc: dt: mtd: partition: add on-flash format binding
>
> V1: Dropped "Section B: On-Flash Partition Tables" with Google's FMAP as this
> patchset doesn't add that new parser.
> V2: Add "We currently only document a binding for fixed layouts." part
> ---
> .../devicetree/bindings/mtd/partition.txt | 30 +++++++++++++++++-----
> 1 file changed, 24 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
> index 81a224da63be..b5de311b967a 100644
> --- a/Documentation/devicetree/bindings/mtd/partition.txt
> +++ b/Documentation/devicetree/bindings/mtd/partition.txt
> @@ -1,29 +1,47 @@
> -Representing flash partitions in devicetree
> +Flash partitions in device tree
> +===============================
>
> -Partitions can be represented by sub-nodes of an mtd device. This can be used
> +Flash devices can be partitioned into one or more functional ranges (e.g. "boot
> +code", "nvram", "kernel").
> +
> +Different devices may be partitioned in a different ways. Some may use a fixed
> +flash layout set at production time. Some may use on-flash table that describes
> +the geometry and naming/purpose of each functional region. It is also possible
> +to see these methods mixed.
> +
> +To assist system software in locating partitions, we provide a binding to
> +describe which method is used for a given flash.
Since patch 3 adds specifying methods through the compatible of the
partitions subnode, maybe we should document that here? Something
along
"To assist system software in locating partitions, we allow describing
which method is used for a given flash device. To describe the method
there should be a subnode of the flash device that is named
'partitions'. It must have a 'compatible' property, which is used to
identify the method to use."
Regards
Jonas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V2 3/4] mtd: partitions: add of_match_table parser matching
From: Jonas Gorski @ 2017-04-24 15:31 UTC (permalink / raw)
To: Rafał Miłecki
Cc: David Woodhouse, Brian Norris, Boris Brezillon, Marek Vasut,
Richard Weinberger, Cyrille Pitchen, Rob Herring, Mark Rutland,
Frank Rowand, Linus Walleij, MTD Maling List,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Geert Uytterhoeven, Rafał Miłecki
In-Reply-To: <20170424124120.31613-4-zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hi,
On 24 April 2017 at 14:41, Rafał Miłecki <zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> From: Brian Norris <computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>
> Partition parsers can now provide an of_match_table to enable
> flash<-->parser matching via device tree.
>
> This support is currently limited to built-in parsers as it uses
> request_module() and friends. This should be sufficient for most cases
> though as compiling parsers as modules isn't a common choice.
>
> Signed-off-by: Brian Norris <computersforpeace-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Rafał Miłecki <rafal-g1n6cQUeyibVItvQsEIGlw@public.gmane.org>
> Acked-by: Brian Norris <computersforpeac-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
> This is based on Brian's patches:
> [RFC PATCH 4/7] mtd: add of_match_mtd_parser() and of_mtd_match_mtd_parser() helpers
> [RFC PATCH 6/7] RFC: mtd: partitions: enable of_match_table matching
>
> V1: Put helpers in mtdpart.c instead of drivers/of/of_mtd.c
> Merge helpers into a single of_mtd_match_mtd_parser
> ---
> drivers/mtd/mtdpart.c | 47 ++++++++++++++++++++++++++++++++++++++++++
> include/linux/mtd/partitions.h | 1 +
> 2 files changed, 48 insertions(+)
>
> diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
> index 73c52f1a2e4c..d0cb1a892ed2 100644
> --- a/drivers/mtd/mtdpart.c
> +++ b/drivers/mtd/mtdpart.c
> @@ -861,6 +861,41 @@ static int mtd_part_do_parse(struct mtd_part_parser *parser,
> return ret;
> }
>
> +static bool of_mtd_match_mtd_parser(struct mtd_info *mtd,
> + struct mtd_part_parser *parser)
> +{
> + struct device_node *np;
> + bool ret;
> +
> + np = mtd_get_of_node(mtd);
> + np = of_get_child_by_name(np, "partitions");
> +
> + ret = !!of_match_node(parser->of_match_table, np);
> +
> + of_node_put(np);
> +
> + return ret;
> +}
> +
> +static struct mtd_part_parser *mtd_part_get_parser_by_of(struct mtd_info *mtd)
> +{
> + struct mtd_part_parser *p, *ret = NULL;
> +
> + spin_lock(&part_parser_lock);
> +
> + list_for_each_entry(p, &part_parsers, list) {
> + if (of_mtd_match_mtd_parser(mtd, p) &&
> + try_module_get(p->owner)) {
> + ret = p;
> + break;
> + }
> + }
Hm, maybe iterate over the compatibles, so parsers matching the most
specific compatible get precedence in case there is more than one
compatible? Currently it will match the first one that matches any
compatible, and registration order of parsers can change that. I'm
thinking of parsers that partially rely on fixed, unprobable layouts,
so can use "fixed-partitions" as a fallback compatible.
E.g. having something like this
partitions {
compatible = "sample,custom-layout", "fixed-partitions";
bootloader@0 { ... };
firmware@10000 { .... }; /* will be split by the parser */
extra@780000 { .... }; /* partition the on-flash format can't specify */
};
Where you will still be able to write an image raw to the image
partition even if the "custom-layout"-parser isn't present/enabled,
but if it is present, it should always be used.
Regards
Jonas
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 2/2] dmaengine: Add DW AXI DMAC driver
From: Eugeniy Paltsev @ 2017-04-24 15:55 UTC (permalink / raw)
To: andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org
Cc: vinod.koul-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
Alexey.Brodkin-HKixBCOQz3hWk0Htik3J/w@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Eugeniy.Paltsev-HKixBCOQz3hWk0Htik3J/w@public.gmane.org,
linux-snps-arc-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
dan.j.williams-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org,
dmaengine-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1492787583.24567.120.camel-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Hi,
On Fri, 2017-04-21 at 18:13 +0300, Andy Shevchenko wrote:
> On Fri, 2017-04-21 at 14:29 +0000, Eugeniy Paltsev wrote:
> > On Tue, 2017-04-18 at 15:31 +0300, Andy Shevchenko wrote:
> > > On Fri, 2017-04-07 at 17:04 +0300, Eugeniy Paltsev wrote:
> > > > This patch adds support for the DW AXI DMAC controller.
> > > > +#define AXI_DMA_BUSWIDTHS \
> > > > + (DMA_SLAVE_BUSWIDTH_1_BYTE | \
> > > > + DMA_SLAVE_BUSWIDTH_2_BYTES | \
> > > > + DMA_SLAVE_BUSWIDTH_4_BYTES | \
> > > > + DMA_SLAVE_BUSWIDTH_8_BYTES | \
> > > > + DMA_SLAVE_BUSWIDTH_16_BYTES | \
> > > > + DMA_SLAVE_BUSWIDTH_32_BYTES | \
> > > > + DMA_SLAVE_BUSWIDTH_64_BYTES)
> > > > +/* TODO: check: do we need to use BIT() macro here? */
> > >
> > > Still TODO? I remember I answered to this on the first round.
> >
> > Yes, I remember it.
> > I left this TODO as a reminder because src_addr_widths and
> > dst_addr_widths are
> > not used anywhere and they are set differently in different drivers
> > (with or without BIT macro).
>
> Strange. AFAIK they are representing bits (which is not the best
> idea) in the resulting u64 field. So, anything bigger than 63 doesn't
> make sense.
They are u32 fields!
From dmaengine.h :
struct dma_device {
...
u32 src_addr_widths;
u32 dst_addr_widths;
};
> In drivers where they are not bits quite likely a bug is hidden.
For example (from pxa_dma.c):
const enum dma_slave_buswidth widths = DMA_SLAVE_BUSWIDTH_1_BYTE |
DMA_SLAVE_BUSWIDTH_2_BYTES | DMA_SLAVE_BUSWIDTH_4_BYTES;
And there are a lot of drivers, which don't use BIT for this fields.
sh/shdmac.c
sh/rcar-dmac.c
qcom/bam_dma.c
mmp_pdma.c
ste_dma40.c
And many others...
> >
> > > > +
> > > > +static inline void
> > > > +axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32 val)
> > > > +{
> > > > + iowrite32(val, chip->regs + reg);
> > >
> > > Are you going to use IO ports for this IP? I don't think so.
> > > Wouldn't be better to call readl()/writel() instead?
> >
> > As I understand, it's better to use ioread/iowrite as more
> > universal
> > IO
> > access way. Am I wrong?
>
> As I said above the ioreadX/iowriteX makes only sense when your IP
> would be accessed via IO region or MMIO. I'm pretty sure IO is not
> the case at all for this IP.
MMIO? This IP works exactly via memory-mapped I/O.
> > > > +static inline void axi_chan_irq_disable(struct axi_dma_chan
> > > > *chan,
> > > > u32 irq_mask)
> > > > +{
> > > > + u32 val;
> > > > +
> > > > + if (likely(irq_mask == DWAXIDMAC_IRQ_ALL)) {
> > > > + axi_chan_iowrite32(chan, CH_INTSTATUS_ENA,
> > > > DWAXIDMAC_IRQ_NONE);
> > > > + } else {
> > >
> > > I don't see the benefit. (Yes, I see one read-less path, I think
> > > it
> > > makes perplexity for nothing here)
> >
> > This function is called mostly with irq_mask = DWAXIDMAC_IRQ_ALL.
> > Actually it is called only with irq_mask = DWAXIDMAC_IRQ_ALL until
> > I add DMA_SLAVE support.
> > But I can cut off this 'if' statment, if it is necessery.
>
> It's not necessary, but from my point of view increases readability
> of the code a lot for the price of an additional readl().
Ok.
> >
> > > > + val = axi_chan_ioread32(chan,
> > > > CH_INTSTATUS_ENA);
> > > > + val &= ~irq_mask;
> > > > + axi_chan_iowrite32(chan, CH_INTSTATUS_ENA,
> > > > val);
> > > > + }
> > > > +
> > > > + return min_t(size_t, __ffs(sdl), max_width);
> > > > +}
> > > > +static void axi_desc_put(struct axi_dma_desc *desc)
> > > > +{
> > > > + struct axi_dma_chan *chan = desc->chan;
> > > > + struct dw_axi_dma *dw = chan->chip->dw;
> > > > + struct axi_dma_desc *child, *_next;
> > > > + unsigned int descs_put = 0;
> > > > + list_for_each_entry_safe(child, _next, &desc-
> > > > >xfer_list,
> > > > xfer_list) {
> > >
> > > xfer_list looks redundant.
> > > Can you elaborate why virtual channel management is not working
> > > for
> > > you?
> >
> > Each virtual descriptor encapsulates several hardware descriptors,
> > which belong to same transfer.
> > This list (xfer_list) is used only for allocating/freeing these
> > descriptors and it doesn't affect on virtual dma work logic.
> > I can see this approach in several drivers with VirtDMA (but they
> > mostly use array instead of list)
>
> You described how most of the DMA drivers are implemented, though
> they
> are using just sg_list directly. I would recommend to do the same and
> get rid of this list.
This IP can be (ans is) configured with small block size.
(note, that I am not saying about runtime HW configuration)
And there is opportunity what we can't use sg_list directly and need to
split sg_list to a smaller chunks.
> > > Btw, are you planning to use priority at all? For now on I didn't
> > > see
> > > a single driver (from the set I have checked, like 4-5 of them)
> > > that
> > > uses priority anyhow. It makes driver more complex for nothing.
> >
> > Only for dma slave operations.
>
> So, in other words you *have* an actual two or more users that *need*
> prioritization?
As I remember there was an idea to give higher priority to audio dma
chanels.
> > > > + if (unlikely(dst_nents == 0 || src_nents == 0))
> > > > + return NULL;
> > > > +
> > > > + if (unlikely(dst_sg == NULL || src_sg == NULL))
> > > > + return NULL;
> > >
> > > If we need those checks they should go to
> > > dmaengine.h/dmaengine.c.
> >
> > I checked several drivers, which implements device_prep_dma_sg and
> > they
> > implements this checkers.
> > Should I add something like "dma_sg_desc_invalid" function to
> > dmaengine.h ?
>
> I suppose it's better to implement them in the corresponding helpers
> in dmaengine.h.
Ok.
> > > > +static void axi_chan_list_dump_lli(struct axi_dma_chan *chan,
> > > > + struct axi_dma_desc
> > > > *desc_head)
> > > > +{
> > > > + struct axi_dma_desc *desc;
> > > > +
> > > > + axi_chan_dump_lli(chan, desc_head);
> > > > + list_for_each_entry(desc, &desc_head->xfer_list,
> > > > xfer_list)
> > > > + axi_chan_dump_lli(chan, desc);
> > > > +}
> > > > +
> > > > +static void axi_chan_handle_err(struct axi_dma_chan *chan, u32
> > > > status)
> > > > +{
> > > > + /* WARN about bad descriptor */
> > > >
> > > > + dev_err(chan2dev(chan),
> > > > + "Bad descriptor submitted for %s, cookie: %d,
> > > > irq:
> > > > 0x%08x\n",
> > > > + axi_chan_name(chan), vd->tx.cookie, status);
> > > > + axi_chan_list_dump_lli(chan, vd_to_axi_desc(vd));
> > >
> > > As I said earlier dw_dmac is *bad* example of the (virtual
> > > channel
> > > based) DMA driver.
> > >
> > > I guess you may just fail the descriptor and don't pretend it has
> > > been processed successfully.
> >
> > What do you mean by saying "fail the descriptor"?
> > After I get error I cancel current transfer and free all
> > descriptors
> > from it (by calling vchan_cookie_complete).
> > I can't store error status in descriptor structure because it will
> > be
> > freed by vchan_cookie_complete.
> > I can't store error status in channel structure because it will be
> > overwritten by next transfer.
>
> Better not to pretend that it has been processed successfully. Don't
> call callback on it and set its status to DMA_ERROR (that's why
> descriptors in many drivers have dma_status field). When user asks
> for
> status (using cookie) the saved value would be returned until
> descriptor
> is active.
>
> Do you have some other workflow in mind?
Hmm...
Do you mean I should left error descriptors in desc_issued list
or I should create another list (like desc_error) in my driver and move
error descriptors to desc_error list?
And when exactly should I free error descriptors?
I checked hsu/hsu.c dma driver implementation:
vdma descriptor is deleted from desc_issued list when transfer
starts. When descriptor marked as error descriptor
vchan_cookie_complete isn't called for this descriptor. And this
descriptor isn't placed in any list. So error descriptors *never*
will be freed.
I don't actually like this approach.
> > > > +
> > > > +static const struct dev_pm_ops dw_axi_dma_pm_ops = {
> > > > + SET_RUNTIME_PM_OPS(axi_dma_runtime_suspend,
> > > > axi_dma_runtime_resume, NULL)
> > > > +};
> > >
> > > Have you tried to build with CONFIG_PM disabled?
> >
> > Yes.
> >
> > > I'm pretty sure you need __maybe_unused applied to your PM ops.
> >
> > I call axi_dma_runtime_suspend / axi_dma_runtime_resume even I
> > dont't
> > use PM.
> > (I call them in probe / remove function.)
>
> Hmm... I didn't check your ->probe() and ->remove(). Do you mean you
> call them explicitly by those names?
>
> If so, please don't do that. Use pm_runtime_*() instead. And...
>
> > So I don't need to declare them with __maybe_unused.
>
> ...in that case it's possible you have them defined but not used.
>
From my ->probe() function:
pm_runtime_get_noresume(chip->dev);
ret = axi_dma_runtime_resume(chip->dev);
Firstly I only incrememt counter.
Secondly explicitly call my resume function.
I call them explicitly because I need driver to work also without
Runtime PM. So I can't just call pm_runtime_get here instead of
pm_runtime_get_noresume + axi_dma_runtime_resume.
Of course I can copy *all* code from axi_dma_runtime_resume
to ->probe() function, but I don't really like this idea.
> > > > +struct axi_dma_chan {
> > > > + struct axi_dma_chip *chip;
> > > > + void __iomem *chan_regs;
> > > > + u8 id;
> > > > + atomic_t descs_allocated;
> > > > +
> > > > + struct virt_dma_chan vc;
> > > > +
> > > > + /* these other elements are all protected by vc.lock
> > > > */
> > > > + bool is_paused;
> > >
> > > I still didn't get (already forgot) why you can't use dma_status
> > > instead for the active descriptor?
> >
> > As I said before, I checked several driver, which have status
> > variable
> > in their channel structure - it is used *only* for determinating is
> > channel paused or not. So there is no much sense in replacing
> > "is_paused" to "status" and I left "is_paused" variable untouched.
>
> Not only (see above), the errored descriptor keeps that status.
>
> > (I described above why we can't use status in channel structure for
> > error handling)
>
> Ah, I'm talking about descriptor.
Again - PAUSED is per-channel flag. So, even if we have status field in
each descriptor, it is simpler to use one per-channel flag instead of
plenty per-descriptor flags.
When we pausing/resuming dma channel it is simpler to set only one flag
instead of writing DMA_PAUSED to *each* descriptor status field.
> > > > Status Fetch Addr */
> > > > +#define CH_INTSTATUS_ENA 0x080 /* R/W Chan Interrupt
> > > > Status
> > > > Enable */
> > > > +#define CH_INTSTATUS 0x088 /* R/W Chan
> > > > Interrupt
> > > > Status */
> > > > +#define CH_INTSIGNAL_ENA 0x090 /* R/W Chan Interrupt
> > > > Signal
> > > > Enable */
> > > > +#define CH_INTCLEAR 0x098 /* W Chan Interrupt
> > > > Clear
> > > > */
> > >
> > > I'm wondering if you can use regmap API instead.
> >
> > Is it really necessary? It'll make driver more complex for nothing.
>
> That's why I'm not suggesting but wondering.
> >
> > > > +};
> > >
> > > Hmm... do you need them in the header?
> >
> > I use some of these definitions in my code so I guess yes.
> > /* Maybe I misunderstood your question... */
>
> I mean, who are the users of them? If it's only one module, there is
> no need to put them in header.
Yes, only one module.
Should I move all this definitions to axi_dma_platform.c file and rid
of both axi_dma_platform_reg.h and axi_dma_platform.h headers?
> >
> > > > +#define CH_CFG_H_TT_FC_POS 0
> > > > +enum {
> > > > + DWAXIDMAC_TT_FC_MEM_TO_MEM_DMAC = 0x0,
> > > > + DWAXIDMAC_TT_FC_MEM_TO_PER_DMAC,
> > > > + DWAXIDMAC_TT_FC_PER_TO_MEM_DMAC,
> > > > + DWAXIDMAC_TT_FC_PER_TO_PER_DMAC,
> > > > + DWAXIDMAC_TT_FC_PER_TO_MEM_SRC,
> > > > + DWAXIDMAC_TT_FC_PER_TO_PER_SRC,
> > > > + DWAXIDMAC_TT_FC_MEM_TO_PER_DST,
> > > > + DWAXIDMAC_TT_FC_PER_TO_PER_DST
> > > > +};
> > >
> > > Some of definitions are the same as for dw_dmac, right? We might
> > > split them to a common header, though I have no strong opinion
> > > about
> >
> > it.
> > > Vinod?
> >
> > APB DMAC and AXI DMAC have completely different regmap. So there is
> > no
> > much sense to do that.
>
> I'm not talking about registers, I'm talking about definitions like
> above. Though it would be indeed little sense to split some common
> code between those two.
This definitions are the fields of some registers. So they are also
different.
--
Eugeniy Paltsev
^ permalink raw reply
* [PATCH v4 00/10] AXP803 PMIC support for Pine64
From: Icenowy Zheng @ 2017-04-24 16:00 UTC (permalink / raw)
To: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
Lee Jones, Liam Girdwood
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Icenowy Zheng
The Pine64 (including Pine64+) boards have an AXP803 PMIC, which is a PMIC
similar to AXP288, but tweaked to use with Allwinner SoCs rather than Intel
tablets (with DCIN and Vbus re-splitted like other AXP PMICs, and RSB bus
support added).
This patchset adds support for it and enabled it in Pine64 device tree.
The basical part of AXP803 MFD driver is already applied, according to Lee.
Thus this patchset is now still two parts, but a bit different to older
revisions:
- Part1: from PATCH 1/10 to PATCH 5/10, which focus on enabling AXP803 in
the device tree: the RSB bus, the R_INTC interrupt controller (for the
NMI line, which is connected to AXP803 on Pine64), and finally the basical
AXP803 node.
- Part2: from PATCH 5/10 to PATCH 10/10, which are enabling the regulator
function of the AXP803 PMIC. Finally Wi-Fi function is added
as a usage of regulators function.
PATCH 1 adds RSB device nodes, which is used for the communication between
A64 and AXP803.
PATCH 2 adds device tree binding of A64 R_INTC.
PATCH 3 really adds support for A64 R_INTC in NMI driver.
PATCH 4 adds R_INTC node in A64 device tree.
PATCH 5 adds AXP803 node to the Pine64 device tree by using already
applied drivers/bindings.
PATCH 6 adds support for AXP803 regulators in AXP20x regulatoe driver.
(The binding is already applied)
PATCH 7 enables the AXP803 regulator cell in MFD driver.
PATCH 8 adds a DTSI file for AXP803, like other older AXP PMICs.
PATCH 9 enables AXP803 regulators in Pine64 device tree.
PATCH 10 enables Wi-Fi for Pine64.
Icenowy Zheng (10):
arm64: allwinner: a64: enable RSB on A64
irqchip/sunxi-nmi: add A64 R_INTC to the binding doc
irqchip/sunxi-nmi: add support for the NMI in A64 R_INTC
arm64: allwinner: a64: add NMI (R_INTC) controller on A64
arm64: allwinner: a64: add AXP803 node to Pine64 device tree
regulator: axp20x-regulator: add support for AXP803
mfd: axp20x: add axp20x-regulator cell for AXP803
arm64: allwinner: a64: add DTSI file for AXP803 PMIC
arm64: allwinner: a64: enable AXP803 regulators for Pine64
arm64: allwinner: a64: enable Wi-Fi for Pine64
.../interrupt-controller/allwinner,sunxi-nmi.txt | 7 +-
arch/arm64/boot/dts/allwinner/axp803.dtsi | 150 ++++++++++++++++++++
.../arm64/boot/dts/allwinner/sun50i-a64-pine64.dts | 136 ++++++++++++++++++
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 27 ++++
drivers/irqchip/irq-sunxi-nmi.c | 13 ++
drivers/mfd/axp20x.c | 3 +-
drivers/regulator/axp20x-regulator.c | 153 ++++++++++++++++++---
include/linux/mfd/axp20x.h | 37 +++++
8 files changed, 501 insertions(+), 25 deletions(-)
create mode 100644 arch/arm64/boot/dts/allwinner/axp803.dtsi
--
2.12.2
^ permalink raw reply
* [PATCH v4 01/10] arm64: allwinner: a64: enable RSB on A64
From: Icenowy Zheng @ 2017-04-24 16:00 UTC (permalink / raw)
To: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
Lee Jones, Liam Girdwood
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Icenowy Zheng
In-Reply-To: <20170424160103.9447-1-icenowy-h8G6r0blFSE@public.gmane.org>
Allwinner A64 have a RSB controller like the one on A23/A33 SoCs.
Add it and its pinmux.
Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
---
Changes in v2:
- Removed bonus properties in pio node.
- Added Chen-Yu's ACK.
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index c7f669f5884f..05ec9fc5e81f 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -422,6 +422,25 @@
#gpio-cells = <3>;
interrupt-controller;
#interrupt-cells = <3>;
+
+ r_rsb_pins: rsb@0 {
+ pins = "PL0", "PL1";
+ function = "s_rsb";
+ };
+ };
+
+ r_rsb: rsb@1f03400 {
+ compatible = "allwinner,sun8i-a23-rsb";
+ reg = <0x01f03400 0x400>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&r_ccu 6>;
+ clock-frequency = <3000000>;
+ resets = <&r_ccu 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_rsb_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
};
};
};
--
2.12.2
^ permalink raw reply related
* [PATCH v4 02/10] irqchip/sunxi-nmi: add A64 R_INTC to the binding doc
From: Icenowy Zheng @ 2017-04-24 16:00 UTC (permalink / raw)
To: Thomas Gleixner, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
Lee Jones, Liam Girdwood
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Icenowy Zheng
In-Reply-To: <20170424160103.9447-1-icenowy-h8G6r0blFSE@public.gmane.org>
The A31 NMI driver seems to be using wrong base address.
As we're going to convert to use a correct NMI base address (and
correctly name it to R_INTC as the datasheet suggests), add a new
compatible string for the "correct" R_INTC, which we will use for A64
SoC.
Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
---
New patch in v4, which is part of NMI refactor.
.../bindings/interrupt-controller/allwinner,sunxi-nmi.txt | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt
index 81cd3692405e..fea0c6a6211f 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt
@@ -3,8 +3,11 @@ Allwinner Sunxi NMI Controller
Required properties:
-- compatible : should be "allwinner,sun7i-a20-sc-nmi" or
- "allwinner,sun6i-a31-sc-nmi" or "allwinner,sun9i-a80-nmi"
+- compatible : should be one of:
+ "allwinner,sun6i-a31-sc-nmi"
+ "allwinner,sun7i-a20-sc-nmi"
+ "allwinner,sun9i-a80-nmi"
+ "allwinner,sun50i-a64-r-intc"
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
--
2.12.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox