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; +} diff --git a/include/regmap.h b/include/regmap.h new file mode 100644 index 0000000000..eccf7707f4 --- /dev/null +++ b/include/regmap.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __REGMAP_H +#define __REGMAP_H + +/** + * struct regmap_range - a register map range + * + * @start: Start address + * @size: Size in bytes + */ +struct regmap_range { + ulong start; + ulong size; +}; + +/** + * struct regmap - a way of accessing hardware/bus registers + * + * @base: Base address of register map + * @range_count: Number of ranges available within the map + * @range: Pointer to the list of ranges, allocated if @range_count > 1 + * @base_range: If @range_count is <= 1, @range points here + */ +struct regmap { + phys_addr_t base; + int range_count; + struct regmap_range *range, base_range; +}; + +/* + * Interface to provide access to registers either through a direct memory + * bus or through a peripheral bus like I2C, SPI. + */ +int regmap_write(struct regmap *map, uint offset, uint val); +int regmap_read(struct regmap *map, uint offset, uint *valp); + +#define regmap_write32(map, ptr, member, val) \ + regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val) + +#define regmap_read32(map, ptr, member, valp) \ + regmap_read(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), valp) + +/** + * regmap_init_mem() - Set up a new register map that uses memory access + * + * Use regmap_uninit() to free it. + * + * @dev: Device that uses this map + * @mapp: Returns allocated map + */ +int regmap_init_mem(struct udevice *dev, struct regmap **mapp); + +/** + * regmap_get_range() - Obtain the base memory address of a regmap range + * + * @map: Regmap to query + * @range_num: Range to look up + */ +void *regmap_get_range(struct regmap *map, unsigned int range_num); + +/** + * regmap_uninit() - free a previously inited regmap + */ +int regmap_uninit(struct regmap *map); + +#endif