]> git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/core/regmap.c
c68bcba54f1e5cfd750ec854f5c12b1a6096b214
[people/ms/u-boot.git] / drivers / core / regmap.c
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->parent->of_offset;
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, "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 }