xref: /openbmc/u-boot/drivers/core/regmap.c (revision 13bdce8f8cadf07bc81d7000a04e48f3028de543)
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  #include <asm/io.h>
16  #include <dm/of_addr.h>
17  #include <linux/ioport.h>
18  
19  DECLARE_GLOBAL_DATA_PTR;
20  
21  static struct regmap *regmap_alloc_count(int count)
22  {
23  	struct regmap *map;
24  
25  	map = malloc(sizeof(struct regmap));
26  	if (!map)
27  		return NULL;
28  	if (count <= 1) {
29  		map->range = &map->base_range;
30  	} else {
31  		map->range = malloc(count * sizeof(struct regmap_range));
32  		if (!map->range) {
33  			free(map);
34  			return NULL;
35  		}
36  	}
37  	map->range_count = count;
38  
39  	return map;
40  }
41  
42  #if CONFIG_IS_ENABLED(OF_PLATDATA)
43  int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
44  			     struct regmap **mapp)
45  {
46  	struct regmap_range *range;
47  	struct regmap *map;
48  
49  	map = regmap_alloc_count(count);
50  	if (!map)
51  		return -ENOMEM;
52  
53  	map->base = *reg;
54  	for (range = map->range; count > 0; reg += 2, range++, count--) {
55  		range->start = *reg;
56  		range->size = reg[1];
57  	}
58  
59  	*mapp = map;
60  
61  	return 0;
62  }
63  #else
64  int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
65  {
66  	struct regmap_range *range;
67  	struct regmap *map;
68  	int count;
69  	int addr_len, size_len, both_len;
70  	int len;
71  	int index;
72  	ofnode node = dev_ofnode(dev);
73  	struct resource r;
74  
75  	addr_len = dev_read_addr_cells(dev->parent);
76  	size_len = dev_read_size_cells(dev->parent);
77  	both_len = addr_len + size_len;
78  
79  	len = dev_read_size(dev, "reg");
80  	if (len < 0)
81  		return len;
82  	len /= sizeof(fdt32_t);
83  	count = len / both_len;
84  	if (!count)
85  		return -EINVAL;
86  
87  	map = regmap_alloc_count(count);
88  	if (!map)
89  		return -ENOMEM;
90  
91  	for (range = map->range, index = 0; count > 0;
92  	     count--, range++, index++) {
93  		fdt_size_t sz;
94  		if (of_live_active()) {
95  			of_address_to_resource(ofnode_to_np(node), index, &r);
96  			range->start = r.start;
97  			range->size = r.end - r.start + 1;
98  		} else {
99  			range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
100  					dev_of_offset(dev), "reg", index,
101  					addr_len, size_len, &sz, true);
102  			range->size = sz;
103  		}
104  	}
105  	map->base = map->range[0].start;
106  
107  	*mapp = map;
108  
109  	return 0;
110  }
111  #endif
112  
113  void *regmap_get_range(struct regmap *map, unsigned int range_num)
114  {
115  	struct regmap_range *range;
116  
117  	if (range_num >= map->range_count)
118  		return NULL;
119  	range = &map->range[range_num];
120  
121  	return map_sysmem(range->start, range->size);
122  }
123  
124  int regmap_uninit(struct regmap *map)
125  {
126  	if (map->range_count > 1)
127  		free(map->range);
128  	free(map);
129  
130  	return 0;
131  }
132  
133  int regmap_read(struct regmap *map, uint offset, uint *valp)
134  {
135  	uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
136  
137  	*valp = le32_to_cpu(readl(ptr));
138  
139  	return 0;
140  }
141  
142  int regmap_write(struct regmap *map, uint offset, uint val)
143  {
144  	uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
145  
146  	writel(cpu_to_le32(val), ptr);
147  
148  	return 0;
149  }
150