From patchwork Mon May 11 12:00:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pratyush Yadav X-Patchwork-Id: 245581 List-Id: U-Boot discussion From: p.yadav at ti.com (Yadav, Pratyush) Date: Mon, 11 May 2020 17:30:30 +0530 Subject: [PATCH v2 2/4] regmap: Allow providing read/write callbacks through struct regmap_config In-Reply-To: References: <20200505194702.j4qekgcu4ytljoyh@ti.com> <20143884-04d0-8e07-6a05-d5c2a61158f6@ti.com> Message-ID: <20200511120030.cqu2mranp7nkgnsm@ti.com> Hi Simon, On 07/05/20 07:36PM, Simon Glass wrote: > > > > If there a way to use DM w/o DT changes, we can definitely explore that... > > You can certainly do that. Just device_bind() a driver that implements > your access mechanism. So long as the driver uses the same access > mechanism no matter what hardware it is running on, that makes sense. > But from what you say above, that might not be true, so you would end > up setting the platform data of the regmap driver from its parent. > That's not terrible, but not ideal. > > Given the simple access you need above, I think you could just add > that as another option in the regmap, perhaps turning endianness into > some flags? I tried doing it without custom regmap accessors. The rough patch below is what I came up with. Does it look any better than custom accessors? PS: I can probably play around with regmap ranges instead of using 'base_offset', but it gets the job done minimally so I think it is good enough for a proof-of-concept. -- 8< -- Subject: [RFC PATCH] regmap: allow specifying base offset and register shift and access size To accommodate more complex access patterns that are needed in the Cadence Sierra PHY driver (which will be added as a follow-up), introduce 'base_offset' and 'reg_offset_shift', two values that can be used to adjust the final regmap read/write address. 'base_offset' is an extra offset on the regmap base discovered from the device tree. This is useful when some regmaps of a device need to access memory at one offset, and some at another. 'reg_offset_shift' will shift the register offset left before access. 'size' can be used to specify the width of reads (1/2/4/8 bytes). If 0, defaults to 4 bytes to maintain backward compatibility. Signed-off-by: Pratyush Yadav --- drivers/core/regmap.c | 16 ++++++++++++---- include/regmap.h | 27 ++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c index 41293e5af0..9bce719b45 100644 --- a/drivers/core/regmap.c +++ b/drivers/core/regmap.c @@ -38,6 +38,7 @@ static struct regmap *regmap_alloc(int count) map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count); if (!map) return NULL; + memset(map, 0, sizeof(*map)); map->range_count = count; return map; @@ -258,6 +259,10 @@ struct regmap *devm_regmap_init(struct udevice *dev, if (rc) return ERR_PTR(rc); + (*mapp)->base_offset = config->base_offset; + (*mapp)->reg_offset_shift = config->reg_offset_shift; + (*mapp)->size = config->size; + devres_add(dev, mapp); return *mapp; } @@ -343,7 +348,9 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset, } range = &map->ranges[range_num]; - ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE); + offset <<= map->reg_offset_shift; + + ptr = map_physmem(range->start + map->base_offset + offset, val_len, MAP_NOCACHE); if (offset + val_len > range->size) { debug("%s: offset/size combination invalid\n", __func__); @@ -380,7 +387,7 @@ int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len) int regmap_read(struct regmap *map, uint offset, uint *valp) { - return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32); + return regmap_raw_read(map, offset, valp, map->size ? map->size : REGMAP_SIZE_32); } static inline void __write_8(u8 *addr, const u8 *val, @@ -452,7 +459,8 @@ int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset, } range = &map->ranges[range_num]; - ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE); + offset <<= map->reg_offset_shift; + ptr = map_physmem(range->start + map->base_offset + offset, val_len, MAP_NOCACHE); if (offset + val_len > range->size) { debug("%s: offset/size combination invalid\n", __func__); @@ -490,7 +498,7 @@ int regmap_raw_write(struct regmap *map, uint offset, const void *val, int regmap_write(struct regmap *map, uint offset, uint val) { - return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32); + return regmap_raw_write(map, offset, &val, map->size ? map->size : REGMAP_SIZE_32); } int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val) diff --git a/include/regmap.h b/include/regmap.h index 2edbf9359a..4adb04f7e3 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -74,16 +74,41 @@ struct regmap_range { }; struct regmap_bus; -struct regmap_config; +/** + * struct regmap_config - a way of accessing hardware/bus registers + * + * @base_offset: Offset from the base of the regmap for reads and writes. + * (OPTIONAL) + * @reg_offset_shift: Left shift register offset by this value before + * performing reads or writes. (OPTIONAL) + * @size: Size/width of the read or write operation. Defaults to + * REGMAP_SIZE_32 if set to zero. + */ +struct regmap_config { + u32 base_offset; + u32 reg_offset_shift; + enum regmap_size_t size; +}; /** * struct regmap - a way of accessing hardware/bus registers * + * @base_offset: Offset from the base of the regmap for reads and writes. + * (OPTIONAL) + * @reg_offset_shift: Left shift register offset by this value before + * performing reads or writes. (OPTIONAL) + * @size: Size/width of the read or write operation. Defaults to + * REGMAP_SIZE_32 if set to zero. * @range_count: Number of ranges available within the map * @ranges: Array of ranges */ struct regmap { enum regmap_endianness_t endianness; + + u32 base_offset; + u32 reg_offset_shift; + enum regmap_size_t size; + int range_count; struct regmap_range ranges[0]; };