blob: dcb1a30d5fb94655df76113c543d362f76e16513 [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)
40int regmap_init_mem_platdata(struct udevice *dev, fdt32_t *reg, int size,
41 struct regmap **mapp)
42{
43 /* TODO(sjg@chromium.org): Implement this when needed */
44 return 0;
45}
46#else
Simon Glassad8f8ab2015-06-23 15:38:42 -060047int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
48{
49 const void *blob = gd->fdt_blob;
50 struct regmap_range *range;
51 const fdt32_t *cell;
52 struct regmap *map;
53 int count;
54 int addr_len, size_len, both_len;
55 int parent;
56 int len;
57
58 parent = dev->parent->of_offset;
59 addr_len = fdt_address_cells(blob, parent);
60 size_len = fdt_size_cells(blob, parent);
61 both_len = addr_len + size_len;
62
63 cell = fdt_getprop(blob, dev->of_offset, "reg", &len);
64 len /= sizeof(*cell);
65 count = len / both_len;
66 if (!cell || !count)
67 return -EINVAL;
68
Simon Glass30d73e82016-07-04 11:58:21 -060069 map = regmap_alloc_count(count);
Simon Glassad8f8ab2015-06-23 15:38:42 -060070 if (!map)
71 return -ENOMEM;
72
Simon Glassad8f8ab2015-06-23 15:38:42 -060073 map->base = fdtdec_get_number(cell, addr_len);
Simon Glassad8f8ab2015-06-23 15:38:42 -060074
75 for (range = map->range; count > 0;
76 count--, cell += both_len, range++) {
77 range->start = fdtdec_get_number(cell, addr_len);
78 range->size = fdtdec_get_number(cell + addr_len, size_len);
79 }
80
81 *mapp = map;
82
83 return 0;
84}
Simon Glassb9443452016-07-04 11:57:59 -060085#endif
Simon Glassad8f8ab2015-06-23 15:38:42 -060086
87void *regmap_get_range(struct regmap *map, unsigned int range_num)
88{
89 struct regmap_range *range;
90
91 if (range_num >= map->range_count)
92 return NULL;
93 range = &map->range[range_num];
94
95 return map_sysmem(range->start, range->size);
96}
97
98int regmap_uninit(struct regmap *map)
99{
100 if (map->range_count > 1)
101 free(map->range);
102 free(map);
103
104 return 0;
105}