summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2022-09-14 15:52:59 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2022-09-14 15:52:59 +0200
commit19df0b5883737c6ce50b893dfc8fe1722cd6560a (patch)
tree4a90f708d33a44f0b40eab69134543c38629c884
parentd01b0a64580833b4ccf10e6361badee1d81e1221 (diff)
parent7a9d2377b5e54cfec28a7645985a7371c1d8b8af (diff)
downloadbarebox-19df0b5883737c6ce50b893dfc8fe1722cd6560a.tar.gz
Merge branch 'for-next/misc'
-rwxr-xr-xDocumentation/gen_commands.py4
-rw-r--r--arch/arm/dts/imx8mm.dtsi52
-rw-r--r--arch/arm/dts/imx8mn.dtsi31
-rw-r--r--commands/Kconfig8
-rw-r--r--commands/Makefile1
-rw-r--r--commands/gpio.c51
-rw-r--r--commands/mm.c6
-rw-r--r--commands/pm_domain.c18
-rw-r--r--commands/selftest.c2
-rw-r--r--common/blspec.c14
-rw-r--r--common/bootm.c5
-rw-r--r--common/oftree.c43
-rw-r--r--common/usbgadget.c37
-rw-r--r--drivers/base/Kconfig3
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/driver.c25
-rw-r--r--drivers/base/featctrl.c160
-rw-r--r--drivers/base/power.c10
-rw-r--r--drivers/gpio/gpiolib.c59
-rw-r--r--drivers/i2c/i2c.c33
-rw-r--r--drivers/mfd/Kconfig8
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/axp20x-i2c.c71
-rw-r--r--drivers/mfd/axp20x.c360
-rw-r--r--drivers/net/phy/mdio_bus.c2
-rw-r--r--drivers/nvmem/core.c33
-rw-r--r--drivers/nvmem/ocotp.c62
-rw-r--r--drivers/of/Kconfig12
-rw-r--r--drivers/of/base.c67
-rw-r--r--drivers/of/overlay.c20
-rw-r--r--drivers/of/platform.c17
-rw-r--r--drivers/power/reset/reboot-mode.c13
-rw-r--r--drivers/reset/Kconfig1
-rw-r--r--drivers/soc/imx/Kconfig6
-rw-r--r--drivers/soc/imx/Makefile1
-rw-r--r--drivers/soc/imx/imx8m-featctrl.c64
-rw-r--r--fs/fs.c50
-rw-r--r--fs/pstore/ram.c34
-rw-r--r--fs/ubifs/super.c5
-rw-r--r--fs/ubifs/ubifs.c9
-rw-r--r--include/bselftest.h5
-rw-r--r--include/driver.h5
-rw-r--r--include/dt-bindings/features/imx8m.h14
-rw-r--r--include/featctrl.h29
-rw-r--r--include/fs.h1
-rw-r--r--include/gpio.h6
-rw-r--r--include/i2c/i2c.h2
-rw-r--r--include/linux/mfd/axp20x.h477
-rw-r--r--include/linux/nvmem-consumer.h9
-rw-r--r--include/of.h28
-rw-r--r--include/pm_domain.h2
-rw-r--r--include/soc/imx8m/featctrl.h25
-rw-r--r--include/usb/gadget-multi.h3
-rw-r--r--test/self/core.c26
-rw-r--r--test/self/of_manipulation.c12
-rw-r--r--test/self/of_manipulation.dts6
56 files changed, 1921 insertions, 128 deletions
diff --git a/Documentation/gen_commands.py b/Documentation/gen_commands.py
index a55b1acd82..7c62a030dc 100755
--- a/Documentation/gen_commands.py
+++ b/Documentation/gen_commands.py
@@ -1,6 +1,4 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
+#!/usr/bin/env python3
import errno
import os
diff --git a/arch/arm/dts/imx8mm.dtsi b/arch/arm/dts/imx8mm.dtsi
index 78bbacb2b1..22ae01a20a 100644
--- a/arch/arm/dts/imx8mm.dtsi
+++ b/arch/arm/dts/imx8mm.dtsi
@@ -1,10 +1,18 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+#include <dt-bindings/features/imx8m.h>
+
/ {
aliases {
gpr.reboot_mode = &reboot_mode_gpr;
};
};
+feat: &ocotp {
+ #feature-cells = <1>;
+ barebox,feature-controller;
+};
+
&src {
compatible = "fsl,imx8mm-src", "fsl,imx8mq-src", "syscon", "simple-mfd";
@@ -16,3 +24,47 @@
mode-serial = <0x00000010>, <0x40000000>;
};
};
+
+&A53_1 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_CPU_DUAL>;
+};
+
+&A53_2 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_CPU_QUAD>;
+};
+
+&A53_3 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_CPU_QUAD>;
+};
+
+&gpc {
+ barebox,feature-gates = <&feat 0>;
+};
+
+&vpu_g1 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_VPU>;
+};
+
+&vpu_g2 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_VPU>;
+};
+
+&vpu_blk_ctrl {
+ barebox,feature-gates = <&feat IMX8M_FEAT_VPU>;
+};
+
+&pgc_vpumix {
+ barebox,feature-gates = <&feat IMX8M_FEAT_VPU>;
+};
+
+&pgc_vpu_g1 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_VPU>;
+};
+
+&pgc_vpu_g2 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_VPU>;
+};
+
+&pgc_vpu_h1 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_VPU>;
+};
diff --git a/arch/arm/dts/imx8mn.dtsi b/arch/arm/dts/imx8mn.dtsi
index 9ce49d735e..17e8f78bf2 100644
--- a/arch/arm/dts/imx8mn.dtsi
+++ b/arch/arm/dts/imx8mn.dtsi
@@ -1 +1,32 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+#include <dt-bindings/features/imx8m.h>
+
+feat: &ocotp {
+ #feature-cells = <1>;
+ barebox,feature-controller;
+};
+
+&A53_1 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_CPU_DUAL>;
+};
+
+&A53_2 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_CPU_QUAD>;
+};
+
+&A53_3 {
+ barebox,feature-gates = <&feat IMX8M_FEAT_CPU_QUAD>;
+};
+
+&gpc {
+ barebox,feature-gates = <&feat 0>;
+};
+
+&gpu {
+ barebox,feature-gates = <&feat IMX8M_FEAT_GPU>;
+};
+
+&pgc_gpumix {
+ barebox,feature-gates = <&feat IMX8M_FEAT_GPU>;
+};
diff --git a/commands/Kconfig b/commands/Kconfig
index 3e21dc4c05..9894ecb9aa 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -240,6 +240,14 @@ config CMD_REGULATOR
the regulator command lists the currently registered regulators and
their current state.
+config CMD_PM_DOMAIN
+ bool
+ depends on PM_GENERIC_DOMAINS
+ prompt "pm_domain command"
+ help
+ The pm_domain command lists the currently registered power domains and
+ their current state.
+
config CMD_NVMEM
bool
depends on NVMEM
diff --git a/commands/Makefile b/commands/Makefile
index 0aae8893d6..068fbb32da 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -116,6 +116,7 @@ obj-$(CONFIG_CMD_READF) += readf.o
obj-$(CONFIG_CMD_MENUTREE) += menutree.o
obj-$(CONFIG_CMD_2048) += 2048.o
obj-$(CONFIG_CMD_REGULATOR) += regulator.o
+obj-$(CONFIG_CMD_PM_DOMAIN) += pm_domain.o
obj-$(CONFIG_CMD_LSPCI) += lspci.o
obj-$(CONFIG_CMD_IMD) += imd.o
obj-$(CONFIG_CMD_HWCLOCK) += hwclock.o
diff --git a/commands/gpio.c b/commands/gpio.c
index 955b60e91b..d04fd65bc8 100644
--- a/commands/gpio.c
+++ b/commands/gpio.c
@@ -4,27 +4,58 @@
#include <command.h>
#include <errno.h>
#include <gpio.h>
+#include <getopt.h>
static int get_gpio_and_value(int argc, char *argv[],
int *gpio, int *value)
{
- const int count = value ? 3 : 2;
+ struct gpio_chip *chip = NULL;
+ struct device_d *dev;
+ int count = 2;
int ret = 0;
+ int opt;
+
+ while ((opt = getopt(argc, argv, "d:")) > 0) {
+ switch (opt) {
+ case 'd':
+ dev = find_device(optarg);
+ if (!dev)
+ return -ENODEV;
+
+ chip = gpio_get_chip_by_dev(dev);
+ if (!chip)
+ return -EINVAL;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ if (value)
+ count++;
- if (argc < count)
+ if (optind < count)
return COMMAND_ERROR_USAGE;
- *gpio = gpio_find_by_name(argv[1]);
+ *gpio = gpio_find_by_name(argv[optind]);
if (*gpio < 0)
- *gpio = gpio_find_by_label(argv[1]);
+ *gpio = gpio_find_by_label(argv[optind]);
if (*gpio < 0) {
- ret = kstrtoint(argv[1], 0, gpio);
+ ret = kstrtoint(argv[optind], 0, gpio);
if (ret < 0)
return ret;
+
+ if (chip)
+ *gpio += chip->base;
+ } else if (chip) {
+ if (gpio_get_chip(*gpio) != chip) {
+ printf("%s: not exporting pin %u\n", dev_name(chip->dev), *gpio);
+ return -EINVAL;
+ }
}
if (value)
- ret = kstrtoint(argv[2], 0, value);
+ ret = kstrtoint(argv[optind + 1], 0, value);
return ret;
}
@@ -47,7 +78,7 @@ static int do_gpio_get_value(int argc, char *argv[])
BAREBOX_CMD_START(gpio_get_value)
.cmd = do_gpio_get_value,
BAREBOX_CMD_DESC("return value of a GPIO pin")
- BAREBOX_CMD_OPTS("GPIO")
+ BAREBOX_CMD_OPTS("[-d CONTROLLER] GPIO")
BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
BAREBOX_CMD_END
@@ -67,7 +98,7 @@ static int do_gpio_set_value(int argc, char *argv[])
BAREBOX_CMD_START(gpio_set_value)
.cmd = do_gpio_set_value,
BAREBOX_CMD_DESC("set a GPIO's output value")
- BAREBOX_CMD_OPTS("GPIO VALUE")
+ BAREBOX_CMD_OPTS("[-d CONTROLLER] GPIO VALUE")
BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
BAREBOX_CMD_END
@@ -89,7 +120,7 @@ static int do_gpio_direction_input(int argc, char *argv[])
BAREBOX_CMD_START(gpio_direction_input)
.cmd = do_gpio_direction_input,
BAREBOX_CMD_DESC("set direction of a GPIO pin to input")
- BAREBOX_CMD_OPTS("GPIO")
+ BAREBOX_CMD_OPTS("[-d CONTROLLER] GPIO")
BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
BAREBOX_CMD_END
@@ -111,6 +142,6 @@ static int do_gpio_direction_output(int argc, char *argv[])
BAREBOX_CMD_START(gpio_direction_output)
.cmd = do_gpio_direction_output,
BAREBOX_CMD_DESC("set direction of a GPIO pin to output")
- BAREBOX_CMD_OPTS("GPIO VALUE")
+ BAREBOX_CMD_OPTS("[-d CONTROLLER] GPIO VALUE")
BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP)
BAREBOX_CMD_END
diff --git a/commands/mm.c b/commands/mm.c
index 9ce8839644..8fe87a80a1 100644
--- a/commands/mm.c
+++ b/commands/mm.c
@@ -16,7 +16,7 @@
static int do_mem_mm(int argc, char *argv[])
{
- int ret = 0;
+ int ret;
int fd;
char *filename = "/dev/mem";
int mode = O_RWSIZE_4;
@@ -65,9 +65,9 @@ static int do_mem_mm(int argc, char *argv[])
goto out_write;
break;
case O_RWSIZE_4:
+ ret = pread(fd, &val32, 4, adr);
if (ret < 0)
goto out_read;
- ret = pread(fd, &val32, 4, adr);
val32 &= ~mask;
val32 |= (value & mask);
ret = pwrite(fd, &val32, 4, adr);
@@ -75,9 +75,9 @@ static int do_mem_mm(int argc, char *argv[])
goto out_write;
break;
case O_RWSIZE_8:
+ ret = pread(fd, &val64, 8, adr);
if (ret < 0)
goto out_read;
- ret = pread(fd, &val64, 8, adr);
val64 &= ~mask;
val64 |= (value & mask);
ret = pwrite(fd, &val64, 8, adr);
diff --git a/commands/pm_domain.c b/commands/pm_domain.c
new file mode 100644
index 0000000000..ec8b769df1
--- /dev/null
+++ b/commands/pm_domain.c
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <common.h>
+#include <command.h>
+#include <pm_domain.h>
+
+static int do_pm_domain(int argc, char *argv[])
+{
+ pm_genpd_print();
+
+ return 0;
+}
+
+BAREBOX_CMD_START(pm_domain)
+ .cmd = do_pm_domain,
+ BAREBOX_CMD_DESC("list power domains")
+ BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+BAREBOX_CMD_END
diff --git a/commands/selftest.c b/commands/selftest.c
index a10f1467fe..bb62575aa7 100644
--- a/commands/selftest.c
+++ b/commands/selftest.c
@@ -24,7 +24,7 @@ static int run_selftest(const char *match, bool list)
if (match && strcmp(test->name, match))
continue;
- err |= test->func();
+ err |= selftest_run(test);
matches++;
}
diff --git a/common/blspec.c b/common/blspec.c
index 9bb25ee721..d391f690ad 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -341,10 +341,10 @@ static char *parse_nfs_url(const char *url)
int ret;
if (!IS_ENABLED(CONFIG_FS_NFS))
- return ERR_PTR(-ENOSYS);
+ return NULL;
if (strncmp(url, "nfs://", 6))
- return ERR_PTR(-EINVAL);
+ return NULL;
url += 6;
@@ -413,7 +413,7 @@ out:
if (ret)
free(mountpath);
- return ret ? ERR_PTR(ret) : mountpath;
+ return ret ? NULL : mountpath;
}
/*
@@ -824,12 +824,12 @@ static int blspec_bootentry_provider(struct bootentries *bootentries,
if (*name == '/' || !strncmp(name, "nfs://", 6)) {
char *nfspath = parse_nfs_url(name);
- if (!IS_ERR(nfspath))
+ if (nfspath)
name = nfspath;
ret = stat(name, &s);
if (ret)
- return found;
+ goto out;
if (S_ISDIR(s.st_mode))
ret = blspec_scan_directory(bootentries, name);
@@ -838,8 +838,8 @@ static int blspec_bootentry_provider(struct bootentries *bootentries,
if (ret > 0)
found += ret;
- if (!IS_ERR(nfspath))
- free(nfspath);
+out:
+ free(nfspath);
}
return found;
diff --git a/common/bootm.c b/common/bootm.c
index c0f7bca6ce..2f02c156e5 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -710,9 +710,8 @@ int bootm_boot(struct bootm_data *bootm_data)
const char *root_dev_name = devpath_to_name(bootm_data->root_dev);
const struct cdev *root_cdev = cdev_by_name(root_dev_name);
- if (root_cdev && root_cdev->uuid[0] != 0) {
- rootarg = basprintf("root=PARTUUID=%s", root_cdev->uuid);
- } else {
+ rootarg = cdev_get_linux_rootarg(root_cdev);
+ if (!rootarg) {
rootarg = ERR_PTR(-EINVAL);
if (!root_cdev)
diff --git a/common/oftree.c b/common/oftree.c
index 91b3fcc9fa..38752e2c19 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -271,6 +271,49 @@ static int of_register_bootargs_fixup(void)
}
late_initcall(of_register_bootargs_fixup);
+int of_fixup_reserved_memory(struct device_node *root, void *_res)
+{
+ struct resource *res = _res;
+ struct device_node *node, *child;
+ struct property *pp;
+ unsigned addr_n_cells = sizeof(void *) / sizeof(__be32),
+ size_n_cells = sizeof(void *) / sizeof(__be32);
+ unsigned rangelen = 0;
+ __be32 reg[4];
+ int ret;
+
+ node = of_get_child_by_name(root, "reserved-memory") ?: of_new_node(root, "reserved-memory");
+
+ ret = of_property_read_u32(node, "#address-cells", &addr_n_cells);
+ if (ret)
+ of_property_write_u32(node, "#address-cells", addr_n_cells);
+
+ ret = of_property_read_u32(node, "#size-cells", &size_n_cells);
+ if (ret)
+ of_property_write_u32(node, "#size-cells", size_n_cells);
+
+ pp = of_find_property(node, "ranges", &rangelen);
+ if (!pp) {
+ of_new_property(node, "ranges", NULL, 0);
+ } else if (rangelen) {
+ pr_warn("reserved-memory ranges not 1:1 mapped. Aborting fixup\n");
+ return -EINVAL;
+ }
+
+ child = of_get_child_by_name(node, res->name) ?: of_new_node(node, res->name);
+
+ if (res->flags & IORESOURCE_BUSY)
+ of_property_write_bool(child, "no-map", true);
+
+ of_write_number(reg, res->start, addr_n_cells);
+ of_write_number(reg + addr_n_cells, resource_size(res), size_n_cells);
+
+ of_new_property(child, "reg", reg,
+ (addr_n_cells + size_n_cells) * sizeof(*reg));
+
+ return 0;
+}
+
struct of_fixup_status_data {
const char *path;
bool status;
diff --git a/common/usbgadget.c b/common/usbgadget.c
index 2ec6d9226c..7291fbf4d5 100644
--- a/common/usbgadget.c
+++ b/common/usbgadget.c
@@ -20,6 +20,7 @@
#include <system-partitions.h>
static int autostart;
+static int nv_loaded;
static int acm;
static char *dfu_function;
@@ -98,13 +99,20 @@ err:
return ret;
}
-static int usbgadget_autostart_set(struct param_d *param, void *ctx)
+static int usbgadget_do_autostart(void)
{
struct usbgadget_funcs funcs = {};
static bool started;
int err;
- if (!autostart || started)
+ if (!IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART))
+ return 0;
+
+ /*
+ * We want to run this function exactly once when the
+ * environment is loaded and autostart is requested
+ */
+ if (!nv_loaded || !autostart || started)
return 0;
if (get_fastboot_bbu())
@@ -121,19 +129,38 @@ static int usbgadget_autostart_set(struct param_d *param, void *ctx)
return err;
}
+static int usbgadget_autostart_set(struct param_d *param, void *ctx)
+{
+ usbgadget_do_autostart();
+
+ return 0;
+}
+
+void usbgadget_autostart(bool enable)
+{
+ autostart = enable;
+
+ usbgadget_do_autostart();
+}
+
static int usbgadget_globalvars_init(void)
{
globalvar_add_simple_bool("usbgadget.acm", &acm);
globalvar_add_simple_string("usbgadget.dfu_function", &dfu_function);
+ if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART))
+ globalvar_add_bool("usbgadget.autostart", usbgadget_autostart_set,
+ &autostart, NULL);
return 0;
}
-device_initcall(usbgadget_globalvars_init);
+coredevice_initcall(usbgadget_globalvars_init);
static int usbgadget_autostart_init(void)
{
- if (IS_ENABLED(CONFIG_USB_GADGET_AUTOSTART))
- globalvar_add_bool("usbgadget.autostart", usbgadget_autostart_set, &autostart, NULL);
+ nv_loaded = true;
+
+ usbgadget_do_autostart();
+
return 0;
}
postenvironment_initcall(usbgadget_autostart_init);
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5bc70aa1e5..eebb60ce91 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -2,3 +2,6 @@
config PM_GENERIC_DOMAINS
bool
+
+config FEATURE_CONTROLLER
+ bool "Feature controller support" if COMPILE_TEST
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 59645c6f53..e8e354cdaa 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -6,3 +6,4 @@ obj-y += resource.o
obj-y += regmap/
obj-$(CONFIG_PM_GENERIC_DOMAINS) += power.o
+obj-$(CONFIG_FEATURE_CONTROLLER) += featctrl.o
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index e7288f6a61..cbe1c974f4 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -27,6 +27,7 @@
#include <linux/err.h>
#include <complete.h>
#include <pinctrl.h>
+#include <featctrl.h>
#include <linux/clk/clk-conf.h>
#ifdef CONFIG_DEBUG_PROBES
@@ -45,6 +46,22 @@ LIST_HEAD(active_device_list);
EXPORT_SYMBOL(active_device_list);
static LIST_HEAD(deferred);
+struct device_d *find_device(const char *str)
+{
+ struct device_d *dev;
+ struct device_node *np;
+
+ dev = get_device_by_name(str);
+ if (dev)
+ return dev;
+
+ np = of_find_node_by_path_or_alias(NULL, str);
+ if (np)
+ return of_find_device_by_node(np);
+
+ return NULL;
+}
+
struct device_d *get_device_by_name(const char *name)
{
struct device_d *dev;
@@ -85,6 +102,14 @@ int device_probe(struct device_d *dev)
static int depth = 0;
int ret;
+ ret = of_feature_controller_check(dev->device_node);
+ if (ret < 0)
+ return ret;
+ if (ret == FEATCTRL_GATED) {
+ dev_dbg(dev, "feature gated, skipping probe\n");
+ return -ENODEV;
+ }
+
depth++;
pr_report_probe("%*sprobe-> %s\n", depth * 4, "", dev_name(dev));
diff --git a/drivers/base/featctrl.c b/drivers/base/featctrl.c
new file mode 100644
index 0000000000..abe21698ed
--- /dev/null
+++ b/drivers/base/featctrl.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2022 Ahmad Fatoum, Pengutronix
+
+#define pr_fmt(fmt) "featctrl: " fmt
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <of.h>
+
+#include <featctrl.h>
+
+/* List of registered feature controllers */
+static LIST_HEAD(of_feature_controllers);
+
+/**
+ * feature_controller_register() - Register a feature controller
+ * @feat: Pointer to feature controller
+ */
+int feature_controller_register(struct feature_controller *feat)
+{
+ struct device_node *np = dev_of_node(feat->dev);
+
+ if (!np)
+ return -EINVAL;
+
+ list_add(&feat->list, &of_feature_controllers);
+ dev_dbg(feat->dev, "Registering feature controller\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(feature_controller_register);
+
+/**
+ * featctrl_get_from_provider() - Look-up feature gate
+ * @spec: OF phandle args to use for look-up
+ * @gateid: ID of feature controller gate populated on successful lookup
+ *
+ * Looks for a feature controller under the node specified by @spec.
+ *
+ * Returns a valid pointer to struct feature_controller on success or ERR_PTR()
+ * on failure.
+ */
+static struct feature_controller *featctrl_get_from_provider(struct of_phandle_args *spec,
+ unsigned *gateid)
+{
+ struct feature_controller *featctrl;
+ int ret;
+
+ if (!spec)
+ return ERR_PTR(-EINVAL);
+
+ ret = of_device_ensure_probed(spec->np);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ /* Check if we have such a controller in our array */
+ list_for_each_entry(featctrl, &of_feature_controllers, list) {
+ if (dev_of_node(featctrl->dev) == spec->np) {
+ *gateid = spec->args[0];
+ return featctrl;
+ }
+ }
+
+ return ERR_PTR(-ENOENT);
+}
+
+/**
+ * of_feature_controller_check - Check whether a feature controller gates the device
+ * @np: Device node to check
+ *
+ * Parse device's OF node to find a feature controller specifier. If such is
+ * found, checks it to determine whether device is gated.
+ *
+ * Returns FEATCTRL_GATED if a specified feature controller gates the device
+ * and FEATCTRL_OKAY if none do. On error a negative error code is returned.
+ */
+int of_feature_controller_check(struct device_node *np)
+{
+ struct of_phandle_args featctrl_args;
+ struct feature_controller *featctrl;
+ int ret, err = 0, i, ngates;
+
+ ngates = of_count_phandle_with_args(np, "barebox,feature-gates",
+ "#feature-cells");
+ if (ngates <= 0)
+ return FEATCTRL_OKAY;
+
+ for (i = 0; i < ngates; i++) {
+ unsigned gateid = 0;
+
+ ret = of_parse_phandle_with_args(np, "barebox,feature-gates",
+ "#feature-cells", i, &featctrl_args);
+ if (ret < 0)
+ return ret;
+
+ featctrl = featctrl_get_from_provider(&featctrl_args, &gateid);
+ if (IS_ERR(featctrl)) {
+ ret = PTR_ERR(featctrl);
+ pr_debug("%s() failed to find feature controller: %pe\n",
+ __func__, ERR_PTR(ret));
+ /*
+ * Assume that missing featctrls are unresolved
+ * dependency are report them as deferred
+ */
+ return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
+ }
+
+ ret = featctrl->check(featctrl, gateid);
+
+ dev_dbg(featctrl->dev, "checking %s: %d\n", np->full_name, ret);
+
+ if (ret == FEATCTRL_OKAY)
+ return FEATCTRL_OKAY;
+ if (ret != FEATCTRL_GATED)
+ err = ret;
+ }
+
+ return err ?: FEATCTRL_GATED;
+}
+EXPORT_SYMBOL_GPL(of_feature_controller_check);
+
+static int of_featctrl_fixup(struct device_node *root, void *context)
+{
+ struct device_node *srcnp, *dstnp;
+ int err = 0;
+
+ for_each_node_with_property(srcnp, "barebox,feature-gates") {
+ int ret;
+
+ ret = of_feature_controller_check(srcnp);
+ if (ret < 0)
+ err = ret;
+ if (ret != FEATCTRL_GATED)
+ continue;
+
+ dstnp = of_get_node_by_reproducible_name(root, srcnp);
+ if (!dstnp) {
+ pr_debug("gated node %s not in fixup DT\n",
+ srcnp->full_name);
+ continue;
+ }
+
+ pr_debug("fixing up gating of node %s\n", dstnp->full_name);
+ /* Convention is deleting non-existing CPUs, not disable them. */
+ if (of_property_match_string(srcnp, "device_type", "cpu") >= 0)
+ of_delete_node(dstnp);
+ else
+ of_device_disable(dstnp);
+ }
+
+ return err;
+}
+
+static __maybe_unused int of_featctrl_fixup_register(void)
+{
+ return of_register_fixup(of_featctrl_fixup, NULL);
+}
+#ifdef CONFIG_FEATURE_CONTROLLER_FIXUP
+device_initcall(of_featctrl_fixup_register);
+#endif
diff --git a/drivers/base/power.c b/drivers/base/power.c
index 4a206051b1..3eabf3c897 100644
--- a/drivers/base/power.c
+++ b/drivers/base/power.c
@@ -266,3 +266,13 @@ int genpd_dev_pm_attach(struct device_d *dev)
return __genpd_dev_pm_attach(dev, dev->device_node, 0, true);
}
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
+
+void pm_genpd_print(void)
+{
+ struct generic_pm_domain *genpd;
+
+ printf("%-20s %6s\n", "name", "active");
+ list_for_each_entry(genpd, &gpd_list, gpd_list_node)
+ printf("%-20s %6s\n", genpd->name,
+ genpd->status == GPD_STATE_ACTIVE ? "on" : "off");
+}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 97a99b84e3..7f20709035 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -636,6 +636,18 @@ static int of_gpio_simple_xlate(struct gpio_chip *chip,
return chip->base + gpiospec->args[0];
}
+struct gpio_chip *gpio_get_chip_by_dev(struct device_d *dev)
+{
+ struct gpio_chip *chip;
+
+ list_for_each_entry(chip, &chip_list, list) {
+ if (chip->dev == dev)
+ return chip;
+ }
+
+ return NULL;
+}
+
int gpio_of_xlate(struct device_d *dev, struct of_phandle_args *gpiospec, int *flags)
{
struct gpio_chip *chip;
@@ -643,16 +655,14 @@ int gpio_of_xlate(struct device_d *dev, struct of_phandle_args *gpiospec, int *f
if (!dev)
return -ENODEV;
- list_for_each_entry(chip, &chip_list, list) {
- if (chip->dev != dev)
- continue;
- if (chip->ops->of_xlate)
- return chip->ops->of_xlate(chip, gpiospec, flags);
- else
- return of_gpio_simple_xlate(chip, gpiospec, flags);
- }
+ chip = gpio_get_chip_by_dev(dev);
+ if (!chip)
+ return -EPROBE_DEFER;
- return -EPROBE_DEFER;
+ if (chip->ops->of_xlate)
+ return chip->ops->of_xlate(chip, gpiospec, flags);
+ else
+ return of_gpio_simple_xlate(chip, gpiospec, flags);
}
struct gpio_chip *gpio_get_chip(int gpio)
@@ -665,15 +675,35 @@ struct gpio_chip *gpio_get_chip(int gpio)
#ifdef CONFIG_CMD_GPIO
static int do_gpiolib(int argc, char *argv[])
{
+ struct gpio_chip *chip = NULL;
int i;
+ if (argc > 2)
+ return COMMAND_ERROR_USAGE;
+
+ if (argc == 1) {
+ struct device_d *dev;
+
+ dev = find_device(argv[1]);
+ if (!dev)
+ return -ENODEV;
+
+ chip = gpio_get_chip_by_dev(dev);
+ if (!chip)
+ return -EINVAL;
+ }
+
for (i = 0; i < ARCH_NR_GPIOS; i++) {
struct gpio_info *gi = &gpio_desc[i];
int val = -1, dir = -1;
+ int idx;
if (!gi->chip)
continue;
+ if (chip && chip != gi->chip)
+ continue;
+
/* print chip information and header on first gpio */
if (gi->chip->base == i) {
printf("\nGPIOs %u-%u, chip %s:\n",
@@ -683,14 +713,14 @@ static int do_gpiolib(int argc, char *argv[])
printf(" %-3s %-3s %-9s %-20s %-20s\n", "dir", "val", "requested", "name", "label");
}
+ idx = i - gi->chip->base;
+
if (gi->chip->ops->get_direction)
- dir = gi->chip->ops->get_direction(gi->chip,
- i - gi->chip->base);
+ dir = gi->chip->ops->get_direction(gi->chip, idx);
if (gi->chip->ops->get)
- val = gi->chip->ops->get(gi->chip,
- i - gi->chip->base);
+ val = gi->chip->ops->get(gi->chip, idx);
- printf(" GPIO %4d: %-3s %-3s %-9s %-20s %-20s\n", i,
+ printf(" GPIO %4d: %-3s %-3s %-9s %-20s %-20s\n", chip ? idx : i,
(dir < 0) ? "unk" : ((dir == GPIOF_DIR_IN) ? "in" : "out"),
(val < 0) ? "unk" : ((val == 0) ? "lo" : "hi"),
gi->requested ? (gi->active_low ? "active low" : "true") : "false",
@@ -704,6 +734,7 @@ static int do_gpiolib(int argc, char *argv[])
BAREBOX_CMD_START(gpioinfo)
.cmd = do_gpiolib,
BAREBOX_CMD_DESC("list registered GPIOs")
+ BAREBOX_CMD_OPTS("[CONTROLLER]")
BAREBOX_CMD_GROUP(CMD_GRP_INFO)
BAREBOX_CMD_COMPLETE(empty_complete)
BAREBOX_CMD_END
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index b24fd88f5b..40590b7d11 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -427,6 +427,12 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
const __be32 *addr;
int len;
+ if (n->dev) {
+ dev_dbg(&adap->dev, "of_i2c: skipping already registered %s\n",
+ dev_name(n->dev));
+ continue;
+ }
+
of_modalias_node(n, info.type, I2C_NAME_SIZE);
info.of_node = n;
@@ -452,6 +458,20 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
}
}
+int of_i2c_register_devices_by_node(struct device_node *node)
+{
+ struct i2c_adapter *adap;
+
+ adap = of_find_i2c_adapter_by_node(node);
+ if (!adap)
+ return -ENODEV;
+ if (IS_ERR(adap))
+ return PTR_ERR(adap);
+
+ of_i2c_register_devices(adap);
+ return 0;
+}
+
/**
* i2c_new_dummy - return a new i2c device bound to a dummy driver
* @adapter: the adapter managing the device
@@ -577,6 +597,19 @@ struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
return to_i2c_client(dev);
}
+int of_i2c_device_enable_and_register_by_alias(const char *alias)
+{
+ struct device_node *np;
+
+ np = of_find_node_by_alias(NULL, alias);
+ if (!np)
+ return -ENODEV;
+
+ of_device_enable(np);
+ return of_i2c_register_devices_by_node(np->parent);
+}
+
+
static void i2c_parse_timing(struct device_d *dev, char *prop_name, u32 *cur_val_p,
u32 def_val, bool use_def)
{
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6c6b65dacf..5fd1a0aaa8 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -117,4 +117,12 @@ config MFD_RK808
This driver provides common support for accessing the device
through I2C interface.
+config MFD_AXP20X_I2C
+ tristate "X-Powers AXP series PMICs with I2C"
+ depends on I2C && OFDEVICE
+ help
+ If you say Y here you get support for the X-Powers AXP series power
+ management ICs (PMICs) controlled with I2C.
+ This driver currently only provide a character device in /dev.
+
endmenu
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 7b5d0398d1..a3cb90e883 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_SMSC_SUPERIO) += smsc-superio.o
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o
obj-$(CONFIG_MFD_RK808) += rk808.o
+obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o axp20x.o
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
new file mode 100644
index 0000000000..d0f6a0f394
--- /dev/null
+++ b/drivers/mfd/axp20x-i2c.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * I2C driver for the X-Powers' Power Management ICs
+ *
+ * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
+ * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
+ * as well as configurable GPIOs.
+ *
+ * This driver supports the I2C variants.
+ *
+ * Copyright (C) 2014 Carlo Caione
+ *
+ * Author: Carlo Caione <carlo@caione.org>
+ */
+
+#include <common.h>
+#include <of.h>
+#include <linux/err.h>
+#include <i2c/i2c.h>
+#include <module.h>
+#include <linux/mfd/axp20x.h>
+#include <regmap.h>
+
+static int axp20x_i2c_probe(struct device_d *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct axp20x_dev *axp20x;
+ int ret;
+
+ axp20x = xzalloc(sizeof(*axp20x));
+
+ axp20x->dev = dev;
+
+ ret = axp20x_match_device(axp20x);
+ if (ret)
+ return ret;
+
+ axp20x->regmap = regmap_init_i2c(client, axp20x->regmap_cfg);
+ if (IS_ERR(axp20x->regmap))
+ return dev_err_probe(dev, PTR_ERR(axp20x->regmap),
+ "regmap init failed\n");
+
+ ret = axp20x_device_probe(axp20x);
+ if (ret)
+ return ret;
+
+ return regmap_register_cdev(axp20x->regmap, NULL);
+}
+
+static const struct of_device_id axp20x_i2c_of_match[] = {
+ { .compatible = "x-powers,axp152", .data = (void *)AXP152_ID },
+ { .compatible = "x-powers,axp202", .data = (void *)AXP202_ID },
+ { .compatible = "x-powers,axp209", .data = (void *)AXP209_ID },
+ { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
+ { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
+ { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
+ { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
+ { },
+};
+
+static struct driver_d axp20x_i2c_driver = {
+ .name = "axp20x-i2c",
+ .probe = axp20x_i2c_probe,
+ .of_compatible = DRV_OF_COMPAT(axp20x_i2c_of_match),
+};
+
+coredevice_i2c_driver(axp20x_i2c_driver);
+
+MODULE_DESCRIPTION("PMIC MFD I2C driver for AXP20X");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
new file mode 100644
index 0000000000..da1e8ce35a
--- /dev/null
+++ b/drivers/mfd/axp20x.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MFD core driver for the X-Powers' Power Management ICs
+ *
+ * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
+ * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
+ * as well as configurable GPIOs.
+ *
+ * This file contains the interface independent core functions.
+ *
+ * Copyright (C) 2014 Carlo Caione
+ *
+ * Author: Carlo Caione <carlo@caione.org>
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+#include <clock.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/mfd/core.h>
+#include <module.h>
+#include <of.h>
+#include <of_device.h>
+#include <regmap.h>
+#include <regulator.h>
+
+#define AXP20X_OFF BIT(7)
+
+#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE 0
+#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4)
+
+static const char * const axp20x_model_names[] = {
+ "AXP152",
+ "AXP202",
+ "AXP209",
+ "AXP221",
+ "AXP223",
+ "AXP288",
+ "AXP803",
+ "AXP806",
+ "AXP809",
+ "AXP813",
+};
+
+static const struct regmap_config axp152_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP152_PWM1_DUTY_CYCLE,
+};
+
+static const struct regmap_config axp20x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP20X_OCV(AXP20X_OCV_MAX),
+};
+
+static const struct regmap_config axp22x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP22X_BATLOW_THRES1,
+};
+
+static const struct regmap_config axp288_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP288_FG_TUNE5,
+};
+
+static const struct regmap_config axp806_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP806_REG_ADDR_EXT,
+};
+
+static const struct mfd_cell axp20x_cells[] = {
+ {
+ .name = "axp20x-gpio",
+ /* .of_compatible = "x-powers,axp209-gpio", */
+ }, {
+ .name = "axp20x-pek",
+ }, {
+ .name = "axp20x-regulator",
+ }, {
+ .name = "axp20x-adc",
+ /* .of_compatible = "x-powers,axp209-adc", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp209-battery-power-supply", */
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp202-ac-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp202-usb-power-supply", */
+ },
+};
+
+static const struct mfd_cell axp221_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp20x-regulator",
+ }, {
+ .name = "axp22x-adc",
+ /* .of_compatible = "x-powers,axp221-adc", */
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp221-ac-power-supply", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp221-battery-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp221-usb-power-supply", */
+ },
+};
+
+static const struct mfd_cell axp223_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp22x-adc",
+ /* .of_compatible = "x-powers,axp221-adc", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp221-battery-power-supply", */
+ }, {
+ .name = "axp20x-regulator",
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp221-ac-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp223-usb-power-supply", */
+ },
+};
+
+static const struct mfd_cell axp152_cells[] = {
+ {
+ .name = "axp20x-pek",
+ },
+};
+
+static const struct mfd_cell axp288_cells[] = {
+ {
+ .name = "axp288_adc",
+ }, {
+ .name = "axp288_extcon",
+ }, {
+ .name = "axp288_charger",
+ }, {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp288_pmic_acpi",
+ },
+};
+
+static const struct mfd_cell axp803_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp20x-gpio",
+ /* .of_compatible = "x-powers,axp813-gpio", */
+ }, {
+ .name = "axp813-adc",
+ /* .of_compatible = "x-powers,axp813-adc", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp813-battery-power-supply", */
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp813-ac-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp813-usb-power-supply", */
+ },
+ { .name = "axp20x-regulator" },
+};
+
+static const struct mfd_cell axp806_cells[] = {
+ {
+ .name = "axp20x-regulator",
+ },
+};
+
+static const struct mfd_cell axp809_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp20x-regulator",
+ },
+};
+
+static const struct mfd_cell axp813_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp20x-regulator",
+ }, {
+ .name = "axp20x-gpio",
+ /* .of_compatible = "x-powers,axp813-gpio", */
+ }, {
+ .name = "axp813-adc",
+ /* .of_compatible = "x-powers,axp813-adc", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp813-battery-power-supply", */
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp813-ac-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp813-usb-power-supply", */
+ },
+};
+
+static void axp20x_power_off(struct poweroff_handler *handler)
+{
+ struct axp20x_dev *axp20x = container_of(handler, struct axp20x_dev, poweroff);
+
+ regmap_write(axp20x->regmap, AXP20X_OFF_CTRL, AXP20X_OFF);
+
+ shutdown_barebox();
+
+ /* Give capacitors etc. time to drain to avoid kernel panic msg. */
+ mdelay(500);
+ hang();
+}
+
+int axp20x_match_device(struct axp20x_dev *axp20x)
+{
+ struct device_d *dev = axp20x->dev;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_device(dev->driver->of_compatible, dev);
+ if (!of_id) {
+ dev_err(dev, "Unable to match OF ID\n");
+ return -ENODEV;
+ }
+ axp20x->variant = (long)of_id->data;
+
+ switch (axp20x->variant) {
+ case AXP152_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp152_cells);
+ axp20x->cells = axp152_cells;
+ axp20x->regmap_cfg = &axp152_regmap_config;
+ break;
+ case AXP202_ID:
+ case AXP209_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
+ axp20x->cells = axp20x_cells;
+ axp20x->regmap_cfg = &axp20x_regmap_config;
+ break;
+ case AXP221_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp221_cells);
+ axp20x->cells = axp221_cells;
+ axp20x->regmap_cfg = &axp22x_regmap_config;
+ break;
+ case AXP223_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp223_cells);
+ axp20x->cells = axp223_cells;
+ axp20x->regmap_cfg = &axp22x_regmap_config;
+ break;
+ case AXP288_ID:
+ axp20x->cells = axp288_cells;
+ axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ break;
+ case AXP803_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp803_cells);
+ axp20x->cells = axp803_cells;
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ break;
+ case AXP806_ID:
+ /*
+ * Don't register the power key part if in slave mode or
+ * if there is no interrupt line.
+ */
+ axp20x->nr_cells = ARRAY_SIZE(axp806_cells);
+ axp20x->cells = axp806_cells;
+ axp20x->regmap_cfg = &axp806_regmap_config;
+ break;
+ case AXP809_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp809_cells);
+ axp20x->cells = axp809_cells;
+ axp20x->regmap_cfg = &axp22x_regmap_config;
+ break;
+ case AXP813_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp813_cells);
+ axp20x->cells = axp813_cells;
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ break;
+ default:
+ dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
+ return -EINVAL;
+ }
+ dev_info(dev, "AXP20x variant %s found\n",
+ axp20x_model_names[axp20x->variant]);
+
+ return 0;
+}
+EXPORT_SYMBOL(axp20x_match_device);
+
+int axp20x_device_probe(struct axp20x_dev *axp20x)
+{
+ int ret;
+
+ /*
+ * The AXP806 supports either master/standalone or slave mode.
+ * Slave mode allows sharing the serial bus, even with multiple
+ * AXP806 which all have the same hardware address.
+ *
+ * This is done with extra "serial interface address extension",
+ * or AXP806_BUS_ADDR_EXT, and "register address extension", or
+ * AXP806_REG_ADDR_EXT, registers. The former is read-only, with
+ * 1 bit customizable at the factory, and 1 bit depending on the
+ * state of an external pin. The latter is writable. The device
+ * will only respond to operations to its other registers when
+ * the these device addressing bits (in the upper 4 bits of the
+ * registers) match.
+ *
+ * By default we support an AXP806 chained to an AXP809 in slave
+ * mode. Boards which use an AXP806 in master mode can set the
+ * property "x-powers,master-mode" to override the default.
+ */
+ if (axp20x->variant == AXP806_ID) {
+ if (of_property_read_bool(axp20x->dev->device_node,
+ "x-powers,master-mode") ||
+ of_property_read_bool(axp20x->dev->device_node,
+ "x-powers,self-working-mode"))
+ regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+ AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE);
+ else
+ regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+ AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
+ }
+
+ ret = mfd_add_devices(axp20x->dev, axp20x->cells, axp20x->nr_cells);
+ if (ret)
+ return dev_err_probe(axp20x->dev, ret, "failed to add MFD devices\n");
+
+
+ axp20x->poweroff.name = "axp20x-poweroff";
+ axp20x->poweroff.poweroff = axp20x_power_off;
+ axp20x->poweroff.priority = 200;
+
+ if (axp20x->variant != AXP288_ID)
+ poweroff_handler_register(&axp20x->poweroff);
+
+ dev_info(axp20x->dev, "AXP20X driver loaded\n");
+
+ return 0;
+}
+EXPORT_SYMBOL(axp20x_device_probe);
+
+MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 99d23ffedf..e37ab79f3e 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -22,6 +22,7 @@
#include <linux/phy.h>
#include <linux/err.h>
#include <of_device.h>
+#include <pinctrl.h>
#define DEFAULT_GPIO_RESET_ASSERT 1000 /* us */
#define DEFAULT_GPIO_RESET_DEASSERT 1000 /* us */
@@ -202,6 +203,7 @@ static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
continue;
}
+ of_pinctrl_select_state_default(child);
of_mdiobus_reset_phy(mdio, child);
of_mdiobus_register_phy(mdio, child, addr);
}
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 093ea71b95..c89ad08f81 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -809,3 +809,36 @@ void *nvmem_cell_get_and_read(struct device_node *np, const char *cell_name,
return value;
}
EXPORT_SYMBOL_GPL(nvmem_cell_get_and_read);
+
+/**
+ * nvmem_cell_read_variable_le_u32() - Read up to 32-bits of data as a little endian number.
+ *
+ * @dev: Device that requests the nvmem cell.
+ * @cell_id: Name of nvmem cell to read.
+ * @val: pointer to output value.
+ *
+ * Return: 0 on success or negative errno.
+ */
+int nvmem_cell_read_variable_le_u32(struct device_d *dev, const char *cell_id,
+ u32 *val)
+{
+ size_t len;
+ const u8 *buf;
+ int i;
+
+ len = sizeof(*val);
+
+ buf = nvmem_cell_get_and_read(dev->device_node, cell_id, len);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ /* Copy w/ implicit endian conversion */
+ *val = 0;
+ for (i = 0; i < len; i++)
+ *val |= buf[i] << (8 * i);
+
+ kfree(buf);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32);
diff --git a/drivers/nvmem/ocotp.c b/drivers/nvmem/ocotp.c
index 1f99a8012f..9fcbd1a6a4 100644
--- a/drivers/nvmem/ocotp.c
+++ b/drivers/nvmem/ocotp.c
@@ -28,6 +28,7 @@
#include <mach/ocotp.h>
#include <machine_id.h>
#include <mach/ocotp-fusemap.h>
+#include <soc/imx8m/featctrl.h>
#include <linux/nvmem-provider.h>
/*
@@ -108,6 +109,7 @@ struct imx_ocotp_data {
int (*fuse_blow)(struct ocotp_priv *priv, u32 addr, u32 value);
u8 mac_offsets[MAX_MAC_OFFSETS];
u8 mac_offsets_num;
+ struct imx8m_featctrl_data *feat;
};
struct ocotp_priv_ethaddr {
@@ -638,19 +640,20 @@ static struct regmap_bus imx_ocotp_regmap_bus = {
.reg_read = imx_ocotp_reg_read,
};
-static void imx_ocotp_init_dt(struct ocotp_priv *priv)
+static int imx_ocotp_init_dt(struct ocotp_priv *priv)
{
char mac[MAC_BYTES];
const __be32 *prop;
struct device_node *node = priv->dev.parent->device_node;
- int len;
+ u32 tester4;
+ int ret, len;
if (!node)
- return;
+ return 0;
prop = of_get_property(node, "barebox,provide-mac-address", &len);
if (!prop)
- return;
+ return 0;
for (; len >= MAC_ADDRESS_PROPLEN; len -= MAC_ADDRESS_PROPLEN) {
struct device_node *rnode;
@@ -668,6 +671,15 @@ static void imx_ocotp_init_dt(struct ocotp_priv *priv)
of_eth_register_ethaddr(rnode, mac);
}
+
+ if (!of_property_read_bool(node, "barebox,feature-controller"))
+ return 0;
+
+ ret = regmap_read(priv->map, OCOTP_OFFSET_TO_ADDR(0x450), &tester4);
+ if (ret != 0)
+ return ret;
+
+ return imx8m_feat_ctrl_init(priv->dev.parent, tester4, priv->data->feat);
}
static int imx_ocotp_write(void *ctx, unsigned offset, const void *val, size_t bytes)
@@ -785,10 +797,12 @@ static int imx_ocotp_probe(struct device_d *dev)
if (IS_ENABLED(CONFIG_MACHINE_ID))
imx_ocotp_set_unique_machine_id();
- imx_ocotp_init_dt(priv);
+ ret = imx_ocotp_init_dt(priv);
+ if (ret)
+ dev_warn(dev, "feature controller registration failed: %pe\n",
+ ERR_PTR(ret));
dev_add_param_bool(&(priv->dev), "sense_enable", NULL, NULL, &priv->sense_enable, priv);
-
return 0;
}
@@ -895,6 +909,38 @@ static struct imx_ocotp_data imx8mq_ocotp_data = {
.fuse_read = imx6_fuse_read_addr,
};
+static struct imx8m_featctrl_data imx8mm_featctrl_data = {
+ .vpu_bitmask = 0x1c0000,
+};
+
+static struct imx_ocotp_data imx8mm_ocotp_data = {
+ .num_regs = 2048,
+ .addr_to_offset = imx6sl_addr_to_offset,
+ .mac_offsets_num = 1,
+ .mac_offsets = { 0x90 },
+ .format_mac = imx_ocotp_format_mac,
+ .set_timing = imx6_ocotp_set_timing,
+ .fuse_blow = imx6_fuse_blow_addr,
+ .fuse_read = imx6_fuse_read_addr,
+ .feat = &imx8mm_featctrl_data,
+};
+
+static struct imx8m_featctrl_data imx8mn_featctrl_data = {
+ .gpu_bitmask = 0x1000000,
+};
+
+static struct imx_ocotp_data imx8mn_ocotp_data = {
+ .num_regs = 2048,
+ .addr_to_offset = imx6sl_addr_to_offset,
+ .mac_offsets_num = 1,
+ .mac_offsets = { 0x90 },
+ .format_mac = imx_ocotp_format_mac,
+ .set_timing = imx6_ocotp_set_timing,
+ .fuse_blow = imx6_fuse_blow_addr,
+ .fuse_read = imx6_fuse_read_addr,
+ .feat = &imx8mn_featctrl_data,
+};
+
static struct imx_ocotp_data imx7d_ocotp_data = {
.num_regs = 2048,
.addr_to_offset = imx6sl_addr_to_offset,
@@ -933,10 +979,10 @@ static __maybe_unused struct of_device_id imx_ocotp_dt_ids[] = {
.data = &imx8mq_ocotp_data,
}, {
.compatible = "fsl,imx8mm-ocotp",
- .data = &imx8mq_ocotp_data,
+ .data = &imx8mm_ocotp_data,
}, {
.compatible = "fsl,imx8mn-ocotp",
- .data = &imx8mq_ocotp_data,
+ .data = &imx8mn_ocotp_data,
}, {
.compatible = "fsl,vf610-ocotp",
.data = &vf610_ocotp_data,
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index f3d2cc00cc..7283331ba9 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -16,6 +16,18 @@ config OFDEVICE
select DTC
bool "Enable probing of devices from the devicetree"
+config FEATURE_CONTROLLER_FIXUP
+ bool "Fix up DT nodes gated by feature controller"
+ depends on FEATURE_CONTROLLER
+ default y
+ help
+ When specified, barebox feature controller drivers are consulted
+ prior to probing nodes to detect whether the device may not
+ be available (e.g. because support is fused out).
+ This option additionally fixes up the kernel device tree,
+ so it doesn't attempt probing these devices either.
+ If unsure, say y.
+
config OF_ADDRESS_PCI
bool
diff --git a/drivers/of/base.c b/drivers/of/base.c
index b91ee92e1b..ea2a88764b 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2301,6 +2301,22 @@ void of_delete_property(struct property *pp)
free(pp);
}
+struct property *of_rename_property(struct device_node *np,
+ const char *old_name, const char *new_name)
+{
+ struct property *pp;
+
+ pp = of_find_property(np, old_name, NULL);
+ if (!pp)
+ return NULL;
+
+ of_property_write_bool(np, new_name, false);
+
+ free(pp->name);
+ pp->name = xstrdup(new_name);
+ return pp;
+}
+
/**
* of_set_property - create a property for a given node
* @node - the node
@@ -2362,6 +2378,36 @@ int of_append_property(struct device_node *np, const char *name, const void *val
return 0;
}
+int of_prepend_property(struct device_node *np, const char *name, const void *val, int len)
+{
+ struct property *pp;
+ const void *oldval;
+ void *buf;
+ int oldlen;
+
+ pp = of_find_property(np, name, &oldlen);
+ if (!pp) {
+ of_new_property(np, name, val, len);
+ return 0;
+ }
+
+ oldval = of_property_get_value(pp);
+
+ buf = malloc(len + oldlen);
+ if (!buf)
+ return -ENOMEM;
+
+ memcpy(buf, val, len);
+ memcpy(buf + len, oldval, oldlen);
+
+ free(pp->value);
+ pp->value = buf;
+ pp->length = len + oldlen;
+ pp->value_const = NULL;
+
+ return 0;
+}
+
int of_property_sprintf(struct device_node *np,
const char *propname, const char *fmt, ...)
{
@@ -2504,6 +2550,12 @@ int of_probe(void)
return -ENODEV;
/*
+ * We do this first thing, so board drivers can patch the device
+ * tree prior to device creation if needed.
+ */
+ of_platform_device_create_root(root_node);
+
+ /*
* Handle certain compatibles explicitly, since we don't want to create
* platform_devices for every node in /reserved-memory with a
* "compatible",
@@ -2515,8 +2567,6 @@ int of_probe(void)
if (node)
of_platform_populate(node, NULL, NULL);
- of_platform_device_create_root(root_node);
-
of_platform_populate(root_node, of_default_bus_match_table, NULL);
return 0;
@@ -2865,6 +2915,19 @@ struct device_node *of_find_node_by_reproducible_name(struct device_node *from,
return NULL;
}
+struct device_node *of_get_node_by_reproducible_name(struct device_node *dstroot,
+ struct device_node *srcnp)
+{
+ struct device_node *dstnp;
+ char *name;
+
+ name = of_get_reproducible_name(srcnp);
+ dstnp = of_find_node_by_reproducible_name(dstroot, name);
+ free(name);
+
+ return dstnp;
+}
+
/**
* of_graph_parse_endpoint() - parse common endpoint node properties
* @node: pointer to endpoint device_node
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index fff1d6ea02..0fc440fdcf 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -102,8 +102,10 @@ static char *of_overlay_fix_path(struct device_node *root,
if (of_get_child_by_name(fragment, "__overlay__"))
break;
}
- if (!fragment)
+ if (!fragment) {
+ pr_info("could not find __overlay__ node\n");
return NULL;
+ }
target = find_target(root, fragment);
if (!target)
@@ -115,8 +117,8 @@ static char *of_overlay_fix_path(struct device_node *root,
return basprintf("%s%s", target->full_name, path_tail);
}
-static void of_overlay_apply_symbols(struct device_node *root,
- struct device_node *overlay)
+static int of_overlay_apply_symbols(struct device_node *root,
+ struct device_node *overlay)
{
const char *old_path;
char *new_path;
@@ -129,12 +131,12 @@ static void of_overlay_apply_symbols(struct device_node *root,
if (!overlay_symbols) {
pr_debug("overlay doesn't have a __symbols__ node\n");
- return;
+ return -EINVAL;
}
if (!root_symbols) {
pr_info("root doesn't have a __symbols__ node\n");
- return;
+ return -EINVAL;
}
list_for_each_entry(prop, &overlay_symbols->properties, list) {
@@ -143,11 +145,15 @@ static void of_overlay_apply_symbols(struct device_node *root,
old_path = of_property_get_value(prop);
new_path = of_overlay_fix_path(root, overlay, old_path);
+ if (!new_path)
+ return -EINVAL;
pr_debug("add symbol %s with new path %s\n",
prop->name, new_path);
of_property_write_string(root_symbols, prop->name, new_path);
}
+
+ return 0;
}
static int of_overlay_apply_fragment(struct device_node *root,
@@ -190,7 +196,9 @@ int of_overlay_apply_tree(struct device_node *root,
goto out_err;
/* Copy symbols from resolved overlay to base device tree */
- of_overlay_apply_symbols(root, resolved);
+ err = of_overlay_apply_symbols(root, resolved);
+ if (err)
+ goto out_err;
/* Copy nodes and properties from resolved overlay to root */
for_each_child_of_node(resolved, fragment) {
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 7f377b8b37..a9a5d4c2da 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -28,6 +28,9 @@ struct device_d *of_find_device_by_node(struct device_node *np)
if (ret)
return NULL;
+ if (deep_probe_is_supported())
+ return np->dev;
+
for_each_device(dev)
if (dev->device_node == np)
return dev;
@@ -522,12 +525,15 @@ int of_devices_ensure_probed_by_property(const char *property_name)
return 0;
for_each_node_with_property(node, property_name) {
- ret = of_device_ensure_probed(node);
+ if (!of_device_is_available(node))
+ continue;
+
+ err = of_device_ensure_probed(node);
if (err)
ret = err;
}
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(of_devices_ensure_probed_by_property);
@@ -540,12 +546,15 @@ int of_devices_ensure_probed_by_name(const char *name)
return 0;
for_each_node_by_name(node, name) {
- ret = of_device_ensure_probed(node);
+ if (!of_device_is_available(node))
+ continue;
+
+ err = of_device_ensure_probed(node);
if (err)
ret = err;
}
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(of_devices_ensure_probed_by_name);
diff --git a/drivers/power/reset/reboot-mode.c b/drivers/power/reset/reboot-mode.c
index 1316af4213..5761128f8e 100644
--- a/drivers/power/reset/reboot-mode.c
+++ b/drivers/power/reset/reboot-mode.c
@@ -48,19 +48,6 @@ static int reboot_mode_add_param(struct device_d *dev,
return PTR_ERR_OR_ZERO(param);
}
-static struct device_node *of_get_node_by_reproducible_name(struct device_node *dstroot,
- struct device_node *srcnp)
-{
- struct device_node *dstnp;
- char *name;
-
- name = of_get_reproducible_name(srcnp);
- dstnp = of_find_node_by_reproducible_name(dstroot, name);
- free(name);
-
- return dstnp;
-}
-
static int of_reboot_mode_fixup(struct device_node *root, void *ctx)
{
struct reboot_mode_driver *reboot = ctx;
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 913b309eac..16c05d50f0 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -41,6 +41,7 @@ config RESET_IMX7
config RESET_STARFIVE
bool "StarFive Controller Driver" if COMPILE_TEST
+ depends on COMMON_CLK
default SOC_STARFIVE
help
This enables the reset controller driver for the StarFive JH7100.
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig
index 8f4f5150c7..06513c02da 100644
--- a/drivers/soc/imx/Kconfig
+++ b/drivers/soc/imx/Kconfig
@@ -7,4 +7,10 @@ config IMX_GPCV2_PM_DOMAINS
select PM_GENERIC_DOMAINS
default y if ARCH_IMX7 || ARCH_IMX8M
+config IMX8M_FEATCTRL
+ bool "i.MX8M feature controller"
+ depends on ARCH_IMX8M
+ select FEATURE_CONTROLLER
+ default y
+
endmenu
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
index 3a8a8d0b00..bd1717b038 100644
--- a/drivers/soc/imx/Makefile
+++ b/drivers/soc/imx/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
+obj-$(CONFIG_IMX8M_FEATCTRL) += imx8m-featctrl.o
diff --git a/drivers/soc/imx/imx8m-featctrl.c b/drivers/soc/imx/imx8m-featctrl.c
new file mode 100644
index 0000000000..480c80e6c1
--- /dev/null
+++ b/drivers/soc/imx/imx8m-featctrl.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2022 Ahmad Fatoum, Pengutronix
+
+#include <common.h>
+#include <linux/bitmap.h>
+#include <featctrl.h>
+#include <soc/imx8m/featctrl.h>
+
+#include <dt-bindings/features/imx8m.h>
+
+struct imx_feat {
+ struct feature_controller feat;
+ unsigned long features[BITS_TO_LONGS(IMX8M_FEAT_END)];
+};
+
+static struct imx_feat *to_imx_feat(struct feature_controller *feat)
+{
+ return container_of(feat, struct imx_feat, feat);
+}
+
+static int imx8m_feat_check(struct feature_controller *feat, int idx)
+{
+ struct imx_feat *priv = to_imx_feat(feat);
+
+ if (idx > IMX8M_FEAT_END)
+ return -EINVAL;
+
+ return test_bit(idx, priv->features) ? FEATCTRL_OKAY : FEATCTRL_GATED;
+}
+
+int imx8m_feat_ctrl_init(struct device_d *dev, u32 tester4,
+ const struct imx8m_featctrl_data *data)
+{
+ unsigned long *features;
+ struct imx_feat *priv;
+
+ if (!dev || !data)
+ return -ENODEV;
+
+ dev_dbg(dev, "tester4 = 0x%08x\n", tester4);
+
+ priv = xzalloc(sizeof(*priv));
+ features = priv->features;
+
+ bitmap_fill(features, IMX8M_FEAT_END);
+
+ if (tester4 & data->vpu_bitmask)
+ clear_bit(IMX8M_FEAT_VPU, features);
+ if (tester4 & data->gpu_bitmask)
+ clear_bit(IMX8M_FEAT_GPU, features);
+
+ switch (tester4 & 3) {
+ case 0b11:
+ clear_bit(IMX8M_FEAT_CPU_DUAL, features);
+ fallthrough;
+ case 0b10:
+ clear_bit(IMX8M_FEAT_CPU_QUAD, features);
+ }
+
+ priv->feat.dev = dev;
+ priv->feat.check = imx8m_feat_check;
+
+ return feature_controller_register(&priv->feat);
+}
diff --git a/fs/fs.c b/fs/fs.c
index 50db689c7e..78878e7112 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -2869,12 +2869,23 @@ int popd(char *oldcwd)
return ret;
}
-static char *get_linux_mmcblkdev(struct fs_device_d *fsdev)
+static bool cdev_partname_equal(const struct cdev *a,
+ const struct cdev *b)
{
- struct cdev *cdevm, *cdev;
+ return a->partname && b->partname &&
+ !strcmp(a->partname, b->partname);
+}
+
+static char *get_linux_mmcblkdev(const struct cdev *root_cdev)
+{
+ struct cdev *cdevm = root_cdev->master, *cdev;
int id, partnum;
- cdevm = fsdev->cdev->master;
+ if (!IS_ENABLED(CONFIG_MMCBLKDEV_ROOTARG))
+ return NULL;
+ if (!cdevm || !cdev_is_mci_main_part_dev(cdevm))
+ return NULL;
+
id = of_alias_get_id(cdevm->device_node, "mmc");
if (id < 0)
return NULL;
@@ -2887,8 +2898,7 @@ static char *get_linux_mmcblkdev(struct fs_device_d *fsdev)
* in the partitions list so we need to count it instead of
* skipping it.
*/
- if (cdev->partname &&
- !strcmp(cdev->partname, fsdev->cdev->partname))
+ if (cdev_partname_equal(root_cdev, cdev))
return basprintf("root=/dev/mmcblk%dp%d", id, partnum);
partnum++;
}
@@ -2896,6 +2906,23 @@ static char *get_linux_mmcblkdev(struct fs_device_d *fsdev)
return NULL;
}
+char *cdev_get_linux_rootarg(const struct cdev *cdev)
+{
+ char *str;
+
+ if (!cdev)
+ return NULL;
+
+ str = get_linux_mmcblkdev(cdev);
+ if (str)
+ return str;
+
+ if (cdev->uuid[0] != 0)
+ return basprintf("root=PARTUUID=%s", cdev->uuid);
+
+ return NULL;
+}
+
/*
* Mount a device to a directory.
* We do this by registering a new device on which the filesystem
@@ -2984,17 +3011,10 @@ int mount(const char *device, const char *fsname, const char *pathname,
fsdev->vfsmount.mnt_root = fsdev->sb.s_root;
- if (!fsdev->linux_rootarg && fsdev->cdev) {
- char *str = NULL;
-
- if (IS_ENABLED(CONFIG_MMCBLKDEV_ROOTARG) &&
- fsdev->cdev->master &&
- cdev_is_mci_main_part_dev(fsdev->cdev->master))
- str = get_linux_mmcblkdev(fsdev);
-
- if (!str && fsdev->cdev->uuid[0] != 0)
- str = basprintf("root=PARTUUID=%s", fsdev->cdev->uuid);
+ if (!fsdev->linux_rootarg) {
+ char *str;
+ str = cdev_get_linux_rootarg(fsdev->cdev);
if (str)
fsdev_set_linux_rootarg(fsdev, str);
}
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 0d8bb8f418..29585bff59 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -474,37 +474,24 @@ static int ramoops_of_fixup(struct device_node *root, void *data)
{
struct ramoops_platform_data *pdata = data;
struct device_node *node;
- u32 reg[2];
+ struct resource res = {};
int ret;
- node = of_get_child_by_name(root, "reserved-memory");
- if (!node) {
- pr_info("Adding reserved-memory node\n");
- node = of_create_node(root, "/reserved-memory");
- if (!node)
- return -ENOMEM;
+ res.start = pdata->mem_address;
+ res.end = res.start + pdata->mem_size;
+ res.name = "ramoops";
- of_property_write_u32(node, "#address-cells", 1);
- of_property_write_u32(node, "#size-cells", 1);
- of_new_property(node, "ranges", NULL, 0);
- }
+ ret = of_fixup_reserved_memory(root, &res);
+ if (ret)
+ return ret;
- node = of_get_child_by_name(node, "ramoops");
- if (!node) {
- pr_info("Adding ramoops node\n");
- node = of_create_node(root, "/reserved-memory/ramoops");
- if (!node)
- return -ENOMEM;
- }
+ node = of_find_node_by_path_from(root, "/reserved-memory/ramoops");
+ if (!node)
+ return -ENOMEM;
ret = of_property_write_string(node, "compatible", "ramoops");
if (ret)
return ret;
- reg[0] = pdata->mem_address;
- reg[1] = pdata->mem_size;
- ret = of_property_write_u32_array(node, "reg", reg, 2);
- if (ret)
- return ret;
ret = of_property_write_bool(node, "unbuffered", pdata->mem_type);
if (ret)
@@ -639,7 +626,6 @@ static int ramoops_probe(struct device_d *dev)
ramoops_ecc);
globalvar_add_simple("linux.bootargs.ramoops", kernelargs);
} else {
- of_add_reserve_entry(cxt->phys_addr, cxt->phys_addr + mem_size);
of_register_fixup(ramoops_of_fixup, pdata);
}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index b48e21fae6..6a0074bd1a 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -86,11 +86,6 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
return 1;
}
- if (ui->compr_type >= UBIFS_COMPR_TYPES_CNT) {
- ubifs_err(c, "unknown compression type %d", ui->compr_type);
- return 2;
- }
-
if (ui->xattr_names + ui->xattr_cnt > XATTR_LIST_MAX)
return 3;
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 0b4f3de773..71ccd2c0e7 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -46,7 +46,14 @@ static ZSTD_DCtx *ubifs_zstd_cctx;
static int gzip_decompress(const unsigned char *in, size_t in_len,
unsigned char *out, size_t *out_len)
{
- return deflate_decompress(&ubifs_zlib_stream, in, in_len, out, out_len);
+ unsigned int olen;
+ int ret;
+
+ ret = deflate_decompress(&ubifs_zlib_stream, in, in_len, out, &olen);
+
+ *out_len = olen;
+
+ return ret;
}
#endif
diff --git a/include/bselftest.h b/include/bselftest.h
index 21eeba0526..f03c803b65 100644
--- a/include/bselftest.h
+++ b/include/bselftest.h
@@ -15,6 +15,7 @@ struct selftest {
const char *name;
int (*func)(void);
struct list_head list;
+ bool running;
};
static inline int selftest_report(unsigned int total_tests, unsigned int failed_tests,
@@ -71,4 +72,8 @@ static inline void selftests_run(void)
} \
__bselftest_initcall(_func##_bselftest_register);
+
+int selftest_run(struct selftest *test);
+bool selftest_is_running(struct selftest *test);
+
#endif
diff --git a/include/driver.h b/include/driver.h
index 67ffbba6be..543287a276 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -169,6 +169,11 @@ struct device_d *get_device_by_type(ulong type, struct device_d *last);
struct device_d *get_device_by_id(const char *id);
struct device_d *get_device_by_name(const char *name);
+/* Find a device by name and if not found look up by device tree path
+ * or alias
+ */
+struct device_d *find_device(const char *str);
+
/* Find a free device id from the given template. This is archieved by
* appending a number to the template. Dynamically created devices should
* use this function rather than filling the id field themselves.
diff --git a/include/dt-bindings/features/imx8m.h b/include/dt-bindings/features/imx8m.h
new file mode 100644
index 0000000000..4dd85aa5c8
--- /dev/null
+++ b/include/dt-bindings/features/imx8m.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) */
+#ifndef __DT_BINDINGS_FEATURES_IMX8M_
+#define __DT_BINDINGS_FEATURES_IMX8M_
+
+#define IMX8M_FEAT_DUMMY 0
+
+#define IMX8M_FEAT_CPU_DUAL 1
+#define IMX8M_FEAT_CPU_QUAD 2
+#define IMX8M_FEAT_VPU 4
+#define IMX8M_FEAT_GPU 4
+
+#define IMX8M_FEAT_END 5
+
+#endif
diff --git a/include/featctrl.h b/include/featctrl.h
new file mode 100644
index 0000000000..fb9e4156bd
--- /dev/null
+++ b/include/featctrl.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __FEATCTRL_H_
+#define __FEATCTRL_H_
+
+#include <linux/list.h>
+
+struct feature_controller;
+struct device_node;
+
+struct feature_controller {
+ struct device_d *dev;
+ int (*check)(struct feature_controller *, int idx);
+ struct list_head list;
+};
+
+enum { FEATCTRL_GATED = 0, FEATCTRL_OKAY = 1 };
+
+int feature_controller_register(struct feature_controller *);
+
+#ifdef CONFIG_FEATURE_CONTROLLER
+int of_feature_controller_check(struct device_node *np);
+#else
+static inline int of_feature_controller_check(struct device_node *np)
+{
+ return FEATCTRL_OKAY;
+}
+#endif
+
+#endif /* PINCTRL_H */
diff --git a/include/fs.h b/include/fs.h
index cd5eb571e0..894cae3e4c 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -168,6 +168,7 @@ void mount_all(void);
void fsdev_set_linux_rootarg(struct fs_device_d *fsdev, const char *str);
char *path_get_linux_rootarg(const char *path);
+char *cdev_get_linux_rootarg(const struct cdev *cdev);
static inline const char *devpath_to_name(const char *devpath)
{
diff --git a/include/gpio.h b/include/gpio.h
index 8218722dcb..d396435aa0 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -34,6 +34,7 @@ static inline int gpio_direction_input(unsigned gpio)
void gpio_set_active(unsigned gpio, bool state);
int gpio_is_active(unsigned gpio);
int gpio_direction_active(unsigned gpio, bool state);
+struct gpio_chip *gpio_get_chip_by_dev(struct device_d *);
/**
* gpio_poll_timeout_us - Poll till GPIO reaches requested active state
@@ -62,6 +63,11 @@ static inline int gpio_direction_active(unsigned gpio, int value)
return -EINVAL;
}
+static inline struct gpio_chip *gpio_get_chip_by_dev(struct device_d *dev)
+{
+ return NULL;
+}
+
#define gpio_poll_timeout_us(gpio, val, timeout_us) (-ENOSYS)
#endif
diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h
index 7207b1180e..e37a1770dc 100644
--- a/include/i2c/i2c.h
+++ b/include/i2c/i2c.h
@@ -295,7 +295,9 @@ static inline int i2c_register_board_info(int busnum,
extern int i2c_add_numbered_adapter(struct i2c_adapter *adapter);
struct i2c_adapter *i2c_get_adapter(int busnum);
struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node);
+int of_i2c_register_devices_by_node(struct device_node *node);
struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
+int of_i2c_device_enable_and_register_by_alias(const char *alias);
void i2c_parse_fw_timings(struct device_d *dev, struct i2c_timings *t, bool use_defaults);
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
new file mode 100644
index 0000000000..5e068eb6ba
--- /dev/null
+++ b/include/linux/mfd/axp20x.h
@@ -0,0 +1,477 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Functions and registers to access AXP20X power management chip.
+ *
+ * Copyright (C) 2013, Carlo Caione <carlo@caione.org>
+ */
+
+#ifndef __LINUX_MFD_AXP20X_H
+#define __LINUX_MFD_AXP20X_H
+
+#include <regmap.h>
+#include <poweroff.h>
+
+enum axp20x_variants {
+ AXP152_ID = 0,
+ AXP202_ID,
+ AXP209_ID,
+ AXP221_ID,
+ AXP223_ID,
+ AXP288_ID,
+ AXP803_ID,
+ AXP806_ID,
+ AXP809_ID,
+ AXP813_ID,
+ NR_AXP20X_VARIANTS,
+};
+
+#define AXP20X_DATACACHE(m) (0x04 + (m))
+
+/* Power supply */
+#define AXP152_PWR_OP_MODE 0x01
+#define AXP152_LDO3456_DC1234_CTRL 0x12
+#define AXP152_ALDO_OP_MODE 0x13
+#define AXP152_LDO0_CTRL 0x15
+#define AXP152_DCDC2_V_OUT 0x23
+#define AXP152_DCDC2_V_RAMP 0x25
+#define AXP152_DCDC1_V_OUT 0x26
+#define AXP152_DCDC3_V_OUT 0x27
+#define AXP152_ALDO12_V_OUT 0x28
+#define AXP152_DLDO1_V_OUT 0x29
+#define AXP152_DLDO2_V_OUT 0x2a
+#define AXP152_DCDC4_V_OUT 0x2b
+#define AXP152_V_OFF 0x31
+#define AXP152_OFF_CTRL 0x32
+#define AXP152_PEK_KEY 0x36
+#define AXP152_DCDC_FREQ 0x37
+#define AXP152_DCDC_MODE 0x80
+
+#define AXP20X_PWR_INPUT_STATUS 0x00
+#define AXP20X_PWR_OP_MODE 0x01
+#define AXP20X_USB_OTG_STATUS 0x02
+#define AXP20X_PWR_OUT_CTRL 0x12
+#define AXP20X_DCDC2_V_OUT 0x23
+#define AXP20X_DCDC2_LDO3_V_RAMP 0x25
+#define AXP20X_DCDC3_V_OUT 0x27
+#define AXP20X_LDO24_V_OUT 0x28
+#define AXP20X_LDO3_V_OUT 0x29
+#define AXP20X_VBUS_IPSOUT_MGMT 0x30
+#define AXP20X_V_OFF 0x31
+#define AXP20X_OFF_CTRL 0x32
+#define AXP20X_CHRG_CTRL1 0x33
+#define AXP20X_CHRG_CTRL2 0x34
+#define AXP20X_CHRG_BAK_CTRL 0x35
+#define AXP20X_PEK_KEY 0x36
+#define AXP20X_DCDC_FREQ 0x37
+#define AXP20X_V_LTF_CHRG 0x38
+#define AXP20X_V_HTF_CHRG 0x39
+#define AXP20X_APS_WARN_L1 0x3a
+#define AXP20X_APS_WARN_L2 0x3b
+#define AXP20X_V_LTF_DISCHRG 0x3c
+#define AXP20X_V_HTF_DISCHRG 0x3d
+
+#define AXP22X_PWR_OUT_CTRL1 0x10
+#define AXP22X_PWR_OUT_CTRL2 0x12
+#define AXP22X_PWR_OUT_CTRL3 0x13
+#define AXP22X_DLDO1_V_OUT 0x15
+#define AXP22X_DLDO2_V_OUT 0x16
+#define AXP22X_DLDO3_V_OUT 0x17
+#define AXP22X_DLDO4_V_OUT 0x18
+#define AXP22X_ELDO1_V_OUT 0x19
+#define AXP22X_ELDO2_V_OUT 0x1a
+#define AXP22X_ELDO3_V_OUT 0x1b
+#define AXP22X_DC5LDO_V_OUT 0x1c
+#define AXP22X_DCDC1_V_OUT 0x21
+#define AXP22X_DCDC2_V_OUT 0x22
+#define AXP22X_DCDC3_V_OUT 0x23
+#define AXP22X_DCDC4_V_OUT 0x24
+#define AXP22X_DCDC5_V_OUT 0x25
+#define AXP22X_DCDC23_V_RAMP_CTRL 0x27
+#define AXP22X_ALDO1_V_OUT 0x28
+#define AXP22X_ALDO2_V_OUT 0x29
+#define AXP22X_ALDO3_V_OUT 0x2a
+#define AXP22X_CHRG_CTRL3 0x35
+
+#define AXP806_STARTUP_SRC 0x00
+#define AXP806_CHIP_ID 0x03
+#define AXP806_PWR_OUT_CTRL1 0x10
+#define AXP806_PWR_OUT_CTRL2 0x11
+#define AXP806_DCDCA_V_CTRL 0x12
+#define AXP806_DCDCB_V_CTRL 0x13
+#define AXP806_DCDCC_V_CTRL 0x14
+#define AXP806_DCDCD_V_CTRL 0x15
+#define AXP806_DCDCE_V_CTRL 0x16
+#define AXP806_ALDO1_V_CTRL 0x17
+#define AXP806_ALDO2_V_CTRL 0x18
+#define AXP806_ALDO3_V_CTRL 0x19
+#define AXP806_DCDC_MODE_CTRL1 0x1a
+#define AXP806_DCDC_MODE_CTRL2 0x1b
+#define AXP806_DCDC_FREQ_CTRL 0x1c
+#define AXP806_BLDO1_V_CTRL 0x20
+#define AXP806_BLDO2_V_CTRL 0x21
+#define AXP806_BLDO3_V_CTRL 0x22
+#define AXP806_BLDO4_V_CTRL 0x23
+#define AXP806_CLDO1_V_CTRL 0x24
+#define AXP806_CLDO2_V_CTRL 0x25
+#define AXP806_CLDO3_V_CTRL 0x26
+#define AXP806_VREF_TEMP_WARN_L 0xf3
+#define AXP806_BUS_ADDR_EXT 0xfe
+#define AXP806_REG_ADDR_EXT 0xff
+
+#define AXP803_POLYPHASE_CTRL 0x14
+#define AXP803_FLDO1_V_OUT 0x1c
+#define AXP803_FLDO2_V_OUT 0x1d
+#define AXP803_DCDC1_V_OUT 0x20
+#define AXP803_DCDC2_V_OUT 0x21
+#define AXP803_DCDC3_V_OUT 0x22
+#define AXP803_DCDC4_V_OUT 0x23
+#define AXP803_DCDC5_V_OUT 0x24
+#define AXP803_DCDC6_V_OUT 0x25
+#define AXP803_DCDC_FREQ_CTRL 0x3b
+
+/* Other DCDC regulator control registers are the same as AXP803 */
+#define AXP813_DCDC7_V_OUT 0x26
+
+/* Interrupt */
+#define AXP152_IRQ1_EN 0x40
+#define AXP152_IRQ2_EN 0x41
+#define AXP152_IRQ3_EN 0x42
+#define AXP152_IRQ1_STATE 0x48
+#define AXP152_IRQ2_STATE 0x49
+#define AXP152_IRQ3_STATE 0x4a
+
+#define AXP20X_IRQ1_EN 0x40
+#define AXP20X_IRQ2_EN 0x41
+#define AXP20X_IRQ3_EN 0x42
+#define AXP20X_IRQ4_EN 0x43
+#define AXP20X_IRQ5_EN 0x44
+#define AXP20X_IRQ6_EN 0x45
+#define AXP20X_IRQ1_STATE 0x48
+#define AXP20X_IRQ2_STATE 0x49
+#define AXP20X_IRQ3_STATE 0x4a
+#define AXP20X_IRQ4_STATE 0x4b
+#define AXP20X_IRQ5_STATE 0x4c
+#define AXP20X_IRQ6_STATE 0x4d
+
+/* ADC */
+#define AXP20X_ACIN_V_ADC_H 0x56
+#define AXP20X_ACIN_V_ADC_L 0x57
+#define AXP20X_ACIN_I_ADC_H 0x58
+#define AXP20X_ACIN_I_ADC_L 0x59
+#define AXP20X_VBUS_V_ADC_H 0x5a
+#define AXP20X_VBUS_V_ADC_L 0x5b
+#define AXP20X_VBUS_I_ADC_H 0x5c
+#define AXP20X_VBUS_I_ADC_L 0x5d
+#define AXP20X_TEMP_ADC_H 0x5e
+#define AXP20X_TEMP_ADC_L 0x5f
+#define AXP20X_TS_IN_H 0x62
+#define AXP20X_TS_IN_L 0x63
+#define AXP20X_GPIO0_V_ADC_H 0x64
+#define AXP20X_GPIO0_V_ADC_L 0x65
+#define AXP20X_GPIO1_V_ADC_H 0x66
+#define AXP20X_GPIO1_V_ADC_L 0x67
+#define AXP20X_PWR_BATT_H 0x70
+#define AXP20X_PWR_BATT_M 0x71
+#define AXP20X_PWR_BATT_L 0x72
+#define AXP20X_BATT_V_H 0x78
+#define AXP20X_BATT_V_L 0x79
+#define AXP20X_BATT_CHRG_I_H 0x7a
+#define AXP20X_BATT_CHRG_I_L 0x7b
+#define AXP20X_BATT_DISCHRG_I_H 0x7c
+#define AXP20X_BATT_DISCHRG_I_L 0x7d
+#define AXP20X_IPSOUT_V_HIGH_H 0x7e
+#define AXP20X_IPSOUT_V_HIGH_L 0x7f
+
+/* Power supply */
+#define AXP20X_DCDC_MODE 0x80
+#define AXP20X_ADC_EN1 0x82
+#define AXP20X_ADC_EN2 0x83
+#define AXP20X_ADC_RATE 0x84
+#define AXP20X_GPIO10_IN_RANGE 0x85
+#define AXP20X_GPIO1_ADC_IRQ_RIS 0x86
+#define AXP20X_GPIO1_ADC_IRQ_FAL 0x87
+#define AXP20X_TIMER_CTRL 0x8a
+#define AXP20X_VBUS_MON 0x8b
+#define AXP20X_OVER_TMP 0x8f
+
+#define AXP22X_PWREN_CTRL1 0x8c
+#define AXP22X_PWREN_CTRL2 0x8d
+
+/* GPIO */
+#define AXP152_GPIO0_CTRL 0x90
+#define AXP152_GPIO1_CTRL 0x91
+#define AXP152_GPIO2_CTRL 0x92
+#define AXP152_GPIO3_CTRL 0x93
+#define AXP152_LDOGPIO2_V_OUT 0x96
+#define AXP152_GPIO_INPUT 0x97
+#define AXP152_PWM0_FREQ_X 0x98
+#define AXP152_PWM0_FREQ_Y 0x99
+#define AXP152_PWM0_DUTY_CYCLE 0x9a
+#define AXP152_PWM1_FREQ_X 0x9b
+#define AXP152_PWM1_FREQ_Y 0x9c
+#define AXP152_PWM1_DUTY_CYCLE 0x9d
+
+#define AXP20X_GPIO0_CTRL 0x90
+#define AXP20X_LDO5_V_OUT 0x91
+#define AXP20X_GPIO1_CTRL 0x92
+#define AXP20X_GPIO2_CTRL 0x93
+#define AXP20X_GPIO20_SS 0x94
+#define AXP20X_GPIO3_CTRL 0x95
+
+#define AXP22X_LDO_IO0_V_OUT 0x91
+#define AXP22X_LDO_IO1_V_OUT 0x93
+#define AXP22X_GPIO_STATE 0x94
+#define AXP22X_GPIO_PULL_DOWN 0x95
+
+/* Battery */
+#define AXP20X_CHRG_CC_31_24 0xb0
+#define AXP20X_CHRG_CC_23_16 0xb1
+#define AXP20X_CHRG_CC_15_8 0xb2
+#define AXP20X_CHRG_CC_7_0 0xb3
+#define AXP20X_DISCHRG_CC_31_24 0xb4
+#define AXP20X_DISCHRG_CC_23_16 0xb5
+#define AXP20X_DISCHRG_CC_15_8 0xb6
+#define AXP20X_DISCHRG_CC_7_0 0xb7
+#define AXP20X_CC_CTRL 0xb8
+#define AXP20X_FG_RES 0xb9
+
+/* OCV */
+#define AXP20X_RDC_H 0xba
+#define AXP20X_RDC_L 0xbb
+#define AXP20X_OCV(m) (0xc0 + (m))
+#define AXP20X_OCV_MAX 0xf
+
+/* AXP22X specific registers */
+#define AXP22X_PMIC_TEMP_H 0x56
+#define AXP22X_PMIC_TEMP_L 0x57
+#define AXP22X_TS_ADC_H 0x58
+#define AXP22X_TS_ADC_L 0x59
+#define AXP22X_BATLOW_THRES1 0xe6
+
+/* AXP288/AXP803 specific registers */
+#define AXP288_POWER_REASON 0x02
+#define AXP288_BC_GLOBAL 0x2c
+#define AXP288_BC_VBUS_CNTL 0x2d
+#define AXP288_BC_USB_STAT 0x2e
+#define AXP288_BC_DET_STAT 0x2f
+#define AXP288_PMIC_ADC_H 0x56
+#define AXP288_PMIC_ADC_L 0x57
+#define AXP288_TS_ADC_H 0x58
+#define AXP288_TS_ADC_L 0x59
+#define AXP288_GP_ADC_H 0x5a
+#define AXP288_GP_ADC_L 0x5b
+#define AXP288_ADC_TS_PIN_CTRL 0x84
+#define AXP288_RT_BATT_V_H 0xa0
+#define AXP288_RT_BATT_V_L 0xa1
+
+#define AXP813_ACIN_PATH_CTRL 0x3a
+#define AXP813_ADC_RATE 0x85
+
+/* Fuel Gauge */
+#define AXP288_FG_RDC1_REG 0xba
+#define AXP288_FG_RDC0_REG 0xbb
+#define AXP288_FG_OCVH_REG 0xbc
+#define AXP288_FG_OCVL_REG 0xbd
+#define AXP288_FG_OCV_CURVE_REG 0xc0
+#define AXP288_FG_DES_CAP1_REG 0xe0
+#define AXP288_FG_DES_CAP0_REG 0xe1
+#define AXP288_FG_CC_MTR1_REG 0xe2
+#define AXP288_FG_CC_MTR0_REG 0xe3
+#define AXP288_FG_OCV_CAP_REG 0xe4
+#define AXP288_FG_CC_CAP_REG 0xe5
+#define AXP288_FG_LOW_CAP_REG 0xe6
+#define AXP288_FG_TUNE0 0xe8
+#define AXP288_FG_TUNE1 0xe9
+#define AXP288_FG_TUNE2 0xea
+#define AXP288_FG_TUNE3 0xeb
+#define AXP288_FG_TUNE4 0xec
+#define AXP288_FG_TUNE5 0xed
+
+/* Regulators IDs */
+enum {
+ AXP20X_LDO1 = 0,
+ AXP20X_LDO2,
+ AXP20X_LDO3,
+ AXP20X_LDO4,
+ AXP20X_LDO5,
+ AXP20X_DCDC2,
+ AXP20X_DCDC3,
+ AXP20X_REG_ID_MAX,
+};
+
+enum {
+ AXP22X_DCDC1 = 0,
+ AXP22X_DCDC2,
+ AXP22X_DCDC3,
+ AXP22X_DCDC4,
+ AXP22X_DCDC5,
+ AXP22X_DC1SW,
+ AXP22X_DC5LDO,
+ AXP22X_ALDO1,
+ AXP22X_ALDO2,
+ AXP22X_ALDO3,
+ AXP22X_ELDO1,
+ AXP22X_ELDO2,
+ AXP22X_ELDO3,
+ AXP22X_DLDO1,
+ AXP22X_DLDO2,
+ AXP22X_DLDO3,
+ AXP22X_DLDO4,
+ AXP22X_RTC_LDO,
+ AXP22X_LDO_IO0,
+ AXP22X_LDO_IO1,
+ AXP22X_REG_ID_MAX,
+};
+
+enum {
+ AXP806_DCDCA = 0,
+ AXP806_DCDCB,
+ AXP806_DCDCC,
+ AXP806_DCDCD,
+ AXP806_DCDCE,
+ AXP806_ALDO1,
+ AXP806_ALDO2,
+ AXP806_ALDO3,
+ AXP806_BLDO1,
+ AXP806_BLDO2,
+ AXP806_BLDO3,
+ AXP806_BLDO4,
+ AXP806_CLDO1,
+ AXP806_CLDO2,
+ AXP806_CLDO3,
+ AXP806_SW,
+ AXP806_REG_ID_MAX,
+};
+
+enum {
+ AXP809_DCDC1 = 0,
+ AXP809_DCDC2,
+ AXP809_DCDC3,
+ AXP809_DCDC4,
+ AXP809_DCDC5,
+ AXP809_DC1SW,
+ AXP809_DC5LDO,
+ AXP809_ALDO1,
+ AXP809_ALDO2,
+ AXP809_ALDO3,
+ AXP809_ELDO1,
+ AXP809_ELDO2,
+ AXP809_ELDO3,
+ AXP809_DLDO1,
+ AXP809_DLDO2,
+ AXP809_RTC_LDO,
+ AXP809_LDO_IO0,
+ AXP809_LDO_IO1,
+ AXP809_SW,
+ AXP809_REG_ID_MAX,
+};
+
+enum {
+ AXP803_DCDC1 = 0,
+ AXP803_DCDC2,
+ AXP803_DCDC3,
+ AXP803_DCDC4,
+ AXP803_DCDC5,
+ AXP803_DCDC6,
+ AXP803_DC1SW,
+ AXP803_ALDO1,
+ AXP803_ALDO2,
+ AXP803_ALDO3,
+ AXP803_DLDO1,
+ AXP803_DLDO2,
+ AXP803_DLDO3,
+ AXP803_DLDO4,
+ AXP803_ELDO1,
+ AXP803_ELDO2,
+ AXP803_ELDO3,
+ AXP803_FLDO1,
+ AXP803_FLDO2,
+ AXP803_RTC_LDO,
+ AXP803_LDO_IO0,
+ AXP803_LDO_IO1,
+ AXP803_REG_ID_MAX,
+};
+
+enum {
+ AXP813_DCDC1 = 0,
+ AXP813_DCDC2,
+ AXP813_DCDC3,
+ AXP813_DCDC4,
+ AXP813_DCDC5,
+ AXP813_DCDC6,
+ AXP813_DCDC7,
+ AXP813_ALDO1,
+ AXP813_ALDO2,
+ AXP813_ALDO3,
+ AXP813_DLDO1,
+ AXP813_DLDO2,
+ AXP813_DLDO3,
+ AXP813_DLDO4,
+ AXP813_ELDO1,
+ AXP813_ELDO2,
+ AXP813_ELDO3,
+ AXP813_FLDO1,
+ AXP813_FLDO2,
+ AXP813_FLDO3,
+ AXP813_RTC_LDO,
+ AXP813_LDO_IO0,
+ AXP813_LDO_IO1,
+ AXP813_SW,
+ AXP813_REG_ID_MAX,
+};
+
+struct axp20x_dev {
+ struct device_d *dev;
+ struct regmap *regmap;
+ long variant;
+ int nr_cells;
+ const struct mfd_cell *cells;
+ const struct regmap_config *regmap_cfg;
+ struct poweroff_handler poweroff;
+};
+
+/* generic helper function for reading 9-16 bit wide regs */
+static inline int axp20x_read_variable_width(struct regmap *regmap,
+ unsigned int reg, unsigned int width)
+{
+ unsigned int reg_val, result;
+ int err;
+
+ err = regmap_read(regmap, reg, &reg_val);
+ if (err)
+ return err;
+
+ result = reg_val << (width - 8);
+
+ err = regmap_read(regmap, reg + 1, &reg_val);
+ if (err)
+ return err;
+
+ result |= reg_val;
+
+ return result;
+}
+
+/**
+ * axp20x_match_device(): Setup axp20x variant related fields
+ *
+ * @axp20x: axp20x device to setup (.dev field must be set)
+ * @dev: device associated with this axp20x device
+ *
+ * This lets the axp20x core configure the mfd cells and register maps
+ * for later use.
+ */
+int axp20x_match_device(struct axp20x_dev *axp20x);
+
+/**
+ * axp20x_device_probe(): Probe a configured axp20x device
+ *
+ * @axp20x: axp20x device to probe (must be configured)
+ *
+ * This function lets the axp20x core register the axp20x mfd devices
+ * The axp20x device passed in must be fully configured
+ * with axp20x_match_device, and regmap created.
+ */
+int axp20x_device_probe(struct axp20x_dev *axp20x);
+
+#endif /* __LINUX_MFD_AXP20X_H */
diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h
index b979f23372..1fce7e1ae0 100644
--- a/include/linux/nvmem-consumer.h
+++ b/include/linux/nvmem-consumer.h
@@ -34,6 +34,8 @@ void nvmem_cell_put(struct nvmem_cell *cell);
void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
void *nvmem_cell_get_and_read(struct device_node *np, const char *cell_name,
size_t bytes);
+int nvmem_cell_read_variable_le_u32(struct device_d *dev, const char *cell_id,
+ u32 *val);
int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len);
@@ -75,6 +77,13 @@ static inline void *nvmem_cell_get_and_read(struct device_node *np,
return ERR_PTR(-EOPNOTSUPP);
}
+static inline int nvmem_cell_read_variable_le_u32(struct device_d *dev,
+ const char *cell_id,
+ u32 *val)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int nvmem_cell_write(struct nvmem_cell *cell,
void *buf, size_t len)
{
diff --git a/include/of.h b/include/of.h
index 187efff57a..052d5fcad8 100644
--- a/include/of.h
+++ b/include/of.h
@@ -113,6 +113,8 @@ int of_parse_dtb(struct fdt_header *fdt);
struct device_node *of_unflatten_dtb(const void *fdt, int size);
struct device_node *of_unflatten_dtb_const(const void *infdt, int size);
+int of_fixup_reserved_memory(struct device_node *node, void *data);
+
struct cdev;
#ifdef CONFIG_OFTREE
@@ -133,6 +135,8 @@ extern int of_set_property(struct device_node *node, const char *p,
const void *val, int len, int create);
extern int of_append_property(struct device_node *np, const char *p,
const void *val, int len);
+extern int of_prepend_property(struct device_node *np, const char *name,
+ const void *val, int len);
extern struct property *of_new_property(struct device_node *node,
const char *name, const void *data, int len);
extern struct property *of_new_property_const(struct device_node *node,
@@ -141,6 +145,8 @@ extern struct property *of_new_property_const(struct device_node *node,
extern struct property *__of_new_property(struct device_node *node,
const char *name, void *data, int len);
extern void of_delete_property(struct property *pp);
+extern struct property *of_rename_property(struct device_node *np,
+ const char *old_name, const char *new_name);
extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
@@ -193,6 +199,9 @@ extern struct device_node *of_get_compatible_child(const struct device_node *par
extern struct device_node *of_get_child_by_name(const struct device_node *node,
const char *name);
extern char *of_get_reproducible_name(struct device_node *node);
+extern struct device_node *of_get_node_by_reproducible_name(struct device_node *dstroot,
+ struct device_node *srcnp);
+
extern struct device_node *of_find_node_by_reproducible_name(struct device_node
*from,
const char *name);
@@ -491,6 +500,13 @@ of_find_node_by_reproducible_name(struct device_node *from, const char *name)
return NULL;
}
+
+static inline struct device_node *of_get_node_by_reproducible_name(struct device_node *dstroot,
+ struct device_node *srcnp)
+{
+ return NULL;
+}
+
static inline struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
@@ -522,6 +538,12 @@ static inline int of_append_property(struct device_node *np, const char *p,
return -ENOSYS;
}
+static inline int of_prepend_property(struct device_node *np, const char *name,
+ const void *val, int len)
+{
+ return -ENOSYS;
+}
+
static inline struct property *of_new_property(struct device_node *node,
const char *name, const void *data, int len)
{
@@ -538,6 +560,12 @@ static inline void of_delete_property(struct property *pp)
{
}
+static inline struct property *of_rename_property(struct device_node *np,
+ const char *old_name, const char *new_name)
+{
+ return NULL;
+}
+
static inline int of_property_read_u32_index(const struct device_node *np,
const char *propname, u32 index, u32 *out_value)
{
diff --git a/include/pm_domain.h b/include/pm_domain.h
index 48fd170007..ff1aa37511 100644
--- a/include/pm_domain.h
+++ b/include/pm_domain.h
@@ -54,6 +54,8 @@ int pm_genpd_init(struct generic_pm_domain *genpd, void *gov, bool is_off);
int of_genpd_add_provider_simple(struct device_node *np,
struct generic_pm_domain *genpd);
+void pm_genpd_print(void);
+
#else
static inline int pm_genpd_init(struct generic_pm_domain *genpd,
diff --git a/include/soc/imx8m/featctrl.h b/include/soc/imx8m/featctrl.h
new file mode 100644
index 0000000000..af94995a91
--- /dev/null
+++ b/include/soc/imx8m/featctrl.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-FileCopyrightText: 2022 Ahmad Fatoum, Pengutronix */
+
+#ifndef __IMX8M_FEATCTRL_H_
+#define __IMX8M_FEATCTRL_H_
+
+#include <linux/types.h>
+
+struct imx8m_featctrl_data {
+ u32 vpu_bitmask;
+ u32 gpu_bitmask;
+};
+
+#ifdef CONFIG_IMX8M_FEATCTRL
+int imx8m_feat_ctrl_init(struct device_d *dev, u32 tester4,
+ const struct imx8m_featctrl_data *data);
+#else
+static inline int imx8m_feat_ctrl_init(struct device_d *dev, u32 tester4,
+ const struct imx8m_featctrl_data *data)
+{
+ return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/include/usb/gadget-multi.h b/include/usb/gadget-multi.h
index 2d8d7533a8..e67ca165c1 100644
--- a/include/usb/gadget-multi.h
+++ b/include/usb/gadget-multi.h
@@ -3,6 +3,7 @@
#ifndef __USB_GADGET_MULTI_H
#define __USB_GADGET_MULTI_H
+#include <linux/types.h>
#include <usb/fastboot.h>
#include <usb/dfu.h>
#include <usb/usbserial.h>
@@ -36,4 +37,6 @@ struct usbgadget_funcs {
int usbgadget_register(const struct usbgadget_funcs *funcs);
+void usbgadget_autostart(bool enable);
+
#endif /* __USB_GADGET_MULTI_H */
diff --git a/test/self/core.c b/test/self/core.c
index caa4c27f6d..40f5ee842d 100644
--- a/test/self/core.c
+++ b/test/self/core.c
@@ -7,6 +7,30 @@
LIST_HEAD(selftests);
+int selftest_run(struct selftest *test)
+{
+ int err;
+
+ test->running = true;
+ err = test->func();
+ test->running = false;
+
+ return err;
+}
+
+bool selftest_is_running(struct selftest *test)
+{
+ if (test)
+ return test->running;
+
+ list_for_each_entry(test, &selftests, list) {
+ if (selftest_is_running(test))
+ return true;
+ }
+
+ return false;
+}
+
void selftests_run(void)
{
struct selftest *test;
@@ -15,7 +39,7 @@ void selftests_run(void)
pr_notice("Configured tests will run now\n");
list_for_each_entry(test, &selftests, list)
- err |= test->func();
+ err |= selftest_run(test);
if (err)
pr_err("Some selftests failed\n");
diff --git a/test/self/of_manipulation.c b/test/self/of_manipulation.c
index 6eb6062e12..f7f95fa269 100644
--- a/test/self/of_manipulation.c
+++ b/test/self/of_manipulation.c
@@ -57,6 +57,16 @@ static void test_of_basics(struct device_node *root)
of_property_write_bool(node1, "property1", true);
assert_equal(node1, node2);
+
+ of_property_write_bool(node2, "property1", false);
+ of_property_write_u32(node2, "property1", 1);
+ of_property_write_u32(node2, "property2", 2);
+
+ of_property_write_u32(node1, "property3", 1);
+ of_property_write_u32(node1, "property2", 2);
+ of_rename_property(node1, "property3", "property1");
+
+ assert_equal(node1, node2);
}
static void test_of_property_strings(struct device_node *root)
@@ -93,9 +103,9 @@ static void test_of_property_strings(struct device_node *root)
of_append_property(np4, "property-single", "ayy", 4);
- of_append_property(np4, "property-multi", "ayy", 4);
of_append_property(np4, "property-multi", "bee", 4);
of_append_property(np4, "property-multi", "sea", 4);
+ of_prepend_property(np4, "property-multi", "ayy", 4);
assert_equal(np3, np4);
}
diff --git a/test/self/of_manipulation.dts b/test/self/of_manipulation.dts
index a69d944c1e..2cc6773fa9 100644
--- a/test/self/of_manipulation.dts
+++ b/test/self/of_manipulation.dts
@@ -4,12 +4,14 @@
/ {
node1 {
- property1;
+ property1 = <1>;
+ property2 = <2>;
node21 { };
};
node2 {
- property1;
+ property1 = <1>;
+ property2 = <2>;
node21 { };
};