diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2022-09-14 15:52:59 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2022-09-14 15:52:59 +0200 |
commit | 19df0b5883737c6ce50b893dfc8fe1722cd6560a (patch) | |
tree | 4a90f708d33a44f0b40eab69134543c38629c884 | |
parent | d01b0a64580833b4ccf10e6361badee1d81e1221 (diff) | |
parent | 7a9d2377b5e54cfec28a7645985a7371c1d8b8af (diff) | |
download | barebox-19df0b5883737c6ce50b893dfc8fe1722cd6560a.tar.gz |
Merge branch 'for-next/misc'
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); +} @@ -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, ®_val); + if (err) + return err; + + result = reg_val << (width - 8); + + err = regmap_read(regmap, reg + 1, ®_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 { }; }; |