xref: /openbmc/linux/arch/powerpc/sysdev/fsl_lbc.c (revision 22246614)
1 /*
2  * Freescale LBC and UPM routines.
3  *
4  * Copyright (c) 2007-2008  MontaVista Software, Inc.
5  *
6  * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13 
14 #include <linux/kernel.h>
15 #include <linux/of.h>
16 #include <asm/fsl_lbc.h>
17 
18 spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
19 
20 struct fsl_lbc_regs __iomem *fsl_lbc_regs;
21 EXPORT_SYMBOL(fsl_lbc_regs);
22 
23 static char __initdata *compat_lbc[] = {
24 	"fsl,pq2-localbus",
25 	"fsl,pq2pro-localbus",
26 	"fsl,pq3-localbus",
27 	"fsl,elbc",
28 };
29 
30 static int __init fsl_lbc_init(void)
31 {
32 	struct device_node *lbus;
33 	int i;
34 
35 	for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
36 		lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
37 		if (lbus)
38 			goto found;
39 	}
40 	return -ENODEV;
41 
42 found:
43 	fsl_lbc_regs = of_iomap(lbus, 0);
44 	of_node_put(lbus);
45 	if (!fsl_lbc_regs)
46 		return -ENOMEM;
47 	return 0;
48 }
49 arch_initcall(fsl_lbc_init);
50 
51 /**
52  * fsl_lbc_find - find Localbus bank
53  * @addr_base:	base address of the memory bank
54  *
55  * This function walks LBC banks comparing "Base address" field of the BR
56  * registers with the supplied addr_base argument. When bases match this
57  * function returns bank number (starting with 0), otherwise it returns
58  * appropriate errno value.
59  */
60 int fsl_lbc_find(phys_addr_t addr_base)
61 {
62 	int i;
63 
64 	if (!fsl_lbc_regs)
65 		return -ENODEV;
66 
67 	for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
68 		__be32 br = in_be32(&fsl_lbc_regs->bank[i].br);
69 		__be32 or = in_be32(&fsl_lbc_regs->bank[i].or);
70 
71 		if (br & BR_V && (br & or & BR_BA) == addr_base)
72 			return i;
73 	}
74 
75 	return -ENOENT;
76 }
77 EXPORT_SYMBOL(fsl_lbc_find);
78 
79 /**
80  * fsl_upm_find - find pre-programmed UPM via base address
81  * @addr_base:	base address of the memory bank controlled by the UPM
82  * @upm:	pointer to the allocated fsl_upm structure
83  *
84  * This function fills fsl_upm structure so you can use it with the rest of
85  * UPM API. On success this function returns 0, otherwise it returns
86  * appropriate errno value.
87  */
88 int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
89 {
90 	int bank;
91 	__be32 br;
92 
93 	bank = fsl_lbc_find(addr_base);
94 	if (bank < 0)
95 		return bank;
96 
97 	br = in_be32(&fsl_lbc_regs->bank[bank].br);
98 
99 	switch (br & BR_MSEL) {
100 	case BR_MS_UPMA:
101 		upm->mxmr = &fsl_lbc_regs->mamr;
102 		break;
103 	case BR_MS_UPMB:
104 		upm->mxmr = &fsl_lbc_regs->mbmr;
105 		break;
106 	case BR_MS_UPMC:
107 		upm->mxmr = &fsl_lbc_regs->mcmr;
108 		break;
109 	default:
110 		return -EINVAL;
111 	}
112 
113 	switch (br & BR_PS) {
114 	case BR_PS_8:
115 		upm->width = 8;
116 		break;
117 	case BR_PS_16:
118 		upm->width = 16;
119 		break;
120 	case BR_PS_32:
121 		upm->width = 32;
122 		break;
123 	default:
124 		return -EINVAL;
125 	}
126 
127 	return 0;
128 }
129 EXPORT_SYMBOL(fsl_upm_find);
130