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