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  * This program is free software; you can redistribute  it and/or modify it
10  *  under  the terms of  the GNU General  Public License as published by the
11  *  Free Software Foundation;  either version 2 of the  License, or (at your
12  *  option) any later version.
13  *
14  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR   IMPLIED
15  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
16  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
17  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT,  INDIRECT,
18  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
20  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
22  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *  You should have received a copy of the  GNU General Public License along
26  *  with this program; if not, write  to the Free Software Foundation, Inc.,
27  *  675 Mass Ave, Cambridge, MA 02139, USA.
28  *
29  *
30  *  TODO: - Add get/put interface & fixup locking to provide same API for
31  *          2.4 and 2.5
32  *	  - Rework PM callbacks
33  */
34 
35 #ifdef __KERNEL__
36 #ifndef __OCP_H__
37 #define __OCP_H__
38 
39 #include <linux/init.h>
40 #include <linux/list.h>
41 #include <linux/config.h>
42 #include <linux/devfs_fs_kernel.h>
43 
44 #include <asm/mmu.h>
45 #include <asm/ocp_ids.h>
46 #include <asm/rwsem.h>
47 #include <asm/semaphore.h>
48 
49 #if defined(CONFIG_IBM_OCP)
50 #include <platforms/ibm_ocp.h>
51 #endif
52 
53 #if defined(CONFIG_MPC_OCP)
54 #include <asm/mpc_ocp.h>
55 #endif
56 
57 #define OCP_MAX_IRQS	7
58 #define MAX_EMACS	4
59 #define OCP_IRQ_NA	-1	/* used when ocp device does not have an irq */
60 #define OCP_IRQ_MUL	-2	/* used for ocp devices with multiply irqs */
61 #define OCP_NULL_TYPE	-1	/* used to mark end of list */
62 #define OCP_CPM_NA	0	/* No Clock or Power Management avaliable */
63 #define OCP_PADDR_NA	0	/* No MMIO registers */
64 
65 #define OCP_ANY_ID	(~0)
66 #define OCP_ANY_INDEX	-1
67 
68 extern struct list_head 	ocp_devices;
69 extern struct list_head 	ocp_drivers;
70 extern struct rw_semaphore	ocp_devices_sem;
71 extern struct semaphore		ocp_drivers_sem;
72 
73 struct ocp_device_id {
74 	unsigned int	vendor, function;	/* Vendor and function ID or OCP_ANY_ID */
75 	unsigned long	driver_data;		/* Data private to the driver */
76 };
77 
78 
79 /*
80  * Static definition of an OCP device.
81  *
82  * @vendor:    Vendor code. It is _STRONGLY_ discouraged to use
83  *             the vendor code as a way to match a unique device,
84  *             though I kept that possibility open, you should
85  *             really define different function codes for different
86  *             device types
87  * @function:  This is the function code for this device.
88  * @index:     This index is used for mapping the Nth function of a
89  *             given core. This is typically used for cross-driver
90  *             matching, like looking for a given MAL or ZMII from
91  *             an EMAC or for getting to the proper set of DCRs.
92  *             Indices are no longer magically calculated based on
93  *             structure ordering, they have to be actually coded
94  *             into the ocp_def to avoid any possible confusion
95  *             I _STRONGLY_ (again ? wow !) encourage anybody relying
96  *             on index mapping to encode the "target" index in an
97  *             associated structure pointed to by "additions", see
98  *             how it's done for the EMAC driver.
99  * @paddr:     Device physical address (may not mean anything...)
100  * @irq:       Interrupt line for this device (TODO: think about making
101  *             an array with this)
102  * @pm:        Currently, contains the bitmask in CPMFR DCR for the device
103  * @additions: Optionally points to a function specific structure
104  *             providing additional informations for a given device
105  *             instance. It's currently used by the EMAC driver for MAL
106  *             channel & ZMII port mapping among others.
107  */
108 struct ocp_def {
109 	unsigned int	vendor;
110 	unsigned int	function;
111 	int		index;
112 	phys_addr_t	paddr;
113 	int	  	irq;
114 	unsigned long	pm;
115 	void		*additions;
116 };
117 
118 
119 /* Struct for a given device instance */
120 struct ocp_device {
121 	struct list_head	link;
122 	char			name[80];	/* device name */
123 	struct ocp_def		*def;		/* device definition */
124 	void			*drvdata;	/* driver data for this device */
125 	struct ocp_driver	*driver;
126 	u32			current_state;	/* Current operating state. In ACPI-speak,
127 						   this is D0-D3, D0 being fully functional,
128 						   and D3 being off. */
129 };
130 
131 /* Structure for a device driver */
132 struct ocp_driver {
133 	const char		   	*name;
134 	const struct ocp_device_id	*id_table;	/* NULL if wants all devices */
135 
136 	int	 (*probe)  (struct ocp_device *dev);	/* New device inserted */
137 	void	 (*remove) (struct ocp_device *dev);	/* Device removed (NULL if not a
138 							   hot-plug capable driver) */
139 	int 	 (*save_state) (struct ocp_device *dev, u32 state);  /* Save Device Context */
140 	int 	 (*suspend) (struct ocp_device *dev, u32 state);     /* Device suspended */
141 	int 	 (*resume) (struct ocp_device *dev);	             /* Device woken up */
142 	int 	 (*enable_wake) (struct ocp_device *dev, u32 state, int enable);
143 	                                                             /* Enable wake event */
144 	struct list_head		link;
145 };
146 
147 /* Similar to the helpers above, these manipulate per-ocp_dev
148  * driver-specific data.  Currently stored as ocp_dev::ocpdev,
149  * a void pointer, but it is not present on older kernels.
150  */
151 static inline void *
ocp_get_drvdata(struct ocp_device * pdev)152 ocp_get_drvdata(struct ocp_device *pdev)
153 {
154 	return pdev->drvdata;
155 }
156 
157 static inline void
ocp_set_drvdata(struct ocp_device * pdev,void * data)158 ocp_set_drvdata(struct ocp_device *pdev, void *data)
159 {
160 	pdev->drvdata = data;
161 }
162 
163 #if defined (CONFIG_PM)
164 /*
165  * This is right for the IBM 405 and 440 but will need to be
166  * generalized if the OCP stuff gets used on other processors.
167  */
168 static inline void
ocp_force_power_off(struct ocp_device * odev)169 ocp_force_power_off(struct ocp_device *odev)
170 {
171 	mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) | odev->def->pm);
172 }
173 
174 static inline void
ocp_force_power_on(struct ocp_device * odev)175 ocp_force_power_on(struct ocp_device *odev)
176 {
177 	mtdcr(DCRN_CPMFR, mfdcr(DCRN_CPMFR) & ~odev->def->pm);
178 }
179 #else
180 #define ocp_force_power_off(x)	(void)(x)
181 #define ocp_force_power_on(x)	(void)(x)
182 #endif
183 
184 /* Register/Unregister an OCP driver */
185 extern int ocp_register_driver(struct ocp_driver *drv);
186 extern void ocp_unregister_driver(struct ocp_driver *drv);
187 
188 /* Build list of devices */
189 extern int ocp_early_init(void) __init;
190 
191 /* Initialize the driver portion of OCP management layer */
192 extern int ocp_driver_init(void);
193 
194 /* Find a device by index */
195 extern struct ocp_device *ocp_find_device(unsigned int vendor, unsigned int function, int index);
196 
197 /* Get a def by index */
198 extern struct ocp_def *ocp_get_one_device(unsigned int vendor, unsigned int function, int index);
199 
200 /* Add a device by index */
201 extern int ocp_add_one_device(struct ocp_def *def);
202 
203 /* Remove a device by index */
204 extern int ocp_remove_one_device(unsigned int vendor, unsigned int function, int index);
205 
206 #endif				/* __OCP_H__ */
207 #endif				/* __KERNEL__ */
208