1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Support for Intel Camera Imaging ISP subsystem.
4  * Copyright (c) 2015, Intel Corporation.
5  */
6 
7 #ifndef _IA_CSS_CIRCBUF_H
8 #define _IA_CSS_CIRCBUF_H
9 
10 #include <sp.h>
11 #include <type_support.h>
12 #include <math_support.h>
13 #include <assert_support.h>
14 #include <platform_support.h>
15 #include "ia_css_circbuf_comm.h"
16 #include "ia_css_circbuf_desc.h"
17 
18 /****************************************************************
19  *
20  * Data structures.
21  *
22  ****************************************************************/
23 /**
24  * @brief Data structure for the circular buffer.
25  */
26 typedef struct ia_css_circbuf_s ia_css_circbuf_t;
27 struct ia_css_circbuf_s {
28 	ia_css_circbuf_desc_t *desc;    /* Pointer to the descriptor of the circbuf */
29 	ia_css_circbuf_elem_t *elems;	/* an array of elements    */
30 };
31 
32 /**
33  * @brief Create the circular buffer.
34  *
35  * @param cb	The pointer to the circular buffer.
36  * @param elems	An array of elements.
37  * @param desc	The descriptor set to the size using ia_css_circbuf_desc_init().
38  */
39 void ia_css_circbuf_create(
40     ia_css_circbuf_t *cb,
41     ia_css_circbuf_elem_t *elems,
42     ia_css_circbuf_desc_t *desc);
43 
44 /**
45  * @brief Destroy the circular buffer.
46  *
47  * @param cb The pointer to the circular buffer.
48  */
49 void ia_css_circbuf_destroy(
50     ia_css_circbuf_t *cb);
51 
52 /**
53  * @brief Pop a value out of the circular buffer.
54  * Get a value at the head of the circular buffer.
55  * The user should call "ia_css_circbuf_is_empty()"
56  * to avoid accessing to an empty buffer.
57  *
58  * @param cb	The pointer to the circular buffer.
59  *
60  * @return the pop-out value.
61  */
62 uint32_t ia_css_circbuf_pop(
63     ia_css_circbuf_t *cb);
64 
65 /**
66  * @brief Extract a value out of the circular buffer.
67  * Get a value at an arbitrary position in the circular
68  * buffer. The user should call "ia_css_circbuf_is_empty()"
69  * to avoid accessing to an empty buffer.
70  *
71  * @param cb	 The pointer to the circular buffer.
72  * @param offset The offset from "start" to the target position.
73  *
74  * @return the extracted value.
75  */
76 uint32_t ia_css_circbuf_extract(
77     ia_css_circbuf_t *cb,
78     int offset);
79 
80 /****************************************************************
81  *
82  * Inline functions.
83  *
84  ****************************************************************/
85 /**
86  * @brief Set the "val" field in the element.
87  *
88  * @param elem The pointer to the element.
89  * @param val  The value to be set.
90  */
ia_css_circbuf_elem_set_val(ia_css_circbuf_elem_t * elem,uint32_t val)91 static inline void ia_css_circbuf_elem_set_val(
92     ia_css_circbuf_elem_t *elem,
93     uint32_t val)
94 {
95 	OP___assert(elem);
96 
97 	elem->val = val;
98 }
99 
100 /**
101  * @brief Initialize the element.
102  *
103  * @param elem The pointer to the element.
104  */
ia_css_circbuf_elem_init(ia_css_circbuf_elem_t * elem)105 static inline void ia_css_circbuf_elem_init(
106     ia_css_circbuf_elem_t *elem)
107 {
108 	OP___assert(elem);
109 	ia_css_circbuf_elem_set_val(elem, 0);
110 }
111 
112 /**
113  * @brief Copy an element.
114  *
115  * @param src  The element as the copy source.
116  * @param dest The element as the copy destination.
117  */
ia_css_circbuf_elem_cpy(ia_css_circbuf_elem_t * src,ia_css_circbuf_elem_t * dest)118 static inline void ia_css_circbuf_elem_cpy(
119     ia_css_circbuf_elem_t *src,
120     ia_css_circbuf_elem_t *dest)
121 {
122 	OP___assert(src);
123 	OP___assert(dest);
124 
125 	ia_css_circbuf_elem_set_val(dest, src->val);
126 }
127 
128 /**
129  * @brief Get position in the circular buffer.
130  *
131  * @param cb		The pointer to the circular buffer.
132  * @param base		The base position.
133  * @param offset	The offset.
134  *
135  * @return the position at offset.
136  */
ia_css_circbuf_get_pos_at_offset(ia_css_circbuf_t * cb,u32 base,int offset)137 static inline uint8_t ia_css_circbuf_get_pos_at_offset(
138     ia_css_circbuf_t *cb,
139     u32 base,
140     int offset)
141 {
142 	u8 dest;
143 
144 	OP___assert(cb);
145 	OP___assert(cb->desc);
146 	OP___assert(cb->desc->size > 0);
147 
148 	/* step 1: adjudst the offset  */
149 	while (offset < 0) {
150 		offset += cb->desc->size;
151 	}
152 
153 	/* step 2: shift and round by the upper limit */
154 	dest = OP_std_modadd(base, offset, cb->desc->size);
155 
156 	return dest;
157 }
158 
159 /**
160  * @brief Get the offset between two positions in the circular buffer.
161  * Get the offset from the source position to the terminal position,
162  * along the direction in which the new elements come in.
163  *
164  * @param cb		The pointer to the circular buffer.
165  * @param src_pos	The source position.
166  * @param dest_pos	The terminal position.
167  *
168  * @return the offset.
169  */
ia_css_circbuf_get_offset(ia_css_circbuf_t * cb,u32 src_pos,uint32_t dest_pos)170 static inline int ia_css_circbuf_get_offset(
171     ia_css_circbuf_t *cb,
172     u32 src_pos,
173     uint32_t dest_pos)
174 {
175 	int offset;
176 
177 	OP___assert(cb);
178 	OP___assert(cb->desc);
179 
180 	offset = (int)(dest_pos - src_pos);
181 	offset += (offset < 0) ? cb->desc->size : 0;
182 
183 	return offset;
184 }
185 
186 /**
187  * @brief Get the maximum number of elements.
188  *
189  * @param cb The pointer to the circular buffer.
190  *
191  * @return the maximum number of elements.
192  *
193  * TODO: Test this API.
194  */
ia_css_circbuf_get_size(ia_css_circbuf_t * cb)195 static inline uint32_t ia_css_circbuf_get_size(
196     ia_css_circbuf_t *cb)
197 {
198 	OP___assert(cb);
199 	OP___assert(cb->desc);
200 
201 	return cb->desc->size;
202 }
203 
204 /**
205  * @brief Get the number of available elements.
206  *
207  * @param cb The pointer to the circular buffer.
208  *
209  * @return the number of available elements.
210  */
ia_css_circbuf_get_num_elems(ia_css_circbuf_t * cb)211 static inline uint32_t ia_css_circbuf_get_num_elems(
212     ia_css_circbuf_t *cb)
213 {
214 	int num;
215 
216 	OP___assert(cb);
217 	OP___assert(cb->desc);
218 
219 	num = ia_css_circbuf_get_offset(cb, cb->desc->start, cb->desc->end);
220 
221 	return (uint32_t)num;
222 }
223 
224 /**
225  * @brief Test if the circular buffer is empty.
226  *
227  * @param cb	The pointer to the circular buffer.
228  *
229  * @return
230  *	- true when it is empty.
231  *	- false when it is not empty.
232  */
ia_css_circbuf_is_empty(ia_css_circbuf_t * cb)233 static inline bool ia_css_circbuf_is_empty(
234     ia_css_circbuf_t *cb)
235 {
236 	OP___assert(cb);
237 	OP___assert(cb->desc);
238 
239 	return ia_css_circbuf_desc_is_empty(cb->desc);
240 }
241 
242 /**
243  * @brief Test if the circular buffer is full.
244  *
245  * @param cb	The pointer to the circular buffer.
246  *
247  * @return
248  *	- true when it is full.
249  *	- false when it is not full.
250  */
ia_css_circbuf_is_full(ia_css_circbuf_t * cb)251 static inline bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb)
252 {
253 	OP___assert(cb);
254 	OP___assert(cb->desc);
255 
256 	return ia_css_circbuf_desc_is_full(cb->desc);
257 }
258 
259 /**
260  * @brief Write a new element into the circular buffer.
261  * Write a new element WITHOUT checking whether the
262  * circular buffer is full or not. So it also overwrites
263  * the oldest element when the buffer is full.
264  *
265  * @param cb	The pointer to the circular buffer.
266  * @param elem	The new element.
267  */
ia_css_circbuf_write(ia_css_circbuf_t * cb,ia_css_circbuf_elem_t elem)268 static inline void ia_css_circbuf_write(
269     ia_css_circbuf_t *cb,
270     ia_css_circbuf_elem_t elem)
271 {
272 	OP___assert(cb);
273 	OP___assert(cb->desc);
274 
275 	/* Cannot continue as the queue is full*/
276 	assert(!ia_css_circbuf_is_full(cb));
277 
278 	ia_css_circbuf_elem_cpy(&elem, &cb->elems[cb->desc->end]);
279 
280 	cb->desc->end = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, 1);
281 }
282 
283 /**
284  * @brief Push a value in the circular buffer.
285  * Put a new value at the tail of the circular buffer.
286  * The user should call "ia_css_circbuf_is_full()"
287  * to avoid accessing to a full buffer.
288  *
289  * @param cb	The pointer to the circular buffer.
290  * @param val	The value to be pushed in.
291  */
ia_css_circbuf_push(ia_css_circbuf_t * cb,uint32_t val)292 static inline void ia_css_circbuf_push(
293     ia_css_circbuf_t *cb,
294     uint32_t val)
295 {
296 	ia_css_circbuf_elem_t elem;
297 
298 	OP___assert(cb);
299 
300 	/* set up an element */
301 	ia_css_circbuf_elem_init(&elem);
302 	ia_css_circbuf_elem_set_val(&elem, val);
303 
304 	/* write the element into the buffer */
305 	ia_css_circbuf_write(cb, elem);
306 }
307 
308 /**
309  * @brief Get the number of free elements.
310  *
311  * @param cb The pointer to the circular buffer.
312  *
313  * @return: The number of free elements.
314  */
ia_css_circbuf_get_free_elems(ia_css_circbuf_t * cb)315 static inline uint32_t ia_css_circbuf_get_free_elems(
316     ia_css_circbuf_t *cb)
317 {
318 	OP___assert(cb);
319 	OP___assert(cb->desc);
320 
321 	return ia_css_circbuf_desc_get_free_elems(cb->desc);
322 }
323 
324 /**
325  * @brief Peek an element in Circular Buffer.
326  *
327  * @param cb	 The pointer to the circular buffer.
328  * @param offset Offset to the element.
329  *
330  * @return the elements value.
331  */
332 uint32_t ia_css_circbuf_peek(
333     ia_css_circbuf_t *cb,
334     int offset);
335 
336 /**
337  * @brief Get an element in Circular Buffer.
338  *
339  * @param cb	 The pointer to the circular buffer.
340  * @param offset Offset to the element.
341  *
342  * @return the elements value.
343  */
344 uint32_t ia_css_circbuf_peek_from_start(
345     ia_css_circbuf_t *cb,
346     int offset);
347 
348 /**
349  * @brief Increase Size of a Circular Buffer.
350  * Use 'CAUTION' before using this function, This was added to
351  * support / fix issue with increasing size for tagger only
352  *
353  * @param cb The pointer to the circular buffer.
354  * @param sz_delta delta increase for new size
355  * @param elems (optional) pointers to new additional elements
356  *		cb element array size will not be increased dynamically,
357  *		but new elements should be added at the end to existing
358  *		cb element array which if of max_size >= new size
359  *
360  * @return	true on successfully increasing the size
361  *			false on failure
362  */
363 bool ia_css_circbuf_increase_size(
364     ia_css_circbuf_t *cb,
365     unsigned int sz_delta,
366     ia_css_circbuf_elem_t *elems);
367 
368 #endif /*_IA_CSS_CIRCBUF_H */
369