16f98b750SSimon Glass /*
26f98b750SSimon Glass * Copyright (c) 2015 Google, Inc
36f98b750SSimon Glass * Written by Simon Glass <sjg@chromium.org>
46f98b750SSimon Glass *
56f98b750SSimon Glass * SPDX-License-Identifier: GPL-2.0+
66f98b750SSimon Glass */
76f98b750SSimon Glass
86f98b750SSimon Glass #include <common.h>
96f98b750SSimon Glass #include <dm.h>
106f98b750SSimon Glass #include <errno.h>
110e00a84cSMasahiro Yamada #include <linux/libfdt.h>
126f98b750SSimon Glass #include <malloc.h>
136f98b750SSimon Glass #include <mapmem.h>
146f98b750SSimon Glass #include <regmap.h>
153bfb8cb4SPaul Burton #include <asm/io.h>
1623d63267SSimon Glass #include <dm/of_addr.h>
1723d63267SSimon Glass #include <linux/ioport.h>
183bfb8cb4SPaul Burton
196f98b750SSimon Glass DECLARE_GLOBAL_DATA_PTR;
206f98b750SSimon Glass
regmap_alloc_count(int count)21a951431eSSimon Glass static struct regmap *regmap_alloc_count(int count)
22a951431eSSimon Glass {
23a951431eSSimon Glass struct regmap *map;
24a951431eSSimon Glass
25a951431eSSimon Glass map = malloc(sizeof(struct regmap));
26a951431eSSimon Glass if (!map)
27a951431eSSimon Glass return NULL;
28a951431eSSimon Glass if (count <= 1) {
29a951431eSSimon Glass map->range = &map->base_range;
30a951431eSSimon Glass } else {
31a951431eSSimon Glass map->range = malloc(count * sizeof(struct regmap_range));
32a951431eSSimon Glass if (!map->range) {
33a951431eSSimon Glass free(map);
34a951431eSSimon Glass return NULL;
35a951431eSSimon Glass }
36a951431eSSimon Glass }
37a951431eSSimon Glass map->range_count = count;
38a951431eSSimon Glass
39a951431eSSimon Glass return map;
40a951431eSSimon Glass }
41a951431eSSimon Glass
423b2a29e0SSimon Glass #if CONFIG_IS_ENABLED(OF_PLATDATA)
regmap_init_mem_platdata(struct udevice * dev,fdt_val_t * reg,int count,struct regmap ** mapp)43a28bfcc3SSimon Glass int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
443b2a29e0SSimon Glass struct regmap **mapp)
453b2a29e0SSimon Glass {
461e6ca1a6SSimon Glass struct regmap_range *range;
471e6ca1a6SSimon Glass struct regmap *map;
481e6ca1a6SSimon Glass
491e6ca1a6SSimon Glass map = regmap_alloc_count(count);
501e6ca1a6SSimon Glass if (!map)
511e6ca1a6SSimon Glass return -ENOMEM;
521e6ca1a6SSimon Glass
531e6ca1a6SSimon Glass map->base = *reg;
541e6ca1a6SSimon Glass for (range = map->range; count > 0; reg += 2, range++, count--) {
551e6ca1a6SSimon Glass range->start = *reg;
561e6ca1a6SSimon Glass range->size = reg[1];
571e6ca1a6SSimon Glass }
581e6ca1a6SSimon Glass
591e6ca1a6SSimon Glass *mapp = map;
601e6ca1a6SSimon Glass
613b2a29e0SSimon Glass return 0;
623b2a29e0SSimon Glass }
633b2a29e0SSimon Glass #else
regmap_init_mem(struct udevice * dev,struct regmap ** mapp)646f98b750SSimon Glass int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
656f98b750SSimon Glass {
666f98b750SSimon Glass struct regmap_range *range;
676f98b750SSimon Glass struct regmap *map;
686f98b750SSimon Glass int count;
696f98b750SSimon Glass int addr_len, size_len, both_len;
706f98b750SSimon Glass int len;
711804044fSJean-Jacques Hiblot int index;
7223d63267SSimon Glass ofnode node = dev_ofnode(dev);
7323d63267SSimon Glass struct resource r;
746f98b750SSimon Glass
75878d68c0SSimon Glass addr_len = dev_read_simple_addr_cells(dev->parent);
76878d68c0SSimon Glass size_len = dev_read_simple_size_cells(dev->parent);
776f98b750SSimon Glass both_len = addr_len + size_len;
786f98b750SSimon Glass
7923d63267SSimon Glass len = dev_read_size(dev, "reg");
8023d63267SSimon Glass if (len < 0)
8123d63267SSimon Glass return len;
8223d63267SSimon Glass len /= sizeof(fdt32_t);
836f98b750SSimon Glass count = len / both_len;
8423d63267SSimon Glass if (!count)
856f98b750SSimon Glass return -EINVAL;
866f98b750SSimon Glass
87a951431eSSimon Glass map = regmap_alloc_count(count);
886f98b750SSimon Glass if (!map)
896f98b750SSimon Glass return -ENOMEM;
906f98b750SSimon Glass
911804044fSJean-Jacques Hiblot for (range = map->range, index = 0; count > 0;
9223d63267SSimon Glass count--, range++, index++) {
931804044fSJean-Jacques Hiblot fdt_size_t sz;
9423d63267SSimon Glass if (of_live_active()) {
9523d63267SSimon Glass of_address_to_resource(ofnode_to_np(node), index, &r);
9623d63267SSimon Glass range->start = r.start;
9723d63267SSimon Glass range->size = r.end - r.start + 1;
9823d63267SSimon Glass } else {
9945c78162SAndy Yan range->start = devfdt_get_addr_size_index(dev, index, &sz);
1001804044fSJean-Jacques Hiblot range->size = sz;
1016f98b750SSimon Glass }
10223d63267SSimon Glass }
1031804044fSJean-Jacques Hiblot map->base = map->range[0].start;
1046f98b750SSimon Glass
1056f98b750SSimon Glass *mapp = map;
1066f98b750SSimon Glass
1076f98b750SSimon Glass return 0;
1086f98b750SSimon Glass }
1093b2a29e0SSimon Glass #endif
1106f98b750SSimon Glass
regmap_get_range(struct regmap * map,unsigned int range_num)1116f98b750SSimon Glass void *regmap_get_range(struct regmap *map, unsigned int range_num)
1126f98b750SSimon Glass {
1136f98b750SSimon Glass struct regmap_range *range;
1146f98b750SSimon Glass
1156f98b750SSimon Glass if (range_num >= map->range_count)
1166f98b750SSimon Glass return NULL;
1176f98b750SSimon Glass range = &map->range[range_num];
1186f98b750SSimon Glass
1196f98b750SSimon Glass return map_sysmem(range->start, range->size);
1206f98b750SSimon Glass }
1216f98b750SSimon Glass
regmap_uninit(struct regmap * map)1226f98b750SSimon Glass int regmap_uninit(struct regmap *map)
1236f98b750SSimon Glass {
1246f98b750SSimon Glass if (map->range_count > 1)
1256f98b750SSimon Glass free(map->range);
1266f98b750SSimon Glass free(map);
1276f98b750SSimon Glass
1286f98b750SSimon Glass return 0;
1296f98b750SSimon Glass }
1303bfb8cb4SPaul Burton
regmap_read(struct regmap * map,uint offset,uint * valp)1313bfb8cb4SPaul Burton int regmap_read(struct regmap *map, uint offset, uint *valp)
1323bfb8cb4SPaul Burton {
1333bfb8cb4SPaul Burton uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
1343bfb8cb4SPaul Burton
1353bfb8cb4SPaul Burton *valp = le32_to_cpu(readl(ptr));
1363bfb8cb4SPaul Burton
1373bfb8cb4SPaul Burton return 0;
1383bfb8cb4SPaul Burton }
1393bfb8cb4SPaul Burton
regmap_write(struct regmap * map,uint offset,uint val)1403bfb8cb4SPaul Burton int regmap_write(struct regmap *map, uint offset, uint val)
1413bfb8cb4SPaul Burton {
1423bfb8cb4SPaul Burton uint32_t *ptr = map_physmem(map->base + offset, 4, MAP_NOCACHE);
1433bfb8cb4SPaul Burton
1443bfb8cb4SPaul Burton writel(cpu_to_le32(val), ptr);
1453bfb8cb4SPaul Burton
1463bfb8cb4SPaul Burton return 0;
1473bfb8cb4SPaul Burton }
148*7ad3d567SNeil Armstrong
regmap_update_bits(struct regmap * map,uint offset,uint mask,uint val)149*7ad3d567SNeil Armstrong int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
150*7ad3d567SNeil Armstrong {
151*7ad3d567SNeil Armstrong uint reg;
152*7ad3d567SNeil Armstrong int ret;
153*7ad3d567SNeil Armstrong
154*7ad3d567SNeil Armstrong ret = regmap_read(map, offset, ®);
155*7ad3d567SNeil Armstrong if (ret)
156*7ad3d567SNeil Armstrong return ret;
157*7ad3d567SNeil Armstrong
158*7ad3d567SNeil Armstrong reg &= ~mask;
159*7ad3d567SNeil Armstrong
160*7ad3d567SNeil Armstrong return regmap_write(map, offset, reg | val);
161*7ad3d567SNeil Armstrong }
162