]>
Commit | Line | Data |
---|---|---|
1f9c0a77 CM |
1 | /* Copyright (c) 2009 - 2016 Freescale Semiconductor, Inc. |
2 | * | |
3 | * Redistribution and use in source and binary forms, with or without | |
4 | * modification, are permitted provided that the following conditions are met: | |
5 | * * Redistributions of source code must retain the above copyright | |
6 | * notice, this list of conditions and the following disclaimer. | |
7 | * * Redistributions in binary form must reproduce the above copyright | |
8 | * notice, this list of conditions and the following disclaimer in the | |
9 | * documentation and/or other materials provided with the distribution. | |
10 | * * Neither the name of Freescale Semiconductor nor the | |
11 | * names of its contributors may be used to endorse or promote products | |
12 | * derived from this software without specific prior written permission. | |
13 | * | |
14 | * ALTERNATIVELY, this software may be distributed under the terms of the | |
15 | * GNU General Public License ("GPL") as published by the Free Software | |
16 | * Foundation, either version 2 of that License or (at your option) any | |
17 | * later version. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | |
20 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
22 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | |
23 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
26 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | |
30 | ||
31 | #include "bman_priv.h" | |
32 | ||
33 | u16 bman_ip_rev; | |
34 | EXPORT_SYMBOL(bman_ip_rev); | |
35 | ||
36 | /* Register offsets */ | |
37 | #define REG_FBPR_FPC 0x0800 | |
38 | #define REG_ECSR 0x0a00 | |
39 | #define REG_ECIR 0x0a04 | |
40 | #define REG_EADR 0x0a08 | |
41 | #define REG_EDATA(n) (0x0a10 + ((n) * 0x04)) | |
42 | #define REG_SBEC(n) (0x0a80 + ((n) * 0x04)) | |
43 | #define REG_IP_REV_1 0x0bf8 | |
44 | #define REG_IP_REV_2 0x0bfc | |
45 | #define REG_FBPR_BARE 0x0c00 | |
46 | #define REG_FBPR_BAR 0x0c04 | |
47 | #define REG_FBPR_AR 0x0c10 | |
48 | #define REG_SRCIDR 0x0d04 | |
49 | #define REG_LIODNR 0x0d08 | |
50 | #define REG_ERR_ISR 0x0e00 | |
51 | #define REG_ERR_IER 0x0e04 | |
52 | #define REG_ERR_ISDR 0x0e08 | |
53 | ||
54 | /* Used by all error interrupt registers except 'inhibit' */ | |
55 | #define BM_EIRQ_IVCI 0x00000010 /* Invalid Command Verb */ | |
56 | #define BM_EIRQ_FLWI 0x00000008 /* FBPR Low Watermark */ | |
57 | #define BM_EIRQ_MBEI 0x00000004 /* Multi-bit ECC Error */ | |
58 | #define BM_EIRQ_SBEI 0x00000002 /* Single-bit ECC Error */ | |
59 | #define BM_EIRQ_BSCN 0x00000001 /* pool State Change Notification */ | |
60 | ||
61 | struct bman_hwerr_txt { | |
62 | u32 mask; | |
63 | const char *txt; | |
64 | }; | |
65 | ||
66 | static const struct bman_hwerr_txt bman_hwerr_txts[] = { | |
67 | { BM_EIRQ_IVCI, "Invalid Command Verb" }, | |
68 | { BM_EIRQ_FLWI, "FBPR Low Watermark" }, | |
69 | { BM_EIRQ_MBEI, "Multi-bit ECC Error" }, | |
70 | { BM_EIRQ_SBEI, "Single-bit ECC Error" }, | |
71 | { BM_EIRQ_BSCN, "Pool State Change Notification" }, | |
72 | }; | |
73 | ||
74 | /* Only trigger low water mark interrupt once only */ | |
75 | #define BMAN_ERRS_TO_DISABLE BM_EIRQ_FLWI | |
76 | ||
77 | /* Pointer to the start of the BMan's CCSR space */ | |
78 | static u32 __iomem *bm_ccsr_start; | |
79 | ||
80 | static inline u32 bm_ccsr_in(u32 offset) | |
81 | { | |
82 | return ioread32be(bm_ccsr_start + offset/4); | |
83 | } | |
84 | static inline void bm_ccsr_out(u32 offset, u32 val) | |
85 | { | |
86 | iowrite32be(val, bm_ccsr_start + offset/4); | |
87 | } | |
88 | ||
89 | static void bm_get_version(u16 *id, u8 *major, u8 *minor) | |
90 | { | |
91 | u32 v = bm_ccsr_in(REG_IP_REV_1); | |
92 | *id = (v >> 16); | |
93 | *major = (v >> 8) & 0xff; | |
94 | *minor = v & 0xff; | |
95 | } | |
96 | ||
97 | /* signal transactions for FBPRs with higher priority */ | |
98 | #define FBPR_AR_RPRIO_HI BIT(30) | |
99 | ||
100 | static void bm_set_memory(u64 ba, u32 size) | |
101 | { | |
102 | u32 exp = ilog2(size); | |
103 | /* choke if size isn't within range */ | |
104 | DPAA_ASSERT(size >= 4096 && size <= 1024*1024*1024 && | |
105 | is_power_of_2(size)); | |
106 | /* choke if '[e]ba' has lower-alignment than 'size' */ | |
107 | DPAA_ASSERT(!(ba & (size - 1))); | |
108 | bm_ccsr_out(REG_FBPR_BARE, upper_32_bits(ba)); | |
109 | bm_ccsr_out(REG_FBPR_BAR, lower_32_bits(ba)); | |
110 | bm_ccsr_out(REG_FBPR_AR, exp - 1); | |
111 | } | |
112 | ||
113 | /* | |
114 | * Location and size of BMan private memory | |
115 | * | |
116 | * Ideally we would use the DMA API to turn rmem->base into a DMA address | |
117 | * (especially if iommu translations ever get involved). Unfortunately, the | |
118 | * DMA API currently does not allow mapping anything that is not backed with | |
119 | * a struct page. | |
120 | */ | |
121 | static dma_addr_t fbpr_a; | |
122 | static size_t fbpr_sz; | |
123 | ||
124 | static int bman_fbpr(struct reserved_mem *rmem) | |
125 | { | |
126 | fbpr_a = rmem->base; | |
127 | fbpr_sz = rmem->size; | |
128 | ||
129 | WARN_ON(!(fbpr_a && fbpr_sz)); | |
130 | ||
131 | return 0; | |
132 | } | |
133 | RESERVEDMEM_OF_DECLARE(bman_fbpr, "fsl,bman-fbpr", bman_fbpr); | |
134 | ||
135 | static irqreturn_t bman_isr(int irq, void *ptr) | |
136 | { | |
137 | u32 isr_val, ier_val, ecsr_val, isr_mask, i; | |
138 | struct device *dev = ptr; | |
139 | ||
140 | ier_val = bm_ccsr_in(REG_ERR_IER); | |
141 | isr_val = bm_ccsr_in(REG_ERR_ISR); | |
142 | ecsr_val = bm_ccsr_in(REG_ECSR); | |
143 | isr_mask = isr_val & ier_val; | |
144 | ||
145 | if (!isr_mask) | |
146 | return IRQ_NONE; | |
147 | ||
148 | for (i = 0; i < ARRAY_SIZE(bman_hwerr_txts); i++) { | |
149 | if (bman_hwerr_txts[i].mask & isr_mask) { | |
150 | dev_err_ratelimited(dev, "ErrInt: %s\n", | |
151 | bman_hwerr_txts[i].txt); | |
152 | if (bman_hwerr_txts[i].mask & ecsr_val) { | |
153 | /* Re-arm error capture registers */ | |
154 | bm_ccsr_out(REG_ECSR, ecsr_val); | |
155 | } | |
156 | if (bman_hwerr_txts[i].mask & BMAN_ERRS_TO_DISABLE) { | |
157 | dev_dbg(dev, "Disabling error 0x%x\n", | |
158 | bman_hwerr_txts[i].mask); | |
159 | ier_val &= ~bman_hwerr_txts[i].mask; | |
160 | bm_ccsr_out(REG_ERR_IER, ier_val); | |
161 | } | |
162 | } | |
163 | } | |
164 | bm_ccsr_out(REG_ERR_ISR, isr_val); | |
165 | ||
166 | return IRQ_HANDLED; | |
167 | } | |
168 | ||
169 | static int fsl_bman_probe(struct platform_device *pdev) | |
170 | { | |
171 | int ret, err_irq; | |
172 | struct device *dev = &pdev->dev; | |
173 | struct device_node *node = dev->of_node; | |
174 | struct resource *res; | |
175 | u16 id, bm_pool_cnt; | |
176 | u8 major, minor; | |
177 | ||
178 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
179 | if (!res) { | |
37c342cb RH |
180 | dev_err(dev, "Can't get %pOF property 'IORESOURCE_MEM'\n", |
181 | node); | |
1f9c0a77 CM |
182 | return -ENXIO; |
183 | } | |
d7544424 | 184 | bm_ccsr_start = devm_ioremap(dev, res->start, resource_size(res)); |
1f9c0a77 CM |
185 | if (!bm_ccsr_start) |
186 | return -ENXIO; | |
187 | ||
188 | bm_get_version(&id, &major, &minor); | |
189 | if (major == 1 && minor == 0) { | |
190 | bman_ip_rev = BMAN_REV10; | |
191 | bm_pool_cnt = BM_POOL_MAX; | |
192 | } else if (major == 2 && minor == 0) { | |
193 | bman_ip_rev = BMAN_REV20; | |
194 | bm_pool_cnt = 8; | |
195 | } else if (major == 2 && minor == 1) { | |
196 | bman_ip_rev = BMAN_REV21; | |
197 | bm_pool_cnt = BM_POOL_MAX; | |
198 | } else { | |
199 | dev_err(dev, "Unknown Bman version:%04x,%02x,%02x\n", | |
200 | id, major, minor); | |
201 | return -ENODEV; | |
202 | } | |
203 | ||
204 | bm_set_memory(fbpr_a, fbpr_sz); | |
205 | ||
206 | err_irq = platform_get_irq(pdev, 0); | |
207 | if (err_irq <= 0) { | |
37c342cb | 208 | dev_info(dev, "Can't get %pOF IRQ\n", node); |
1f9c0a77 CM |
209 | return -ENODEV; |
210 | } | |
211 | ret = devm_request_irq(dev, err_irq, bman_isr, IRQF_SHARED, "bman-err", | |
212 | dev); | |
213 | if (ret) { | |
37c342cb RH |
214 | dev_err(dev, "devm_request_irq() failed %d for '%pOF'\n", |
215 | ret, node); | |
1f9c0a77 CM |
216 | return ret; |
217 | } | |
218 | /* Disable Buffer Pool State Change */ | |
219 | bm_ccsr_out(REG_ERR_ISDR, BM_EIRQ_BSCN); | |
220 | /* | |
221 | * Write-to-clear any stale bits, (eg. starvation being asserted prior | |
222 | * to resource allocation during driver init). | |
223 | */ | |
224 | bm_ccsr_out(REG_ERR_ISR, 0xffffffff); | |
225 | /* Enable Error Interrupts */ | |
226 | bm_ccsr_out(REG_ERR_IER, 0xffffffff); | |
227 | ||
228 | bm_bpalloc = devm_gen_pool_create(dev, 0, -1, "bman-bpalloc"); | |
229 | if (IS_ERR(bm_bpalloc)) { | |
230 | ret = PTR_ERR(bm_bpalloc); | |
231 | dev_err(dev, "bman-bpalloc pool init failed (%d)\n", ret); | |
232 | return ret; | |
233 | } | |
234 | ||
235 | /* seed BMan resource pool */ | |
236 | ret = gen_pool_add(bm_bpalloc, DPAA_GENALLOC_OFF, bm_pool_cnt, -1); | |
237 | if (ret) { | |
238 | dev_err(dev, "Failed to seed BPID range [%d..%d] (%d)\n", | |
239 | 0, bm_pool_cnt - 1, ret); | |
240 | return ret; | |
241 | } | |
242 | ||
243 | return 0; | |
244 | }; | |
245 | ||
246 | static const struct of_device_id fsl_bman_ids[] = { | |
247 | { | |
248 | .compatible = "fsl,bman", | |
249 | }, | |
250 | {} | |
251 | }; | |
252 | ||
253 | static struct platform_driver fsl_bman_driver = { | |
254 | .driver = { | |
255 | .name = KBUILD_MODNAME, | |
256 | .of_match_table = fsl_bman_ids, | |
257 | .suppress_bind_attrs = true, | |
258 | }, | |
259 | .probe = fsl_bman_probe, | |
260 | }; | |
261 | ||
262 | builtin_platform_driver(fsl_bman_driver); |