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