cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

regmap-mmio.c (9762B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Register map access API - MMIO support
      4//
      5// Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
      6
      7#include <linux/clk.h>
      8#include <linux/err.h>
      9#include <linux/io.h>
     10#include <linux/module.h>
     11#include <linux/regmap.h>
     12#include <linux/slab.h>
     13
     14#include "internal.h"
     15
     16struct regmap_mmio_context {
     17	void __iomem *regs;
     18	unsigned int val_bytes;
     19	bool relaxed_mmio;
     20
     21	bool attached_clk;
     22	struct clk *clk;
     23
     24	void (*reg_write)(struct regmap_mmio_context *ctx,
     25			  unsigned int reg, unsigned int val);
     26	unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
     27			         unsigned int reg);
     28};
     29
     30static int regmap_mmio_regbits_check(size_t reg_bits)
     31{
     32	switch (reg_bits) {
     33	case 8:
     34	case 16:
     35	case 32:
     36#ifdef CONFIG_64BIT
     37	case 64:
     38#endif
     39		return 0;
     40	default:
     41		return -EINVAL;
     42	}
     43}
     44
     45static int regmap_mmio_get_min_stride(size_t val_bits)
     46{
     47	int min_stride;
     48
     49	switch (val_bits) {
     50	case 8:
     51		/* The core treats 0 as 1 */
     52		min_stride = 0;
     53		return 0;
     54	case 16:
     55		min_stride = 2;
     56		break;
     57	case 32:
     58		min_stride = 4;
     59		break;
     60#ifdef CONFIG_64BIT
     61	case 64:
     62		min_stride = 8;
     63		break;
     64#endif
     65	default:
     66		return -EINVAL;
     67	}
     68
     69	return min_stride;
     70}
     71
     72static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
     73				unsigned int reg,
     74				unsigned int val)
     75{
     76	writeb(val, ctx->regs + reg);
     77}
     78
     79static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx,
     80				unsigned int reg,
     81				unsigned int val)
     82{
     83	writeb_relaxed(val, ctx->regs + reg);
     84}
     85
     86static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
     87				  unsigned int reg,
     88				  unsigned int val)
     89{
     90	writew(val, ctx->regs + reg);
     91}
     92
     93static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx,
     94				  unsigned int reg,
     95				  unsigned int val)
     96{
     97	writew_relaxed(val, ctx->regs + reg);
     98}
     99
    100static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
    101				  unsigned int reg,
    102				  unsigned int val)
    103{
    104	iowrite16be(val, ctx->regs + reg);
    105}
    106
    107static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
    108				  unsigned int reg,
    109				  unsigned int val)
    110{
    111	writel(val, ctx->regs + reg);
    112}
    113
    114static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx,
    115				  unsigned int reg,
    116				  unsigned int val)
    117{
    118	writel_relaxed(val, ctx->regs + reg);
    119}
    120
    121static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
    122				  unsigned int reg,
    123				  unsigned int val)
    124{
    125	iowrite32be(val, ctx->regs + reg);
    126}
    127
    128#ifdef CONFIG_64BIT
    129static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
    130				  unsigned int reg,
    131				  unsigned int val)
    132{
    133	writeq(val, ctx->regs + reg);
    134}
    135
    136static void regmap_mmio_write64le_relaxed(struct regmap_mmio_context *ctx,
    137				  unsigned int reg,
    138				  unsigned int val)
    139{
    140	writeq_relaxed(val, ctx->regs + reg);
    141}
    142#endif
    143
    144static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
    145{
    146	struct regmap_mmio_context *ctx = context;
    147	int ret;
    148
    149	if (!IS_ERR(ctx->clk)) {
    150		ret = clk_enable(ctx->clk);
    151		if (ret < 0)
    152			return ret;
    153	}
    154
    155	ctx->reg_write(ctx, reg, val);
    156
    157	if (!IS_ERR(ctx->clk))
    158		clk_disable(ctx->clk);
    159
    160	return 0;
    161}
    162
    163static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
    164				      unsigned int reg)
    165{
    166	return readb(ctx->regs + reg);
    167}
    168
    169static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
    170				      unsigned int reg)
    171{
    172	return readb_relaxed(ctx->regs + reg);
    173}
    174
    175static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
    176				         unsigned int reg)
    177{
    178	return readw(ctx->regs + reg);
    179}
    180
    181static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx,
    182						 unsigned int reg)
    183{
    184	return readw_relaxed(ctx->regs + reg);
    185}
    186
    187static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
    188				         unsigned int reg)
    189{
    190	return ioread16be(ctx->regs + reg);
    191}
    192
    193static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
    194				         unsigned int reg)
    195{
    196	return readl(ctx->regs + reg);
    197}
    198
    199static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx,
    200						 unsigned int reg)
    201{
    202	return readl_relaxed(ctx->regs + reg);
    203}
    204
    205static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
    206				         unsigned int reg)
    207{
    208	return ioread32be(ctx->regs + reg);
    209}
    210
    211#ifdef CONFIG_64BIT
    212static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
    213				         unsigned int reg)
    214{
    215	return readq(ctx->regs + reg);
    216}
    217
    218static unsigned int regmap_mmio_read64le_relaxed(struct regmap_mmio_context *ctx,
    219						 unsigned int reg)
    220{
    221	return readq_relaxed(ctx->regs + reg);
    222}
    223#endif
    224
    225static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
    226{
    227	struct regmap_mmio_context *ctx = context;
    228	int ret;
    229
    230	if (!IS_ERR(ctx->clk)) {
    231		ret = clk_enable(ctx->clk);
    232		if (ret < 0)
    233			return ret;
    234	}
    235
    236	*val = ctx->reg_read(ctx, reg);
    237
    238	if (!IS_ERR(ctx->clk))
    239		clk_disable(ctx->clk);
    240
    241	return 0;
    242}
    243
    244static void regmap_mmio_free_context(void *context)
    245{
    246	struct regmap_mmio_context *ctx = context;
    247
    248	if (!IS_ERR(ctx->clk)) {
    249		clk_unprepare(ctx->clk);
    250		if (!ctx->attached_clk)
    251			clk_put(ctx->clk);
    252	}
    253	kfree(context);
    254}
    255
    256static const struct regmap_bus regmap_mmio = {
    257	.fast_io = true,
    258	.reg_write = regmap_mmio_write,
    259	.reg_read = regmap_mmio_read,
    260	.free_context = regmap_mmio_free_context,
    261	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
    262};
    263
    264static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
    265					const char *clk_id,
    266					void __iomem *regs,
    267					const struct regmap_config *config)
    268{
    269	struct regmap_mmio_context *ctx;
    270	int min_stride;
    271	int ret;
    272
    273	ret = regmap_mmio_regbits_check(config->reg_bits);
    274	if (ret)
    275		return ERR_PTR(ret);
    276
    277	if (config->pad_bits)
    278		return ERR_PTR(-EINVAL);
    279
    280	min_stride = regmap_mmio_get_min_stride(config->val_bits);
    281	if (min_stride < 0)
    282		return ERR_PTR(min_stride);
    283
    284	if (config->reg_stride < min_stride)
    285		return ERR_PTR(-EINVAL);
    286
    287	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
    288	if (!ctx)
    289		return ERR_PTR(-ENOMEM);
    290
    291	ctx->regs = regs;
    292	ctx->val_bytes = config->val_bits / 8;
    293	ctx->relaxed_mmio = config->use_relaxed_mmio;
    294	ctx->clk = ERR_PTR(-ENODEV);
    295
    296	switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
    297	case REGMAP_ENDIAN_DEFAULT:
    298	case REGMAP_ENDIAN_LITTLE:
    299#ifdef __LITTLE_ENDIAN
    300	case REGMAP_ENDIAN_NATIVE:
    301#endif
    302		switch (config->val_bits) {
    303		case 8:
    304			if (ctx->relaxed_mmio) {
    305				ctx->reg_read = regmap_mmio_read8_relaxed;
    306				ctx->reg_write = regmap_mmio_write8_relaxed;
    307			} else {
    308				ctx->reg_read = regmap_mmio_read8;
    309				ctx->reg_write = regmap_mmio_write8;
    310			}
    311			break;
    312		case 16:
    313			if (ctx->relaxed_mmio) {
    314				ctx->reg_read = regmap_mmio_read16le_relaxed;
    315				ctx->reg_write = regmap_mmio_write16le_relaxed;
    316			} else {
    317				ctx->reg_read = regmap_mmio_read16le;
    318				ctx->reg_write = regmap_mmio_write16le;
    319			}
    320			break;
    321		case 32:
    322			if (ctx->relaxed_mmio) {
    323				ctx->reg_read = regmap_mmio_read32le_relaxed;
    324				ctx->reg_write = regmap_mmio_write32le_relaxed;
    325			} else {
    326				ctx->reg_read = regmap_mmio_read32le;
    327				ctx->reg_write = regmap_mmio_write32le;
    328			}
    329			break;
    330#ifdef CONFIG_64BIT
    331		case 64:
    332			if (ctx->relaxed_mmio) {
    333				ctx->reg_read = regmap_mmio_read64le_relaxed;
    334				ctx->reg_write = regmap_mmio_write64le_relaxed;
    335			} else {
    336				ctx->reg_read = regmap_mmio_read64le;
    337				ctx->reg_write = regmap_mmio_write64le;
    338			}
    339			break;
    340#endif
    341		default:
    342			ret = -EINVAL;
    343			goto err_free;
    344		}
    345		break;
    346	case REGMAP_ENDIAN_BIG:
    347#ifdef __BIG_ENDIAN
    348	case REGMAP_ENDIAN_NATIVE:
    349#endif
    350		switch (config->val_bits) {
    351		case 8:
    352			ctx->reg_read = regmap_mmio_read8;
    353			ctx->reg_write = regmap_mmio_write8;
    354			break;
    355		case 16:
    356			ctx->reg_read = regmap_mmio_read16be;
    357			ctx->reg_write = regmap_mmio_write16be;
    358			break;
    359		case 32:
    360			ctx->reg_read = regmap_mmio_read32be;
    361			ctx->reg_write = regmap_mmio_write32be;
    362			break;
    363		default:
    364			ret = -EINVAL;
    365			goto err_free;
    366		}
    367		break;
    368	default:
    369		ret = -EINVAL;
    370		goto err_free;
    371	}
    372
    373	if (clk_id == NULL)
    374		return ctx;
    375
    376	ctx->clk = clk_get(dev, clk_id);
    377	if (IS_ERR(ctx->clk)) {
    378		ret = PTR_ERR(ctx->clk);
    379		goto err_free;
    380	}
    381
    382	ret = clk_prepare(ctx->clk);
    383	if (ret < 0) {
    384		clk_put(ctx->clk);
    385		goto err_free;
    386	}
    387
    388	return ctx;
    389
    390err_free:
    391	kfree(ctx);
    392
    393	return ERR_PTR(ret);
    394}
    395
    396struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
    397				      void __iomem *regs,
    398				      const struct regmap_config *config,
    399				      struct lock_class_key *lock_key,
    400				      const char *lock_name)
    401{
    402	struct regmap_mmio_context *ctx;
    403
    404	ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
    405	if (IS_ERR(ctx))
    406		return ERR_CAST(ctx);
    407
    408	return __regmap_init(dev, &regmap_mmio, ctx, config,
    409			     lock_key, lock_name);
    410}
    411EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
    412
    413struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
    414					   const char *clk_id,
    415					   void __iomem *regs,
    416					   const struct regmap_config *config,
    417					   struct lock_class_key *lock_key,
    418					   const char *lock_name)
    419{
    420	struct regmap_mmio_context *ctx;
    421
    422	ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
    423	if (IS_ERR(ctx))
    424		return ERR_CAST(ctx);
    425
    426	return __devm_regmap_init(dev, &regmap_mmio, ctx, config,
    427				  lock_key, lock_name);
    428}
    429EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
    430
    431int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk)
    432{
    433	struct regmap_mmio_context *ctx = map->bus_context;
    434
    435	ctx->clk = clk;
    436	ctx->attached_clk = true;
    437
    438	return clk_prepare(ctx->clk);
    439}
    440EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk);
    441
    442void regmap_mmio_detach_clk(struct regmap *map)
    443{
    444	struct regmap_mmio_context *ctx = map->bus_context;
    445
    446	clk_unprepare(ctx->clk);
    447
    448	ctx->attached_clk = false;
    449	ctx->clk = NULL;
    450}
    451EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk);
    452
    453MODULE_LICENSE("GPL v2");