Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // Register map access API - MMIO support
0004 //
0005 // Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
0006 
0007 #include <linux/clk.h>
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/regmap.h>
0012 #include <linux/slab.h>
0013 
0014 #include "internal.h"
0015 
0016 struct regmap_mmio_context {
0017     void __iomem *regs;
0018     unsigned int val_bytes;
0019     bool relaxed_mmio;
0020 
0021     bool attached_clk;
0022     struct clk *clk;
0023 
0024     void (*reg_write)(struct regmap_mmio_context *ctx,
0025               unsigned int reg, unsigned int val);
0026     unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
0027                      unsigned int reg);
0028 };
0029 
0030 static int regmap_mmio_regbits_check(size_t reg_bits)
0031 {
0032     switch (reg_bits) {
0033     case 8:
0034     case 16:
0035     case 32:
0036 #ifdef CONFIG_64BIT
0037     case 64:
0038 #endif
0039         return 0;
0040     default:
0041         return -EINVAL;
0042     }
0043 }
0044 
0045 static int regmap_mmio_get_min_stride(size_t val_bits)
0046 {
0047     int min_stride;
0048 
0049     switch (val_bits) {
0050     case 8:
0051         /* The core treats 0 as 1 */
0052         min_stride = 0;
0053         return 0;
0054     case 16:
0055         min_stride = 2;
0056         break;
0057     case 32:
0058         min_stride = 4;
0059         break;
0060 #ifdef CONFIG_64BIT
0061     case 64:
0062         min_stride = 8;
0063         break;
0064 #endif
0065     default:
0066         return -EINVAL;
0067     }
0068 
0069     return min_stride;
0070 }
0071 
0072 static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
0073                 unsigned int reg,
0074                 unsigned int val)
0075 {
0076     writeb(val, ctx->regs + reg);
0077 }
0078 
0079 static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx,
0080                 unsigned int reg,
0081                 unsigned int val)
0082 {
0083     writeb_relaxed(val, ctx->regs + reg);
0084 }
0085 
0086 static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
0087                   unsigned int reg,
0088                   unsigned int val)
0089 {
0090     writew(val, ctx->regs + reg);
0091 }
0092 
0093 static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx,
0094                   unsigned int reg,
0095                   unsigned int val)
0096 {
0097     writew_relaxed(val, ctx->regs + reg);
0098 }
0099 
0100 static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
0101                   unsigned int reg,
0102                   unsigned int val)
0103 {
0104     iowrite16be(val, ctx->regs + reg);
0105 }
0106 
0107 static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
0108                   unsigned int reg,
0109                   unsigned int val)
0110 {
0111     writel(val, ctx->regs + reg);
0112 }
0113 
0114 static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx,
0115                   unsigned int reg,
0116                   unsigned int val)
0117 {
0118     writel_relaxed(val, ctx->regs + reg);
0119 }
0120 
0121 static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
0122                   unsigned int reg,
0123                   unsigned int val)
0124 {
0125     iowrite32be(val, ctx->regs + reg);
0126 }
0127 
0128 #ifdef CONFIG_64BIT
0129 static void regmap_mmio_write64le(struct regmap_mmio_context *ctx,
0130                   unsigned int reg,
0131                   unsigned int val)
0132 {
0133     writeq(val, ctx->regs + reg);
0134 }
0135 
0136 static void regmap_mmio_write64le_relaxed(struct regmap_mmio_context *ctx,
0137                   unsigned int reg,
0138                   unsigned int val)
0139 {
0140     writeq_relaxed(val, ctx->regs + reg);
0141 }
0142 #endif
0143 
0144 static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
0145 {
0146     struct regmap_mmio_context *ctx = context;
0147     int ret;
0148 
0149     if (!IS_ERR(ctx->clk)) {
0150         ret = clk_enable(ctx->clk);
0151         if (ret < 0)
0152             return ret;
0153     }
0154 
0155     ctx->reg_write(ctx, reg, val);
0156 
0157     if (!IS_ERR(ctx->clk))
0158         clk_disable(ctx->clk);
0159 
0160     return 0;
0161 }
0162 
0163 static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
0164                       unsigned int reg)
0165 {
0166     return readb(ctx->regs + reg);
0167 }
0168 
0169 static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
0170                       unsigned int reg)
0171 {
0172     return readb_relaxed(ctx->regs + reg);
0173 }
0174 
0175 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
0176                          unsigned int reg)
0177 {
0178     return readw(ctx->regs + reg);
0179 }
0180 
0181 static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx,
0182                          unsigned int reg)
0183 {
0184     return readw_relaxed(ctx->regs + reg);
0185 }
0186 
0187 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
0188                          unsigned int reg)
0189 {
0190     return ioread16be(ctx->regs + reg);
0191 }
0192 
0193 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
0194                          unsigned int reg)
0195 {
0196     return readl(ctx->regs + reg);
0197 }
0198 
0199 static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx,
0200                          unsigned int reg)
0201 {
0202     return readl_relaxed(ctx->regs + reg);
0203 }
0204 
0205 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
0206                          unsigned int reg)
0207 {
0208     return ioread32be(ctx->regs + reg);
0209 }
0210 
0211 #ifdef CONFIG_64BIT
0212 static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx,
0213                          unsigned int reg)
0214 {
0215     return readq(ctx->regs + reg);
0216 }
0217 
0218 static unsigned int regmap_mmio_read64le_relaxed(struct regmap_mmio_context *ctx,
0219                          unsigned int reg)
0220 {
0221     return readq_relaxed(ctx->regs + reg);
0222 }
0223 #endif
0224 
0225 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
0226 {
0227     struct regmap_mmio_context *ctx = context;
0228     int ret;
0229 
0230     if (!IS_ERR(ctx->clk)) {
0231         ret = clk_enable(ctx->clk);
0232         if (ret < 0)
0233             return ret;
0234     }
0235 
0236     *val = ctx->reg_read(ctx, reg);
0237 
0238     if (!IS_ERR(ctx->clk))
0239         clk_disable(ctx->clk);
0240 
0241     return 0;
0242 }
0243 
0244 static void regmap_mmio_free_context(void *context)
0245 {
0246     struct regmap_mmio_context *ctx = context;
0247 
0248     if (!IS_ERR(ctx->clk)) {
0249         clk_unprepare(ctx->clk);
0250         if (!ctx->attached_clk)
0251             clk_put(ctx->clk);
0252     }
0253     kfree(context);
0254 }
0255 
0256 static const struct regmap_bus regmap_mmio = {
0257     .fast_io = true,
0258     .reg_write = regmap_mmio_write,
0259     .reg_read = regmap_mmio_read,
0260     .free_context = regmap_mmio_free_context,
0261     .val_format_endian_default = REGMAP_ENDIAN_LITTLE,
0262 };
0263 
0264 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
0265                     const char *clk_id,
0266                     void __iomem *regs,
0267                     const struct regmap_config *config)
0268 {
0269     struct regmap_mmio_context *ctx;
0270     int min_stride;
0271     int ret;
0272 
0273     ret = regmap_mmio_regbits_check(config->reg_bits);
0274     if (ret)
0275         return ERR_PTR(ret);
0276 
0277     if (config->pad_bits)
0278         return ERR_PTR(-EINVAL);
0279 
0280     min_stride = regmap_mmio_get_min_stride(config->val_bits);
0281     if (min_stride < 0)
0282         return ERR_PTR(min_stride);
0283 
0284     if (config->reg_stride < min_stride)
0285         return ERR_PTR(-EINVAL);
0286 
0287     ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
0288     if (!ctx)
0289         return ERR_PTR(-ENOMEM);
0290 
0291     ctx->regs = regs;
0292     ctx->val_bytes = config->val_bits / 8;
0293     ctx->relaxed_mmio = config->use_relaxed_mmio;
0294     ctx->clk = ERR_PTR(-ENODEV);
0295 
0296     switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
0297     case REGMAP_ENDIAN_DEFAULT:
0298     case REGMAP_ENDIAN_LITTLE:
0299 #ifdef __LITTLE_ENDIAN
0300     case REGMAP_ENDIAN_NATIVE:
0301 #endif
0302         switch (config->val_bits) {
0303         case 8:
0304             if (ctx->relaxed_mmio) {
0305                 ctx->reg_read = regmap_mmio_read8_relaxed;
0306                 ctx->reg_write = regmap_mmio_write8_relaxed;
0307             } else {
0308                 ctx->reg_read = regmap_mmio_read8;
0309                 ctx->reg_write = regmap_mmio_write8;
0310             }
0311             break;
0312         case 16:
0313             if (ctx->relaxed_mmio) {
0314                 ctx->reg_read = regmap_mmio_read16le_relaxed;
0315                 ctx->reg_write = regmap_mmio_write16le_relaxed;
0316             } else {
0317                 ctx->reg_read = regmap_mmio_read16le;
0318                 ctx->reg_write = regmap_mmio_write16le;
0319             }
0320             break;
0321         case 32:
0322             if (ctx->relaxed_mmio) {
0323                 ctx->reg_read = regmap_mmio_read32le_relaxed;
0324                 ctx->reg_write = regmap_mmio_write32le_relaxed;
0325             } else {
0326                 ctx->reg_read = regmap_mmio_read32le;
0327                 ctx->reg_write = regmap_mmio_write32le;
0328             }
0329             break;
0330 #ifdef CONFIG_64BIT
0331         case 64:
0332             if (ctx->relaxed_mmio) {
0333                 ctx->reg_read = regmap_mmio_read64le_relaxed;
0334                 ctx->reg_write = regmap_mmio_write64le_relaxed;
0335             } else {
0336                 ctx->reg_read = regmap_mmio_read64le;
0337                 ctx->reg_write = regmap_mmio_write64le;
0338             }
0339             break;
0340 #endif
0341         default:
0342             ret = -EINVAL;
0343             goto err_free;
0344         }
0345         break;
0346     case REGMAP_ENDIAN_BIG:
0347 #ifdef __BIG_ENDIAN
0348     case REGMAP_ENDIAN_NATIVE:
0349 #endif
0350         switch (config->val_bits) {
0351         case 8:
0352             ctx->reg_read = regmap_mmio_read8;
0353             ctx->reg_write = regmap_mmio_write8;
0354             break;
0355         case 16:
0356             ctx->reg_read = regmap_mmio_read16be;
0357             ctx->reg_write = regmap_mmio_write16be;
0358             break;
0359         case 32:
0360             ctx->reg_read = regmap_mmio_read32be;
0361             ctx->reg_write = regmap_mmio_write32be;
0362             break;
0363         default:
0364             ret = -EINVAL;
0365             goto err_free;
0366         }
0367         break;
0368     default:
0369         ret = -EINVAL;
0370         goto err_free;
0371     }
0372 
0373     if (clk_id == NULL)
0374         return ctx;
0375 
0376     ctx->clk = clk_get(dev, clk_id);
0377     if (IS_ERR(ctx->clk)) {
0378         ret = PTR_ERR(ctx->clk);
0379         goto err_free;
0380     }
0381 
0382     ret = clk_prepare(ctx->clk);
0383     if (ret < 0) {
0384         clk_put(ctx->clk);
0385         goto err_free;
0386     }
0387 
0388     return ctx;
0389 
0390 err_free:
0391     kfree(ctx);
0392 
0393     return ERR_PTR(ret);
0394 }
0395 
0396 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
0397                       void __iomem *regs,
0398                       const struct regmap_config *config,
0399                       struct lock_class_key *lock_key,
0400                       const char *lock_name)
0401 {
0402     struct regmap_mmio_context *ctx;
0403 
0404     ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
0405     if (IS_ERR(ctx))
0406         return ERR_CAST(ctx);
0407 
0408     return __regmap_init(dev, &regmap_mmio, ctx, config,
0409                  lock_key, lock_name);
0410 }
0411 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
0412 
0413 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
0414                        const char *clk_id,
0415                        void __iomem *regs,
0416                        const struct regmap_config *config,
0417                        struct lock_class_key *lock_key,
0418                        const char *lock_name)
0419 {
0420     struct regmap_mmio_context *ctx;
0421 
0422     ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
0423     if (IS_ERR(ctx))
0424         return ERR_CAST(ctx);
0425 
0426     return __devm_regmap_init(dev, &regmap_mmio, ctx, config,
0427                   lock_key, lock_name);
0428 }
0429 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
0430 
0431 int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk)
0432 {
0433     struct regmap_mmio_context *ctx = map->bus_context;
0434 
0435     ctx->clk = clk;
0436     ctx->attached_clk = true;
0437 
0438     return clk_prepare(ctx->clk);
0439 }
0440 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk);
0441 
0442 void regmap_mmio_detach_clk(struct regmap *map)
0443 {
0444     struct regmap_mmio_context *ctx = map->bus_context;
0445 
0446     clk_unprepare(ctx->clk);
0447 
0448     ctx->attached_clk = false;
0449     ctx->clk = NULL;
0450 }
0451 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk);
0452 
0453 MODULE_LICENSE("GPL v2");