1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Simple memory allocator for on-board SRAM |
4 | * |
5 | * Maintainer : Sylvain Munaut <tnt@246tNt.com> |
6 | * |
7 | * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com> |
8 | */ |
9 | |
10 | #include <linux/err.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/export.h> |
13 | #include <linux/slab.h> |
14 | #include <linux/spinlock.h> |
15 | #include <linux/string.h> |
16 | #include <linux/ioport.h> |
17 | #include <linux/of.h> |
18 | #include <linux/of_address.h> |
19 | |
20 | #include <asm/io.h> |
21 | #include <asm/mmu.h> |
22 | |
23 | #include <linux/fsl/bestcomm/sram.h> |
24 | |
25 | |
26 | /* Struct keeping our 'state' */ |
27 | struct bcom_sram *bcom_sram = NULL; |
28 | EXPORT_SYMBOL_GPL(bcom_sram); /* needed for inline functions */ |
29 | |
30 | |
31 | /* ======================================================================== */ |
32 | /* Public API */ |
33 | /* ======================================================================== */ |
34 | /* DO NOT USE in interrupts, if needed in irq handler, we should use the |
35 | _irqsave version of the spin_locks */ |
36 | |
37 | int bcom_sram_init(struct device_node *sram_node, char *owner) |
38 | { |
39 | int rv; |
40 | const u32 *regaddr_p; |
41 | struct resource res; |
42 | unsigned int psize; |
43 | |
44 | /* Create our state struct */ |
45 | if (bcom_sram) { |
46 | printk(KERN_ERR "%s: bcom_sram_init: " |
47 | "Already initialized !\n" , owner); |
48 | return -EBUSY; |
49 | } |
50 | |
51 | bcom_sram = kmalloc(size: sizeof(struct bcom_sram), GFP_KERNEL); |
52 | if (!bcom_sram) { |
53 | printk(KERN_ERR "%s: bcom_sram_init: " |
54 | "Couldn't allocate internal state !\n" , owner); |
55 | return -ENOMEM; |
56 | } |
57 | |
58 | /* Get address and size of the sram */ |
59 | rv = of_address_to_resource(dev: sram_node, index: 0, r: &res); |
60 | if (rv) { |
61 | printk(KERN_ERR "%s: bcom_sram_init: " |
62 | "Invalid device node !\n" , owner); |
63 | goto error_free; |
64 | } |
65 | |
66 | bcom_sram->base_phys = res.start; |
67 | bcom_sram->size = resource_size(res: &res); |
68 | |
69 | /* Request region */ |
70 | if (!request_mem_region(res.start, resource_size(&res), owner)) { |
71 | printk(KERN_ERR "%s: bcom_sram_init: " |
72 | "Couldn't request region !\n" , owner); |
73 | rv = -EBUSY; |
74 | goto error_free; |
75 | } |
76 | |
77 | /* Map SRAM */ |
78 | /* sram is not really __iomem */ |
79 | bcom_sram->base_virt = (void *)ioremap(offset: res.start, size: resource_size(res: &res)); |
80 | |
81 | if (!bcom_sram->base_virt) { |
82 | printk(KERN_ERR "%s: bcom_sram_init: " |
83 | "Map error SRAM zone 0x%08lx (0x%0x)!\n" , |
84 | owner, (long)bcom_sram->base_phys, bcom_sram->size ); |
85 | rv = -ENOMEM; |
86 | goto error_release; |
87 | } |
88 | |
89 | /* Create an rheap (defaults to 32 bits word alignment) */ |
90 | bcom_sram->rh = rh_create(4); |
91 | |
92 | /* Attach the free zones */ |
93 | #if 0 |
94 | /* Currently disabled ... for future use only */ |
95 | reg_addr_p = of_get_property(sram_node, "available" , &psize); |
96 | #else |
97 | regaddr_p = NULL; |
98 | psize = 0; |
99 | #endif |
100 | |
101 | if (!regaddr_p || !psize) { |
102 | /* Attach the whole zone */ |
103 | rh_attach_region(bcom_sram->rh, 0, bcom_sram->size); |
104 | } else { |
105 | /* Attach each zone independently */ |
106 | while (psize >= 2 * sizeof(u32)) { |
107 | phys_addr_t zbase = of_translate_address(np: sram_node, addr: regaddr_p); |
108 | rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]); |
109 | regaddr_p += 2; |
110 | psize -= 2 * sizeof(u32); |
111 | } |
112 | } |
113 | |
114 | /* Init our spinlock */ |
115 | spin_lock_init(&bcom_sram->lock); |
116 | |
117 | return 0; |
118 | |
119 | error_release: |
120 | release_mem_region(res.start, resource_size(&res)); |
121 | error_free: |
122 | kfree(objp: bcom_sram); |
123 | bcom_sram = NULL; |
124 | |
125 | return rv; |
126 | } |
127 | EXPORT_SYMBOL_GPL(bcom_sram_init); |
128 | |
129 | void bcom_sram_cleanup(void) |
130 | { |
131 | /* Free resources */ |
132 | if (bcom_sram) { |
133 | rh_destroy(bcom_sram->rh); |
134 | iounmap(addr: (void __iomem *)bcom_sram->base_virt); |
135 | release_mem_region(bcom_sram->base_phys, bcom_sram->size); |
136 | kfree(objp: bcom_sram); |
137 | bcom_sram = NULL; |
138 | } |
139 | } |
140 | EXPORT_SYMBOL_GPL(bcom_sram_cleanup); |
141 | |
142 | void* bcom_sram_alloc(int size, int align, phys_addr_t *phys) |
143 | { |
144 | unsigned long offset; |
145 | |
146 | spin_lock(lock: &bcom_sram->lock); |
147 | offset = rh_alloc_align(bcom_sram->rh, size, align, NULL); |
148 | spin_unlock(lock: &bcom_sram->lock); |
149 | |
150 | if (IS_ERR_VALUE(offset)) |
151 | return NULL; |
152 | |
153 | *phys = bcom_sram->base_phys + offset; |
154 | return bcom_sram->base_virt + offset; |
155 | } |
156 | EXPORT_SYMBOL_GPL(bcom_sram_alloc); |
157 | |
158 | void bcom_sram_free(void *ptr) |
159 | { |
160 | unsigned long offset; |
161 | |
162 | if (!ptr) |
163 | return; |
164 | |
165 | offset = ptr - bcom_sram->base_virt; |
166 | |
167 | spin_lock(lock: &bcom_sram->lock); |
168 | rh_free(bcom_sram->rh, offset); |
169 | spin_unlock(lock: &bcom_sram->lock); |
170 | } |
171 | EXPORT_SYMBOL_GPL(bcom_sram_free); |
172 | |