xref: /openbmc/u-boot/drivers/core/regmap.c (revision fcf2fba4)
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