aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Neuendorffer <stephen.neuendorffer@xilinx.com>2008-05-06 14:29:17 -0400
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2008-05-29 08:06:56 -0400
commitb786af117b360843349cf66165c4efa0217ca2a7 (patch)
tree713c515b49003fe2b593703820169ffc326ed4bb
parentacf464817d5e7be9fb67aec4027dbee0ac9be17a (diff)
[POWERPC] Refactor DCR code
Previously, DCR support was configured at compile time to either use MMIO or native dcr instructions. Although this works for most platforms, it fails on FPGA platforms: 1) Systems may include more than one DCR bus. 2) Systems may be native DCR capable and still use memory mapped DCR interface. This patch provides runtime support based on the device trees for the case where CONFIG_PPC_DCR_MMIO and CONFIG_PPC_DCR_NATIVE are both selected. Previously, this was a poorly defined configuration, which happened to provide NATIVE support. The runtime selection is made based on the dcr-controller having a 'dcr-access-method' attribute in the device tree. If only one of the above options is selected, then the code uses #defines to select only the used code in order to avoid introducing overhead in existing usage. Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
-rw-r--r--arch/powerpc/sysdev/dcr.c154
-rw-r--r--include/asm-powerpc/dcr-generic.h49
-rw-r--r--include/asm-powerpc/dcr-mmio.h20
-rw-r--r--include/asm-powerpc/dcr-native.h16
-rw-r--r--include/asm-powerpc/dcr.h39
5 files changed, 231 insertions, 47 deletions
diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c
index 437e48d3ae33..5f39a79b0660 100644
--- a/arch/powerpc/sysdev/dcr.c
+++ b/arch/powerpc/sysdev/dcr.c
@@ -23,6 +23,105 @@
23#include <asm/prom.h> 23#include <asm/prom.h>
24#include <asm/dcr.h> 24#include <asm/dcr.h>
25 25
26static struct device_node *find_dcr_parent(struct device_node *node)
27{
28 struct device_node *par, *tmp;
29 const u32 *p;
30
31 for (par = of_node_get(node); par;) {
32 if (of_get_property(par, "dcr-controller", NULL))
33 break;
34 p = of_get_property(par, "dcr-parent", NULL);
35 tmp = par;
36 if (p == NULL)
37 par = of_get_parent(par);
38 else
39 par = of_find_node_by_phandle(*p);
40 of_node_put(tmp);
41 }
42 return par;
43}
44
45#if defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO)
46
47bool dcr_map_ok_generic(dcr_host_t host)
48{
49 if (host.type == DCR_HOST_NATIVE)
50 return dcr_map_ok_native(host.host.native);
51 else if (host.type == DCR_HOST_MMIO)
52 return dcr_map_ok_mmio(host.host.mmio);
53 else
54 return 0;
55}
56EXPORT_SYMBOL_GPL(dcr_map_ok_generic);
57
58dcr_host_t dcr_map_generic(struct device_node *dev,
59 unsigned int dcr_n,
60 unsigned int dcr_c)
61{
62 dcr_host_t host;
63 struct device_node *dp;
64 const char *prop;
65
66 host.type = DCR_HOST_INVALID;
67
68 dp = find_dcr_parent(dev);
69 if (dp == NULL)
70 return host;
71
72 prop = of_get_property(dp, "dcr-access-method", NULL);
73
74 pr_debug("dcr_map_generic(dcr-access-method = %s)\n", prop);
75
76 if (!strcmp(prop, "native")) {
77 host.type = DCR_HOST_NATIVE;
78 host.host.native = dcr_map_native(dev, dcr_n, dcr_c);
79 } else if (!strcmp(prop, "mmio")) {
80 host.type = DCR_HOST_MMIO;
81 host.host.mmio = dcr_map_mmio(dev, dcr_n, dcr_c);
82 }
83
84 of_node_put(dp);
85 return host;
86}
87EXPORT_SYMBOL_GPL(dcr_map_generic);
88
89void dcr_unmap_generic(dcr_host_t host, unsigned int dcr_c)
90{
91 if (host.type == DCR_HOST_NATIVE)
92 dcr_unmap_native(host.host.native, dcr_c);
93 else if (host.type == DCR_HOST_MMIO)
94 dcr_unmap_mmio(host.host.mmio, dcr_c);
95 else /* host.type == DCR_HOST_INVALID */
96 WARN_ON(true);
97}
98EXPORT_SYMBOL_GPL(dcr_unmap_generic);
99
100u32 dcr_read_generic(dcr_host_t host, unsigned int dcr_n)
101{
102 if (host.type == DCR_HOST_NATIVE)
103 return dcr_read_native(host.host.native, dcr_n);
104 else if (host.type == DCR_HOST_MMIO)
105 return dcr_read_mmio(host.host.mmio, dcr_n);
106 else /* host.type == DCR_HOST_INVALID */
107 WARN_ON(true);
108 return 0;
109}
110EXPORT_SYMBOL_GPL(dcr_read_generic);
111
112void dcr_write_generic(dcr_host_t host, unsigned int dcr_n, u32 value)
113{
114 if (host.type == DCR_HOST_NATIVE)
115 dcr_write_native(host.host.native, dcr_n, value);
116 else if (host.type == DCR_HOST_MMIO)
117 dcr_write_mmio(host.host.mmio, dcr_n, value);
118 else /* host.type == DCR_HOST_INVALID */
119 WARN_ON(true);
120}
121EXPORT_SYMBOL_GPL(dcr_write_generic);
122
123#endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */
124
26unsigned int dcr_resource_start(struct device_node *np, unsigned int index) 125unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
27{ 126{
28 unsigned int ds; 127 unsigned int ds;
@@ -47,26 +146,7 @@ unsigned int dcr_resource_len(struct device_node *np, unsigned int index)
47} 146}
48EXPORT_SYMBOL_GPL(dcr_resource_len); 147EXPORT_SYMBOL_GPL(dcr_resource_len);
49 148
50#ifndef CONFIG_PPC_DCR_NATIVE 149#ifdef CONFIG_PPC_DCR_MMIO
51
52static struct device_node * find_dcr_parent(struct device_node * node)
53{
54 struct device_node *par, *tmp;
55 const u32 *p;
56
57 for (par = of_node_get(node); par;) {
58 if (of_get_property(par, "dcr-controller", NULL))
59 break;
60 p = of_get_property(par, "dcr-parent", NULL);
61 tmp = par;
62 if (p == NULL)
63 par = of_get_parent(par);
64 else
65 par = of_find_node_by_phandle(*p);
66 of_node_put(tmp);
67 }
68 return par;
69}
70 150
71u64 of_translate_dcr_address(struct device_node *dev, 151u64 of_translate_dcr_address(struct device_node *dev,
72 unsigned int dcr_n, 152 unsigned int dcr_n,
@@ -75,7 +155,7 @@ u64 of_translate_dcr_address(struct device_node *dev,
75 struct device_node *dp; 155 struct device_node *dp;
76 const u32 *p; 156 const u32 *p;
77 unsigned int stride; 157 unsigned int stride;
78 u64 ret; 158 u64 ret = OF_BAD_ADDR;
79 159
80 dp = find_dcr_parent(dev); 160 dp = find_dcr_parent(dev);
81 if (dp == NULL) 161 if (dp == NULL)
@@ -90,7 +170,7 @@ u64 of_translate_dcr_address(struct device_node *dev,
90 if (p == NULL) 170 if (p == NULL)
91 p = of_get_property(dp, "dcr-mmio-space", NULL); 171 p = of_get_property(dp, "dcr-mmio-space", NULL);
92 if (p == NULL) 172 if (p == NULL)
93 return OF_BAD_ADDR; 173 goto done;
94 174
95 /* Maybe could do some better range checking here */ 175 /* Maybe could do some better range checking here */
96 ret = of_translate_address(dp, p); 176 ret = of_translate_address(dp, p);
@@ -98,21 +178,25 @@ u64 of_translate_dcr_address(struct device_node *dev,
98 ret += (u64)(stride) * (u64)dcr_n; 178 ret += (u64)(stride) * (u64)dcr_n;
99 if (out_stride) 179 if (out_stride)
100 *out_stride = stride; 180 *out_stride = stride;
181
182 done:
183 of_node_put(dp);
101 return ret; 184 return ret;
102} 185}
103 186
104dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n, 187dcr_host_mmio_t dcr_map_mmio(struct device_node *dev,
105 unsigned int dcr_c) 188 unsigned int dcr_n,
189 unsigned int dcr_c)
106{ 190{
107 dcr_host_t ret = { .token = NULL, .stride = 0, .base = dcr_n }; 191 dcr_host_mmio_t ret = { .token = NULL, .stride = 0, .base = dcr_n };
108 u64 addr; 192 u64 addr;
109 193
110 pr_debug("dcr_map(%s, 0x%x, 0x%x)\n", 194 pr_debug("dcr_map(%s, 0x%x, 0x%x)\n",
111 dev->full_name, dcr_n, dcr_c); 195 dev->full_name, dcr_n, dcr_c);
112 196
113 addr = of_translate_dcr_address(dev, dcr_n, &ret.stride); 197 addr = of_translate_dcr_address(dev, dcr_n, &ret.stride);
114 pr_debug("translates to addr: 0x%lx, stride: 0x%x\n", 198 pr_debug("translates to addr: 0x%llx, stride: 0x%x\n",
115 addr, ret.stride); 199 (unsigned long long) addr, ret.stride);
116 if (addr == OF_BAD_ADDR) 200 if (addr == OF_BAD_ADDR)
117 return ret; 201 return ret;
118 pr_debug("mapping 0x%x bytes\n", dcr_c * ret.stride); 202 pr_debug("mapping 0x%x bytes\n", dcr_c * ret.stride);
@@ -124,11 +208,11 @@ dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n,
124 ret.token -= dcr_n * ret.stride; 208 ret.token -= dcr_n * ret.stride;
125 return ret; 209 return ret;
126} 210}
127EXPORT_SYMBOL_GPL(dcr_map); 211EXPORT_SYMBOL_GPL(dcr_map_mmio);
128 212
129void dcr_unmap(dcr_host_t host, unsigned int dcr_c) 213void dcr_unmap_mmio(dcr_host_mmio_t host, unsigned int dcr_c)
130{ 214{
131 dcr_host_t h = host; 215 dcr_host_mmio_t h = host;
132 216
133 if (h.token == NULL) 217 if (h.token == NULL)
134 return; 218 return;
@@ -136,7 +220,11 @@ void dcr_unmap(dcr_host_t host, unsigned int dcr_c)
136 iounmap(h.token); 220 iounmap(h.token);
137 h.token = NULL; 221 h.token = NULL;
138} 222}
139EXPORT_SYMBOL_GPL(dcr_unmap); 223EXPORT_SYMBOL_GPL(dcr_unmap_mmio);
140#else /* defined(CONFIG_PPC_DCR_NATIVE) */ 224
225#endif /* defined(CONFIG_PPC_DCR_MMIO) */
226
227#ifdef CONFIG_PPC_DCR_NATIVE
141DEFINE_SPINLOCK(dcr_ind_lock); 228DEFINE_SPINLOCK(dcr_ind_lock);
142#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */ 229#endif /* defined(CONFIG_PPC_DCR_NATIVE) */
230
diff --git a/include/asm-powerpc/dcr-generic.h b/include/asm-powerpc/dcr-generic.h
new file mode 100644
index 000000000000..35b71599ec46
--- /dev/null
+++ b/include/asm-powerpc/dcr-generic.h
@@ -0,0 +1,49 @@
1/*
2 * (c) Copyright 2006 Benjamin Herrenschmidt, IBM Corp.
3 * <benh@kernel.crashing.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#ifndef _ASM_POWERPC_DCR_GENERIC_H
21#define _ASM_POWERPC_DCR_GENERIC_H
22#ifdef __KERNEL__
23#ifndef __ASSEMBLY__
24
25enum host_type_t {DCR_HOST_MMIO, DCR_HOST_NATIVE, DCR_HOST_INVALID};
26
27typedef struct {
28 enum host_type_t type;
29 union {
30 dcr_host_mmio_t mmio;
31 dcr_host_native_t native;
32 } host;
33} dcr_host_t;
34
35extern bool dcr_map_ok_generic(dcr_host_t host);
36
37extern dcr_host_t dcr_map_generic(struct device_node *dev, unsigned int dcr_n,
38 unsigned int dcr_c);
39extern void dcr_unmap_generic(dcr_host_t host, unsigned int dcr_c);
40
41extern u32 dcr_read_generic(dcr_host_t host, unsigned int dcr_n);
42
43extern void dcr_write_generic(dcr_host_t host, unsigned int dcr_n, u32 value);
44
45#endif /* __ASSEMBLY__ */
46#endif /* __KERNEL__ */
47#endif /* _ASM_POWERPC_DCR_GENERIC_H */
48
49
diff --git a/include/asm-powerpc/dcr-mmio.h b/include/asm-powerpc/dcr-mmio.h
index 08532ff1899c..acd491dbd45a 100644
--- a/include/asm-powerpc/dcr-mmio.h
+++ b/include/asm-powerpc/dcr-mmio.h
@@ -27,20 +27,26 @@ typedef struct {
27 void __iomem *token; 27 void __iomem *token;
28 unsigned int stride; 28 unsigned int stride;
29 unsigned int base; 29 unsigned int base;
30} dcr_host_t; 30} dcr_host_mmio_t;
31 31
32#define DCR_MAP_OK(host) ((host).token != NULL) 32static inline bool dcr_map_ok_mmio(dcr_host_mmio_t host)
33{
34 return host.token != NULL;
35}
33 36
34extern dcr_host_t dcr_map(struct device_node *dev, unsigned int dcr_n, 37extern dcr_host_mmio_t dcr_map_mmio(struct device_node *dev,
35 unsigned int dcr_c); 38 unsigned int dcr_n,
36extern void dcr_unmap(dcr_host_t host, unsigned int dcr_c); 39 unsigned int dcr_c);
40extern void dcr_unmap_mmio(dcr_host_mmio_t host, unsigned int dcr_c);
37 41
38static inline u32 dcr_read(dcr_host_t host, unsigned int dcr_n) 42static inline u32 dcr_read_mmio(dcr_host_mmio_t host, unsigned int dcr_n)
39{ 43{
40 return in_be32(host.token + ((host.base + dcr_n) * host.stride)); 44 return in_be32(host.token + ((host.base + dcr_n) * host.stride));
41} 45}
42 46
43static inline void dcr_write(dcr_host_t host, unsigned int dcr_n, u32 value) 47static inline void dcr_write_mmio(dcr_host_mmio_t host,
48 unsigned int dcr_n,
49 u32 value)
44{ 50{
45 out_be32(host.token + ((host.base + dcr_n) * host.stride), value); 51 out_be32(host.token + ((host.base + dcr_n) * host.stride), value);
46} 52}
diff --git a/include/asm-powerpc/dcr-native.h b/include/asm-powerpc/dcr-native.h
index f8398ce80372..72d2b72c7390 100644
--- a/include/asm-powerpc/dcr-native.h
+++ b/include/asm-powerpc/dcr-native.h
@@ -26,14 +26,18 @@
26 26
27typedef struct { 27typedef struct {
28 unsigned int base; 28 unsigned int base;
29} dcr_host_t; 29} dcr_host_native_t;
30 30
31#define DCR_MAP_OK(host) (1) 31static inline bool dcr_map_ok_native(dcr_host_native_t host)
32{
33 return 1;
34}
32 35
33#define dcr_map(dev, dcr_n, dcr_c) ((dcr_host_t){ .base = (dcr_n) }) 36#define dcr_map_native(dev, dcr_n, dcr_c) \
34#define dcr_unmap(host, dcr_c) do {} while (0) 37 ((dcr_host_native_t){ .base = (dcr_n) })
35#define dcr_read(host, dcr_n) mfdcr(dcr_n + host.base) 38#define dcr_unmap_native(host, dcr_c) do {} while (0)
36#define dcr_write(host, dcr_n, value) mtdcr(dcr_n + host.base, value) 39#define dcr_read_native(host, dcr_n) mfdcr(dcr_n + host.base)
40#define dcr_write_native(host, dcr_n, value) mtdcr(dcr_n + host.base, value)
37 41
38/* Device Control Registers */ 42/* Device Control Registers */
39void __mtdcr(int reg, unsigned int val); 43void __mtdcr(int reg, unsigned int val);
diff --git a/include/asm-powerpc/dcr.h b/include/asm-powerpc/dcr.h
index 9338d50538f1..53b283050ab3 100644
--- a/include/asm-powerpc/dcr.h
+++ b/include/asm-powerpc/dcr.h
@@ -20,14 +20,50 @@
20#ifndef _ASM_POWERPC_DCR_H 20#ifndef _ASM_POWERPC_DCR_H
21#define _ASM_POWERPC_DCR_H 21#define _ASM_POWERPC_DCR_H
22#ifdef __KERNEL__ 22#ifdef __KERNEL__
23#ifndef __ASSEMBLY__
23#ifdef CONFIG_PPC_DCR 24#ifdef CONFIG_PPC_DCR
24 25
25#ifdef CONFIG_PPC_DCR_NATIVE 26#ifdef CONFIG_PPC_DCR_NATIVE
26#include <asm/dcr-native.h> 27#include <asm/dcr-native.h>
27#else 28#endif
29
30#ifdef CONFIG_PPC_DCR_MMIO
28#include <asm/dcr-mmio.h> 31#include <asm/dcr-mmio.h>
29#endif 32#endif
30 33
34
35/* Indirection layer for providing both NATIVE and MMIO support. */
36
37#if defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO)
38
39#include <asm/dcr-generic.h>
40
41#define DCR_MAP_OK(host) dcr_map_ok_generic(host)
42#define dcr_map(dev, dcr_n, dcr_c) dcr_map_generic(dev, dcr_n, dcr_c)
43#define dcr_unmap(host, dcr_c) dcr_unmap_generic(host, dcr_c)
44#define dcr_read(host, dcr_n) dcr_read_generic(host, dcr_n)
45#define dcr_write(host, dcr_n, value) dcr_write_generic(host, dcr_n, value)
46
47#else
48
49#ifdef CONFIG_PPC_DCR_NATIVE
50typedef dcr_host_native_t dcr_host_t;
51#define DCR_MAP_OK(host) dcr_map_ok_native(host)
52#define dcr_map(dev, dcr_n, dcr_c) dcr_map_native(dev, dcr_n, dcr_c)
53#define dcr_unmap(host, dcr_c) dcr_unmap_native(host, dcr_c)
54#define dcr_read(host, dcr_n) dcr_read_native(host, dcr_n)
55#define dcr_write(host, dcr_n, value) dcr_write_native(host, dcr_n, value)
56#else
57typedef dcr_host_mmio_t dcr_host_t;
58#define DCR_MAP_OK(host) dcr_map_ok_mmio(host)
59#define dcr_map(dev, dcr_n, dcr_c) dcr_map_mmio(dev, dcr_n, dcr_c)
60#define dcr_unmap(host, dcr_c) dcr_unmap_mmio(host, dcr_c)
61#define dcr_read(host, dcr_n) dcr_read_mmio(host, dcr_n)
62#define dcr_write(host, dcr_n, value) dcr_write_mmio(host, dcr_n, value)
63#endif
64
65#endif /* defined(CONFIG_PPC_DCR_NATIVE) && defined(CONFIG_PPC_DCR_MMIO) */
66
31/* 67/*
32 * On CONFIG_PPC_MERGE, we have additional helpers to read the DCR 68 * On CONFIG_PPC_MERGE, we have additional helpers to read the DCR
33 * base from the device-tree 69 * base from the device-tree
@@ -41,5 +77,6 @@ extern unsigned int dcr_resource_len(struct device_node *np,
41#endif /* CONFIG_PPC_MERGE */ 77#endif /* CONFIG_PPC_MERGE */
42 78
43#endif /* CONFIG_PPC_DCR */ 79#endif /* CONFIG_PPC_DCR */
80#endif /* __ASSEMBLY__ */
44#endif /* __KERNEL__ */ 81#endif /* __KERNEL__ */
45#endif /* _ASM_POWERPC_DCR_H */ 82#endif /* _ASM_POWERPC_DCR_H */