diff options
Diffstat (limited to 'include/asm-ppc/ocp.h')
-rw-r--r-- | include/asm-ppc/ocp.h | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h new file mode 100644 index 000000000000..5ea44cabfaa4 --- /dev/null +++ b/include/asm-ppc/ocp.h | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * ocp.h | ||
3 | * | ||
4 | * (c) Benjamin Herrenschmidt (benh@kernel.crashing.org) | ||
5 | * Mipsys - France | ||
6 | * | ||
7 | * Derived from work (c) Armin Kuster akuster@pacbell.net | ||
8 | * | ||
9 | * Additional support and port to 2.6 LDM/sysfs by | ||
10 | * Matt Porter <mporter@kernel.crashing.org> | ||
11 | * Copyright 2003-2004 MontaVista Software, Inc. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | * TODO: - Add get/put interface & fixup locking to provide same API for | ||
19 | * 2.4 and 2.5 | ||
20 | * - Rework PM callbacks | ||
21 | */ | ||
22 | |||
23 | #ifdef __KERNEL__ | ||
24 | #ifndef __OCP_H__ | ||
25 | #define __OCP_H__ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/config.h> | ||
30 | #include <linux/devfs_fs_kernel.h> | ||
31 | #include <linux/device.h> | ||
32 | |||
33 | #include <asm/mmu.h> | ||
34 | #include <asm/ocp_ids.h> | ||
35 | #include <asm/rwsem.h> | ||
36 | #include <asm/semaphore.h> | ||
37 | |||
38 | #ifdef CONFIG_PPC_OCP | ||
39 | |||
40 | #define OCP_MAX_IRQS 7 | ||
41 | #define MAX_EMACS 4 | ||
42 | #define OCP_IRQ_NA -1 /* used when ocp device does not have an irq */ | ||
43 | #define OCP_IRQ_MUL -2 /* used for ocp devices with multiply irqs */ | ||
44 | #define OCP_NULL_TYPE -1 /* used to mark end of list */ | ||
45 | #define OCP_CPM_NA 0 /* No Clock or Power Management avaliable */ | ||
46 | #define OCP_PADDR_NA 0 /* No MMIO registers */ | ||
47 | |||
48 | #define OCP_ANY_ID (~0) | ||
49 | #define OCP_ANY_INDEX -1 | ||
50 | |||
51 | extern struct list_head ocp_devices; | ||
52 | extern struct rw_semaphore ocp_devices_sem; | ||
53 | |||
54 | struct ocp_device_id { | ||
55 | unsigned int vendor, function; /* Vendor and function ID or OCP_ANY_ID */ | ||
56 | unsigned long driver_data; /* Data private to the driver */ | ||
57 | }; | ||
58 | |||
59 | |||
60 | /* | ||
61 | * Static definition of an OCP device. | ||
62 | * | ||
63 | * @vendor: Vendor code. It is _STRONGLY_ discouraged to use | ||
64 | * the vendor code as a way to match a unique device, | ||
65 | * though I kept that possibility open, you should | ||
66 | * really define different function codes for different | ||
67 | * device types | ||
68 | * @function: This is the function code for this device. | ||
69 | * @index: This index is used for mapping the Nth function of a | ||
70 | * given core. This is typically used for cross-driver | ||
71 | * matching, like looking for a given MAL or ZMII from | ||
72 | * an EMAC or for getting to the proper set of DCRs. | ||
73 | * Indices are no longer magically calculated based on | ||
74 | * structure ordering, they have to be actually coded | ||
75 | * into the ocp_def to avoid any possible confusion | ||
76 | * I _STRONGLY_ (again ? wow !) encourage anybody relying | ||
77 | * on index mapping to encode the "target" index in an | ||
78 | * associated structure pointed to by "additions", see | ||
79 | * how it's done for the EMAC driver. | ||
80 | * @paddr: Device physical address (may not mean anything...) | ||
81 | * @irq: Interrupt line for this device (TODO: think about making | ||
82 | * an array with this) | ||
83 | * @pm: Currently, contains the bitmask in CPMFR DCR for the device | ||
84 | * @additions: Optionally points to a function specific structure | ||
85 | * providing additional informations for a given device | ||
86 | * instance. It's currently used by the EMAC driver for MAL | ||
87 | * channel & ZMII port mapping among others. | ||
88 | * @show: Optionally points to a function specific structure | ||
89 | * providing a sysfs show routine for additions fields. | ||
90 | */ | ||
91 | struct ocp_def { | ||
92 | unsigned int vendor; | ||
93 | unsigned int function; | ||
94 | int index; | ||
95 | phys_addr_t paddr; | ||
96 | int irq; | ||
97 | unsigned long pm; | ||
98 | void *additions; | ||
99 | void (*show)(struct device *); | ||
100 | }; | ||
101 | |||
102 | |||
103 | /* Struct for a given device instance */ | ||
104 | struct ocp_device { | ||
105 | struct list_head link; | ||
106 | char name[80]; /* device name */ | ||
107 | struct ocp_def *def; /* device definition */ | ||
108 | void *drvdata; /* driver data for this device */ | ||
109 | struct ocp_driver *driver; | ||
110 | u32 current_state; /* Current operating state. In ACPI-speak, | ||
111 | this is D0-D3, D0 being fully functional, | ||
112 | and D3 being off. */ | ||
113 | struct device dev; | ||
114 | }; | ||
115 | |||
116 | struct ocp_driver { | ||
117 | struct list_head node; | ||
118 | char *name; | ||
119 | const struct ocp_device_id *id_table; /* NULL if wants all devices */ | ||
120 | int (*probe) (struct ocp_device *dev); /* New device inserted */ | ||
121 | void (*remove) (struct ocp_device *dev); /* Device removed (NULL if not a hot-plug capable driver) */ | ||
122 | int (*suspend) (struct ocp_device *dev, u32 state); /* Device suspended */ | ||
123 | int (*resume) (struct ocp_device *dev); /* Device woken up */ | ||
124 | struct device_driver driver; | ||
125 | }; | ||
126 | |||
127 | #define to_ocp_dev(n) container_of(n, struct ocp_device, dev) | ||
128 | #define to_ocp_drv(n) container_of(n, struct ocp_driver, driver) | ||
129 | |||
130 | /* Similar to the helpers above, these manipulate per-ocp_dev | ||
131 | * driver-specific data. Currently stored as ocp_dev::ocpdev, | ||
132 | * a void pointer, but it is not present on older kernels. | ||
133 | */ | ||
134 | static inline void * | ||
135 | ocp_get_drvdata(struct ocp_device *pdev) | ||
136 | { | ||
137 | return pdev->drvdata; | ||
138 | } | ||
139 | |||
140 | static inline void | ||
141 | ocp_set_drvdata(struct ocp_device *pdev, void *data) | ||
142 | { | ||
143 | pdev->drvdata = data; | ||
144 | } | ||
145 | |||
146 | #if defined (CONFIG_PM) | ||
147 | /* | ||
148 | * This is right for the IBM 405 and 440 but will need to be | ||
149 | * generalized if the OCP stuff gets used on other processors. | ||
150 | */ | ||
151 | static inline void | ||
152 | ocp_force_power_off(struct ocp_device *odev) | ||
153 | { | ||
154 | mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | odev->def->pm); | ||
155 | } | ||
156 | |||
157 | static inline void | ||
158 | ocp_force_power_on(struct ocp_device *odev) | ||
159 | { | ||
160 | mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) & ~odev->def->pm); | ||
161 | } | ||
162 | #else | ||
163 | #define ocp_force_power_off(x) (void)(x) | ||
164 | #define ocp_force_power_on(x) (void)(x) | ||
165 | #endif | ||
166 | |||
167 | /* Register/Unregister an OCP driver */ | ||
168 | extern int ocp_register_driver(struct ocp_driver *drv); | ||
169 | extern void ocp_unregister_driver(struct ocp_driver *drv); | ||
170 | |||
171 | /* Build list of devices */ | ||
172 | extern int ocp_early_init(void) __init; | ||
173 | |||
174 | /* Find a device by index */ | ||
175 | extern struct ocp_device *ocp_find_device(unsigned int vendor, unsigned int function, int index); | ||
176 | |||
177 | /* Get a def by index */ | ||
178 | extern struct ocp_def *ocp_get_one_device(unsigned int vendor, unsigned int function, int index); | ||
179 | |||
180 | /* Add a device by index */ | ||
181 | extern int ocp_add_one_device(struct ocp_def *def); | ||
182 | |||
183 | /* Remove a device by index */ | ||
184 | extern int ocp_remove_one_device(unsigned int vendor, unsigned int function, int index); | ||
185 | |||
186 | /* Iterate over devices and execute a routine */ | ||
187 | extern void ocp_for_each_device(void(*callback)(struct ocp_device *, void *arg), void *arg); | ||
188 | |||
189 | /* Sysfs support */ | ||
190 | #define OCP_SYSFS_ADDTL(type, format, name, field) \ | ||
191 | static ssize_t \ | ||
192 | show_##name##_##field(struct device *dev, char *buf) \ | ||
193 | { \ | ||
194 | struct ocp_device *odev = to_ocp_dev(dev); \ | ||
195 | type *add = odev->def->additions; \ | ||
196 | \ | ||
197 | return sprintf(buf, format, add->field); \ | ||
198 | } \ | ||
199 | static DEVICE_ATTR(name##_##field, S_IRUGO, show_##name##_##field, NULL); | ||
200 | |||
201 | #ifdef CONFIG_IBM_OCP | ||
202 | #include <asm/ibm_ocp.h> | ||
203 | #endif | ||
204 | |||
205 | #ifdef CONFIG_FSL_OCP | ||
206 | #include <asm/fsl_ocp.h> | ||
207 | #endif | ||
208 | |||
209 | #endif /* CONFIG_PPC_OCP */ | ||
210 | #endif /* __OCP_H__ */ | ||
211 | #endif /* __KERNEL__ */ | ||