Commit | Line | Data |
---|---|---|
acaa7aa3 AV |
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); |