blob: 0299ff087937f406a939a15a585046b900584143 [file] [log] [blame]
Simon Glassad8f8ab2015-06-23 15:38:42 -06001/*
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
16DECLARE_GLOBAL_DATA_PTR;
17
Simon Glass30d73e82016-07-04 11:58:21 -060018static struct regmap *regmap_alloc_count(int count)
19{
20 struct regmap *map;
21
22 map = malloc(sizeof(struct regmap));
23 if (!map)
24 return NULL;
25 if (count <= 1) {
26 map->range = &map->base_range;
27 } else {
28 map->range = malloc(count * sizeof(struct regmap_range));
29 if (!map->range) {
30 free(map);
31 return NULL;
32 }
33 }
34 map->range_count = count;
35
36 return map;
37}
38
Simon Glassb9443452016-07-04 11:57:59 -060039#if CONFIG_IS_ENABLED(OF_PLATDATA)
Simon Glassb6114332016-07-04 11:58:22 -060040int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
Simon Glassb9443452016-07-04 11:57:59 -060041 struct regmap **mapp)
42{
Simon Glassb6114332016-07-04 11:58:22 -060043 struct regmap_range *range;
44 struct regmap *map;
45
46 map = regmap_alloc_count(count);
47 if (!map)
48 return -ENOMEM;
49
50 map->base = *reg;
51 for (range = map->range; count > 0; reg += 2, range++, count--) {
52 range->start = *reg;
53 range->size = reg[1];
54 }
55
56 *mapp = map;
57
Simon Glassb9443452016-07-04 11:57:59 -060058 return 0;
59}
60#else
Simon Glassad8f8ab2015-06-23 15:38:42 -060061int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
62{
63 const void *blob = gd->fdt_blob;
64 struct regmap_range *range;
65 const fdt32_t *cell;
66 struct regmap *map;
67 int count;
68 int addr_len, size_len, both_len;
69 int parent;
70 int len;
71
72 parent = dev->parent->of_offset;
73 addr_len = fdt_address_cells(blob, parent);
74 size_len = fdt_size_cells(blob, parent);
75 both_len = addr_len + size_len;
76
77 cell = fdt_getprop(blob, dev->of_offset, "reg", &len);
78 len /= sizeof(*cell);
79 count = len / both_len;
80 if (!cell || !count)
81 return -EINVAL;
82
Simon Glass30d73e82016-07-04 11:58:21 -060083 map = regmap_alloc_count(count);
Simon Glassad8f8ab2015-06-23 15:38:42 -060084 if (!map)
85 return -ENOMEM;
86
Simon Glassad8f8ab2015-06-23 15:38:42 -060087 map->base = fdtdec_get_number(cell, addr_len);
Simon Glassad8f8ab2015-06-23 15:38:42 -060088
89 for (range = map->range; count > 0;
90 count--, cell += both_len, range++) {
91 range->start = fdtdec_get_number(cell, addr_len);
92 range->size = fdtdec_get_number(cell + addr_len, size_len);
93 }
94
95 *mapp = map;
96
97 return 0;
98}
Simon Glassb9443452016-07-04 11:57:59 -060099#endif
Simon Glassad8f8ab2015-06-23 15:38:42 -0600100
101void *regmap_get_range(struct regmap *map, unsigned int range_num)
102{
103 struct regmap_range *range;
104
105 if (range_num >= map->range_count)
106 return NULL;
107 range = &map->range[range_num];
108
109 return map_sysmem(range->start, range->size);
110}
111
112int regmap_uninit(struct regmap *map)
113{
114 if (map->range_count > 1)
115 free(map->range);
116 free(map);
117
118 return 0;
119}