From 6f98b7504f7097ea36df451c58d718f3ad2aa4ea Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 23 Jun 2015 15:38:42 -0600 Subject: dm: Add support for register maps (regmap) Add a simple implementaton of register maps, supporting only direct I/O for now. This can be enhanced later to support buses which have registers, such as I2C, SPI and PCI. It allows drivers which can operate with multiple buses to avoid dealing with the particulars of register access on that bus. Signed-off-by: Simon Glass --- drivers/core/Makefile | 1 + drivers/core/regmap.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 drivers/core/regmap.c (limited to 'drivers') diff --git a/drivers/core/Makefile b/drivers/core/Makefile index ed21fedbc0..7851824143 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_OF_CONTROL) += simple-bus.o endif obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o obj-$(CONFIG_DM) += dump.o +obj-$(CONFIG_OF_CONTROL) += regmap.o diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c new file mode 100644 index 0000000000..519832f173 --- /dev/null +++ b/drivers/core/regmap.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int regmap_init_mem(struct udevice *dev, struct regmap **mapp) +{ + const void *blob = gd->fdt_blob; + struct regmap_range *range; + const fdt32_t *cell; + struct regmap *map; + int count; + int addr_len, size_len, both_len; + int parent; + int len; + + parent = dev->parent->of_offset; + addr_len = fdt_address_cells(blob, parent); + size_len = fdt_size_cells(blob, parent); + both_len = addr_len + size_len; + + cell = fdt_getprop(blob, dev->of_offset, "reg", &len); + len /= sizeof(*cell); + count = len / both_len; + if (!cell || !count) + return -EINVAL; + + map = malloc(sizeof(struct regmap)); + if (!map) + return -ENOMEM; + + if (count <= 1) { + map->range = &map->base_range; + } else { + map->range = malloc(count * sizeof(struct regmap_range)); + if (!map->range) { + free(map); + return -ENOMEM; + } + } + + map->base = fdtdec_get_number(cell, addr_len); + map->range_count = count; + + for (range = map->range; count > 0; + count--, cell += both_len, range++) { + range->start = fdtdec_get_number(cell, addr_len); + range->size = fdtdec_get_number(cell + addr_len, size_len); + } + + *mapp = map; + + return 0; +} + +void *regmap_get_range(struct regmap *map, unsigned int range_num) +{ + struct regmap_range *range; + + if (range_num >= map->range_count) + return NULL; + range = &map->range[range_num]; + + return map_sysmem(range->start, range->size); +} + +int regmap_uninit(struct regmap *map) +{ + if (map->range_count > 1) + free(map->range); + free(map); + + return 0; +} -- cgit v1.2.1