aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-powerpc
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-01-06 19:41:02 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 23:47:18 -0500
commit5b9ca526917b7bc7d1da3beaccb2251a8f0b5fe2 (patch)
treef345cbb73a4c5bb4c5645d53df2653c916e54172 /include/asm-powerpc
parenta28d3af2a26c89aaa6470ca36edb212e05143d67 (diff)
[PATCH] 3/5 powerpc: Add platform functions interpreter
This is the platform function interpreter itself along with the backends for UniN/U3/U4, mac-io, GPIOs and i2c. It adds the ability to execute those do-platform-* scripts in the device-tree (at least for most devices for which a backend is provided). This should replace the clock spreading hacks properly. It might also have an impact on all sort of machines since some of the scripts marked "at init" will now be executed on boot (or some other on sleep/wakeup), those will possibly do things that the kernel didn't do at all, like setting some values into some i2c devices (changing thermal sensor calibration or conversion rate) etc... Thus regression testing is MUCH welcome. Also loook for errors in dmesg. That's also why I've left rather verbose debugging enabled in this version of the patch. (I do expect some Windtunnel G4s to show some errors as they have an i2c clock chip on the PMU bus that uses some primitives that the i2c backend doesn't implement yet. I really need users that have one of those machine to come back to me so we can get that done right, though the errors themselves should be harmless, I suspect the machine might not run at full speed). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'include/asm-powerpc')
-rw-r--r--include/asm-powerpc/pmac_feature.h19
-rw-r--r--include/asm-powerpc/pmac_low_i2c.h3
-rw-r--r--include/asm-powerpc/pmac_pfunc.h253
3 files changed, 275 insertions, 0 deletions
diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h
index e654ad0e5b42..3221628130c4 100644
--- a/include/asm-powerpc/pmac_feature.h
+++ b/include/asm-powerpc/pmac_feature.h
@@ -374,5 +374,24 @@ extern struct macio_chip* macio_find(struct device_node* child, int type);
374#define MACIO_IN8(r) (in_8(MACIO_FCR8(macio,r))) 374#define MACIO_IN8(r) (in_8(MACIO_FCR8(macio,r)))
375#define MACIO_OUT8(r,v) (out_8(MACIO_FCR8(macio,r), (v))) 375#define MACIO_OUT8(r,v) (out_8(MACIO_FCR8(macio,r), (v)))
376 376
377/*
378 * Those are exported by pmac feature for internal use by arch code
379 * only like the platform function callbacks, do not use directly in drivers
380 */
381extern spinlock_t feature_lock;
382extern struct device_node *uninorth_node;
383extern u32 __iomem *uninorth_base;
384
385/*
386 * Uninorth reg. access. Note that Uni-N regs are big endian
387 */
388
389#define UN_REG(r) (uninorth_base + ((r) >> 2))
390#define UN_IN(r) (in_be32(UN_REG(r)))
391#define UN_OUT(r,v) (out_be32(UN_REG(r), (v)))
392#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v)))
393#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v)))
394
395
377#endif /* __PPC_ASM_PMAC_FEATURE_H */ 396#endif /* __PPC_ASM_PMAC_FEATURE_H */
378#endif /* __KERNEL__ */ 397#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/pmac_low_i2c.h b/include/asm-powerpc/pmac_low_i2c.h
index 480018f41e1a..131011bd7e76 100644
--- a/include/asm-powerpc/pmac_low_i2c.h
+++ b/include/asm-powerpc/pmac_low_i2c.h
@@ -99,6 +99,9 @@ extern int pmac_i2c_setmode(struct pmac_i2c_bus *bus, int mode);
99extern int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize, 99extern int pmac_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
100 u32 subaddr, u8 *data, int len); 100 u32 subaddr, u8 *data, int len);
101 101
102/* Suspend/resume code called by via-pmu directly for now */
103extern void pmac_pfunc_i2c_suspend(void);
104extern void pmac_pfunc_i2c_resume(void);
102 105
103#endif /* __KERNEL__ */ 106#endif /* __KERNEL__ */
104#endif /* __PMAC_LOW_I2C_H__ */ 107#endif /* __PMAC_LOW_I2C_H__ */
diff --git a/include/asm-powerpc/pmac_pfunc.h b/include/asm-powerpc/pmac_pfunc.h
new file mode 100644
index 000000000000..d9728c80f86d
--- /dev/null
+++ b/include/asm-powerpc/pmac_pfunc.h
@@ -0,0 +1,253 @@
1#ifndef __PMAC_PFUNC_H__
2#define __PMAC_PFUNC_H__
3
4#include <linux/types.h>
5#include <linux/list.h>
6
7/* Flags in command lists */
8#define PMF_FLAGS_ON_INIT 0x80000000u
9#define PMF_FLGAS_ON_TERM 0x40000000u
10#define PMF_FLAGS_ON_SLEEP 0x20000000u
11#define PMF_FLAGS_ON_WAKE 0x10000000u
12#define PMF_FLAGS_ON_DEMAND 0x08000000u
13#define PMF_FLAGS_INT_GEN 0x04000000u
14#define PMF_FLAGS_HIGH_SPEED 0x02000000u
15#define PMF_FLAGS_LOW_SPEED 0x01000000u
16#define PMF_FLAGS_SIDE_EFFECTS 0x00800000u
17
18/*
19 * Arguments to a platform function call.
20 *
21 * NOTE: By convention, pointer arguments point to an u32
22 */
23struct pmf_args {
24 union {
25 u32 v;
26 u32 *p;
27 } u[4];
28 unsigned int count;
29};
30
31/*
32 * A driver capable of interpreting commands provides a handlers
33 * structure filled with whatever handlers are implemented by this
34 * driver. Non implemented handlers are left NULL.
35 *
36 * PMF_STD_ARGS are the same arguments that are passed to the parser
37 * and that gets passed back to the various handlers.
38 *
39 * Interpreting a given function always start with a begin() call which
40 * returns an instance data to be passed around subsequent calls, and
41 * ends with an end() call. This allows the low level driver to implement
42 * locking policy or per-function instance data.
43 *
44 * For interrupt capable functions, irq_enable() is called when a client
45 * registers, and irq_disable() is called when the last client unregisters
46 * Note that irq_enable & irq_disable are called within a semaphore held
47 * by the core, thus you should not try to register yourself to some other
48 * pmf interrupt during those calls.
49 */
50
51#define PMF_STD_ARGS struct pmf_function *func, void *instdata, \
52 struct pmf_args *args
53
54struct pmf_function;
55
56struct pmf_handlers {
57 void * (*begin)(struct pmf_function *func, struct pmf_args *args);
58 void (*end)(struct pmf_function *func, void *instdata);
59
60 int (*irq_enable)(struct pmf_function *func);
61 int (*irq_disable)(struct pmf_function *func);
62
63 int (*write_gpio)(PMF_STD_ARGS, u8 value, u8 mask);
64 int (*read_gpio)(PMF_STD_ARGS, u8 mask, int rshift, u8 xor);
65
66 int (*write_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask);
67 int (*read_reg32)(PMF_STD_ARGS, u32 offset);
68 int (*write_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask);
69 int (*read_reg16)(PMF_STD_ARGS, u32 offset);
70 int (*write_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask);
71 int (*read_reg8)(PMF_STD_ARGS, u32 offset);
72
73 int (*delay)(PMF_STD_ARGS, u32 duration);
74
75 int (*wait_reg32)(PMF_STD_ARGS, u32 offset, u32 value, u32 mask);
76 int (*wait_reg16)(PMF_STD_ARGS, u32 offset, u16 value, u16 mask);
77 int (*wait_reg8)(PMF_STD_ARGS, u32 offset, u8 value, u8 mask);
78
79 int (*read_i2c)(PMF_STD_ARGS, u32 len);
80 int (*write_i2c)(PMF_STD_ARGS, u32 len, const u8 *data);
81 int (*rmw_i2c)(PMF_STD_ARGS, u32 masklen, u32 valuelen, u32 totallen,
82 const u8 *maskdata, const u8 *valuedata);
83
84 int (*read_cfg)(PMF_STD_ARGS, u32 offset, u32 len);
85 int (*write_cfg)(PMF_STD_ARGS, u32 offset, u32 len, const u8 *data);
86 int (*rmw_cfg)(PMF_STD_ARGS, u32 offset, u32 masklen, u32 valuelen,
87 u32 totallen, const u8 *maskdata, const u8 *valuedata);
88
89 int (*read_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len);
90 int (*write_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 len, const u8 *data);
91 int (*set_i2c_mode)(PMF_STD_ARGS, int mode);
92 int (*rmw_i2c_sub)(PMF_STD_ARGS, u8 subaddr, u32 masklen, u32 valuelen,
93 u32 totallen, const u8 *maskdata,
94 const u8 *valuedata);
95
96 int (*read_reg32_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
97 u32 xor);
98 int (*read_reg16_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
99 u32 xor);
100 int (*read_reg8_msrx)(PMF_STD_ARGS, u32 offset, u32 mask, u32 shift,
101 u32 xor);
102
103 int (*write_reg32_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
104 int (*write_reg16_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
105 int (*write_reg8_slm)(PMF_STD_ARGS, u32 offset, u32 shift, u32 mask);
106
107 int (*mask_and_compare)(PMF_STD_ARGS, u32 len, const u8 *maskdata,
108 const u8 *valuedata);
109
110 struct module *owner;
111};
112
113
114/*
115 * Drivers who expose platform functions register at init time, this
116 * causes the platform functions for that device node to be parsed in
117 * advance and associated with the device. The data structures are
118 * partially public so a driver can walk the list of platform functions
119 * and eventually inspect the flags
120 */
121struct pmf_device;
122
123struct pmf_function {
124 /* All functions for a given driver are linked */
125 struct list_head link;
126
127 /* Function node & driver data */
128 struct device_node *node;
129 void *driver_data;
130
131 /* For internal use by core */
132 struct pmf_device *dev;
133
134 /* The name is the "xxx" in "platform-do-xxx", this is how
135 * platform functions are identified by this code. Some functions
136 * only operate for a given target, in which case the phandle is
137 * here (or 0 if the filter doesn't apply)
138 */
139 const char *name;
140 u32 phandle;
141
142 /* The flags for that function. You can have several functions
143 * with the same name and different flag
144 */
145 u32 flags;
146
147 /* The actual tokenized function blob */
148 const void *data;
149 unsigned int length;
150
151 /* Interrupt clients */
152 struct list_head irq_clients;
153
154 /* Refcounting */
155 struct kref ref;
156};
157
158/*
159 * For platform functions that are interrupts, one can register
160 * irq_client structures. You canNOT use the same structure twice
161 * as it contains a link member. Also, the callback is called with
162 * a spinlock held, you must not call back into any of the pmf_* functions
163 * from within that callback
164 */
165struct pmf_irq_client {
166 void (*handler)(void *data);
167 void *data;
168 struct module *owner;
169 struct list_head link;
170};
171
172
173/*
174 * Register/Unregister a function-capable driver and its handlers
175 */
176extern int pmf_register_driver(struct device_node *np,
177 struct pmf_handlers *handlers,
178 void *driverdata);
179
180extern void pmf_unregister_driver(struct device_node *np);
181
182
183/*
184 * Register/Unregister interrupt clients
185 */
186extern int pmf_register_irq_client(struct device_node *np,
187 const char *name,
188 struct pmf_irq_client *client);
189
190extern void pmf_unregister_irq_client(struct device_node *np,
191 const char *name,
192 struct pmf_irq_client *client);
193
194/*
195 * Called by the handlers when an irq happens
196 */
197extern void pmf_do_irq(struct pmf_function *func);
198
199
200/*
201 * Low level call to platform functions.
202 *
203 * The phandle can filter on the target object for functions that have
204 * multiple targets, the flags allow you to restrict the call to a given
205 * combination of flags.
206 *
207 * The args array contains as many arguments as is required by the function,
208 * this is dependent on the function you are calling, unfortunately Apple
209 * mecanism provides no way to encode that so you have to get it right at
210 * the call site. Some functions require no args, in which case, you can
211 * pass NULL.
212 *
213 * You can also pass NULL to the name. This will match any function that has
214 * the appropriate combination of flags & phandle or you can pass 0 to the
215 * phandle to match any
216 */
217extern int pmf_do_functions(struct device_node *np, const char *name,
218 u32 phandle, u32 flags, struct pmf_args *args);
219
220
221
222/*
223 * High level call to a platform function.
224 *
225 * This one looks for the platform-xxx first so you should call it to the
226 * actual target if any. It will fallback to platform-do-xxx if it can't
227 * find one. It will also exclusively target functions that have
228 * the "OnDemand" flag.
229 */
230
231extern int pmf_call_function(struct device_node *target, const char *name,
232 struct pmf_args *args);
233
234
235/*
236 * For low latency interrupt usage, you can lookup for on-demand functions
237 * using the functions below
238 */
239
240extern struct pmf_function *pmf_find_function(struct device_node *target,
241 const char *name);
242
243extern struct pmf_function * pmf_get_function(struct pmf_function *func);
244extern void pmf_put_function(struct pmf_function *func);
245
246extern int pmf_call_one(struct pmf_function *func, struct pmf_args *args);
247
248
249/* Suspend/resume code called by via-pmu directly for now */
250extern void pmac_pfunc_base_suspend(void);
251extern void pmac_pfunc_base_resume(void);
252
253#endif /* __PMAC_PFUNC_H__ */