1 /* 2 * Copyright (c) 2015 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <libfdt.h> 12 #include <malloc.h> 13 #include <mapmem.h> 14 #include <regmap.h> 15 16 #include <asm/io.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 static struct regmap *regmap_alloc_count(int count) 21 { 22 struct regmap *map; 23 24 map = malloc(sizeof(struct regmap)); 25 if (!map) 26 return NULL; 27 if (count <= 1) { 28 map->range = &map->base_range; 29 } else { 30 map->range = malloc(count * sizeof(struct regmap_range)); 31 if (!map->range) { 32 free(map); 33 return NULL; 34 } 35 } 36 map->range_count = count; 37 38 return map; 39 } 40 41 #if CONFIG_IS_ENABLED(OF_PLATDATA) 42 int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count, 43 struct regmap **mapp) 44 { 45 struct regmap_range *range; 46 struct regmap *map; 47 48 map = regmap_alloc_count(count); 49 if (!map) 50 return -ENOMEM; 51 52 map->base = *reg; 53 for (range = map->range; count > 0; reg += 2, range++, count--) { 54 range->start = *reg; 55 range->size = reg[1]; 56 } 57 58 *mapp = map; 59 60 return 0; 61 } 62 #else 63 int regmap_init_mem(struct udevice *dev, struct regmap **mapp) 64 { 65 const void *blob = gd->fdt_blob; 66 struct regmap_range *range; 67 const fdt32_t *cell; 68 struct regmap *map; 69 int count; 70 int addr_len, size_len, both_len; 71 int parent; 72 int len; 73 74 parent = dev_of_offset(dev->parent); 75 addr_len = fdt_address_cells(blob, parent); 76 size_len = fdt_size_cells(blob, parent); 77 both_len = addr_len + size_len; 78 79 cell = fdt_getprop(blob, dev_of_offset(dev), "reg", &len); 80 len /= sizeof(*cell); 81 count = len / both_len; 82 if (!cell || !count) 83 return -EINVAL; 84 85 map = regmap_alloc_count(count); 86 if (!map) 87 return -ENOMEM; 88 89 map->base = fdtdec_get_number(cell, addr_len); 90 91 for (range = map->range; count > 0; 92 count--, cell += both_len, range++) { 93 range->start = fdtdec_get_number(cell, addr_len); 94 range->size = fdtdec_get_number(cell + addr_len, size_len); 95 } 96 97 *mapp = map; 98 99 return 0; 100 } 101 #endif 102 103 void *regmap_get_range(struct regmap *map, unsigned int range_num) 104 { 105 struct regmap_range *range; 106 107 if (range_num >= map->range_count) 108 return NULL; 109 range = &map->range[range_num]; 110 111 return map_sysmem(range->start, range->size); 112 } 113 114 int regmap_uninit(struct regmap *map) 115 { 116 if (map->range_count > 1) 117 free(map->range); 118 free(map); 119 120 return 0; 121 } 122 123 int regmap_read(struct regmap *map, uint offset, uint *valp) 124 { 125 uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); 126 127 *valp = le32_to_cpu(readl(ptr)); 128 129 return 0; 130 } 131 132 int regmap_write(struct regmap *map, uint offset, uint val) 133 { 134 uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); 135 136 writel(cpu_to_le32(val), ptr); 137 138 return 0; 139 } 140