• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/powerpc/sysdev/
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/init.h>
15#include <linux/module.h>
16#include <linux/kernel.h>
17#include <linux/compiler.h>
18#include <linux/spinlock.h>
19#include <linux/types.h>
20#include <linux/io.h>
21#include <linux/of.h>
22#include <asm/prom.h>
23#include <asm/fsl_lbc.h>
24
25static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
26static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
27
28static char __initdata *compat_lbc[] = {
29	"fsl,pq2-localbus",
30	"fsl,pq2pro-localbus",
31	"fsl,pq3-localbus",
32	"fsl,elbc",
33};
34
35static int __init fsl_lbc_init(void)
36{
37	struct device_node *lbus;
38	int i;
39
40	for (i = 0; i < ARRAY_SIZE(compat_lbc); i++) {
41		lbus = of_find_compatible_node(NULL, NULL, compat_lbc[i]);
42		if (lbus)
43			goto found;
44	}
45	return -ENODEV;
46
47found:
48	fsl_lbc_regs = of_iomap(lbus, 0);
49	of_node_put(lbus);
50	if (!fsl_lbc_regs)
51		return -ENOMEM;
52	return 0;
53}
54arch_initcall(fsl_lbc_init);
55
56/**
57 * fsl_lbc_find - find Localbus bank
58 * @addr_base:	base address of the memory bank
59 *
60 * This function walks LBC banks comparing "Base address" field of the BR
61 * registers with the supplied addr_base argument. When bases match this
62 * function returns bank number (starting with 0), otherwise it returns
63 * appropriate errno value.
64 */
65int fsl_lbc_find(phys_addr_t addr_base)
66{
67	int i;
68
69	if (!fsl_lbc_regs)
70		return -ENODEV;
71
72	for (i = 0; i < ARRAY_SIZE(fsl_lbc_regs->bank); i++) {
73		__be32 br = in_be32(&fsl_lbc_regs->bank[i].br);
74		__be32 or = in_be32(&fsl_lbc_regs->bank[i].or);
75
76		if (br & BR_V && (br & or & BR_BA) == addr_base)
77			return i;
78	}
79
80	return -ENOENT;
81}
82EXPORT_SYMBOL(fsl_lbc_find);
83
84/**
85 * fsl_upm_find - find pre-programmed UPM via base address
86 * @addr_base:	base address of the memory bank controlled by the UPM
87 * @upm:	pointer to the allocated fsl_upm structure
88 *
89 * This function fills fsl_upm structure so you can use it with the rest of
90 * UPM API. On success this function returns 0, otherwise it returns
91 * appropriate errno value.
92 */
93int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
94{
95	int bank;
96	__be32 br;
97
98	bank = fsl_lbc_find(addr_base);
99	if (bank < 0)
100		return bank;
101
102	br = in_be32(&fsl_lbc_regs->bank[bank].br);
103
104	switch (br & BR_MSEL) {
105	case BR_MS_UPMA:
106		upm->mxmr = &fsl_lbc_regs->mamr;
107		break;
108	case BR_MS_UPMB:
109		upm->mxmr = &fsl_lbc_regs->mbmr;
110		break;
111	case BR_MS_UPMC:
112		upm->mxmr = &fsl_lbc_regs->mcmr;
113		break;
114	default:
115		return -EINVAL;
116	}
117
118	switch (br & BR_PS) {
119	case BR_PS_8:
120		upm->width = 8;
121		break;
122	case BR_PS_16:
123		upm->width = 16;
124		break;
125	case BR_PS_32:
126		upm->width = 32;
127		break;
128	default:
129		return -EINVAL;
130	}
131
132	return 0;
133}
134EXPORT_SYMBOL(fsl_upm_find);
135
136/**
137 * fsl_upm_run_pattern - actually run an UPM pattern
138 * @upm:	pointer to the fsl_upm structure obtained via fsl_upm_find
139 * @io_base:	remapped pointer to where memory access should happen
140 * @mar:	MAR register content during pattern execution
141 *
142 * This function triggers dummy write to the memory specified by the io_base,
143 * thus UPM pattern actually executed. Note that mar usage depends on the
144 * pre-programmed AMX bits in the UPM RAM.
145 */
146int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
147{
148	int ret = 0;
149	unsigned long flags;
150
151	spin_lock_irqsave(&fsl_lbc_lock, flags);
152
153	out_be32(&fsl_lbc_regs->mar, mar);
154
155	switch (upm->width) {
156	case 8:
157		out_8(io_base, 0x0);
158		break;
159	case 16:
160		out_be16(io_base, 0x0);
161		break;
162	case 32:
163		out_be32(io_base, 0x0);
164		break;
165	default:
166		ret = -EINVAL;
167		break;
168	}
169
170	spin_unlock_irqrestore(&fsl_lbc_lock, flags);
171
172	return ret;
173}
174EXPORT_SYMBOL(fsl_upm_run_pattern);
175