1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
2 /*
3  * Copyright 2008 - 2015 Freescale Semiconductor Inc.
4  */
5 
6 #include "fman_muram.h"
7 
8 #include <linux/io.h>
9 #include <linux/slab.h>
10 #include <linux/genalloc.h>
11 
12 struct muram_info {
13 	struct gen_pool *pool;
14 	void __iomem *vbase;
15 	size_t size;
16 	phys_addr_t pbase;
17 };
18 
fman_muram_vbase_to_offset(struct muram_info * muram,unsigned long vaddr)19 static unsigned long fman_muram_vbase_to_offset(struct muram_info *muram,
20 						unsigned long vaddr)
21 {
22 	return vaddr - (unsigned long)muram->vbase;
23 }
24 
25 /**
26  * fman_muram_init
27  * @base:	Pointer to base of memory mapped FM-MURAM.
28  * @size:	Size of the FM-MURAM partition.
29  *
30  * Creates partition in the MURAM.
31  * The routine returns a pointer to the MURAM partition.
32  * This pointer must be passed as to all other FM-MURAM function calls.
33  * No actual initialization or configuration of FM_MURAM hardware is done by
34  * this routine.
35  *
36  * Return: pointer to FM-MURAM object, or NULL for Failure.
37  */
fman_muram_init(phys_addr_t base,size_t size)38 struct muram_info *fman_muram_init(phys_addr_t base, size_t size)
39 {
40 	struct muram_info *muram;
41 	void __iomem *vaddr;
42 	int ret;
43 
44 	muram = kzalloc(sizeof(*muram), GFP_KERNEL);
45 	if (!muram)
46 		return NULL;
47 
48 	muram->pool = gen_pool_create(ilog2(64), -1);
49 	if (!muram->pool) {
50 		pr_err("%s(): MURAM pool create failed\n", __func__);
51 		goto  muram_free;
52 	}
53 
54 	vaddr = ioremap(base, size);
55 	if (!vaddr) {
56 		pr_err("%s(): MURAM ioremap failed\n", __func__);
57 		goto pool_destroy;
58 	}
59 
60 	ret = gen_pool_add_virt(muram->pool, (unsigned long)vaddr,
61 				base, size, -1);
62 	if (ret < 0) {
63 		pr_err("%s(): MURAM pool add failed\n", __func__);
64 		iounmap(vaddr);
65 		goto pool_destroy;
66 	}
67 
68 	memset_io(vaddr, 0, (int)size);
69 
70 	muram->vbase = vaddr;
71 	muram->pbase = base;
72 	return muram;
73 
74 pool_destroy:
75 	gen_pool_destroy(muram->pool);
76 muram_free:
77 	kfree(muram);
78 	return NULL;
79 }
80 
81 /**
82  * fman_muram_offset_to_vbase
83  * @muram:	FM-MURAM module pointer.
84  * @offset:	the offset of the memory block
85  *
86  * Gives the address of the memory region from specific offset
87  *
88  * Return: The address of the memory block
89  */
fman_muram_offset_to_vbase(struct muram_info * muram,unsigned long offset)90 unsigned long fman_muram_offset_to_vbase(struct muram_info *muram,
91 					 unsigned long offset)
92 {
93 	return offset + (unsigned long)muram->vbase;
94 }
95 
96 /**
97  * fman_muram_alloc
98  * @muram:	FM-MURAM module pointer.
99  * @size:	Size of the memory to be allocated.
100  *
101  * Allocate some memory from FM-MURAM partition.
102  *
103  * Return: address of the allocated memory; NULL otherwise.
104  */
fman_muram_alloc(struct muram_info * muram,size_t size)105 unsigned long fman_muram_alloc(struct muram_info *muram, size_t size)
106 {
107 	unsigned long vaddr;
108 
109 	vaddr = gen_pool_alloc(muram->pool, size);
110 	if (!vaddr)
111 		return -ENOMEM;
112 
113 	memset_io((void __iomem *)vaddr, 0, size);
114 
115 	return fman_muram_vbase_to_offset(muram, vaddr);
116 }
117 
118 /**
119  * fman_muram_free_mem
120  * @muram:	FM-MURAM module pointer.
121  * @offset:	offset of the memory region to be freed.
122  * @size:	size of the memory to be freed.
123  *
124  * Free an allocated memory from FM-MURAM partition.
125  */
fman_muram_free_mem(struct muram_info * muram,unsigned long offset,size_t size)126 void fman_muram_free_mem(struct muram_info *muram, unsigned long offset,
127 			 size_t size)
128 {
129 	unsigned long addr = fman_muram_offset_to_vbase(muram, offset);
130 
131 	gen_pool_free(muram->pool, addr, size);
132 }
133