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 | |
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 | */ |
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(size: 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(offset: 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(pool: muram->pool, addr: (unsigned long)vaddr, |
61 | phys: base, size, nid: -1); |
62 | if (ret < 0) { |
63 | pr_err("%s(): MURAM pool add failed\n" , __func__); |
64 | iounmap(addr: 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(objp: 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 | */ |
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 | */ |
105 | unsigned long fman_muram_alloc(struct muram_info *muram, size_t size) |
106 | { |
107 | unsigned long vaddr; |
108 | |
109 | vaddr = gen_pool_alloc(pool: 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 | */ |
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(pool: muram->pool, addr, size); |
132 | } |
133 | |