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