blob: 0f787ab4e139b0c1a875a1ef6f525d6621e4dc7e [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass6f98b752015-06-23 15:38:42 -06002/*
3 * Copyright (c) 2015 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glass6f98b752015-06-23 15:38:42 -06005 */
6
7#include <common.h>
8#include <dm.h>
9#include <errno.h>
Masahiro Yamadab08c8c42018-03-05 01:20:11 +090010#include <linux/libfdt.h>
Simon Glass6f98b752015-06-23 15:38:42 -060011#include <malloc.h>
12#include <mapmem.h>
13#include <regmap.h>
Paul Burton3bfb8cb2016-09-08 07:47:35 +010014#include <asm/io.h>
Simon Glass23d63262017-05-18 20:09:10 -060015#include <dm/of_addr.h>
16#include <linux/ioport.h>
Paul Burton3bfb8cb2016-09-08 07:47:35 +010017
Simon Glass6f98b752015-06-23 15:38:42 -060018DECLARE_GLOBAL_DATA_PTR;
19
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +090020static struct regmap *regmap_alloc(int count)
Simon Glassa9514312016-07-04 11:58:21 -060021{
22 struct regmap *map;
23
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +090024 map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count);
Simon Glassa9514312016-07-04 11:58:21 -060025 if (!map)
26 return NULL;
Simon Glassa9514312016-07-04 11:58:21 -060027 map->range_count = count;
28
29 return map;
30}
31
Simon Glass3b2a29e2016-07-04 11:57:59 -060032#if CONFIG_IS_ENABLED(OF_PLATDATA)
Simon Glassc20ee0e2017-08-29 14:15:50 -060033int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
Simon Glass3b2a29e2016-07-04 11:57:59 -060034 struct regmap **mapp)
35{
Simon Glass1e6ca1a2016-07-04 11:58:22 -060036 struct regmap_range *range;
37 struct regmap *map;
38
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +090039 map = regmap_alloc(count);
Simon Glass1e6ca1a2016-07-04 11:58:22 -060040 if (!map)
41 return -ENOMEM;
42
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +090043 for (range = map->ranges; count > 0; reg += 2, range++, count--) {
Simon Glass1e6ca1a2016-07-04 11:58:22 -060044 range->start = *reg;
45 range->size = reg[1];
46 }
47
48 *mapp = map;
49
Simon Glass3b2a29e2016-07-04 11:57:59 -060050 return 0;
51}
52#else
Simon Glass6f98b752015-06-23 15:38:42 -060053int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
54{
Simon Glass6f98b752015-06-23 15:38:42 -060055 struct regmap_range *range;
Simon Glass6f98b752015-06-23 15:38:42 -060056 struct regmap *map;
57 int count;
58 int addr_len, size_len, both_len;
Simon Glass6f98b752015-06-23 15:38:42 -060059 int len;
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010060 int index;
Simon Glass23d63262017-05-18 20:09:10 -060061 ofnode node = dev_ofnode(dev);
62 struct resource r;
Simon Glass6f98b752015-06-23 15:38:42 -060063
Simon Glass878d68c2017-06-12 06:21:31 -060064 addr_len = dev_read_simple_addr_cells(dev->parent);
65 size_len = dev_read_simple_size_cells(dev->parent);
Simon Glass6f98b752015-06-23 15:38:42 -060066 both_len = addr_len + size_len;
67
Simon Glass23d63262017-05-18 20:09:10 -060068 len = dev_read_size(dev, "reg");
69 if (len < 0)
70 return len;
71 len /= sizeof(fdt32_t);
Simon Glass6f98b752015-06-23 15:38:42 -060072 count = len / both_len;
Simon Glass23d63262017-05-18 20:09:10 -060073 if (!count)
Simon Glass6f98b752015-06-23 15:38:42 -060074 return -EINVAL;
75
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +090076 map = regmap_alloc(count);
Simon Glass6f98b752015-06-23 15:38:42 -060077 if (!map)
78 return -ENOMEM;
79
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +090080 for (range = map->ranges, index = 0; count > 0;
Simon Glass23d63262017-05-18 20:09:10 -060081 count--, range++, index++) {
Jean-Jacques Hiblot18040442017-02-13 16:17:48 +010082 fdt_size_t sz;
Simon Glass23d63262017-05-18 20:09:10 -060083 if (of_live_active()) {
84 of_address_to_resource(ofnode_to_np(node), index, &r);
85 range->start = r.start;
86 range->size = r.end - r.start + 1;
87 } else {
88 range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
89 dev_of_offset(dev), "reg", index,
90 addr_len, size_len, &sz, true);
91 range->size = sz;
92 }
Simon Glass6f98b752015-06-23 15:38:42 -060093 }
94
95 *mapp = map;
96
97 return 0;
98}
Simon Glass3b2a29e2016-07-04 11:57:59 -060099#endif
Simon Glass6f98b752015-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;
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +0900107 range = &map->ranges[range_num];
Simon Glass6f98b752015-06-23 15:38:42 -0600108
109 return map_sysmem(range->start, range->size);
110}
111
112int regmap_uninit(struct regmap *map)
113{
Simon Glass6f98b752015-06-23 15:38:42 -0600114 free(map);
115
116 return 0;
117}
Paul Burton3bfb8cb2016-09-08 07:47:35 +0100118
119int regmap_read(struct regmap *map, uint offset, uint *valp)
120{
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +0900121 u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
Paul Burton3bfb8cb2016-09-08 07:47:35 +0100122
123 *valp = le32_to_cpu(readl(ptr));
124
125 return 0;
126}
127
128int regmap_write(struct regmap *map, uint offset, uint val)
129{
Masahiro Yamada8c1de5e2018-04-19 12:14:01 +0900130 u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
Paul Burton3bfb8cb2016-09-08 07:47:35 +0100131
132 writel(cpu_to_le32(val), ptr);
133
134 return 0;
135}