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