aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2008-04-11 13:03:40 -0400
committerKumar Gala <galak@kernel.crashing.org>2008-04-17 02:01:38 -0400
commitacaa7aa30a8cdf7276945629f56d6daf30beb157 (patch)
tree8fa70d5f1417f3d6f48dbb4ceb671e48ad0f752d
parentd4a32fe40a57d1a47d6ec3ebbf3d3153b12baa2c (diff)
[POWERPC] fsl_lbc: implement few UPM routines
Freescale UPM can be used to adjust localbus timings or to generate orbitrary, pre-programmed "patterns" on the external Localbus signals. This patch implements few routines so drivers could work with UPMs in safe and generic manner. So far there is just one user of these routines: Freescale UPM NAND driver. Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r--arch/powerpc/Kconfig5
-rw-r--r--arch/powerpc/sysdev/Makefile1
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c129
-rw-r--r--include/asm-powerpc/fsl_lbc.h88
4 files changed, 223 insertions, 0 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d1fe425cfb5..7f2f126d1c2 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -520,6 +520,11 @@ config FSL_PCI
520config 4xx_SOC 520config 4xx_SOC
521 bool 521 bool
522 522
523config FSL_LBC
524 bool
525 help
526 Freescale Localbus support
527
523# Yes MCA RS/6000s exist but Linux-PPC does not currently support any 528# Yes MCA RS/6000s exist but Linux-PPC does not currently support any
524config MCA 529config MCA
525 bool 530 bool
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 851a0be7194..6d386d0071a 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_U3_DART) += dart_iommu.o
12obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o 12obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
13obj-$(CONFIG_FSL_SOC) += fsl_soc.o 13obj-$(CONFIG_FSL_SOC) += fsl_soc.o
14obj-$(CONFIG_FSL_PCI) += fsl_pci.o 14obj-$(CONFIG_FSL_PCI) += fsl_pci.o
15obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
15obj-$(CONFIG_RAPIDIO) += fsl_rio.o 16obj-$(CONFIG_RAPIDIO) += fsl_rio.o
16obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o 17obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
17obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ 18obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
new file mode 100644
index 00000000000..422c8faef59
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -0,0 +1,129 @@
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
18spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
19
20struct fsl_lbc_regs __iomem *fsl_lbc_regs;
21EXPORT_SYMBOL(fsl_lbc_regs);
22
23static char __initdata *compat_lbc[] = {
24 "fsl,pq2-localbus",
25 "fsl,pq2pro-localbus",
26 "fsl,pq3-localbus",
27 "fsl,elbc",
28};
29
30static 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
42found:
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}
49arch_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 */
60int 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}
77EXPORT_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 */
88int 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}
129EXPORT_SYMBOL(fsl_upm_find);
diff --git a/include/asm-powerpc/fsl_lbc.h b/include/asm-powerpc/fsl_lbc.h
index 13a3c28e1e1..303f5484c05 100644
--- a/include/asm-powerpc/fsl_lbc.h
+++ b/include/asm-powerpc/fsl_lbc.h
@@ -24,6 +24,8 @@
24#define __ASM_FSL_LBC_H 24#define __ASM_FSL_LBC_H
25 25
26#include <linux/types.h> 26#include <linux/types.h>
27#include <linux/spinlock.h>
28#include <asm/io.h>
27 29
28struct fsl_lbc_bank { 30struct fsl_lbc_bank {
29 __be32 br; /**< Base Register */ 31 __be32 br; /**< Base Register */
@@ -98,6 +100,11 @@ struct fsl_lbc_regs {
98 __be32 mar; /**< UPM Address Register */ 100 __be32 mar; /**< UPM Address Register */
99 u8 res1[0x4]; 101 u8 res1[0x4];
100 __be32 mamr; /**< UPMA Mode Register */ 102 __be32 mamr; /**< UPMA Mode Register */
103#define MxMR_OP_NO (0 << 28) /**< normal operation */
104#define MxMR_OP_WA (1 << 28) /**< write array */
105#define MxMR_OP_RA (2 << 28) /**< read array */
106#define MxMR_OP_RP (3 << 28) /**< run pattern */
107#define MxMR_MAD 0x3f /**< machine address */
101 __be32 mbmr; /**< UPMB Mode Register */ 108 __be32 mbmr; /**< UPMB Mode Register */
102 __be32 mcmr; /**< UPMC Mode Register */ 109 __be32 mcmr; /**< UPMC Mode Register */
103 u8 res2[0x8]; 110 u8 res2[0x8];
@@ -220,4 +227,85 @@ struct fsl_lbc_regs {
220 u8 res8[0xF00]; 227 u8 res8[0xF00];
221}; 228};
222 229
230extern struct fsl_lbc_regs __iomem *fsl_lbc_regs;
231extern spinlock_t fsl_lbc_lock;
232
233/*
234 * FSL UPM routines
235 */
236struct fsl_upm {
237 __be32 __iomem *mxmr;
238 int width;
239};
240
241extern int fsl_lbc_find(phys_addr_t addr_base);
242extern int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm);
243
244/**
245 * fsl_upm_start_pattern - start UPM patterns execution
246 * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find
247 * @pat_offset: UPM pattern offset for the command to be executed
248 *
249 * This routine programmes UPM so the next memory access that hits an UPM
250 * will trigger pattern execution, starting at pat_offset.
251 */
252static inline void fsl_upm_start_pattern(struct fsl_upm *upm, u8 pat_offset)
253{
254 clrsetbits_be32(upm->mxmr, MxMR_MAD, MxMR_OP_RP | pat_offset);
255}
256
257/**
258 * fsl_upm_end_pattern - end UPM patterns execution
259 * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find
260 *
261 * This routine reverts UPM to normal operation mode.
262 */
263static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
264{
265 clrbits32(upm->mxmr, MxMR_OP_RP);
266
267 while (in_be32(upm->mxmr) & MxMR_OP_RP)
268 cpu_relax();
269}
270
271/**
272 * fsl_upm_run_pattern - actually run an UPM pattern
273 * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find
274 * @io_base: remapped pointer to where memory access should happen
275 * @mar: MAR register content during pattern execution
276 *
277 * This function triggers dummy write to the memory specified by the io_base,
278 * thus UPM pattern actually executed. Note that mar usage depends on the
279 * pre-programmed AMX bits in the UPM RAM.
280 */
281static inline int fsl_upm_run_pattern(struct fsl_upm *upm,
282 void __iomem *io_base, u32 mar)
283{
284 int ret = 0;
285 unsigned long flags;
286
287 spin_lock_irqsave(&fsl_lbc_lock, flags);
288
289 out_be32(&fsl_lbc_regs->mar, mar << (32 - upm->width));
290
291 switch (upm->width) {
292 case 8:
293 out_8(io_base, 0x0);
294 break;
295 case 16:
296 out_be16(io_base, 0x0);
297 break;
298 case 32:
299 out_be32(io_base, 0x0);
300 break;
301 default:
302 ret = -EINVAL;
303 break;
304 }
305
306 spin_unlock_irqrestore(&fsl_lbc_lock, flags);
307
308 return ret;
309}
310
223#endif /* __ASM_FSL_LBC_H */ 311#endif /* __ASM_FSL_LBC_H */