uboot/drivers/core/regmap.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2015 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 */
   6
   7#include <common.h>
   8#include <dm.h>
   9#include <errno.h>
  10#include <linux/libfdt.h>
  11#include <malloc.h>
  12#include <mapmem.h>
  13#include <regmap.h>
  14#include <asm/io.h>
  15#include <dm/of_addr.h>
  16#include <linux/ioport.h>
  17
  18DECLARE_GLOBAL_DATA_PTR;
  19
  20static struct regmap *regmap_alloc(int count)
  21{
  22        struct regmap *map;
  23
  24        map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count);
  25        if (!map)
  26                return NULL;
  27        map->range_count = count;
  28
  29        return map;
  30}
  31
  32#if CONFIG_IS_ENABLED(OF_PLATDATA)
  33int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
  34                             struct regmap **mapp)
  35{
  36        struct regmap_range *range;
  37        struct regmap *map;
  38
  39        map = regmap_alloc(count);
  40        if (!map)
  41                return -ENOMEM;
  42
  43        for (range = map->ranges; count > 0; reg += 2, range++, count--) {
  44                range->start = *reg;
  45                range->size = reg[1];
  46        }
  47
  48        *mapp = map;
  49
  50        return 0;
  51}
  52#else
  53int regmap_init_mem(ofnode node, struct regmap **mapp)
  54{
  55        struct regmap_range *range;
  56        struct regmap *map;
  57        int count;
  58        int addr_len, size_len, both_len;
  59        int len;
  60        int index;
  61        struct resource r;
  62
  63        addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
  64        size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
  65        both_len = addr_len + size_len;
  66
  67        len = ofnode_read_size(node, "reg");
  68        if (len < 0)
  69                return len;
  70        len /= sizeof(fdt32_t);
  71        count = len / both_len;
  72        if (!count)
  73                return -EINVAL;
  74
  75        map = regmap_alloc(count);
  76        if (!map)
  77                return -ENOMEM;
  78
  79        for (range = map->ranges, index = 0; count > 0;
  80             count--, range++, index++) {
  81                fdt_size_t sz;
  82                if (of_live_active()) {
  83                        of_address_to_resource(ofnode_to_np(node), index, &r);
  84                        range->start = r.start;
  85                        range->size = r.end - r.start + 1;
  86                } else {
  87                        range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
  88                                        ofnode_to_offset(node), "reg", index,
  89                                        addr_len, size_len, &sz, true);
  90                        range->size = sz;
  91                }
  92        }
  93
  94        *mapp = map;
  95
  96        return 0;
  97}
  98#endif
  99
 100void *regmap_get_range(struct regmap *map, unsigned int range_num)
 101{
 102        struct regmap_range *range;
 103
 104        if (range_num >= map->range_count)
 105                return NULL;
 106        range = &map->ranges[range_num];
 107
 108        return map_sysmem(range->start, range->size);
 109}
 110
 111int regmap_uninit(struct regmap *map)
 112{
 113        free(map);
 114
 115        return 0;
 116}
 117
 118int regmap_read(struct regmap *map, uint offset, uint *valp)
 119{
 120        u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
 121
 122        *valp = le32_to_cpu(readl(ptr));
 123
 124        return 0;
 125}
 126
 127int regmap_write(struct regmap *map, uint offset, uint val)
 128{
 129        u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
 130
 131        writel(cpu_to_le32(val), ptr);
 132
 133        return 0;
 134}
 135
 136int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
 137{
 138        uint reg;
 139        int ret;
 140
 141        ret = regmap_read(map, offset, &reg);
 142        if (ret)
 143                return ret;
 144
 145        reg &= ~mask;
 146
 147        return regmap_write(map, offset, reg | val);
 148}
 149