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