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, dev->of_offset, 94 "reg", index, addr_len, size_len, &sz, true); 95 range->size = sz; 96 } 97 map->base = map->range[0].start; 98 99 *mapp = map; 100 101 return 0; 102 } 103 #endif 104 105 void *regmap_get_range(struct regmap *map, unsigned int range_num) 106 { 107 struct regmap_range *range; 108 109 if (range_num >= map->range_count) 110 return NULL; 111 range = &map->range[range_num]; 112 113 return map_sysmem(range->start, range->size); 114 } 115 116 int regmap_uninit(struct regmap *map) 117 { 118 if (map->range_count > 1) 119 free(map->range); 120 free(map); 121 122 return 0; 123 } 124 125 int regmap_read(struct regmap *map, uint offset, uint *valp) 126 { 127 uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); 128 129 *valp = le32_to_cpu(readl(ptr)); 130 131 return 0; 132 } 133 134 int regmap_write(struct regmap *map, uint offset, uint val) 135 { 136 uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE); 137 138 writel(cpu_to_le32(val), ptr); 139 140 return 0; 141 } 142