1 /*
2  * Public header for the MPC52xx processor BestComm driver
3  *
4  *
5  * Copyright (C) 2006      Sylvain Munaut <tnt@246tNt.com>
6  * Copyright (C) 2005      Varma Electronics Oy,
7  *                         ( by Andrey Volkov <avolkov@varma-el.com> )
8  * Copyright (C) 2003-2004 MontaVista, Software, Inc.
9  *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
10  *
11  * This file is licensed under the terms of the GNU General Public License
12  * version 2. This program is licensed "as is" without any warranty of any
13  * kind, whether express or implied.
14  */
15 
16 #ifndef __BESTCOMM_H__
17 #define __BESTCOMM_H__
18 
19 /**
20  * struct bcom_bd - Structure describing a generic BestComm buffer descriptor
21  * @status: The current status of this buffer. Exact meaning depends on the
22  *          task type
23  * @data: An array of u32 extra data.  Size of array is task dependent.
24  *
25  * Note: Don't dereference a bcom_bd pointer as an array.  The size of the
26  *       bcom_bd is variable.  Use bcom_get_bd() instead.
27  */
28 struct bcom_bd {
29 	u32	status;
30 	u32	data[];	/* variable payload size */
31 };
32 
33 /* ======================================================================== */
34 /* Generic task management                                                   */
35 /* ======================================================================== */
36 
37 /**
38  * struct bcom_task - Structure describing a loaded BestComm task
39  *
40  * This structure is never built by the driver it self. It's built and
41  * filled the intermediate layer of the BestComm API, the task dependent
42  * support code.
43  *
44  * Most likely you don't need to poke around inside this structure. The
45  * fields are exposed in the header just for the sake of inline functions
46  */
47 struct bcom_task {
48 	unsigned int	tasknum;
49 	unsigned int	flags;
50 	int		irq;
51 
52 	struct bcom_bd	*bd;
53 	phys_addr_t	bd_pa;
54 	void		**cookie;
55 	unsigned short	index;
56 	unsigned short	outdex;
57 	unsigned int	num_bd;
58 	unsigned int	bd_size;
59 
60 	void*		priv;
61 };
62 
63 #define BCOM_FLAGS_NONE         0x00000000ul
64 #define BCOM_FLAGS_ENABLE_TASK  (1ul <<  0)
65 
66 /**
67  * bcom_enable - Enable a BestComm task
68  * @tsk: The BestComm task structure
69  *
70  * This function makes sure the given task is enabled and can be run
71  * by the BestComm engine as needed
72  */
73 extern void bcom_enable(struct bcom_task *tsk);
74 
75 /**
76  * bcom_disable - Disable a BestComm task
77  * @tsk: The BestComm task structure
78  *
79  * This function disable a given task, making sure it's not executed
80  * by the BestComm engine.
81  */
82 extern void bcom_disable(struct bcom_task *tsk);
83 
84 
85 /**
86  * bcom_get_task_irq - Returns the irq number of a BestComm task
87  * @tsk: The BestComm task structure
88  */
89 static inline int
90 bcom_get_task_irq(struct bcom_task *tsk) {
91 	return tsk->irq;
92 }
93 
94 /* ======================================================================== */
95 /* BD based tasks helpers                                                   */
96 /* ======================================================================== */
97 
98 #define BCOM_BD_READY	0x40000000ul
99 
100 /** _bcom_next_index - Get next input index.
101  * @tsk: pointer to task structure
102  *
103  * Support function; Device drivers should not call this
104  */
105 static inline int
106 _bcom_next_index(struct bcom_task *tsk)
107 {
108 	return ((tsk->index + 1) == tsk->num_bd) ? 0 : tsk->index + 1;
109 }
110 
111 /** _bcom_next_outdex - Get next output index.
112  * @tsk: pointer to task structure
113  *
114  * Support function; Device drivers should not call this
115  */
116 static inline int
117 _bcom_next_outdex(struct bcom_task *tsk)
118 {
119 	return ((tsk->outdex + 1) == tsk->num_bd) ? 0 : tsk->outdex + 1;
120 }
121 
122 /**
123  * bcom_queue_empty - Checks if a BestComm task BD queue is empty
124  * @tsk: The BestComm task structure
125  */
126 static inline int
127 bcom_queue_empty(struct bcom_task *tsk)
128 {
129 	return tsk->index == tsk->outdex;
130 }
131 
132 /**
133  * bcom_queue_full - Checks if a BestComm task BD queue is full
134  * @tsk: The BestComm task structure
135  */
136 static inline int
137 bcom_queue_full(struct bcom_task *tsk)
138 {
139 	return tsk->outdex == _bcom_next_index(tsk);
140 }
141 
142 /**
143  * bcom_get_bd - Get a BD from the queue
144  * @tsk: The BestComm task structure
145  * index: Index of the BD to fetch
146  */
147 static inline struct bcom_bd
148 *bcom_get_bd(struct bcom_task *tsk, unsigned int index)
149 {
150 	/* A cast to (void*) so the address can be incremented by the
151 	 * real size instead of by sizeof(struct bcom_bd) */
152 	return ((void *)tsk->bd) + (index * tsk->bd_size);
153 }
154 
155 /**
156  * bcom_buffer_done - Checks if a BestComm
157  * @tsk: The BestComm task structure
158  */
159 static inline int
160 bcom_buffer_done(struct bcom_task *tsk)
161 {
162 	struct bcom_bd *bd;
163 	if (bcom_queue_empty(tsk))
164 		return 0;
165 
166 	bd = bcom_get_bd(tsk, tsk->outdex);
167 	return !(bd->status & BCOM_BD_READY);
168 }
169 
170 /**
171  * bcom_prepare_next_buffer - clear status of next available buffer.
172  * @tsk: The BestComm task structure
173  *
174  * Returns pointer to next buffer descriptor
175  */
176 static inline struct bcom_bd *
177 bcom_prepare_next_buffer(struct bcom_task *tsk)
178 {
179 	struct bcom_bd *bd;
180 
181 	bd = bcom_get_bd(tsk, tsk->index);
182 	bd->status = 0;	/* cleanup last status */
183 	return bd;
184 }
185 
186 static inline void
187 bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie)
188 {
189 	struct bcom_bd *bd = bcom_get_bd(tsk, tsk->index);
190 
191 	tsk->cookie[tsk->index] = cookie;
192 	mb();	/* ensure the bd is really up-to-date */
193 	bd->status |= BCOM_BD_READY;
194 	tsk->index = _bcom_next_index(tsk);
195 	if (tsk->flags & BCOM_FLAGS_ENABLE_TASK)
196 		bcom_enable(tsk);
197 }
198 
199 static inline void *
200 bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd)
201 {
202 	void *cookie = tsk->cookie[tsk->outdex];
203 	struct bcom_bd *bd = bcom_get_bd(tsk, tsk->outdex);
204 
205 	if (p_status)
206 		*p_status = bd->status;
207 	if (p_bd)
208 		*p_bd = bd;
209 	tsk->outdex = _bcom_next_outdex(tsk);
210 	return cookie;
211 }
212 
213 #endif /* __BESTCOMM_H__ */
214