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 int index; 74 75 parent = dev_of_offset(dev->parent); 76 addr_len = fdt_address_cells(blob, parent); 77 size_len = fdt_size_cells(blob, parent); 78 both_len = addr_len + size_len; 79 80 cell = fdt_getprop(blob, dev_of_offset(dev), "reg", &len); 81 len /= sizeof(*cell); 82 count = len / both_len; 83 if (!cell || !count) 84 return -EINVAL; 85 86 map = regmap_alloc_count(count); 87 if (!map) 88 return -ENOMEM; 89 90 for (range = map->range, index = 0; count > 0; 91 count--, cell += both_len, range++, index++) { 92 fdt_size_t sz; 93 range->start = fdtdec_get_addr_size_fixed(blob, 94 dev_of_offset(dev), "reg", index, addr_len, 95 size_len, &sz, true); 96 range->size = sz; 97 } 98 map->base = map->range[0].start; 99 100 *mapp = map; 101 102 return 0; 103 } 104 #endif 105 106 void *regmap_get_range(struct regmap *map, unsigned int range_num) 107 { 108 struct regmap_range *range; 109 110 if (range_num >= map->range_count) 111 return NULL; 112 range = &map->range[range_num]; 113 114 return map_sysmem(range->start, range->size); 115 } 116 117 int regmap_uninit(struct regmap *map) 118 { 119 if (map->range_count > 1) 120 free(map->range); 121 free(map); 122 123 return 0; 124 } 125 126 int regmap_read(struct regmap *map, uint offset, uint *valp) 127 { 128 uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); 129 130 *valp = le32_to_cpu(readl(ptr)); 131 132 return 0; 133 } 134 135 int regmap_write(struct regmap *map, uint offset, uint val) 136 { 137 uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); 138 139 writel(cpu_to_le32(val), ptr); 140 141 return 0; 142 } 143