]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/src/circbuf.c
staging/atomisp: Add support for the Intel IPU v2
[mirror_ubuntu-hirsute-kernel.git] / drivers / staging / media / atomisp / pci / atomisp2 / css2400 / base / circbuf / src / circbuf.c
1 /*
2 * Support for Intel Camera Imaging ISP subsystem.
3 * Copyright (c) 2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15 #include "ia_css_circbuf.h"
16
17 #include <assert_support.h>
18
19 #ifdef __SP
20 #include <hive_isp_css_sp_api_modified.h>
21 #include <ia_css_sp_file_id.sp.h>
22 #ifndef SP_FILE_ID
23 #define SP_FILE_ID SP_FILE_ID_CIRCBUF /* overrule default in ia_css_sp_assert_level.sp.h */
24 #endif
25 #include <ia_css_sp_assert_level.sp.h>
26 #endif
27
28 /**********************************************************************
29 *
30 * Forward declarations.
31 *
32 **********************************************************************/
33 /**
34 * @brief Read the oldest element from the circular buffer.
35 * Read the oldest element WITHOUT checking whehter the
36 * circular buffer is empty or not. The oldest element is
37 * also removed out from the circular buffer.
38 *
39 * @param cb The pointer to the circular buffer.
40 *
41 * @return the oldest element.
42 */
43 static inline ia_css_circbuf_elem_t
44 ia_css_circbuf_read(ia_css_circbuf_t *cb);
45
46 /**
47 * @brief Shift a chunk of elements in the circular buffer.
48 * A chunk of elements (i.e. the ones from the "start" position
49 * to the "chunk_src" position) are shifted in the circular buffer,
50 * along the direction of new elements coming.
51 *
52 * @param cb The pointer to the circular buffer.
53 * @param chunk_src The position at which the first element in the chunk is.
54 * @param chunk_dest The position to which the first element in the chunk would be shift.
55 */
56 static inline void ia_css_circbuf_shift_chunk(ia_css_circbuf_t *cb,
57 uint32_t chunk_src,
58 uint32_t chunk_dest);
59
60 /**
61 * @brief Get the "val" field in the element.
62 *
63 * @param elem The pointer to the element.
64 *
65 * @return the "val" field.
66 */
67 static inline uint32_t
68 ia_css_circbuf_elem_get_val(ia_css_circbuf_elem_t *elem);
69
70 /**********************************************************************
71 *
72 * Non-inline functions.
73 *
74 **********************************************************************/
75 /**
76 * @brief Create the circular buffer.
77 * Refer to "ia_css_circbuf.h" for details.
78 */
79 void
80 ia_css_circbuf_create(ia_css_circbuf_t *cb,
81 ia_css_circbuf_elem_t *elems,
82 ia_css_circbuf_desc_t *desc)
83 {
84 uint32_t i;
85
86 OP___assert(desc);
87
88 cb->desc = desc;
89 /* Initialize to defaults */
90 cb->desc->start = 0;
91 cb->desc->end = 0;
92 cb->desc->step = 0;
93
94 for (i = 0; i < cb->desc->size; i++)
95 ia_css_circbuf_elem_init(&elems[i]);
96
97 cb->elems = elems;
98 }
99
100 /**
101 * @brief Destroy the circular buffer.
102 * Refer to "ia_css_circbuf.h" for details.
103 */
104 void ia_css_circbuf_destroy(ia_css_circbuf_t *cb)
105 {
106 cb->desc = NULL;
107
108 cb->elems = NULL;
109 }
110
111 /**
112 * @brief Pop a value out of the circular buffer.
113 * Refer to "ia_css_circbuf.h" for details.
114 */
115 uint32_t ia_css_circbuf_pop(ia_css_circbuf_t *cb)
116 {
117 uint32_t ret;
118 ia_css_circbuf_elem_t elem;
119
120 #ifdef __SP
121 SP_ASSERT_FATAL(!ia_css_circbuf_is_empty(cb));
122 #else
123 assert(!ia_css_circbuf_is_empty(cb));
124 #endif
125
126 /* read an element from the buffer */
127 elem = ia_css_circbuf_read(cb);
128 ret = ia_css_circbuf_elem_get_val(&elem);
129 return ret;
130 }
131
132 /**
133 * @brief Extract a value out of the circular buffer.
134 * Refer to "ia_css_circbuf.h" for details.
135 */
136 uint32_t ia_css_circbuf_extract(ia_css_circbuf_t *cb, int offset)
137 {
138 int max_offset;
139 uint32_t val;
140 uint32_t pos;
141 uint32_t src_pos;
142 uint32_t dest_pos;
143
144 /* get the maximum offest */
145 max_offset = ia_css_circbuf_get_offset(cb, cb->desc->start, cb->desc->end);
146 max_offset--;
147
148 /*
149 * Step 1: When the target element is at the "start" position.
150 */
151 if (offset == 0) {
152 val = ia_css_circbuf_pop(cb);
153 return val;
154 }
155
156 /*
157 * Step 2: When the target element is out of the range.
158 */
159 if (offset > max_offset) {
160 val = 0;
161 return val;
162 }
163
164 /*
165 * Step 3: When the target element is between the "start" and
166 * "end" position.
167 */
168 /* get the position of the target element */
169 pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, offset);
170
171 /* get the value from the target element */
172 val = ia_css_circbuf_elem_get_val(&cb->elems[pos]);
173
174 /* shift the elements */
175 src_pos = ia_css_circbuf_get_pos_at_offset(cb, pos, -1);
176 dest_pos = pos;
177 ia_css_circbuf_shift_chunk(cb, src_pos, dest_pos);
178
179 return val;
180 }
181
182 /**
183 * @brief Peek an element from the circular buffer.
184 * Refer to "ia_css_circbuf.h" for details.
185 */
186 uint32_t ia_css_circbuf_peek(ia_css_circbuf_t *cb, int offset)
187 {
188 int pos;
189
190 pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, offset);
191
192 /* get the value at the position */
193 return cb->elems[pos].val;
194 }
195
196 /**
197 * @brief Get the value of an element from the circular buffer.
198 * Refer to "ia_css_circbuf.h" for details.
199 */
200 uint32_t ia_css_circbuf_peek_from_start(ia_css_circbuf_t *cb, int offset)
201 {
202 int pos;
203
204 pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, offset);
205
206 /* get the value at the position */
207 return cb->elems[pos].val;
208 }
209
210 /** @brief increase size of a circular buffer.
211 * Use 'CAUTION' before using this function. This was added to
212 * support / fix issue with increasing size for tagger only
213 * Please refer to "ia_css_circbuf.h" for details.
214 */
215 bool ia_css_circbuf_increase_size(
216 ia_css_circbuf_t *cb,
217 unsigned int sz_delta,
218 ia_css_circbuf_elem_t *elems)
219 {
220 uint8_t curr_size;
221 uint8_t curr_end;
222 unsigned int i = 0;
223
224 if (!cb || sz_delta == 0)
225 return false;
226
227 curr_size = cb->desc->size;
228 curr_end = cb->desc->end;
229 /* We assume cb was pre defined as global to allow
230 * increase in size */
231 /* FM: are we sure this cannot cause size to become too big? */
232 if (((uint8_t)(cb->desc->size + (uint8_t)sz_delta) > cb->desc->size) && ((uint8_t)sz_delta == sz_delta))
233 cb->desc->size += (uint8_t)sz_delta;
234 else
235 return false; /* overflow in size */
236
237 /* If elems are passed update them else we assume its been taken
238 * care before calling this function */
239 if (elems) {
240 /* cb element array size will not be increased dynamically,
241 * but pointers to new elements can be added at the end
242 * of existing pre defined cb element array of
243 * size >= new size if not already added */
244 for (i = curr_size; i < cb->desc->size; i++)
245 cb->elems[i] = elems[i - curr_size];
246 }
247 /* Fix Start / End */
248 if (curr_end < cb->desc->start) {
249 if (curr_end == 0) {
250 /* Easily fix End */
251 cb->desc->end = curr_size;
252 } else {
253 /* Move elements and fix Start*/
254 ia_css_circbuf_shift_chunk(cb,
255 curr_size - 1,
256 curr_size + sz_delta - 1);
257 }
258 }
259
260 return true;
261 }
262
263 /****************************************************************
264 *
265 * Inline functions.
266 *
267 ****************************************************************/
268 /**
269 * @brief Get the "val" field in the element.
270 * Refer to "Forward declarations" for details.
271 */
272 static inline uint32_t
273 ia_css_circbuf_elem_get_val(ia_css_circbuf_elem_t *elem)
274 {
275 return elem->val;
276 }
277
278 /**
279 * @brief Read the oldest element from the circular buffer.
280 * Refer to "Forward declarations" for details.
281 */
282 static inline ia_css_circbuf_elem_t
283 ia_css_circbuf_read(ia_css_circbuf_t *cb)
284 {
285 ia_css_circbuf_elem_t elem;
286
287 /* get the element from the target position */
288 elem = cb->elems[cb->desc->start];
289
290 /* clear the target position */
291 ia_css_circbuf_elem_init(&cb->elems[cb->desc->start]);
292
293 /* adjust the "start" position */
294 cb->desc->start = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, 1);
295 return elem;
296 }
297
298 /**
299 * @brief Shift a chunk of elements in the circular buffer.
300 * Refer to "Forward declarations" for details.
301 */
302 static inline void
303 ia_css_circbuf_shift_chunk(ia_css_circbuf_t *cb,
304 uint32_t chunk_src, uint32_t chunk_dest)
305 {
306 int chunk_offset;
307 int chunk_sz;
308 int i;
309
310 /* get the chunk offset and size */
311 chunk_offset = ia_css_circbuf_get_offset(cb,
312 chunk_src, chunk_dest);
313 chunk_sz = ia_css_circbuf_get_offset(cb, cb->desc->start, chunk_src) + 1;
314
315 /* shift each element to its terminal position */
316 for (i = 0; i < chunk_sz; i++) {
317
318 /* copy the element from the source to the destination */
319 ia_css_circbuf_elem_cpy(&cb->elems[chunk_src],
320 &cb->elems[chunk_dest]);
321
322 /* clear the source position */
323 ia_css_circbuf_elem_init(&cb->elems[chunk_src]);
324
325 /* adjust the source/terminal positions */
326 chunk_src = ia_css_circbuf_get_pos_at_offset(cb, chunk_src, -1);
327 chunk_dest = ia_css_circbuf_get_pos_at_offset(cb, chunk_dest, -1);
328
329 }
330
331 /* adjust the index "start" */
332 cb->desc->start = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, chunk_offset);
333 }
334