blob: 7f21dee7e476e749891891b4e6a8f8b8bef02567 [file] [log] [blame]
Simon Glass6f98b752015-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
Paul Burton3bfb8cb2016-09-08 07:47:35 +010016#include <asm/io.h>
17
Simon Glass6f98b752015-06-23 15:38:42 -060018DECLARE_GLOBAL_DATA_PTR;
19
Simon Glassa9514312016-07-04 11:58:21 -060020static 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
Simon Glass3b2a29e2016-07-04 11:57:59 -060041#if CONFIG_IS_ENABLED(OF_PLATDATA)
Simon Glass1e6ca1a2016-07-04 11:58:22 -060042int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
Simon Glass3b2a29e2016-07-04 11:57:59 -060043 struct regmap **mapp)
44{
Simon Glass1e6ca1a2016-07-04 11:58:22 -060045 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
Simon Glass3b2a29e2016-07-04 11:57:59 -060060 return 0;
61}
62#else
Simon Glass6f98b752015-06-23 15:38:42 -060063int 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;
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010073 int index;
Simon Glass6f98b752015-06-23 15:38:42 -060074
Simon Glasse160f7d2017-01-17 16:52:55 -070075 parent = dev_of_offset(dev->parent);
Simon Glass6f98b752015-06-23 15:38:42 -060076 addr_len = fdt_address_cells(blob, parent);
77 size_len = fdt_size_cells(blob, parent);
78 both_len = addr_len + size_len;
79
Simon Glasse160f7d2017-01-17 16:52:55 -070080 cell = fdt_getprop(blob, dev_of_offset(dev), "reg", &len);
Simon Glass6f98b752015-06-23 15:38:42 -060081 len /= sizeof(*cell);
82 count = len / both_len;
83 if (!cell || !count)
84 return -EINVAL;
85
Simon Glassa9514312016-07-04 11:58:21 -060086 map = regmap_alloc_count(count);
Simon Glass6f98b752015-06-23 15:38:42 -060087 if (!map)
88 return -ENOMEM;
89
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010090 for (range = map->range, index = 0; count > 0;
91 count--, cell += both_len, range++, index++) {
92 fdt_size_t sz;
Simon Glassda409cc2017-05-17 17:18:09 -060093 range->start = fdtdec_get_addr_size_fixed(blob,
94 dev_of_offset(dev), "reg", index, addr_len,
95 size_len, &sz, true);
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010096 range->size = sz;
Simon Glass6f98b752015-06-23 15:38:42 -060097 }
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010098 map->base = map->range[0].start;
Simon Glass6f98b752015-06-23 15:38:42 -060099
100 *mapp = map;
101
102 return 0;
103}
Simon Glass3b2a29e2016-07-04 11:57:59 -0600104#endif
Simon Glass6f98b752015-06-23 15:38:42 -0600105
106void *regmap_get_range(struct regmap *map, unsigned int range_num)
107{
108 struct regmap_range *range;
109
110 if (range_num >= map->range_count)
111 return NULL;
112 range = &map->range[range_num];
113
114 return map_sysmem(range->start, range->size);
115}
116
117int regmap_uninit(struct regmap *map)
118{
119 if (map->range_count > 1)
120 free(map->range);
121 free(map);
122
123 return 0;
124}
Paul Burton3bfb8cb2016-09-08 07:47:35 +0100125
126int regmap_read(struct regmap *map, uint offset, uint *valp)
127{
128 uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
129
130 *valp = le32_to_cpu(readl(ptr));
131
132 return 0;
133}
134
135int regmap_write(struct regmap *map, uint offset, uint val)
136{
137 uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
138
139 writel(cpu_to_le32(val), ptr);
140
141 return 0;
142}