summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/fastboot/fb_mmc.c6
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_agent.c207
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_devices.c25
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c10
-rw-r--r--drivers/firmware/scmi/smt.c15
-rw-r--r--drivers/gpio/gpio-uclass.c11
-rw-r--r--drivers/i2c/i2c-gpio.c19
-rw-r--r--drivers/misc/Kconfig18
-rw-r--r--drivers/misc/Makefile7
-rw-r--r--drivers/misc/qfw.c243
-rw-r--r--drivers/misc/qfw_mmio.c119
-rw-r--r--drivers/misc/qfw_pio.c69
-rw-r--r--drivers/misc/qfw_sandbox.c127
-rw-r--r--drivers/mtd/nand/raw/nand_base.c2
-rw-r--r--drivers/pci/pci_auto.c3
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/pmic_max77696.c31
-rw-r--r--drivers/power/regulator/Kconfig8
-rw-r--r--drivers/power/regulator/Makefile1
-rw-r--r--drivers/power/regulator/scmi_regulator.c195
-rw-r--r--drivers/rtc/Kconfig6
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rv3028.c208
-rw-r--r--drivers/tee/optee/core.c6
-rw-r--r--drivers/usb/dwc3/linux-compat.h6
25 files changed, 1107 insertions, 237 deletions
diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c
index 8e74e50e918..2f3837e5591 100644
--- a/drivers/fastboot/fb_mmc.c
+++ b/drivers/fastboot/fb_mmc.c
@@ -40,7 +40,7 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
/* check for raw partition descriptor */
strcpy(env_desc_name, "fastboot_raw_partition_");
- strncat(env_desc_name, name, PART_NAME_LEN);
+ strlcat(env_desc_name, name, PART_NAME_LEN);
raw_part_desc = strdup(env_get(env_desc_name));
if (raw_part_desc == NULL)
return -ENODEV;
@@ -61,7 +61,7 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
info->start = simple_strtoul(argv[0], NULL, 0);
info->size = simple_strtoul(argv[1], NULL, 0);
info->blksz = dev_desc->blksz;
- strncpy((char *)info->name, name, PART_NAME_LEN);
+ strlcpy((char *)info->name, name, PART_NAME_LEN);
if (raw_part_desc) {
if (strcmp(strsep(&raw_part_desc, " "), "mmcpart") == 0) {
@@ -114,7 +114,7 @@ static int part_get_info_by_name_or_alias(struct blk_desc **dev_desc,
/* check for alias */
strcpy(env_alias_name, "fastboot_partition_alias_");
- strncat(env_alias_name, name, PART_NAME_LEN);
+ strlcat(env_alias_name, name, PART_NAME_LEN);
aliased_part_name = env_get(env_alias_name);
if (aliased_part_name != NULL)
ret = do_get_part_info(dev_desc, aliased_part_name,
diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c
index 97a5dace15f..4b968205c2f 100644
--- a/drivers/firmware/scmi/sandbox-scmi_agent.c
+++ b/drivers/firmware/scmi/sandbox-scmi_agent.c
@@ -20,17 +20,18 @@
* processing. It simulates few of the SCMI services for some of the
* SCMI protocols embedded in U-Boot. Currently:
* - SCMI clock protocol: emulate 2 agents each exposing few clocks
- * - SCMI reset protocol: emulate 1 agents each exposing a reset
+ * - SCMI reset protocol: emulate 1 agent exposing a reset controller
+ * - SCMI voltage domain protocol: emulate 1 agent exposing 2 regulators
*
- * Agent #0 simulates 2 clocks and 1 reset domain.
+ * Agent #0 simulates 2 clocks, 1 reset domain and 1 voltage domain.
* See IDs in scmi0_clk[]/scmi0_reset[] and "sandbox-scmi-agent@0" in test.dts.
*
* Agent #1 simulates 1 clock.
* See IDs in scmi1_clk[] and "sandbox-scmi-agent@1" in test.dts.
*
- * All clocks are default disabled and reset levels down.
+ * All clocks and regulators are default disabled and reset controller down.
*
- * This Driver exports sandbox_scmi_service_ct() for the test sequence to
+ * This Driver exports sandbox_scmi_service_ctx() for the test sequence to
* get the state of the simulated services (clock state, rate, ...) and
* check back-end device state reflects the request send through the
* various uclass devices, as clocks and reset controllers.
@@ -47,6 +48,11 @@ static struct sandbox_scmi_reset scmi0_reset[] = {
{ .id = 3 },
};
+static struct sandbox_scmi_voltd scmi0_voltd[] = {
+ { .id = 0, .voltage_uv = 3300000 },
+ { .id = 1, .voltage_uv = 1800000 },
+};
+
static struct sandbox_scmi_clk scmi1_clk[] = {
{ .id = 1, .rate = 44 },
};
@@ -83,6 +89,13 @@ static void debug_print_agent_state(struct udevice *dev, char *str)
agent->reset_count,
agent->reset_count ? agent->reset[0].asserted : -1,
agent->reset_count > 1 ? agent->reset[1].asserted : -1);
+ dev_dbg(dev, " scmi%u_voltd (%zu): %u/%d, %u/%d, ...\n",
+ agent->idx,
+ agent->voltd_count,
+ agent->voltd_count ? agent->voltd[0].enabled : -1,
+ agent->voltd_count ? agent->voltd[0].voltage_uv : -1,
+ agent->voltd_count ? agent->voltd[1].enabled : -1,
+ agent->voltd_count ? agent->voltd[1].voltage_uv : -1);
};
static struct sandbox_scmi_clk *get_scmi_clk_state(uint agent_id, uint clock_id)
@@ -125,6 +138,20 @@ static struct sandbox_scmi_reset *get_scmi_reset_state(uint agent_id,
return NULL;
}
+static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint agent_id,
+ uint domain_id)
+{
+ size_t n;
+
+ if (agent_id == 0) {
+ for (n = 0; n < ARRAY_SIZE(scmi0_voltd); n++)
+ if (scmi0_voltd[n].id == domain_id)
+ return scmi0_voltd + n;
+ }
+
+ return NULL;
+}
+
/*
* Sandbox SCMI agent ops
*/
@@ -292,6 +319,160 @@ static int sandbox_scmi_rd_reset(struct udevice *dev, struct scmi_msg *msg)
return 0;
}
+static int sandbox_scmi_voltd_attribs(struct udevice *dev, struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_attr_in *in = NULL;
+ struct scmi_voltd_attr_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_attr_in *)msg->in_msg;
+ out = (struct scmi_voltd_attr_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ memset(out, 0, sizeof(*out));
+ snprintf(out->name, sizeof(out->name), "regu%u", in->domain_id);
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_voltd_config_set(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_config_set_in *in = NULL;
+ struct scmi_voltd_config_set_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_config_set_in *)msg->in_msg;
+ out = (struct scmi_voltd_config_set_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else if (in->config & ~SCMI_VOLTD_CONFIG_MASK) {
+ dev_err(dev, "Invalid config value 0x%x\n", in->config);
+
+ out->status = SCMI_INVALID_PARAMETERS;
+ } else if (in->config != SCMI_VOLTD_CONFIG_ON &&
+ in->config != SCMI_VOLTD_CONFIG_OFF) {
+ dev_err(dev, "Unexpected custom value 0x%x\n", in->config);
+
+ out->status = SCMI_INVALID_PARAMETERS;
+ } else {
+ voltd_state->enabled = in->config == SCMI_VOLTD_CONFIG_ON;
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_voltd_config_get(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_config_get_in *in = NULL;
+ struct scmi_voltd_config_get_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_config_get_in *)msg->in_msg;
+ out = (struct scmi_voltd_config_get_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ if (voltd_state->enabled)
+ out->config = SCMI_VOLTD_CONFIG_ON;
+ else
+ out->config = SCMI_VOLTD_CONFIG_OFF;
+
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_voltd_level_set(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_level_set_in *in = NULL;
+ struct scmi_voltd_level_set_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_level_set_in *)msg->in_msg;
+ out = (struct scmi_voltd_level_set_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ voltd_state->voltage_uv = in->voltage_level;
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
+static int sandbox_scmi_voltd_level_get(struct udevice *dev,
+ struct scmi_msg *msg)
+{
+ struct sandbox_scmi_agent *agent = dev_get_priv(dev);
+ struct scmi_voltd_level_get_in *in = NULL;
+ struct scmi_voltd_level_get_out *out = NULL;
+ struct sandbox_scmi_voltd *voltd_state = NULL;
+
+ if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
+ !msg->out_msg || msg->out_msg_sz < sizeof(*out))
+ return -EINVAL;
+
+ in = (struct scmi_voltd_level_get_in *)msg->in_msg;
+ out = (struct scmi_voltd_level_get_out *)msg->out_msg;
+
+ voltd_state = get_scmi_voltd_state(agent->idx, in->domain_id);
+ if (!voltd_state) {
+ dev_err(dev, "Unexpected domain ID %u\n", in->domain_id);
+
+ out->status = SCMI_NOT_FOUND;
+ } else {
+ out->voltage_level = voltd_state->voltage_uv;
+ out->status = SCMI_SUCCESS;
+ }
+
+ return 0;
+}
+
static int sandbox_scmi_test_process_msg(struct udevice *dev,
struct scmi_msg *msg)
{
@@ -318,6 +499,22 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
break;
}
break;
+ case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+ switch (msg->message_id) {
+ case SCMI_VOLTAGE_DOMAIN_ATTRIBUTES:
+ return sandbox_scmi_voltd_attribs(dev, msg);
+ case SCMI_VOLTAGE_DOMAIN_CONFIG_SET:
+ return sandbox_scmi_voltd_config_set(dev, msg);
+ case SCMI_VOLTAGE_DOMAIN_CONFIG_GET:
+ return sandbox_scmi_voltd_config_get(dev, msg);
+ case SCMI_VOLTAGE_DOMAIN_LEVEL_SET:
+ return sandbox_scmi_voltd_level_set(dev, msg);
+ case SCMI_VOLTAGE_DOMAIN_LEVEL_GET:
+ return sandbox_scmi_voltd_level_get(dev, msg);
+ default:
+ break;
+ }
+ break;
case SCMI_PROTOCOL_ID_BASE:
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
case SCMI_PROTOCOL_ID_SYSTEM:
@@ -369,6 +566,8 @@ static int sandbox_scmi_test_probe(struct udevice *dev)
.clk_count = ARRAY_SIZE(scmi0_clk),
.reset = scmi0_reset,
.reset_count = ARRAY_SIZE(scmi0_reset),
+ .voltd = scmi0_voltd,
+ .voltd_count = ARRAY_SIZE(scmi0_voltd),
};
break;
case '1':
diff --git a/drivers/firmware/scmi/sandbox-scmi_devices.c b/drivers/firmware/scmi/sandbox-scmi_devices.c
index 69239a198f0..66a67928817 100644
--- a/drivers/firmware/scmi/sandbox-scmi_devices.c
+++ b/drivers/firmware/scmi/sandbox-scmi_devices.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2020, Linaro Limited
+ * Copyright (C) 2020-2021, Linaro Limited
*/
#define LOG_CATEGORY UCLASS_MISC
@@ -8,11 +8,13 @@
#include <common.h>
#include <clk.h>
#include <dm.h>
+#include <log.h>
#include <malloc.h>
#include <reset.h>
#include <asm/io.h>
#include <asm/scmi_test.h>
#include <dm/device_compat.h>
+#include <power/regulator.h>
/*
* Simulate to some extent a SCMI exchange.
@@ -23,16 +25,19 @@
#define SCMI_TEST_DEVICES_CLK_COUNT 3
#define SCMI_TEST_DEVICES_RD_COUNT 1
+#define SCMI_TEST_DEVICES_VOLTD_COUNT 2
/*
* struct sandbox_scmi_device_priv - Storage for device handles used by test
* @clk: Array of clock instances used by tests
* @reset_clt: Array of the reset controller instances used by tests
+ * @regulators: Array of regulator device references used by the tests
* @devices: Resources exposed by sandbox_scmi_devices_ctx()
*/
struct sandbox_scmi_device_priv {
struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT];
struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT];
+ struct udevice *regulators[SCMI_TEST_DEVICES_VOLTD_COUNT];
struct sandbox_scmi_devices devices;
};
@@ -76,6 +81,8 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
.clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
.reset = priv->reset_ctl,
.reset_count = SCMI_TEST_DEVICES_RD_COUNT,
+ .regul = priv->regulators,
+ .regul_count = SCMI_TEST_DEVICES_VOLTD_COUNT,
};
for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
@@ -94,8 +101,24 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
}
}
+ for (n = 0; n < SCMI_TEST_DEVICES_VOLTD_COUNT; n++) {
+ char name[32];
+
+ ret = snprintf(name, sizeof(name), "regul%zu-supply", n);
+ assert(ret >= 0 && ret < sizeof(name));
+
+ ret = device_get_supply_regulator(dev, name,
+ priv->devices.regul + n);
+ if (ret) {
+ dev_err(dev, "%s: Failed on voltd %zu\n", __func__, n);
+ goto err_regul;
+ }
+ }
+
return 0;
+err_regul:
+ n = SCMI_TEST_DEVICES_RD_COUNT;
err_reset:
for (; n > 0; n--)
reset_free(priv->devices.reset + n - 1);
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 527163b5ce3..4f5870b4838 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -80,6 +80,16 @@ static int scmi_bind_protocols(struct udevice *dev)
if (IS_ENABLED(CONFIG_RESET_SCMI))
drv = DM_DRIVER_GET(scmi_reset_domain);
break;
+ case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
+ if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
+ node = ofnode_find_subnode(node, "regulators");
+ if (!ofnode_valid(node)) {
+ dev_err(dev, "no regulators node\n");
+ return -ENXIO;
+ }
+ drv = DM_DRIVER_GET(scmi_voltage_domain);
+ }
+ break;
default:
break;
}
diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c
index 60b9d499b79..f1915c00741 100644
--- a/drivers/firmware/scmi/smt.c
+++ b/drivers/firmware/scmi/smt.c
@@ -41,8 +41,13 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
if (ret)
return ret;
- faddr = cpu_to_fdt32(resource.start);
- paddr = ofnode_translate_address(args.node, &faddr);
+ /* TEMP workaround for ofnode_read_resource translation issue */
+ if (of_live_active()) {
+ paddr = resource.start;
+ } else {
+ faddr = cpu_to_fdt32(resource.start);
+ paddr = ofnode_translate_address(args.node, &faddr);
+ }
smt->size = resource_size(&resource);
if (smt->size < sizeof(struct scmi_smt_header)) {
@@ -56,8 +61,10 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
#ifdef CONFIG_ARM
if (dcache_status())
- mmu_set_region_dcache_behaviour((uintptr_t)smt->buf,
- smt->size, DCACHE_OFF);
+ mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, MMU_SECTION_SIZE),
+ ALIGN(smt->size, MMU_SECTION_SIZE),
+ DCACHE_OFF);
+
#endif
return 0;
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index f24db87ef06..e4e7f58c39a 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -713,17 +713,6 @@ int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
return dm_gpio_clrset_flags(desc, GPIOD_MASK_DIR, flags);
}
-int dm_gpio_set_dir(struct gpio_desc *desc)
-{
- int ret;
-
- ret = check_reserved(desc, "set_dir");
- if (ret)
- return ret;
-
- return _dm_gpio_set_flags(desc, desc->flags);
-}
-
int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
ulong set)
{
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
index a301a4460b3..cf8f8f40359 100644
--- a/drivers/i2c/i2c-gpio.c
+++ b/drivers/i2c/i2c-gpio.c
@@ -48,12 +48,13 @@ static int i2c_gpio_sda_get(struct i2c_gpio_bus *bus)
static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit)
{
struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+ ulong flags;
if (bit)
- sda->flags = (sda->flags & ~GPIOD_IS_OUT) | GPIOD_IS_IN;
+ flags = GPIOD_IS_IN;
else
- sda->flags = (sda->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
- dm_gpio_set_dir(sda);
+ flags = GPIOD_IS_OUT;
+ dm_gpio_clrset_flags(sda, GPIOD_MASK_DIR, flags);
}
static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
@@ -62,16 +63,14 @@ static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
int count = 0;
if (bit) {
- scl->flags = (scl->flags & ~GPIOD_IS_OUT) | GPIOD_IS_IN;
- dm_gpio_set_dir(scl);
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, GPIOD_IS_IN);
while (!dm_gpio_get_value(scl) && count++ < 100000)
udelay(1);
if (!dm_gpio_get_value(scl))
pr_err("timeout waiting on slave to release scl\n");
} else {
- scl->flags = (scl->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
- dm_gpio_set_dir(scl);
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, GPIOD_IS_OUT);
}
}
@@ -79,11 +78,11 @@ static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
static void i2c_gpio_scl_set_output_only(struct i2c_gpio_bus *bus, int bit)
{
struct gpio_desc *scl = &bus->gpios[PIN_SCL];
- scl->flags = (scl->flags & (~GPIOD_IS_IN & ~GPIOD_IS_OUT_ACTIVE)) | GPIOD_IS_OUT;
+ ulong flags = GPIOD_IS_OUT;
if (bit)
- scl->flags |= GPIOD_IS_OUT_ACTIVE;
- dm_gpio_set_dir(scl);
+ flags |= GPIOD_IS_OUT_ACTIVE;
+ dm_gpio_clrset_flags(scl, GPIOD_MASK_DIR, flags);
}
static void i2c_gpio_write_bit(struct i2c_gpio_bus *bus, int delay, uchar bit)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7d2a2997797..c650471ff7c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -368,8 +368,22 @@ config WINBOND_W83627
config QFW
bool
help
- Hidden option to enable QEMU fw_cfg interface. This will be selected by
- either CONFIG_CMD_QFW or CONFIG_GENERATE_ACPI_TABLE.
+ Hidden option to enable QEMU fw_cfg interface and uclass. This will
+ be selected by either CONFIG_CMD_QFW or CONFIG_GENERATE_ACPI_TABLE.
+
+config QFW_PIO
+ bool
+ depends on QFW
+ help
+ Hidden option to enable PIO QEMU fw_cfg interface. This will be
+ selected by the appropriate QEMU board.
+
+config QFW_MMIO
+ bool
+ depends on QFW
+ help
+ Hidden option to enable MMIO QEMU fw_cfg interface. This will be
+ selected by the appropriate QEMU board.
config I2C_EEPROM
bool "Enable driver for generic I2C-attached EEPROMs"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 1a493960074..0c67d43a5d4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,7 +55,12 @@ obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
obj-$(CONFIG_P2SB) += p2sb-uclass.o
obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
-obj-$(CONFIG_QFW) += qfw.o
+ifdef CONFIG_QFW
+obj-y += qfw.o
+obj-$(CONFIG_QFW_PIO) += qfw_pio.o
+obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o
+obj-$(CONFIG_SANDBOX) += qfw_sandbox.o
+endif
obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c
index f6eb6583ed0..ea00be88a8d 100644
--- a/drivers/misc/qfw.c
+++ b/drivers/misc/qfw.c
@@ -1,25 +1,22 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
*/
+#define LOG_CATEGORY UCLASS_QFW
+
#include <common.h>
#include <command.h>
#include <errno.h>
#include <log.h>
#include <malloc.h>
#include <qfw.h>
-#include <asm/io.h>
+#include <dm.h>
+#include <misc.h>
#ifdef CONFIG_GENERATE_ACPI_TABLE
#include <asm/tables.h>
#endif
-#include <linux/list.h>
-
-static bool fwcfg_present;
-static bool fwcfg_dma_present;
-static struct fw_cfg_arch_ops *fwcfg_arch_ops;
-
-static LIST_HEAD(fw_list);
#ifdef CONFIG_GENERATE_ACPI_TABLE
/*
@@ -32,7 +29,8 @@ static LIST_HEAD(fw_list);
* be ignored.
* @return: 0 on success, or negative value on failure
*/
-static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr)
+static int bios_linker_allocate(struct udevice *dev,
+ struct bios_linker_entry *entry, ulong *addr)
{
uint32_t size, align;
struct fw_file *file;
@@ -45,7 +43,7 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr)
return -EINVAL;
}
- file = qemu_fwcfg_find_file(entry->alloc.file);
+ file = qfw_find_file(dev, entry->alloc.file);
if (!file) {
printf("error: can't find file %s\n", entry->alloc.file);
return -ENOENT;
@@ -75,8 +73,8 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr)
debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n",
file->cfg.name, size, entry->alloc.zone, align, aligned_addr);
- qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
- size, (void *)aligned_addr);
+ qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size,
+ (void *)aligned_addr);
file->addr = aligned_addr;
/* adjust address for low memory allocation */
@@ -94,16 +92,17 @@ static int bios_linker_allocate(struct bios_linker_entry *entry, ulong *addr)
* ACPI tables
* @return: 0 on success, or negative value on failure
*/
-static int bios_linker_add_pointer(struct bios_linker_entry *entry)
+static int bios_linker_add_pointer(struct udevice *dev,
+ struct bios_linker_entry *entry)
{
struct fw_file *dest, *src;
uint32_t offset = le32_to_cpu(entry->pointer.offset);
uint64_t pointer = 0;
- dest = qemu_fwcfg_find_file(entry->pointer.dest_file);
+ dest = qfw_find_file(dev, entry->pointer.dest_file);
if (!dest || !dest->addr)
return -ENOENT;
- src = qemu_fwcfg_find_file(entry->pointer.src_file);
+ src = qfw_find_file(dev, entry->pointer.src_file);
if (!src || !src->addr)
return -ENOENT;
@@ -127,13 +126,14 @@ static int bios_linker_add_pointer(struct bios_linker_entry *entry)
* checksums
* @return: 0 on success, or negative value on failure
*/
-static int bios_linker_add_checksum(struct bios_linker_entry *entry)
+static int bios_linker_add_checksum(struct udevice *dev,
+ struct bios_linker_entry *entry)
{
struct fw_file *file;
uint8_t *data, cksum = 0;
uint8_t *cksum_start;
- file = qemu_fwcfg_find_file(entry->cksum.file);
+ file = qfw_find_file(dev, entry->cksum.file);
if (!file || !file->addr)
return -ENOENT;
@@ -149,20 +149,27 @@ static int bios_linker_add_checksum(struct bios_linker_entry *entry)
/* This function loads and patches ACPI tables provided by QEMU */
ulong write_acpi_tables(ulong addr)
{
- int i, ret = 0;
+ int i, ret;
struct fw_file *file;
struct bios_linker_entry *table_loader;
struct bios_linker_entry *entry;
uint32_t size;
+ struct udevice *dev;
+
+ ret = qfw_get_dev(&dev);
+ if (ret) {
+ printf("error: no qfw\n");
+ return addr;
+ }
/* make sure fw_list is loaded */
- ret = qemu_fwcfg_read_firmware_list();
+ ret = qfw_read_firmware_list(dev);
if (ret) {
printf("error: can't read firmware file list\n");
return addr;
}
- file = qemu_fwcfg_find_file("etc/table-loader");
+ file = qfw_find_file(dev, "etc/table-loader");
if (!file) {
printf("error: can't find etc/table-loader\n");
return addr;
@@ -180,24 +187,23 @@ ulong write_acpi_tables(ulong addr)
return addr;
}
- qemu_fwcfg_read_entry(be16_to_cpu(file->cfg.select),
- size, table_loader);
+ qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader);
for (i = 0; i < (size / sizeof(*entry)); i++) {
entry = table_loader + i;
switch (le32_to_cpu(entry->command)) {
case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
- ret = bios_linker_allocate(entry, &addr);
+ ret = bios_linker_allocate(dev, entry, &addr);
if (ret)
goto out;
break;
case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
- ret = bios_linker_add_pointer(entry);
+ ret = bios_linker_add_pointer(dev, entry);
if (ret)
goto out;
break;
case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
- ret = bios_linker_add_checksum(entry);
+ ret = bios_linker_add_checksum(dev, entry);
if (ret)
goto out;
break;
@@ -209,9 +215,9 @@ ulong write_acpi_tables(ulong addr)
out:
if (ret) {
struct fw_cfg_file_iter iter;
- for (file = qemu_fwcfg_file_iter_init(&iter);
- !qemu_fwcfg_file_iter_end(&iter);
- file = qemu_fwcfg_file_iter_next(&iter)) {
+ for (file = qfw_file_iter_init(dev, &iter);
+ !qfw_file_iter_end(&iter);
+ file = qfw_file_iter_next(&iter)) {
if (file->addr) {
free((void *)file->addr);
file->addr = 0;
@@ -225,170 +231,89 @@ out:
ulong acpi_get_rsdp_addr(void)
{
+ int ret;
struct fw_file *file;
+ struct udevice *dev;
- file = qemu_fwcfg_find_file("etc/acpi/rsdp");
+ ret = qfw_get_dev(&dev);
+ if (ret) {
+ printf("error: no qfw\n");
+ return 0;
+ }
+
+ file = qfw_find_file(dev, "etc/acpi/rsdp");
return file->addr;
}
#endif
-/* Read configuration item using fw_cfg PIO interface */
-static void qemu_fwcfg_read_entry_pio(uint16_t entry,
- uint32_t size, void *address)
+static void qfw_read_entry_io(struct qfw_dev *qdev, u16 entry, u32 size,
+ void *address)
{
- debug("qemu_fwcfg_read_entry_pio: entry 0x%x, size %u address %p\n",
- entry, size, address);
+ struct dm_qfw_ops *ops = dm_qfw_get_ops(qdev->dev);
+
+ debug("%s: entry 0x%x, size %u address %p\n", __func__, entry, size,
+ address);
- return fwcfg_arch_ops->arch_read_pio(entry, size, address);
+ ops->read_entry_io(qdev->dev, entry, size, address);
}
-/* Read configuration item using fw_cfg DMA interface */
-static void qemu_fwcfg_read_entry_dma(uint16_t entry,
- uint32_t size, void *address)
+static void qfw_read_entry_dma(struct qfw_dev *qdev, u16 entry, u32 size,
+ void *address)
{
- struct fw_cfg_dma_access dma;
+ struct dm_qfw_ops *ops = dm_qfw_get_ops(qdev->dev);
- dma.length = cpu_to_be32(size);
- dma.address = cpu_to_be64((uintptr_t)address);
- dma.control = cpu_to_be32(FW_CFG_DMA_READ);
+ struct qfw_dma dma = {
+ .length = cpu_to_be32(size),
+ .address = cpu_to_be64((uintptr_t)address),
+ .control = cpu_to_be32(FW_CFG_DMA_READ),
+ };
/*
- * writting FW_CFG_INVALID will cause read operation to resume at
- * last offset, otherwise read will start at offset 0
+ * writing FW_CFG_INVALID will cause read operation to resume at last
+ * offset, otherwise read will start at offset 0
*/
if (entry != FW_CFG_INVALID)
dma.control |= cpu_to_be32(FW_CFG_DMA_SELECT | (entry << 16));
- barrier();
-
- debug("qemu_fwcfg_read_entry_dma: entry 0x%x, size %u address %p, control 0x%x\n",
+ debug("%s: entry 0x%x, size %u address %p, control 0x%x\n", __func__,
entry, size, address, be32_to_cpu(dma.control));
- fwcfg_arch_ops->arch_read_dma(&dma);
-}
+ barrier();
-bool qemu_fwcfg_present(void)
-{
- return fwcfg_present;
+ ops->read_entry_dma(qdev->dev, &dma);
}
-bool qemu_fwcfg_dma_present(void)
+void qfw_read_entry(struct udevice *dev, u16 entry, u32 size, void *address)
{
- return fwcfg_dma_present;
-}
+ struct qfw_dev *qdev = dev_get_uclass_priv(dev);
-void qemu_fwcfg_read_entry(uint16_t entry, uint32_t length, void *address)
-{
- if (fwcfg_dma_present)
- qemu_fwcfg_read_entry_dma(entry, length, address);
+ if (qdev->dma_present)
+ qfw_read_entry_dma(qdev, entry, size, address);
else
- qemu_fwcfg_read_entry_pio(entry, length, address);
+ qfw_read_entry_io(qdev, entry, size, address);
}
-int qemu_fwcfg_online_cpus(void)
+int qfw_register(struct udevice *dev)
{
- uint16_t nb_cpus;
+ struct qfw_dev *qdev = dev_get_uclass_priv(dev);
+ u32 qemu, dma_enabled;
- if (!fwcfg_present)
- return -ENODEV;
-
- qemu_fwcfg_read_entry(FW_CFG_NB_CPUS, 2, &nb_cpus);
-
- return le16_to_cpu(nb_cpus);
-}
+ qdev->dev = dev;
+ INIT_LIST_HEAD(&qdev->fw_list);
-int qemu_fwcfg_read_firmware_list(void)
-{
- int i;
- uint32_t count;
- struct fw_file *file;
- struct list_head *entry;
-
- /* don't read it twice */
- if (!list_empty(&fw_list))
- return 0;
+ qfw_read_entry_io(qdev, FW_CFG_SIGNATURE, 4, &qemu);
+ if (be32_to_cpu(qemu) != QEMU_FW_CFG_SIGNATURE)
+ return -ENODEV;
- qemu_fwcfg_read_entry(FW_CFG_FILE_DIR, 4, &count);
- if (!count)
- return 0;
-
- count = be32_to_cpu(count);
- for (i = 0; i < count; i++) {
- file = malloc(sizeof(*file));
- if (!file) {
- printf("error: allocating resource\n");
- goto err;
- }
- qemu_fwcfg_read_entry(FW_CFG_INVALID,
- sizeof(struct fw_cfg_file), &file->cfg);
- file->addr = 0;
- list_add_tail(&file->list, &fw_list);
- }
+ qfw_read_entry_io(qdev, FW_CFG_ID, 1, &dma_enabled);
+ if (dma_enabled & FW_CFG_DMA_ENABLED)
+ qdev->dma_present = true;
return 0;
-
-err:
- list_for_each(entry, &fw_list) {
- file = list_entry(entry, struct fw_file, list);
- free(file);
- }
-
- return -ENOMEM;
}
-struct fw_file *qemu_fwcfg_find_file(const char *name)
-{
- struct list_head *entry;
- struct fw_file *file;
-
- list_for_each(entry, &fw_list) {
- file = list_entry(entry, struct fw_file, list);
- if (!strcmp(file->cfg.name, name))
- return file;
- }
-
- return NULL;
-}
-
-struct fw_file *qemu_fwcfg_file_iter_init(struct fw_cfg_file_iter *iter)
-{
- iter->entry = fw_list.next;
- return list_entry((struct list_head *)iter->entry,
- struct fw_file, list);
-}
-
-struct fw_file *qemu_fwcfg_file_iter_next(struct fw_cfg_file_iter *iter)
-{
- iter->entry = ((struct list_head *)iter->entry)->next;
- return list_entry((struct list_head *)iter->entry,
- struct fw_file, list);
-}
-
-bool qemu_fwcfg_file_iter_end(struct fw_cfg_file_iter *iter)
-{
- return iter->entry == &fw_list;
-}
-
-void qemu_fwcfg_init(struct fw_cfg_arch_ops *ops)
-{
- uint32_t qemu;
- uint32_t dma_enabled;
-
- fwcfg_present = false;
- fwcfg_dma_present = false;
- fwcfg_arch_ops = NULL;
-
- if (!ops || !ops->arch_read_pio || !ops->arch_read_dma)
- return;
- fwcfg_arch_ops = ops;
-
- qemu_fwcfg_read_entry_pio(FW_CFG_SIGNATURE, 4, &qemu);
- if (be32_to_cpu(qemu) == QEMU_FW_CFG_SIGNATURE)
- fwcfg_present = true;
-
- if (fwcfg_present) {
- qemu_fwcfg_read_entry_pio(FW_CFG_ID, 1, &dma_enabled);
- if (dma_enabled & FW_CFG_DMA_ENABLED)
- fwcfg_dma_present = true;
- }
-}
+UCLASS_DRIVER(qfw) = {
+ .id = UCLASS_QFW,
+ .name = "qfw",
+ .per_device_auto = sizeof(struct qfw_dev),
+};
diff --git a/drivers/misc/qfw_mmio.c b/drivers/misc/qfw_mmio.c
new file mode 100644
index 00000000000..f397384054a
--- /dev/null
+++ b/drivers/misc/qfw_mmio.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * MMIO interface for QFW
+ *
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
+ */
+
+#define LOG_CATEGORY UCLASS_QFW
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <qfw.h>
+
+struct qfw_mmio {
+ /*
+ * Each access to the 64-bit data register can be 8/16/32/64 bits wide.
+ */
+ union {
+ u8 data8;
+ u16 data16;
+ u32 data32;
+ u64 data64;
+ };
+ u16 selector;
+ u8 padding[6];
+ u64 dma;
+};
+
+struct qfw_mmio_plat {
+ volatile struct qfw_mmio *mmio;
+};
+
+static void qfw_mmio_read_entry_io(struct udevice *dev, u16 entry, u32 size,
+ void *address)
+{
+ struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+ /*
+ * writing FW_CFG_INVALID will cause read operation to resume at last
+ * offset, otherwise read will start at offset 0
+ *
+ * Note: on platform where the control register is MMIO, the register
+ * is big endian.
+ */
+ if (entry != FW_CFG_INVALID)
+ plat->mmio->selector = cpu_to_be16(entry);
+
+ /* the endianness of data register is string-preserving */
+ while (size >= 8) {
+ *(u64 *)address = plat->mmio->data64;
+ address += 8;
+ size -= 8;
+ }
+ while (size >= 4) {
+ *(u32 *)address = plat->mmio->data32;
+ address += 4;
+ size -= 4;
+ }
+ while (size >= 2) {
+ *(u16 *)address = plat->mmio->data16;
+ address += 2;
+ size -= 2;
+ }
+ while (size >= 1) {
+ *(u8 *)address = plat->mmio->data8;
+ address += 1;
+ size -= 1;
+ }
+}
+
+/* Read configuration item using fw_cfg DMA interface */
+static void qfw_mmio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
+{
+ struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+ /* the DMA address register is big-endian */
+ plat->mmio->dma = cpu_to_be64((uintptr_t)dma);
+
+ while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR);
+}
+
+static int qfw_mmio_of_to_plat(struct udevice *dev)
+{
+ struct qfw_mmio_plat *plat = dev_get_plat(dev);
+
+ plat->mmio = map_physmem(dev_read_addr(dev),
+ sizeof(struct qfw_mmio),
+ MAP_NOCACHE);
+
+ return 0;
+}
+
+static int qfw_mmio_probe(struct udevice *dev)
+{
+ return qfw_register(dev);
+}
+
+static struct dm_qfw_ops qfw_mmio_ops = {
+ .read_entry_io = qfw_mmio_read_entry_io,
+ .read_entry_dma = qfw_mmio_read_entry_dma,
+};
+
+static const struct udevice_id qfw_mmio_ids[] = {
+ { .compatible = "qemu,fw-cfg-mmio" },
+ {}
+};
+
+U_BOOT_DRIVER(qfw_mmio) = {
+ .name = "qfw_mmio",
+ .id = UCLASS_QFW,
+ .of_match = qfw_mmio_ids,
+ .plat_auto = sizeof(struct qfw_mmio_plat),
+ .of_to_plat = qfw_mmio_of_to_plat,
+ .probe = qfw_mmio_probe,
+ .ops = &qfw_mmio_ops,
+};
diff --git a/drivers/misc/qfw_pio.c b/drivers/misc/qfw_pio.c
new file mode 100644
index 00000000000..e2f628d3383
--- /dev/null
+++ b/drivers/misc/qfw_pio.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PIO interface for QFW
+ *
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
+ */
+
+#define LOG_CATEGORY UCLASS_QFW
+
+#include <asm/io.h>
+#include <dm/device.h>
+#include <qfw.h>
+
+/*
+ * PIO ports are correct for x86, which appears to be the only arch that uses
+ * PIO.
+ */
+#define FW_CONTROL_PORT 0x510
+#define FW_DATA_PORT 0x511
+#define FW_DMA_PORT_LOW 0x514
+#define FW_DMA_PORT_HIGH 0x518
+
+static void qfw_pio_read_entry_io(struct udevice *dev, u16 entry, u32 size,
+ void *address)
+{
+ /*
+ * writing FW_CFG_INVALID will cause read operation to resume at last
+ * offset, otherwise read will start at offset 0
+ *
+ * Note: on platform where the control register is IO port, the
+ * endianness is little endian.
+ */
+ if (entry != FW_CFG_INVALID)
+ outw(cpu_to_le16(entry), FW_CONTROL_PORT);
+
+ /* the endianness of data register is string-preserving */
+ u32 i = 0;
+ u8 *data = address;
+
+ while (size--)
+ data[i++] = inb(FW_DATA_PORT);
+}
+
+/* Read configuration item using fw_cfg DMA interface */
+static void qfw_pio_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
+{
+ /* the DMA address register is big-endian */
+ outl(cpu_to_be32((uintptr_t)dma), FW_DMA_PORT_HIGH);
+
+ while (be32_to_cpu(dma->control) & ~FW_CFG_DMA_ERROR);
+}
+
+static int qfw_pio_probe(struct udevice *dev)
+{
+ return qfw_register(dev);
+}
+
+static struct dm_qfw_ops qfw_pio_ops = {
+ .read_entry_io = qfw_pio_read_entry_io,
+ .read_entry_dma = qfw_pio_read_entry_dma,
+};
+
+U_BOOT_DRIVER(qfw_pio) = {
+ .name = "qfw_pio",
+ .id = UCLASS_QFW,
+ .probe = qfw_pio_probe,
+ .ops = &qfw_pio_ops,
+};
diff --git a/drivers/misc/qfw_sandbox.c b/drivers/misc/qfw_sandbox.c
new file mode 100644
index 00000000000..b09974d33bd
--- /dev/null
+++ b/drivers/misc/qfw_sandbox.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sandbox interface for QFW
+ *
+ * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
+ * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
+ */
+
+#define LOG_CATEGORY UCLASS_QFW
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <qfw.h>
+
+struct qfw_sandbox_plat {
+ u8 file_dir_offset;
+};
+
+static void qfw_sandbox_read_entry_io(struct udevice *dev, u16 entry, u32 size,
+ void *address)
+{
+ debug("%s: entry 0x%x size %u address %p\n", __func__, entry, size,
+ address);
+
+ switch (entry) {
+ case FW_CFG_SIGNATURE:
+ if (size == 4)
+ *((u32 *)address) = cpu_to_be32(QEMU_FW_CFG_SIGNATURE);
+ break;
+ case FW_CFG_ID:
+ /* Advertise DMA support */
+ if (size == 1)
+ *((u8 *)address) = FW_CFG_DMA_ENABLED;
+ break;
+ default:
+ debug("%s got unsupported entry 0x%x\n", __func__, entry);
+ /*
+ * Sandbox driver doesn't support other entries here, assume we use DMA
+ * to read them -- the uclass driver will exclusively use it when
+ * advertised.
+ */
+ }
+}
+
+static void qfw_sandbox_read_entry_dma(struct udevice *dev, struct qfw_dma *dma)
+{
+ u16 entry;
+ u32 control = be32_to_cpu(dma->control);
+ void *address = (void *)be64_to_cpu(dma->address);
+ u32 length = be32_to_cpu(dma->length);
+ struct qfw_sandbox_plat *plat = dev_get_plat(dev);
+ struct fw_cfg_file *file;
+
+ debug("%s\n", __func__);
+
+ if (!(control & FW_CFG_DMA_READ))
+ return;
+
+ if (control & FW_CFG_DMA_SELECT) {
+ /* Start new read. */
+ entry = control >> 16;
+
+ /* Arbitrary values to be used by tests. */
+ switch (entry) {
+ case FW_CFG_NB_CPUS:
+ if (length == 2)
+ *((u16 *)address) = cpu_to_le16(5);
+ break;
+ case FW_CFG_FILE_DIR:
+ if (length == 4) {
+ *((u32 *)address) = cpu_to_be32(2);
+ plat->file_dir_offset = 1;
+ }
+ break;
+ default:
+ debug("%s got unsupported entry 0x%x\n", __func__,
+ entry);
+ }
+ } else if (plat->file_dir_offset && length == 64) {
+ file = address;
+ switch (plat->file_dir_offset) {
+ case 1:
+ file->size = cpu_to_be32(8);
+ file->select = cpu_to_be16(FW_CFG_FILE_FIRST);
+ strcpy(file->name, "test-one");
+ plat->file_dir_offset++;
+ break;
+ case 2:
+ file->size = cpu_to_be32(8);
+ file->select = cpu_to_be16(FW_CFG_FILE_FIRST + 1);
+ strcpy(file->name, "test-two");
+ plat->file_dir_offset++;
+ break;
+ }
+ }
+
+ /*
+ * Signal that we are finished. No-one checks this in sandbox --
+ * normally the platform-specific driver looks for it -- but let's
+ * replicate the behaviour in case someone relies on it later.
+ */
+ dma->control = 0;
+}
+
+static int qfw_sandbox_probe(struct udevice *dev)
+{
+ return qfw_register(dev);
+}
+
+static struct dm_qfw_ops qfw_sandbox_ops = {
+ .read_entry_io = qfw_sandbox_read_entry_io,
+ .read_entry_dma = qfw_sandbox_read_entry_dma,
+};
+
+U_BOOT_DRIVER(qfw_sandbox) = {
+ .name = "qfw_sandbox",
+ .id = UCLASS_QFW,
+ .plat_auto = sizeof(struct qfw_sandbox_plat),
+ .probe = qfw_sandbox_probe,
+ .ops = &qfw_sandbox_ops,
+};
+
+U_BOOT_DRVINFO(qfw_sandbox) = {
+ .name = "qfw_sandbox",
+};
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 6557faddf94..3679ee727e9 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -3559,6 +3559,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
pr_warn("%s: attempt to erase a bad block at page 0x%08x\n",
__func__, page);
instr->state = MTD_ERASE_FAILED;
+ instr->fail_addr =
+ ((loff_t)page << chip->page_shift);
goto erase_exit;
}
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index da76148c583..05663c72b4b 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -88,8 +88,9 @@ static void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
else
bar_res = mem;
- debug("PCI Autoconfig: BAR %d, %s, size=0x%llx, ",
+ debug("PCI Autoconfig: BAR %d, %s%s, size=0x%llx, ",
bar_nr, bar_res == prefetch ? "Prf" : "Mem",
+ found_mem64 ? "64" : "",
(unsigned long long)bar_size);
}
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 7b4c0f02c60..89099fde573 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o
obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o
obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o
-obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o
obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
obj-$(CONFIG_POWER_PCA9450) += pmic_pca9450.o
obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o
diff --git a/drivers/power/pmic/pmic_max77696.c b/drivers/power/pmic/pmic_max77696.c
deleted file mode 100644
index f3a73d6405f..00000000000
--- a/drivers/power/pmic/pmic_max77696.c
+++ /dev/null
@@ -1,31 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2015 Freescale Semiconductor, Inc.
- * Fabio Estevam <fabio.estevam@freescale.com>
- */
-
-#include <common.h>
-#include <errno.h>
-#include <i2c.h>
-#include <power/pmic.h>
-#include <power/max77696_pmic.h>
-
-int power_max77696_init(unsigned char bus)
-{
- static const char name[] = "MAX77696";
- struct pmic *p = pmic_alloc();
-
- if (!p) {
- printf("%s: POWER allocation error!\n", __func__);
- return -ENOMEM;
- }
-
- p->name = name;
- p->interface = PMIC_I2C;
- p->number_of_regs = PMIC_NUM_OF_REGS;
- p->hw.i2c.addr = CONFIG_POWER_MAX77696_I2C_ADDR;
- p->hw.i2c.tx_num = 1;
- p->bus = bus;
-
- return 0;
-}
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index fbbea18c7d1..5d6180229e9 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -353,3 +353,11 @@ config DM_REGULATOR_TPS65941
TPS65941 series of PMICs have 5 single phase BUCKs that can also
be configured in multi phase modes & 4 LDOs. The driver implements
get/set api for value and enable.
+
+config DM_REGULATOR_SCMI
+ bool "Enable driver for SCMI voltage domain regulators"
+ depends on DM_REGULATOR
+ select SCMI_AGENT
+ help
+ Enable this option if you want to support regulators exposed through
+ the SCMI voltage domain protocol by a SCMI server.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 9d58112dcb1..b2f5972ea79 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
obj-$(CONFIG_DM_REGULATOR_TPS62360) += tps62360_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_STPMIC1) += stpmic1.o
obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
+obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c
new file mode 100644
index 00000000000..b3142bf4e1f
--- /dev/null
+++ b/drivers/power/regulator/scmi_regulator.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020-2021 Linaro Limited
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h>
+#include <linux/kernel.h>
+#include <power/regulator.h>
+
+/**
+ * struct scmi_regulator_platdata - Platform data for a scmi voltage domain regulator
+ * @domain_id: ID representing the regulator for the related SCMI agent
+ */
+struct scmi_regulator_platdata {
+ u32 domain_id;
+};
+
+static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_config_set_in in = {
+ .domain_id = pdata->domain_id,
+ .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
+ };
+ struct scmi_voltd_config_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_CONFIG_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int scmi_voltd_get_enable(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_config_get_in in = {
+ .domain_id = pdata->domain_id,
+ };
+ struct scmi_voltd_config_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_CONFIG_GET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return out.config == SCMI_VOLTD_CONFIG_ON;
+}
+
+static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_level_set_in in = {
+ .domain_id = pdata->domain_id,
+ .voltage_level = uV,
+ };
+ struct scmi_voltd_level_set_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_LEVEL_SET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_voltd_get_voltage_level(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_level_get_in in = {
+ .domain_id = pdata->domain_id,
+ };
+ struct scmi_voltd_level_get_out out;
+ struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ SCMI_VOLTAGE_DOMAIN_LEVEL_GET,
+ in, out);
+ int ret;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &msg);
+ if (ret < 0)
+ return ret;
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0)
+ return ret;
+
+ return out.voltage_level;
+}
+
+static int scmi_regulator_of_to_plat(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ fdt_addr_t reg;
+
+ reg = dev_read_addr(dev);
+ if (reg == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ pdata->domain_id = (u32)reg;
+
+ return 0;
+}
+
+static int scmi_regulator_probe(struct udevice *dev)
+{
+ struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
+ struct scmi_voltd_attr_in in = { 0 };
+ struct scmi_voltd_attr_out out = { 0 };
+ struct scmi_msg scmi_msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
+ .message_id = SCMI_VOLTAGE_DOMAIN_ATTRIBUTES,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+ int ret;
+
+ /* Check voltage domain is known from SCMI server */
+ in.domain_id = pdata->domain_id;
+
+ ret = devm_scmi_process_msg(dev->parent->parent, &scmi_msg);
+ if (ret) {
+ dev_err(dev, "Failed to query voltage domain %u: %d\n",
+ pdata->domain_id, ret);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static const struct dm_regulator_ops scmi_voltd_ops = {
+ .get_value = scmi_voltd_get_voltage_level,
+ .set_value = scmi_voltd_set_voltage_level,
+ .get_enable = scmi_voltd_get_enable,
+ .set_enable = scmi_voltd_set_enable,
+};
+
+U_BOOT_DRIVER(scmi_regulator) = {
+ .name = "scmi_regulator",
+ .id = UCLASS_REGULATOR,
+ .ops = &scmi_voltd_ops,
+ .probe = scmi_regulator_probe,
+ .of_to_plat = scmi_regulator_of_to_plat,
+ .plat_auto = sizeof(struct scmi_regulator_platdata),
+};
+
+static int scmi_regulator_bind(struct udevice *dev)
+{
+ struct driver *drv;
+ ofnode node;
+ int ret;
+
+ drv = DM_DRIVER_GET(scmi_regulator);
+
+ ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+ ret = device_bind(dev, drv, ofnode_get_name(node),
+ NULL, node, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+U_BOOT_DRIVER(scmi_voltage_domain) = {
+ .name = "scmi_voltage_domain",
+ .id = UCLASS_NOP,
+ .bind = scmi_regulator_bind,
+};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index dafba35279b..c84a9d2b27b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -102,6 +102,12 @@ config RTC_PCF8563
If you say yes here you get support for the Philips PCF8563 RTC
and compatible chips.
+config RTC_RV3028
+ bool "Enable RV3028 driver"
+ depends on DM_RTC
+ help
+ The MicroCrystal RV3028 is a I2C Real Time Clock (RTC)
+
config RTC_RV3029
bool "Enable RV3029 driver"
depends on DM_RTC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 15609e7b182..f668cf9050c 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_RTC_PCF2127) += pcf2127.o
obj-$(CONFIG_RTC_PL031) += pl031.o
obj-$(CONFIG_RTC_PT7C4338) += pt7c4338.o
obj-$(CONFIG_RTC_RS5C372A) += rs5c372.o
+obj-$(CONFIG_RTC_RV3028) += rv3028.o
obj-$(CONFIG_RTC_RV3029) += rv3029.o
obj-$(CONFIG_RTC_RV8803) += rv8803.o
obj-$(CONFIG_RTC_RX8025) += rx8025.o
diff --git a/drivers/rtc/rv3028.c b/drivers/rtc/rv3028.c
new file mode 100644
index 00000000000..9f63afc14a8
--- /dev/null
+++ b/drivers/rtc/rv3028.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RTC driver for the Micro Crystal RV3028
+ *
+ * based on linux driver from
+ * Copyright (C) 2019 Micro Crystal SA
+ *
+ * Alexandre Belloni <alexandre.belloni@bootlin.com>
+ *
+ */
+
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+
+#define RV3028_SEC 0x00
+#define RV3028_MIN 0x01
+#define RV3028_HOUR 0x02
+#define RV3028_WDAY 0x03
+#define RV3028_DAY 0x04
+#define RV3028_MONTH 0x05
+#define RV3028_YEAR 0x06
+#define RV3028_ALARM_MIN 0x07
+#define RV3028_ALARM_HOUR 0x08
+#define RV3028_ALARM_DAY 0x09
+#define RV3028_STATUS 0x0E
+#define RV3028_CTRL1 0x0F
+#define RV3028_CTRL2 0x10
+#define RV3028_EVT_CTRL 0x13
+#define RV3028_TS_COUNT 0x14
+#define RV3028_TS_SEC 0x15
+#define RV3028_RAM1 0x1F
+#define RV3028_EEPROM_ADDR 0x25
+#define RV3028_EEPROM_DATA 0x26
+#define RV3028_EEPROM_CMD 0x27
+#define RV3028_CLKOUT 0x35
+#define RV3028_OFFSET 0x36
+#define RV3028_BACKUP 0x37
+
+#define RV3028_STATUS_PORF BIT(0)
+#define RV3028_STATUS_EVF BIT(1)
+#define RV3028_STATUS_AF BIT(2)
+#define RV3028_STATUS_TF BIT(3)
+#define RV3028_STATUS_UF BIT(4)
+#define RV3028_STATUS_BSF BIT(5)
+#define RV3028_STATUS_CLKF BIT(6)
+#define RV3028_STATUS_EEBUSY BIT(7)
+
+#define RV3028_CLKOUT_FD_MASK GENMASK(2, 0)
+#define RV3028_CLKOUT_PORIE BIT(3)
+#define RV3028_CLKOUT_CLKSY BIT(6)
+#define RV3028_CLKOUT_CLKOE BIT(7)
+
+#define RV3028_CTRL1_EERD BIT(3)
+#define RV3028_CTRL1_WADA BIT(5)
+
+#define RV3028_CTRL2_RESET BIT(0)
+#define RV3028_CTRL2_12_24 BIT(1)
+#define RV3028_CTRL2_EIE BIT(2)
+#define RV3028_CTRL2_AIE BIT(3)
+#define RV3028_CTRL2_TIE BIT(4)
+#define RV3028_CTRL2_UIE BIT(5)
+#define RV3028_CTRL2_TSE BIT(7)
+
+#define RV3028_EVT_CTRL_TSR BIT(2)
+
+#define RV3028_EEPROM_CMD_UPDATE 0x11
+#define RV3028_EEPROM_CMD_WRITE 0x21
+#define RV3028_EEPROM_CMD_READ 0x22
+
+#define RV3028_EEBUSY_POLL 10000
+#define RV3028_EEBUSY_TIMEOUT 100000
+
+#define RV3028_BACKUP_TCE BIT(5)
+#define RV3028_BACKUP_TCR_MASK GENMASK(1, 0)
+
+#define OFFSET_STEP_PPT 953674
+
+#define RTC_RV3028_LEN 7
+
+static int rv3028_rtc_get(struct udevice *dev, struct rtc_time *tm)
+{
+ u8 regs[RTC_RV3028_LEN];
+ u8 status;
+ int ret;
+
+ ret = dm_i2c_read(dev, RV3028_STATUS, &status, 1);
+ if (ret < 0) {
+ printf("%s: error reading RTC status: %x\n", __func__, ret);
+ return -EIO;
+ }
+
+ if (status & RV3028_STATUS_PORF) {
+ printf("Voltage low, data is invalid.\n");
+ return -EINVAL;
+ }
+
+ ret = dm_i2c_read(dev, RV3028_SEC, regs, sizeof(regs));
+ if (ret < 0) {
+ printf("%s: error reading RTC: %x\n", __func__, ret);
+ return -EIO;
+ }
+
+ tm->tm_sec = bcd2bin(regs[RV3028_SEC] & 0x7f);
+ tm->tm_min = bcd2bin(regs[RV3028_MIN] & 0x7f);
+ tm->tm_hour = bcd2bin(regs[RV3028_HOUR] & 0x3f);
+ tm->tm_wday = regs[RV3028_WDAY] & 0x7;
+ tm->tm_mday = bcd2bin(regs[RV3028_DAY] & 0x3f);
+ tm->tm_mon = bcd2bin(regs[RV3028_MONTH] & 0x1f);
+ tm->tm_year = bcd2bin(regs[RV3028_YEAR]) + 2000;
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ debug("%s: %4d-%02d-%02d (wday=%d) %2d:%02d:%02d\n",
+ __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static int rv3028_rtc_set(struct udevice *dev, const struct rtc_time *tm)
+{
+ u8 regs[RTC_RV3028_LEN];
+ u8 status;
+ int ret;
+
+ debug("%s: %4d-%02d-%02d (wday=%d( %2d:%02d:%02d\n",
+ __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ if (tm->tm_year < 2000) {
+ printf("%s: year %d (before 2000) not supported\n",
+ __func__, tm->tm_year);
+ return -EINVAL;
+ }
+
+ regs[RV3028_SEC] = bin2bcd(tm->tm_sec);
+ regs[RV3028_MIN] = bin2bcd(tm->tm_min);
+ regs[RV3028_HOUR] = bin2bcd(tm->tm_hour);
+ regs[RV3028_WDAY] = tm->tm_wday;
+ regs[RV3028_DAY] = bin2bcd(tm->tm_mday);
+ regs[RV3028_MONTH] = bin2bcd(tm->tm_mon);
+ regs[RV3028_YEAR] = bin2bcd(tm->tm_year - 2000);
+
+ ret = dm_i2c_write(dev, RV3028_SEC, regs, sizeof(regs));
+ if (ret) {
+ printf("%s: set rtc error: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = dm_i2c_read(dev, RV3028_STATUS, &status, 1);
+ if (ret < 0) {
+ printf("%s: error reading RTC status: %x\n", __func__, ret);
+ return -EIO;
+ }
+ status |= RV3028_STATUS_PORF;
+ return dm_i2c_write(dev, RV3028_STATUS, &status, 1);
+}
+
+static int rv3028_rtc_reset(struct udevice *dev)
+{
+ return 0;
+}
+
+static int rv3028_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ u8 data;
+ int ret;
+
+ ret = dm_i2c_read(dev, reg, &data, sizeof(data));
+ return ret < 0 ? ret : data;
+}
+
+static int rv3028_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ u8 data = val;
+
+ return dm_i2c_write(dev, reg, &data, 1);
+}
+
+static int rv3028_probe(struct udevice *dev)
+{
+ i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
+ DM_I2C_CHIP_WR_ADDRESS);
+
+ return 0;
+}
+
+static const struct rtc_ops rv3028_rtc_ops = {
+ .get = rv3028_rtc_get,
+ .set = rv3028_rtc_set,
+ .read8 = rv3028_rtc_read8,
+ .write8 = rv3028_rtc_write8,
+ .reset = rv3028_rtc_reset,
+};
+
+static const struct udevice_id rv3028_rtc_ids[] = {
+ { .compatible = "microcrystal,rv3028" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_rv3028) = {
+ .name = "rtc-rv3028",
+ .id = UCLASS_RTC,
+ .probe = rv3028_probe,
+ .of_match = rv3028_rtc_ids,
+ .ops = &rv3028_rtc_ops,
+};
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index b898c32edc0..73dbb22ba09 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -624,14 +624,14 @@ static int optee_probe(struct udevice *dev)
u32 sec_caps;
if (!is_optee_api(pdata->invoke_fn)) {
- debug("%s: OP-TEE api uid mismatch\n", __func__);
+ dev_err(dev, "OP-TEE api uid mismatch\n");
return -ENOENT;
}
print_os_revision(dev, pdata->invoke_fn);
if (!api_revision_is_compatible(pdata->invoke_fn)) {
- debug("%s: OP-TEE api revision mismatch\n", __func__);
+ dev_err(dev, "OP-TEE api revision mismatch\n");
return -ENOENT;
}
@@ -642,7 +642,7 @@ static int optee_probe(struct udevice *dev)
*/
if (!exchange_capabilities(pdata->invoke_fn, &sec_caps) ||
!(sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)) {
- debug("%s: OP-TEE capabilities mismatch\n", __func__);
+ dev_err(dev, "OP-TEE capabilities mismatch\n");
return -ENOENT;
}
diff --git a/drivers/usb/dwc3/linux-compat.h b/drivers/usb/dwc3/linux-compat.h
index 82793765bea..3bb0bda5a6b 100644
--- a/drivers/usb/dwc3/linux-compat.h
+++ b/drivers/usb/dwc3/linux-compat.h
@@ -13,10 +13,4 @@
#define dev_WARN(dev, format, arg...) debug(format, ##arg)
-static inline size_t strlcat(char *dest, const char *src, size_t n)
-{
- strcat(dest, src);
- return strlen(dest) + strlen(src);
-}
-
#endif