blob: d4e16a27ef345fc078d3bb258e1d409bd959edaf [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>
Paul Burton3bfb8cb2016-09-08 07:47:35 +010015#include <asm/io.h>
Simon Glass23d63262017-05-18 20:09:10 -060016#include <dm/of_addr.h>
17#include <linux/ioport.h>
Paul Burton3bfb8cb2016-09-08 07:47:35 +010018
Simon Glass6f98b752015-06-23 15:38:42 -060019DECLARE_GLOBAL_DATA_PTR;
20
Simon Glassa9514312016-07-04 11:58:21 -060021static 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
Simon Glass3b2a29e2016-07-04 11:57:59 -060042#if CONFIG_IS_ENABLED(OF_PLATDATA)
Simon Glass1e6ca1a2016-07-04 11:58:22 -060043int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
Simon Glass3b2a29e2016-07-04 11:57:59 -060044 struct regmap **mapp)
45{
Simon Glass1e6ca1a2016-07-04 11:58:22 -060046 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
Simon Glass3b2a29e2016-07-04 11:57:59 -060061 return 0;
62}
63#else
Simon Glass6f98b752015-06-23 15:38:42 -060064int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
65{
Simon Glass6f98b752015-06-23 15:38:42 -060066 struct regmap_range *range;
Simon Glass6f98b752015-06-23 15:38:42 -060067 struct regmap *map;
68 int count;
69 int addr_len, size_len, both_len;
Simon Glass6f98b752015-06-23 15:38:42 -060070 int len;
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010071 int index;
Simon Glass23d63262017-05-18 20:09:10 -060072 ofnode node = dev_ofnode(dev);
73 struct resource r;
Simon Glass6f98b752015-06-23 15:38:42 -060074
Simon Glass878d68c2017-06-12 06:21:31 -060075 addr_len = dev_read_simple_addr_cells(dev->parent);
76 size_len = dev_read_simple_size_cells(dev->parent);
Simon Glass6f98b752015-06-23 15:38:42 -060077 both_len = addr_len + size_len;
78
Simon Glass23d63262017-05-18 20:09:10 -060079 len = dev_read_size(dev, "reg");
80 if (len < 0)
81 return len;
82 len /= sizeof(fdt32_t);
Simon Glass6f98b752015-06-23 15:38:42 -060083 count = len / both_len;
Simon Glass23d63262017-05-18 20:09:10 -060084 if (!count)
Simon Glass6f98b752015-06-23 15:38:42 -060085 return -EINVAL;
86
Simon Glassa9514312016-07-04 11:58:21 -060087 map = regmap_alloc_count(count);
Simon Glass6f98b752015-06-23 15:38:42 -060088 if (!map)
89 return -ENOMEM;
90
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010091 for (range = map->range, index = 0; count > 0;
Simon Glass23d63262017-05-18 20:09:10 -060092 count--, range++, index++) {
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010093 fdt_size_t sz;
Simon Glass23d63262017-05-18 20:09:10 -060094 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 }
Simon Glass6f98b752015-06-23 15:38:42 -0600104 }
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +0100105 map->base = map->range[0].start;
Simon Glass6f98b752015-06-23 15:38:42 -0600106
107 *mapp = map;
108
109 return 0;
110}
Simon Glass3b2a29e2016-07-04 11:57:59 -0600111#endif
Simon Glass6f98b752015-06-23 15:38:42 -0600112
113void *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
124int regmap_uninit(struct regmap *map)
125{
126 if (map->range_count > 1)
127 free(map->range);
128 free(map);
129
130 return 0;
131}
Paul Burton3bfb8cb2016-09-08 07:47:35 +0100132
133int 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
142int 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}