summaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/core')
-rw-r--r--drivers/core/Kconfig7
-rw-r--r--drivers/core/Makefile1
-rw-r--r--drivers/core/dump.c55
-rw-r--r--drivers/core/read.c6
-rw-r--r--drivers/core/regmap.c8
-rw-r--r--drivers/core/simple-pm-bus.c56
-rw-r--r--drivers/core/uclass.c21
7 files changed, 141 insertions, 13 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index a3b0399342..a594899f37 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -195,6 +195,13 @@ config SPL_SIMPLE_BUS
Supports the 'simple-bus' driver, which is used on some systems
in SPL.
+config SIMPLE_PM_BUS
+ bool "Support simple-pm-bus driver"
+ depends on DM && OF_CONTROL && CLK && POWER_DOMAIN
+ help
+ Supports the 'simple-pm-bus' driver, which is used for busses that
+ have power domains and/or clocks which need to be enabled before use.
+
config OF_TRANSLATE
bool "Translate addresses using fdt_translate_address"
depends on DM && OF_CONTROL
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index c707026a3a..10f4bece33 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_$(SPL_TPL_)ACPIGEN) += acpi.o
obj-$(CONFIG_DEVRES) += devres.o
obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE) += device-remove.o
obj-$(CONFIG_$(SPL_)SIMPLE_BUS) += simple-bus.o
+obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_DM) += dump.o
obj-$(CONFIG_$(SPL_TPL_)REGMAP) += regmap.o
obj-$(CONFIG_$(SPL_TPL_)SYSCON) += syscon-uclass.o
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index cb8a25b9ad..6debaf97a1 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -97,7 +97,7 @@ void dm_dump_uclass(void)
}
}
-void dm_dump_drivers(void)
+void dm_dump_driver_compat(void)
{
struct driver *d = ll_entry_start(struct driver, driver);
const int n_ents = ll_entry_count(struct driver, driver);
@@ -120,3 +120,56 @@ void dm_dump_drivers(void)
printf("%-20.20s %s\n", "", match->compatible);
}
}
+
+void dm_dump_drivers(void)
+{
+ struct driver *d = ll_entry_start(struct driver, driver);
+ const int n_ents = ll_entry_count(struct driver, driver);
+ struct driver *entry;
+ struct udevice *udev;
+ struct uclass *uc;
+ int i;
+
+ puts("Driver uid uclass Devices\n");
+ puts("----------------------------------------------------------\n");
+
+ for (entry = d; entry < d + n_ents; entry++) {
+ uclass_get(entry->id, &uc);
+
+ printf("%-25.25s %-3.3d %-20.20s ", entry->name, entry->id,
+ uc ? uc->uc_drv->name : "<no uclass>");
+
+ if (!uc) {
+ puts("\n");
+ continue;
+ }
+
+ i = 0;
+ uclass_foreach_dev(udev, uc) {
+ if (udev->driver != entry)
+ continue;
+ if (i)
+ printf("%-51.51s", "");
+
+ printf("%-25.25s\n", udev->name);
+ i++;
+ }
+ if (!i)
+ puts("<none>\n");
+ }
+}
+
+void dm_dump_static_driver_info(void)
+{
+ struct driver_info *drv = ll_entry_start(struct driver_info,
+ driver_info);
+ const int n_ents = ll_entry_count(struct driver_info, driver_info);
+ struct driver_info *entry;
+
+ puts("Driver Address\n");
+ puts("---------------------------------\n");
+ for (entry = drv; entry != drv + n_ents; entry++) {
+ printf("%-25.25s @%08lx\n", entry->name,
+ (ulong)map_to_sysmem(entry->platdata));
+ }
+}
diff --git a/drivers/core/read.c b/drivers/core/read.c
index 047089c886..8bb456bc3f 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -167,7 +167,7 @@ void *dev_read_addr_ptr(const struct udevice *dev)
{
fdt_addr_t addr = dev_read_addr(dev);
- return (addr == FDT_ADDR_T_NONE) ? NULL : map_sysmem(addr, 0);
+ return (addr == FDT_ADDR_T_NONE) ? NULL : (void *)(uintptr_t)addr;
}
void *dev_remap_addr(const struct udevice *dev)
@@ -275,15 +275,17 @@ int dev_read_alias_seq(const struct udevice *dev, int *devnump)
{
ofnode node = dev_ofnode(dev);
const char *uc_name = dev->uclass->uc_drv->name;
- int ret;
+ int ret = -ENOTSUPP;
if (ofnode_is_np(node)) {
ret = of_alias_get_id(ofnode_to_np(node), uc_name);
if (ret >= 0)
*devnump = ret;
} else {
+#if CONFIG_IS_ENABLED(OF_CONTROL)
ret = fdtdec_get_alias_seq(gd->fdt_blob, uc_name,
ofnode_to_offset(node), devnump);
+#endif
}
return ret;
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index 4a214eff7c..a67a237b88 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -310,13 +310,13 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
}
range = &map->ranges[range_num];
- ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
-
if (offset + val_len > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -ERANGE;
}
+ ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
+
switch (val_len) {
case REGMAP_SIZE_8:
*((u8 *)valp) = __read_8(ptr, map->endianness);
@@ -419,13 +419,13 @@ int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
}
range = &map->ranges[range_num];
- ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
-
if (offset + val_len > range->size) {
debug("%s: offset/size combination invalid\n", __func__);
return -ERANGE;
}
+ ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
+
switch (val_len) {
case REGMAP_SIZE_8:
__write_8(ptr, val, map->endianness);
diff --git a/drivers/core/simple-pm-bus.c b/drivers/core/simple-pm-bus.c
new file mode 100644
index 0000000000..51dc9b206f
--- /dev/null
+++ b/drivers/core/simple-pm-bus.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+
+/*
+ * Power domains are taken care of by driver_probe, so we just have to enable
+ * clocks
+ */
+static int simple_pm_bus_probe(struct udevice *dev)
+{
+ int ret;
+ struct clk_bulk *bulk = dev_get_priv(dev);
+
+ ret = clk_get_bulk(dev, bulk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable_bulk(bulk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
+ clk_release_bulk(bulk);
+ return ret;
+ }
+ return 0;
+}
+
+static int simple_pm_bus_remove(struct udevice *dev)
+{
+ int ret;
+ struct clk_bulk *bulk = dev_get_priv(dev);
+
+ ret = clk_release_bulk(bulk);
+ if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
+ return ret;
+ else
+ return 0;
+}
+
+static const struct udevice_id simple_pm_bus_ids[] = {
+ { .compatible = "simple-pm-bus" },
+ { }
+};
+
+U_BOOT_DRIVER(simple_pm_bus_drv) = {
+ .name = "simple_pm_bus",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = simple_pm_bus_ids,
+ .probe = simple_pm_bus_probe,
+ .remove = simple_pm_bus_remove,
+ .priv_auto_alloc_size = sizeof(struct clk_bulk),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 2ab419cfe4..c3f1b73cd6 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -689,13 +689,14 @@ int uclass_unbind_device(struct udevice *dev)
int uclass_resolve_seq(struct udevice *dev)
{
+ struct uclass *uc = dev->uclass;
+ struct uclass_driver *uc_drv = uc->uc_drv;
struct udevice *dup;
- int seq;
+ int seq = 0;
int ret;
assert(dev->seq == -1);
- ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq,
- false, &dup);
+ ret = uclass_find_device_by_seq(uc_drv->id, dev->req_seq, false, &dup);
if (!ret) {
dm_warn("Device '%s': seq %d is in use by '%s'\n",
dev->name, dev->req_seq, dup->name);
@@ -707,9 +708,17 @@ int uclass_resolve_seq(struct udevice *dev)
return ret;
}
- for (seq = 0; seq < DM_MAX_SEQ; seq++) {
- ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, seq,
- false, &dup);
+ if (CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
+ (uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) {
+ /*
+ * dev_read_alias_highest_id() will return -1 if there no
+ * alias. Thus we can always add one.
+ */
+ seq = dev_read_alias_highest_id(uc_drv->name) + 1;
+ }
+
+ for (; seq < DM_MAX_SEQ; seq++) {
+ ret = uclass_find_device_by_seq(uc_drv->id, seq, false, &dup);
if (ret == -ENODEV)
break;
if (ret)