• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <linux/swab.h>
14 
15 #include "internal.h"
16 
17 struct regmap_mmio_context {
18 	void __iomem *regs;
19 	unsigned int val_bytes;
20 	bool big_endian;
21 
22 	bool attached_clk;
23 	struct clk *clk;
24 
25 	void (*reg_write)(struct regmap_mmio_context *ctx,
26 			  unsigned int reg, unsigned int val);
27 	unsigned int (*reg_read)(struct regmap_mmio_context *ctx,
28 			         unsigned int reg);
29 };
30 
regmap_mmio_regbits_check(size_t reg_bits)31 static int regmap_mmio_regbits_check(size_t reg_bits)
32 {
33 	switch (reg_bits) {
34 	case 8:
35 	case 16:
36 	case 32:
37 		return 0;
38 	default:
39 		return -EINVAL;
40 	}
41 }
42 
regmap_mmio_get_min_stride(size_t val_bits)43 static int regmap_mmio_get_min_stride(size_t val_bits)
44 {
45 	int min_stride;
46 
47 	switch (val_bits) {
48 	case 8:
49 		/* The core treats 0 as 1 */
50 		min_stride = 0;
51 		break;
52 	case 16:
53 		min_stride = 2;
54 		break;
55 	case 32:
56 		min_stride = 4;
57 		break;
58 	default:
59 		return -EINVAL;
60 	}
61 
62 	return min_stride;
63 }
64 
regmap_mmio_write8(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)65 static void regmap_mmio_write8(struct regmap_mmio_context *ctx,
66 				unsigned int reg,
67 				unsigned int val)
68 {
69 	writeb(val, ctx->regs + reg);
70 }
71 
regmap_mmio_write8_relaxed(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)72 static void regmap_mmio_write8_relaxed(struct regmap_mmio_context *ctx,
73 				unsigned int reg,
74 				unsigned int val)
75 {
76 	writeb_relaxed(val, ctx->regs + reg);
77 }
78 
regmap_mmio_iowrite8(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)79 static void regmap_mmio_iowrite8(struct regmap_mmio_context *ctx,
80 				 unsigned int reg, unsigned int val)
81 {
82 	iowrite8(val, ctx->regs + reg);
83 }
84 
regmap_mmio_write16le(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)85 static void regmap_mmio_write16le(struct regmap_mmio_context *ctx,
86 				  unsigned int reg,
87 				  unsigned int val)
88 {
89 	writew(val, ctx->regs + reg);
90 }
91 
regmap_mmio_write16le_relaxed(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)92 static void regmap_mmio_write16le_relaxed(struct regmap_mmio_context *ctx,
93 				  unsigned int reg,
94 				  unsigned int val)
95 {
96 	writew_relaxed(val, ctx->regs + reg);
97 }
98 
regmap_mmio_iowrite16le(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)99 static void regmap_mmio_iowrite16le(struct regmap_mmio_context *ctx,
100 				    unsigned int reg, unsigned int val)
101 {
102 	iowrite16(val, ctx->regs + reg);
103 }
104 
regmap_mmio_write16be(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)105 static void regmap_mmio_write16be(struct regmap_mmio_context *ctx,
106 				  unsigned int reg,
107 				  unsigned int val)
108 {
109 	writew(swab16(val), ctx->regs + reg);
110 }
111 
regmap_mmio_iowrite16be(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)112 static void regmap_mmio_iowrite16be(struct regmap_mmio_context *ctx,
113 				    unsigned int reg, unsigned int val)
114 {
115 	iowrite16be(val, ctx->regs + reg);
116 }
117 
regmap_mmio_write32le(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)118 static void regmap_mmio_write32le(struct regmap_mmio_context *ctx,
119 				  unsigned int reg,
120 				  unsigned int val)
121 {
122 	writel(val, ctx->regs + reg);
123 }
124 
regmap_mmio_write32le_relaxed(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)125 static void regmap_mmio_write32le_relaxed(struct regmap_mmio_context *ctx,
126 				  unsigned int reg,
127 				  unsigned int val)
128 {
129 	writel_relaxed(val, ctx->regs + reg);
130 }
131 
regmap_mmio_iowrite32le(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)132 static void regmap_mmio_iowrite32le(struct regmap_mmio_context *ctx,
133 				    unsigned int reg, unsigned int val)
134 {
135 	iowrite32(val, ctx->regs + reg);
136 }
137 
regmap_mmio_write32be(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)138 static void regmap_mmio_write32be(struct regmap_mmio_context *ctx,
139 				  unsigned int reg,
140 				  unsigned int val)
141 {
142 	writel(swab32(val), ctx->regs + reg);
143 }
144 
regmap_mmio_iowrite32be(struct regmap_mmio_context * ctx,unsigned int reg,unsigned int val)145 static void regmap_mmio_iowrite32be(struct regmap_mmio_context *ctx,
146 				    unsigned int reg, unsigned int val)
147 {
148 	iowrite32be(val, ctx->regs + reg);
149 }
150 
regmap_mmio_write(void * context,unsigned int reg,unsigned int val)151 static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val)
152 {
153 	struct regmap_mmio_context *ctx = context;
154 	int ret;
155 
156 	if (!IS_ERR(ctx->clk)) {
157 		ret = clk_enable(ctx->clk);
158 		if (ret < 0)
159 			return ret;
160 	}
161 
162 	ctx->reg_write(ctx, reg, val);
163 
164 	if (!IS_ERR(ctx->clk))
165 		clk_disable(ctx->clk);
166 
167 	return 0;
168 }
169 
regmap_mmio_noinc_write(void * context,unsigned int reg,const void * val,size_t val_count)170 static int regmap_mmio_noinc_write(void *context, unsigned int reg,
171 				   const void *val, size_t val_count)
172 {
173 	struct regmap_mmio_context *ctx = context;
174 	int ret = 0;
175 	int i;
176 
177 	if (!IS_ERR(ctx->clk)) {
178 		ret = clk_enable(ctx->clk);
179 		if (ret < 0)
180 			return ret;
181 	}
182 
183 	/*
184 	 * There are no native, assembly-optimized write single register
185 	 * operations for big endian, so fall back to emulation if this
186 	 * is needed. (Single bytes are fine, they are not affected by
187 	 * endianness.)
188 	 */
189 	if (ctx->big_endian && (ctx->val_bytes > 1)) {
190 		switch (ctx->val_bytes) {
191 		case 2:
192 		{
193 			const u16 *valp = (const u16 *)val;
194 			for (i = 0; i < val_count; i++)
195 				writew(swab16(valp[i]), ctx->regs + reg);
196 			goto out_clk;
197 		}
198 		case 4:
199 		{
200 			const u32 *valp = (const u32 *)val;
201 			for (i = 0; i < val_count; i++)
202 				writel(swab32(valp[i]), ctx->regs + reg);
203 			goto out_clk;
204 		}
205 		default:
206 			ret = -EINVAL;
207 			goto out_clk;
208 		}
209 	}
210 
211 	switch (ctx->val_bytes) {
212 	case 1:
213 		writesb(ctx->regs + reg, (const u8 *)val, val_count);
214 		break;
215 	case 2:
216 		writesw(ctx->regs + reg, (const u16 *)val, val_count);
217 		break;
218 	case 4:
219 		writesl(ctx->regs + reg, (const u32 *)val, val_count);
220 		break;
221 	default:
222 		ret = -EINVAL;
223 		break;
224 	}
225 
226 out_clk:
227 	if (!IS_ERR(ctx->clk))
228 		clk_disable(ctx->clk);
229 
230 	return ret;
231 }
232 
regmap_mmio_read8(struct regmap_mmio_context * ctx,unsigned int reg)233 static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx,
234 				      unsigned int reg)
235 {
236 	return readb(ctx->regs + reg);
237 }
238 
regmap_mmio_read8_relaxed(struct regmap_mmio_context * ctx,unsigned int reg)239 static unsigned int regmap_mmio_read8_relaxed(struct regmap_mmio_context *ctx,
240 				      unsigned int reg)
241 {
242 	return readb_relaxed(ctx->regs + reg);
243 }
244 
regmap_mmio_ioread8(struct regmap_mmio_context * ctx,unsigned int reg)245 static unsigned int regmap_mmio_ioread8(struct regmap_mmio_context *ctx,
246 					unsigned int reg)
247 {
248 	return ioread8(ctx->regs + reg);
249 }
250 
regmap_mmio_read16le(struct regmap_mmio_context * ctx,unsigned int reg)251 static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx,
252 				         unsigned int reg)
253 {
254 	return readw(ctx->regs + reg);
255 }
256 
regmap_mmio_read16le_relaxed(struct regmap_mmio_context * ctx,unsigned int reg)257 static unsigned int regmap_mmio_read16le_relaxed(struct regmap_mmio_context *ctx,
258 						 unsigned int reg)
259 {
260 	return readw_relaxed(ctx->regs + reg);
261 }
262 
regmap_mmio_ioread16le(struct regmap_mmio_context * ctx,unsigned int reg)263 static unsigned int regmap_mmio_ioread16le(struct regmap_mmio_context *ctx,
264 					   unsigned int reg)
265 {
266 	return ioread16(ctx->regs + reg);
267 }
268 
regmap_mmio_read16be(struct regmap_mmio_context * ctx,unsigned int reg)269 static unsigned int regmap_mmio_read16be(struct regmap_mmio_context *ctx,
270 				         unsigned int reg)
271 {
272 	return swab16(readw(ctx->regs + reg));
273 }
274 
regmap_mmio_ioread16be(struct regmap_mmio_context * ctx,unsigned int reg)275 static unsigned int regmap_mmio_ioread16be(struct regmap_mmio_context *ctx,
276 					   unsigned int reg)
277 {
278 	return ioread16be(ctx->regs + reg);
279 }
280 
regmap_mmio_read32le(struct regmap_mmio_context * ctx,unsigned int reg)281 static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx,
282 				         unsigned int reg)
283 {
284 	return readl(ctx->regs + reg);
285 }
286 
regmap_mmio_read32le_relaxed(struct regmap_mmio_context * ctx,unsigned int reg)287 static unsigned int regmap_mmio_read32le_relaxed(struct regmap_mmio_context *ctx,
288 						 unsigned int reg)
289 {
290 	return readl_relaxed(ctx->regs + reg);
291 }
292 
regmap_mmio_ioread32le(struct regmap_mmio_context * ctx,unsigned int reg)293 static unsigned int regmap_mmio_ioread32le(struct regmap_mmio_context *ctx,
294 					   unsigned int reg)
295 {
296 	return ioread32(ctx->regs + reg);
297 }
298 
regmap_mmio_read32be(struct regmap_mmio_context * ctx,unsigned int reg)299 static unsigned int regmap_mmio_read32be(struct regmap_mmio_context *ctx,
300 				         unsigned int reg)
301 {
302 	return swab32(readl(ctx->regs + reg));
303 }
304 
regmap_mmio_ioread32be(struct regmap_mmio_context * ctx,unsigned int reg)305 static unsigned int regmap_mmio_ioread32be(struct regmap_mmio_context *ctx,
306 					   unsigned int reg)
307 {
308 	return ioread32be(ctx->regs + reg);
309 }
310 
regmap_mmio_read(void * context,unsigned int reg,unsigned int * val)311 static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val)
312 {
313 	struct regmap_mmio_context *ctx = context;
314 	int ret;
315 
316 	if (!IS_ERR(ctx->clk)) {
317 		ret = clk_enable(ctx->clk);
318 		if (ret < 0)
319 			return ret;
320 	}
321 
322 	*val = ctx->reg_read(ctx, reg);
323 
324 	if (!IS_ERR(ctx->clk))
325 		clk_disable(ctx->clk);
326 
327 	return 0;
328 }
329 
regmap_mmio_noinc_read(void * context,unsigned int reg,void * val,size_t val_count)330 static int regmap_mmio_noinc_read(void *context, unsigned int reg,
331 				  void *val, size_t val_count)
332 {
333 	struct regmap_mmio_context *ctx = context;
334 	int ret = 0;
335 
336 	if (!IS_ERR(ctx->clk)) {
337 		ret = clk_enable(ctx->clk);
338 		if (ret < 0)
339 			return ret;
340 	}
341 
342 	switch (ctx->val_bytes) {
343 	case 1:
344 		readsb(ctx->regs + reg, (u8 *)val, val_count);
345 		break;
346 	case 2:
347 		readsw(ctx->regs + reg, (u16 *)val, val_count);
348 		break;
349 	case 4:
350 		readsl(ctx->regs + reg, (u32 *)val, val_count);
351 		break;
352 	default:
353 		ret = -EINVAL;
354 		goto out_clk;
355 	}
356 
357 	/*
358 	 * There are no native, assembly-optimized write single register
359 	 * operations for big endian, so fall back to emulation if this
360 	 * is needed. (Single bytes are fine, they are not affected by
361 	 * endianness.)
362 	 */
363 	if (ctx->big_endian && (ctx->val_bytes > 1)) {
364 		switch (ctx->val_bytes) {
365 		case 2:
366 			swab16_array(val, val_count);
367 			break;
368 		case 4:
369 			swab32_array(val, val_count);
370 			break;
371 		default:
372 			ret = -EINVAL;
373 			break;
374 		}
375 	}
376 
377 out_clk:
378 	if (!IS_ERR(ctx->clk))
379 		clk_disable(ctx->clk);
380 
381 	return ret;
382 }
383 
384 
regmap_mmio_free_context(void * context)385 static void regmap_mmio_free_context(void *context)
386 {
387 	struct regmap_mmio_context *ctx = context;
388 
389 	if (!IS_ERR(ctx->clk)) {
390 		clk_unprepare(ctx->clk);
391 		if (!ctx->attached_clk)
392 			clk_put(ctx->clk);
393 	}
394 	kfree(context);
395 }
396 
397 static const struct regmap_bus regmap_mmio = {
398 	.fast_io = true,
399 	.reg_write = regmap_mmio_write,
400 	.reg_read = regmap_mmio_read,
401 	.reg_noinc_write = regmap_mmio_noinc_write,
402 	.reg_noinc_read = regmap_mmio_noinc_read,
403 	.free_context = regmap_mmio_free_context,
404 	.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
405 };
406 
regmap_mmio_gen_context(struct device * dev,const char * clk_id,void __iomem * regs,const struct regmap_config * config)407 static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
408 					const char *clk_id,
409 					void __iomem *regs,
410 					const struct regmap_config *config)
411 {
412 	struct regmap_mmio_context *ctx;
413 	int min_stride;
414 	int ret;
415 
416 	ret = regmap_mmio_regbits_check(config->reg_bits);
417 	if (ret)
418 		return ERR_PTR(ret);
419 
420 	if (config->pad_bits)
421 		return ERR_PTR(-EINVAL);
422 
423 	min_stride = regmap_mmio_get_min_stride(config->val_bits);
424 	if (min_stride < 0)
425 		return ERR_PTR(min_stride);
426 
427 	if (config->reg_stride && config->reg_stride < min_stride)
428 		return ERR_PTR(-EINVAL);
429 
430 	if (config->use_relaxed_mmio && config->io_port)
431 		return ERR_PTR(-EINVAL);
432 
433 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
434 	if (!ctx)
435 		return ERR_PTR(-ENOMEM);
436 
437 	ctx->regs = regs;
438 	ctx->val_bytes = config->val_bits / 8;
439 	ctx->clk = ERR_PTR(-ENODEV);
440 
441 	switch (regmap_get_val_endian(dev, &regmap_mmio, config)) {
442 	case REGMAP_ENDIAN_DEFAULT:
443 	case REGMAP_ENDIAN_LITTLE:
444 #ifdef __LITTLE_ENDIAN
445 	case REGMAP_ENDIAN_NATIVE:
446 #endif
447 		switch (config->val_bits) {
448 		case 8:
449 			if (config->io_port) {
450 				ctx->reg_read = regmap_mmio_ioread8;
451 				ctx->reg_write = regmap_mmio_iowrite8;
452 			} else if (config->use_relaxed_mmio) {
453 				ctx->reg_read = regmap_mmio_read8_relaxed;
454 				ctx->reg_write = regmap_mmio_write8_relaxed;
455 			} else {
456 				ctx->reg_read = regmap_mmio_read8;
457 				ctx->reg_write = regmap_mmio_write8;
458 			}
459 			break;
460 		case 16:
461 			if (config->io_port) {
462 				ctx->reg_read = regmap_mmio_ioread16le;
463 				ctx->reg_write = regmap_mmio_iowrite16le;
464 			} else if (config->use_relaxed_mmio) {
465 				ctx->reg_read = regmap_mmio_read16le_relaxed;
466 				ctx->reg_write = regmap_mmio_write16le_relaxed;
467 			} else {
468 				ctx->reg_read = regmap_mmio_read16le;
469 				ctx->reg_write = regmap_mmio_write16le;
470 			}
471 			break;
472 		case 32:
473 			if (config->io_port) {
474 				ctx->reg_read = regmap_mmio_ioread32le;
475 				ctx->reg_write = regmap_mmio_iowrite32le;
476 			} else if (config->use_relaxed_mmio) {
477 				ctx->reg_read = regmap_mmio_read32le_relaxed;
478 				ctx->reg_write = regmap_mmio_write32le_relaxed;
479 			} else {
480 				ctx->reg_read = regmap_mmio_read32le;
481 				ctx->reg_write = regmap_mmio_write32le;
482 			}
483 			break;
484 		default:
485 			ret = -EINVAL;
486 			goto err_free;
487 		}
488 		break;
489 	case REGMAP_ENDIAN_BIG:
490 #ifdef __BIG_ENDIAN
491 	case REGMAP_ENDIAN_NATIVE:
492 #endif
493 		ctx->big_endian = true;
494 		switch (config->val_bits) {
495 		case 8:
496 			if (config->io_port) {
497 				ctx->reg_read = regmap_mmio_ioread8;
498 				ctx->reg_write = regmap_mmio_iowrite8;
499 			} else {
500 				ctx->reg_read = regmap_mmio_read8;
501 				ctx->reg_write = regmap_mmio_write8;
502 			}
503 			break;
504 		case 16:
505 			if (config->io_port) {
506 				ctx->reg_read = regmap_mmio_ioread16be;
507 				ctx->reg_write = regmap_mmio_iowrite16be;
508 			} else {
509 				ctx->reg_read = regmap_mmio_read16be;
510 				ctx->reg_write = regmap_mmio_write16be;
511 			}
512 			break;
513 		case 32:
514 			if (config->io_port) {
515 				ctx->reg_read = regmap_mmio_ioread32be;
516 				ctx->reg_write = regmap_mmio_iowrite32be;
517 			} else {
518 				ctx->reg_read = regmap_mmio_read32be;
519 				ctx->reg_write = regmap_mmio_write32be;
520 			}
521 			break;
522 		default:
523 			ret = -EINVAL;
524 			goto err_free;
525 		}
526 		break;
527 	default:
528 		ret = -EINVAL;
529 		goto err_free;
530 	}
531 
532 	if (clk_id == NULL)
533 		return ctx;
534 
535 	ctx->clk = clk_get(dev, clk_id);
536 	if (IS_ERR(ctx->clk)) {
537 		ret = PTR_ERR(ctx->clk);
538 		goto err_free;
539 	}
540 
541 	ret = clk_prepare(ctx->clk);
542 	if (ret < 0) {
543 		clk_put(ctx->clk);
544 		goto err_free;
545 	}
546 
547 	return ctx;
548 
549 err_free:
550 	kfree(ctx);
551 
552 	return ERR_PTR(ret);
553 }
554 
__regmap_init_mmio_clk(struct device * dev,const char * clk_id,void __iomem * regs,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)555 struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,
556 				      void __iomem *regs,
557 				      const struct regmap_config *config,
558 				      struct lock_class_key *lock_key,
559 				      const char *lock_name)
560 {
561 	struct regmap_mmio_context *ctx;
562 
563 	ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
564 	if (IS_ERR(ctx))
565 		return ERR_CAST(ctx);
566 
567 	return __regmap_init(dev, &regmap_mmio, ctx, config,
568 			     lock_key, lock_name);
569 }
570 EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);
571 
__devm_regmap_init_mmio_clk(struct device * dev,const char * clk_id,void __iomem * regs,const struct regmap_config * config,struct lock_class_key * lock_key,const char * lock_name)572 struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,
573 					   const char *clk_id,
574 					   void __iomem *regs,
575 					   const struct regmap_config *config,
576 					   struct lock_class_key *lock_key,
577 					   const char *lock_name)
578 {
579 	struct regmap_mmio_context *ctx;
580 
581 	ctx = regmap_mmio_gen_context(dev, clk_id, regs, config);
582 	if (IS_ERR(ctx))
583 		return ERR_CAST(ctx);
584 
585 	return __devm_regmap_init(dev, &regmap_mmio, ctx, config,
586 				  lock_key, lock_name);
587 }
588 EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);
589 
regmap_mmio_attach_clk(struct regmap * map,struct clk * clk)590 int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk)
591 {
592 	struct regmap_mmio_context *ctx = map->bus_context;
593 
594 	ctx->clk = clk;
595 	ctx->attached_clk = true;
596 
597 	return clk_prepare(ctx->clk);
598 }
599 EXPORT_SYMBOL_GPL(regmap_mmio_attach_clk);
600 
regmap_mmio_detach_clk(struct regmap * map)601 void regmap_mmio_detach_clk(struct regmap *map)
602 {
603 	struct regmap_mmio_context *ctx = map->bus_context;
604 
605 	clk_unprepare(ctx->clk);
606 
607 	ctx->attached_clk = false;
608 	ctx->clk = NULL;
609 }
610 EXPORT_SYMBOL_GPL(regmap_mmio_detach_clk);
611 
612 MODULE_LICENSE("GPL v2");
613