summaryrefslogtreecommitdiffstats
path: root/drivers/staging/media/atomisp/pci/atomisp2/css2400/base
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2017-02-17 16:55:17 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-06 09:39:54 +0100
commita49d25364dfb9f8a64037488a39ab1f56c5fa419 (patch)
treebd97382cf06a958cef045e75334fc622500ba209 /drivers/staging/media/atomisp/pci/atomisp2/css2400/base
parent372499b589ae5ec38d3dec88b72f2bde3b3790d4 (diff)
downloadop-kernel-dev-a49d25364dfb9f8a64037488a39ab1f56c5fa419.zip
op-kernel-dev-a49d25364dfb9f8a64037488a39ab1f56c5fa419.tar.gz
staging/atomisp: Add support for the Intel IPU v2
This patch adds support for the Intel IPU v2 as found on Android and IoT Baytrail-T and Baytrail-CR platforms (those with the IPU PCI mapped). You will also need the firmware files from your device (Android usually puts them into /etc) - or you can find them in the downloadable restore/upgrade kits if you blew them away for some reason. It may be possible to extend the driver to handle the BYT/T windows platforms such as the ASUS T100TA. These platforms don't expose the IPU via the PCI interface but via ACPI buried in the GPU description and with the camera information somewhere unknown so would need a platform driver interface adding to the codebase *IFF* the firmware works on such devices. To get good results you also need a suitable support library such as libxcam. The camera is intended to be driven from Android so it has a lot of features that many desktop apps don't fully spport. In theory all the pieces are there to build it with -DISP2401 and some differing files to get CherryTrail/T support, but unifying the drivers properlly is a work in progress. The IPU driver represents the work of a lot of people within Intel over many years. It's historical goal was portability rather than Linux upstream. Any queries about the upstream aimed driver should be sent to me not to the original authors. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/media/atomisp/pci/atomisp2/css2400/base')
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf.h386
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_comm.h56
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_desc.h170
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/src/circbuf.c334
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/base/refcount/interface/ia_css_refcount.h83
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp2/css2400/base/refcount/src/refcount.c281
6 files changed, 1310 insertions, 0 deletions
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf.h
new file mode 100644
index 0000000..2a38e2b
--- /dev/null
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf.h
@@ -0,0 +1,386 @@
+/*
+ * Support for Intel Camera Imaging ISP subsystem.
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _IA_CSS_CIRCBUF_H
+#define _IA_CSS_CIRCBUF_H
+
+#include <sp.h>
+#include <type_support.h>
+#include <math_support.h>
+#include <storage_class.h>
+#include <assert_support.h>
+#include <platform_support.h>
+#include "ia_css_circbuf_comm.h"
+#include "ia_css_circbuf_desc.h"
+#ifdef __SP
+#include "event_handler.sp.h"
+/* We should not #define SP_FILE_ID here, because we are in a header file. */
+#include "ia_css_sp_assert_level.sp.h"
+#endif
+
+/****************************************************************
+ *
+ * Data structures.
+ *
+ ****************************************************************/
+/**
+ * @brief Data structure for the circular buffer.
+ */
+typedef struct ia_css_circbuf_s ia_css_circbuf_t;
+struct ia_css_circbuf_s {
+ ia_css_circbuf_desc_t *desc; /* Pointer to the descriptor of the circbuf */
+ ia_css_circbuf_elem_t *elems; /* an array of elements */
+};
+
+/**
+ * @brief Create the circular buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param elems An array of elements.
+ * @param desc The descriptor set to the size using ia_css_circbuf_desc_init().
+ */
+STORAGE_CLASS_EXTERN void ia_css_circbuf_create(
+ ia_css_circbuf_t *cb,
+ ia_css_circbuf_elem_t *elems,
+ ia_css_circbuf_desc_t *desc);
+
+/**
+ * @brief Destroy the circular buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ */
+STORAGE_CLASS_EXTERN void ia_css_circbuf_destroy(
+ ia_css_circbuf_t *cb);
+
+/**
+ * @brief Pop a value out of the circular buffer.
+ * Get a value at the head of the circular buffer.
+ * The user should call "ia_css_circbuf_is_empty()"
+ * to avoid accessing to an empty buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ *
+ * @return the pop-out value.
+ */
+STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_pop(
+ ia_css_circbuf_t *cb);
+
+/**
+ * @brief Extract a value out of the circular buffer.
+ * Get a value at an arbitrary poistion in the circular
+ * buffer. The user should call "ia_css_circbuf_is_empty()"
+ * to avoid accessing to an empty buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param offset The offset from "start" to the target position.
+ *
+ * @return the extracted value.
+ */
+STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_extract(
+ ia_css_circbuf_t *cb,
+ int offset);
+
+/****************************************************************
+ *
+ * Inline functions.
+ *
+ ****************************************************************/
+/**
+ * @brief Set the "val" field in the element.
+ *
+ * @param elem The pointer to the element.
+ * @param val The value to be set.
+ */
+STORAGE_CLASS_INLINE void ia_css_circbuf_elem_set_val(
+ ia_css_circbuf_elem_t *elem,
+ uint32_t val)
+{
+ OP___assert(elem != NULL);
+
+ elem->val = val;
+}
+
+/**
+ * @brief Initialize the element.
+ *
+ * @param elem The pointer to the element.
+ */
+STORAGE_CLASS_INLINE void ia_css_circbuf_elem_init(
+ ia_css_circbuf_elem_t *elem)
+{
+ OP___assert(elem != NULL);
+ ia_css_circbuf_elem_set_val(elem, 0);
+}
+
+/**
+ * @brief Copy an element.
+ *
+ * @param src The element as the copy source.
+ * @param dest The element as the copy destination.
+ */
+STORAGE_CLASS_INLINE void ia_css_circbuf_elem_cpy(
+ ia_css_circbuf_elem_t *src,
+ ia_css_circbuf_elem_t *dest)
+{
+ OP___assert(src != NULL);
+ OP___assert(dest != NULL);
+
+ ia_css_circbuf_elem_set_val(dest, src->val);
+}
+
+/**
+ * @brief Get position in the circular buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param base The base position.
+ * @param offset The offset.
+ *
+ * @return the position at offset.
+ */
+STORAGE_CLASS_INLINE uint8_t ia_css_circbuf_get_pos_at_offset(
+ ia_css_circbuf_t *cb,
+ uint32_t base,
+ int offset)
+{
+ uint8_t dest;
+
+ OP___assert(cb != NULL);
+ OP___assert(cb->desc != NULL);
+ OP___assert(cb->desc->size > 0);
+
+ /* step 1: adjudst the offset */
+ while (offset < 0) {
+ offset += cb->desc->size;
+ }
+
+ /* step 2: shift and round by the upper limit */
+ dest = OP_std_modadd(base, offset, cb->desc->size);
+
+ return dest;
+}
+
+/**
+ * @brief Get the offset between two positions in the circular buffer.
+ * Get the offset from the source position to the terminal position,
+ * along the direction in which the new elements come in.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param src_pos The source position.
+ * @param dest_pos The terminal position.
+ *
+ * @return the offset.
+ */
+STORAGE_CLASS_INLINE int ia_css_circbuf_get_offset(
+ ia_css_circbuf_t *cb,
+ uint32_t src_pos,
+ uint32_t dest_pos)
+{
+ int offset;
+
+ OP___assert(cb != NULL);
+ OP___assert(cb->desc != NULL);
+
+ offset = (int)(dest_pos - src_pos);
+ offset += (offset < 0) ? cb->desc->size : 0;
+
+ return offset;
+}
+
+/**
+ * @brief Get the maximum number of elements.
+ *
+ * @param cb The pointer to the circular buffer.
+ *
+ * @return the maximum number of elements.
+ *
+ * TODO: Test this API.
+ */
+STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_size(
+ ia_css_circbuf_t *cb)
+{
+ OP___assert(cb != NULL);
+ OP___assert(cb->desc != NULL);
+
+ return cb->desc->size;
+}
+
+/**
+ * @brief Get the number of available elements.
+ *
+ * @param cb The pointer to the circular buffer.
+ *
+ * @return the number of available elements.
+ */
+STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_num_elems(
+ ia_css_circbuf_t *cb)
+{
+ int num;
+
+ OP___assert(cb != NULL);
+ OP___assert(cb->desc != NULL);
+
+ num = ia_css_circbuf_get_offset(cb, cb->desc->start, cb->desc->end);
+
+ return (uint32_t)num;
+}
+
+/**
+ * @brief Test if the circular buffer is empty.
+ *
+ * @param cb The pointer to the circular buffer.
+ *
+ * @return
+ * - true when it is empty.
+ * - false when it is not empty.
+ */
+STORAGE_CLASS_INLINE bool ia_css_circbuf_is_empty(
+ ia_css_circbuf_t *cb)
+{
+ OP___assert(cb != NULL);
+ OP___assert(cb->desc != NULL);
+
+ return ia_css_circbuf_desc_is_empty(cb->desc);
+}
+
+/**
+ * @brief Test if the circular buffer is full.
+ *
+ * @param cb The pointer to the circular buffer.
+ *
+ * @return
+ * - true when it is full.
+ * - false when it is not full.
+ */
+STORAGE_CLASS_INLINE bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb)
+{
+ OP___assert(cb != NULL);
+ OP___assert(cb->desc != NULL);
+
+ return ia_css_circbuf_desc_is_full(cb->desc);
+}
+
+/**
+ * @brief Write a new element into the circular buffer.
+ * Write a new element WITHOUT checking whether the
+ * circular buffer is full or not. So it also overwrites
+ * the oldest element when the buffer is full.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param elem The new element.
+ */
+STORAGE_CLASS_INLINE void ia_css_circbuf_write(
+ ia_css_circbuf_t *cb,
+ ia_css_circbuf_elem_t elem)
+{
+ OP___assert(cb != NULL);
+ OP___assert(cb->desc != NULL);
+
+ /* Cannot continue as the queue is full*/
+#ifdef __SP
+ SP_ASSERT_FATAL(!ia_css_circbuf_is_full(cb));
+#else
+ assert(!ia_css_circbuf_is_full(cb));
+#endif
+
+ ia_css_circbuf_elem_cpy(&elem, &cb->elems[cb->desc->end]);
+
+ cb->desc->end = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, 1);
+}
+
+/**
+ * @brief Push a value in the circular buffer.
+ * Put a new value at the tail of the circular buffer.
+ * The user should call "ia_css_circbuf_is_full()"
+ * to avoid accessing to a full buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param val The value to be pushed in.
+ */
+STORAGE_CLASS_INLINE void ia_css_circbuf_push(
+ ia_css_circbuf_t *cb,
+ uint32_t val)
+{
+ ia_css_circbuf_elem_t elem;
+
+ OP___assert(cb != NULL);
+
+ /* set up an element */
+ ia_css_circbuf_elem_init(&elem);
+ ia_css_circbuf_elem_set_val(&elem, val);
+
+ /* write the element into the buffer */
+ ia_css_circbuf_write(cb, elem);
+}
+
+/**
+ * @brief Get the number of free elements.
+ *
+ * @param cb The pointer to the circular buffer.
+ *
+ * @return: The number of free elements.
+ */
+STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_free_elems(
+ ia_css_circbuf_t *cb)
+{
+ OP___assert(cb != NULL);
+ OP___assert(cb->desc != NULL);
+
+ return ia_css_circbuf_desc_get_free_elems(cb->desc);
+}
+
+/**
+ * @brief Peek an element in Circular Buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param offset Offset to the element.
+ *
+ * @return the elements value.
+ */
+STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_peek(
+ ia_css_circbuf_t *cb,
+ int offset);
+
+/**
+ * @brief Get an element in Circular Buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param offset Offset to the element.
+ *
+ * @return the elements value.
+ */
+STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_peek_from_start(
+ ia_css_circbuf_t *cb,
+ int offset);
+
+/**
+ * @brief Increase Size of a Circular Buffer.
+ * Use 'CAUTION' before using this function, This was added to
+ * support / fix issue with increasing size for tagger only
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param sz_delta delta increase for new size
+ * @param elems (optional) pointers to new additional elements
+ * cb element array size will not be increased dynamically,
+ * but new elements should be added at the end to existing
+ * cb element array which if of max_size >= new size
+ *
+ * @return true on succesfully increasing the size
+ * false on failure
+ */
+STORAGE_CLASS_EXTERN bool ia_css_circbuf_increase_size(
+ ia_css_circbuf_t *cb,
+ unsigned int sz_delta,
+ ia_css_circbuf_elem_t *elems);
+
+#endif /*_IA_CSS_CIRCBUF_H */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_comm.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_comm.h
new file mode 100644
index 0000000..3fc0330
--- /dev/null
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_comm.h
@@ -0,0 +1,56 @@
+/*
+ * Support for Intel Camera Imaging ISP subsystem.
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _IA_CSS_CIRCBUF_COMM_H
+#define _IA_CSS_CIRCBUF_COMM_H
+
+#include <type_support.h> /* uint8_t, uint32_t */
+
+#define IA_CSS_CIRCBUF_PADDING 1 /* The circular buffer is implemented in lock-less manner, wherein
+ * the head and tail can advance independently without any locks.
+ * But to achieve this, an extra buffer element is required to detect
+ * queue full & empty conditions, wherein the tail trails the head for
+ * full and is equal to head for empty condition. This causes 1 buffer
+ * not being available for use.
+ */
+
+/****************************************************************
+ *
+ * Portable Data structures
+ *
+ ****************************************************************/
+/**
+ * @brief Data structure for the circular descriptor.
+ */
+typedef struct ia_css_circbuf_desc_s ia_css_circbuf_desc_t;
+struct ia_css_circbuf_desc_s {
+ uint8_t size; /* the maximum number of elements*/
+ uint8_t step; /* number of bytes per element */
+ uint8_t start; /* index of the oldest element */
+ uint8_t end; /* index at which to write the new element */
+};
+#define SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT \
+ (4 * sizeof(uint8_t))
+
+/**
+ * @brief Data structure for the circular buffer element.
+ */
+typedef struct ia_css_circbuf_elem_s ia_css_circbuf_elem_t;
+struct ia_css_circbuf_elem_s {
+ uint32_t val; /* the value stored in the element */
+};
+#define SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT \
+ (sizeof(uint32_t))
+
+#endif /*_IA_CSS_CIRCBUF_COMM_H*/
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_desc.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_desc.h
new file mode 100644
index 0000000..a8447d4
--- /dev/null
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_desc.h
@@ -0,0 +1,170 @@
+/*
+ * Support for Intel Camera Imaging ISP subsystem.
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _IA_CSS_CIRCBUF_DESC_H_
+#define _IA_CSS_CIRCBUF_DESC_H_
+
+#include <type_support.h>
+#include <math_support.h>
+#include <storage_class.h>
+#include <platform_support.h>
+#include <sp.h>
+#include "ia_css_circbuf_comm.h"
+/****************************************************************
+ *
+ * Inline functions.
+ *
+ ****************************************************************/
+/**
+ * @brief Test if the circular buffer is empty.
+ *
+ * @param cb_desc The pointer to the circular buffer descriptor.
+ *
+ * @return
+ * - true when it is empty.
+ * - false when it is not empty.
+ */
+STORAGE_CLASS_INLINE bool ia_css_circbuf_desc_is_empty(
+ ia_css_circbuf_desc_t *cb_desc)
+{
+ OP___assert(cb_desc != NULL);
+ return (cb_desc->end == cb_desc->start);
+}
+
+/**
+ * @brief Test if the circular buffer descriptor is full.
+ *
+ * @param cb_desc The pointer to the circular buffer
+ * descriptor.
+ *
+ * @return
+ * - true when it is full.
+ * - false when it is not full.
+ */
+STORAGE_CLASS_INLINE bool ia_css_circbuf_desc_is_full(
+ ia_css_circbuf_desc_t *cb_desc)
+{
+ OP___assert(cb_desc != NULL);
+ return (OP_std_modadd(cb_desc->end, 1, cb_desc->size) == cb_desc->start);
+}
+
+/**
+ * @brief Initialize the circular buffer descriptor
+ *
+ * @param cb_desc The pointer circular buffer descriptor
+ * @param size The size of the circular buffer
+ */
+STORAGE_CLASS_INLINE void ia_css_circbuf_desc_init(
+ ia_css_circbuf_desc_t *cb_desc,
+ int8_t size)
+{
+ OP___assert(cb_desc != NULL);
+ cb_desc->size = size;
+}
+
+/**
+ * @brief Get a position in the circular buffer descriptor.
+ *
+ * @param cb The pointer to the circular buffer descriptor.
+ * @param base The base position.
+ * @param offset The offset.
+ *
+ * @return the position in the circular buffer descriptor.
+ */
+STORAGE_CLASS_INLINE uint8_t ia_css_circbuf_desc_get_pos_at_offset(
+ ia_css_circbuf_desc_t *cb_desc,
+ uint32_t base,
+ int offset)
+{
+ uint8_t dest;
+ OP___assert(cb_desc != NULL);
+ OP___assert(cb_desc->size > 0);
+
+ /* step 1: adjust the offset */
+ while (offset < 0) {
+ offset += cb_desc->size;
+ }
+
+ /* step 2: shift and round by the upper limit */
+ dest = OP_std_modadd(base, offset, cb_desc->size);
+
+ return dest;
+}
+
+/**
+ * @brief Get the offset between two positions in the circular buffer
+ * descriptor.
+ * Get the offset from the source position to the terminal position,
+ * along the direction in which the new elements come in.
+ *
+ * @param cb_desc The pointer to the circular buffer descriptor.
+ * @param src_pos The source position.
+ * @param dest_pos The terminal position.
+ *
+ * @return the offset.
+ */
+STORAGE_CLASS_INLINE int ia_css_circbuf_desc_get_offset(
+ ia_css_circbuf_desc_t *cb_desc,
+ uint32_t src_pos,
+ uint32_t dest_pos)
+{
+ int offset;
+ OP___assert(cb_desc != NULL);
+
+ offset = (int)(dest_pos - src_pos);
+ offset += (offset < 0) ? cb_desc->size : 0;
+
+ return offset;
+}
+
+/**
+ * @brief Get the number of available elements.
+ *
+ * @param cb_desc The pointer to the circular buffer.
+ *
+ * @return The number of available elements.
+ */
+STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_desc_get_num_elems(
+ ia_css_circbuf_desc_t *cb_desc)
+{
+ int num;
+ OP___assert(cb_desc != NULL);
+
+ num = ia_css_circbuf_desc_get_offset(cb_desc,
+ cb_desc->start,
+ cb_desc->end);
+
+ return (uint32_t)num;
+}
+
+/**
+ * @brief Get the number of free elements.
+ *
+ * @param cb_desc The pointer to the circular buffer descriptor.
+ *
+ * @return: The number of free elements.
+ */
+STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_desc_get_free_elems(
+ ia_css_circbuf_desc_t *cb_desc)
+{
+ uint32_t num;
+ OP___assert(cb_desc != NULL);
+
+ num = ia_css_circbuf_desc_get_offset(cb_desc,
+ cb_desc->start,
+ cb_desc->end);
+
+ return (cb_desc->size - num);
+}
+#endif /*_IA_CSS_CIRCBUF_DESC_H_ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/src/circbuf.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/src/circbuf.c
new file mode 100644
index 0000000..2493dd2
--- /dev/null
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/src/circbuf.c
@@ -0,0 +1,334 @@
+/*
+ * Support for Intel Camera Imaging ISP subsystem.
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include "ia_css_circbuf.h"
+
+#include <assert_support.h>
+
+#ifdef __SP
+#include <hive_isp_css_sp_api_modified.h>
+#include <ia_css_sp_file_id.sp.h>
+#ifndef SP_FILE_ID
+#define SP_FILE_ID SP_FILE_ID_CIRCBUF /* overrule default in ia_css_sp_assert_level.sp.h */
+#endif
+#include <ia_css_sp_assert_level.sp.h>
+#endif
+
+/**********************************************************************
+ *
+ * Forward declarations.
+ *
+ **********************************************************************/
+/**
+ * @brief Read the oldest element from the circular buffer.
+ * Read the oldest element WITHOUT checking whehter the
+ * circular buffer is empty or not. The oldest element is
+ * also removed out from the circular buffer.
+ *
+ * @param cb The pointer to the circular buffer.
+ *
+ * @return the oldest element.
+ */
+static inline ia_css_circbuf_elem_t
+ia_css_circbuf_read(ia_css_circbuf_t *cb);
+
+/**
+ * @brief Shift a chunk of elements in the circular buffer.
+ * A chunk of elements (i.e. the ones from the "start" position
+ * to the "chunk_src" position) are shifted in the circular buffer,
+ * along the direction of new elements coming.
+ *
+ * @param cb The pointer to the circular buffer.
+ * @param chunk_src The position at which the first element in the chunk is.
+ * @param chunk_dest The position to which the first element in the chunk would be shift.
+ */
+static inline void ia_css_circbuf_shift_chunk(ia_css_circbuf_t *cb,
+ uint32_t chunk_src,
+ uint32_t chunk_dest);
+
+/**
+ * @brief Get the "val" field in the element.
+ *
+ * @param elem The pointer to the element.
+ *
+ * @return the "val" field.
+ */
+static inline uint32_t
+ia_css_circbuf_elem_get_val(ia_css_circbuf_elem_t *elem);
+
+/**********************************************************************
+ *
+ * Non-inline functions.
+ *
+ **********************************************************************/
+/**
+ * @brief Create the circular buffer.
+ * Refer to "ia_css_circbuf.h" for details.
+ */
+void
+ia_css_circbuf_create(ia_css_circbuf_t *cb,
+ ia_css_circbuf_elem_t *elems,
+ ia_css_circbuf_desc_t *desc)
+{
+ uint32_t i;
+
+ OP___assert(desc);
+
+ cb->desc = desc;
+ /* Initialize to defaults */
+ cb->desc->start = 0;
+ cb->desc->end = 0;
+ cb->desc->step = 0;
+
+ for (i = 0; i < cb->desc->size; i++)
+ ia_css_circbuf_elem_init(&elems[i]);
+
+ cb->elems = elems;
+}
+
+/**
+ * @brief Destroy the circular buffer.
+ * Refer to "ia_css_circbuf.h" for details.
+ */
+void ia_css_circbuf_destroy(ia_css_circbuf_t *cb)
+{
+ cb->desc = NULL;
+
+ cb->elems = NULL;
+}
+
+/**
+ * @brief Pop a value out of the circular buffer.
+ * Refer to "ia_css_circbuf.h" for details.
+ */
+uint32_t ia_css_circbuf_pop(ia_css_circbuf_t *cb)
+{
+ uint32_t ret;
+ ia_css_circbuf_elem_t elem;
+
+#ifdef __SP
+ SP_ASSERT_FATAL(!ia_css_circbuf_is_empty(cb));
+#else
+ assert(!ia_css_circbuf_is_empty(cb));
+#endif
+
+ /* read an element from the buffer */
+ elem = ia_css_circbuf_read(cb);
+ ret = ia_css_circbuf_elem_get_val(&elem);
+ return ret;
+}
+
+/**
+ * @brief Extract a value out of the circular buffer.
+ * Refer to "ia_css_circbuf.h" for details.
+ */
+uint32_t ia_css_circbuf_extract(ia_css_circbuf_t *cb, int offset)
+{
+ int max_offset;
+ uint32_t val;
+ uint32_t pos;
+ uint32_t src_pos;
+ uint32_t dest_pos;
+
+ /* get the maximum offest */
+ max_offset = ia_css_circbuf_get_offset(cb, cb->desc->start, cb->desc->end);
+ max_offset--;
+
+ /*
+ * Step 1: When the target element is at the "start" position.
+ */
+ if (offset == 0) {
+ val = ia_css_circbuf_pop(cb);
+ return val;
+ }
+
+ /*
+ * Step 2: When the target element is out of the range.
+ */
+ if (offset > max_offset) {
+ val = 0;
+ return val;
+ }
+
+ /*
+ * Step 3: When the target element is between the "start" and
+ * "end" position.
+ */
+ /* get the position of the target element */
+ pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, offset);
+
+ /* get the value from the target element */
+ val = ia_css_circbuf_elem_get_val(&cb->elems[pos]);
+
+ /* shift the elements */
+ src_pos = ia_css_circbuf_get_pos_at_offset(cb, pos, -1);
+ dest_pos = pos;
+ ia_css_circbuf_shift_chunk(cb, src_pos, dest_pos);
+
+ return val;
+}
+
+/**
+ * @brief Peek an element from the circular buffer.
+ * Refer to "ia_css_circbuf.h" for details.
+ */
+uint32_t ia_css_circbuf_peek(ia_css_circbuf_t *cb, int offset)
+{
+ int pos;
+
+ pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, offset);
+
+ /* get the value at the position */
+ return cb->elems[pos].val;
+}
+
+/**
+ * @brief Get the value of an element from the circular buffer.
+ * Refer to "ia_css_circbuf.h" for details.
+ */
+uint32_t ia_css_circbuf_peek_from_start(ia_css_circbuf_t *cb, int offset)
+{
+ int pos;
+
+ pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, offset);
+
+ /* get the value at the position */
+ return cb->elems[pos].val;
+}
+
+/** @brief increase size of a circular buffer.
+ * Use 'CAUTION' before using this function. This was added to
+ * support / fix issue with increasing size for tagger only
+ * Please refer to "ia_css_circbuf.h" for details.
+ */
+bool ia_css_circbuf_increase_size(
+ ia_css_circbuf_t *cb,
+ unsigned int sz_delta,
+ ia_css_circbuf_elem_t *elems)
+{
+ uint8_t curr_size;
+ uint8_t curr_end;
+ unsigned int i = 0;
+
+ if (!cb || sz_delta == 0)
+ return false;
+
+ curr_size = cb->desc->size;
+ curr_end = cb->desc->end;
+ /* We assume cb was pre defined as global to allow
+ * increase in size */
+ /* FM: are we sure this cannot cause size to become too big? */
+ if (((uint8_t)(cb->desc->size + (uint8_t)sz_delta) > cb->desc->size) && ((uint8_t)sz_delta == sz_delta))
+ cb->desc->size += (uint8_t)sz_delta;
+ else
+ return false; /* overflow in size */
+
+ /* If elems are passed update them else we assume its been taken
+ * care before calling this function */
+ if (elems) {
+ /* cb element array size will not be increased dynamically,
+ * but pointers to new elements can be added at the end
+ * of existing pre defined cb element array of
+ * size >= new size if not already added */
+ for (i = curr_size; i < cb->desc->size; i++)
+ cb->elems[i] = elems[i - curr_size];
+ }
+ /* Fix Start / End */
+ if (curr_end < cb->desc->start) {
+ if (curr_end == 0) {
+ /* Easily fix End */
+ cb->desc->end = curr_size;
+ } else {
+ /* Move elements and fix Start*/
+ ia_css_circbuf_shift_chunk(cb,
+ curr_size - 1,
+ curr_size + sz_delta - 1);
+ }
+ }
+
+ return true;
+}
+
+/****************************************************************
+ *
+ * Inline functions.
+ *
+ ****************************************************************/
+/**
+ * @brief Get the "val" field in the element.
+ * Refer to "Forward declarations" for details.
+ */
+static inline uint32_t
+ia_css_circbuf_elem_get_val(ia_css_circbuf_elem_t *elem)
+{
+ return elem->val;
+}
+
+/**
+ * @brief Read the oldest element from the circular buffer.
+ * Refer to "Forward declarations" for details.
+ */
+static inline ia_css_circbuf_elem_t
+ia_css_circbuf_read(ia_css_circbuf_t *cb)
+{
+ ia_css_circbuf_elem_t elem;
+
+ /* get the element from the target position */
+ elem = cb->elems[cb->desc->start];
+
+ /* clear the target position */
+ ia_css_circbuf_elem_init(&cb->elems[cb->desc->start]);
+
+ /* adjust the "start" position */
+ cb->desc->start = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, 1);
+ return elem;
+}
+
+/**
+ * @brief Shift a chunk of elements in the circular buffer.
+ * Refer to "Forward declarations" for details.
+ */
+static inline void
+ia_css_circbuf_shift_chunk(ia_css_circbuf_t *cb,
+ uint32_t chunk_src, uint32_t chunk_dest)
+{
+ int chunk_offset;
+ int chunk_sz;
+ int i;
+
+ /* get the chunk offset and size */
+ chunk_offset = ia_css_circbuf_get_offset(cb,
+ chunk_src, chunk_dest);
+ chunk_sz = ia_css_circbuf_get_offset(cb, cb->desc->start, chunk_src) + 1;
+
+ /* shift each element to its terminal position */
+ for (i = 0; i < chunk_sz; i++) {
+
+ /* copy the element from the source to the destination */
+ ia_css_circbuf_elem_cpy(&cb->elems[chunk_src],
+ &cb->elems[chunk_dest]);
+
+ /* clear the source position */
+ ia_css_circbuf_elem_init(&cb->elems[chunk_src]);
+
+ /* adjust the source/terminal positions */
+ chunk_src = ia_css_circbuf_get_pos_at_offset(cb, chunk_src, -1);
+ chunk_dest = ia_css_circbuf_get_pos_at_offset(cb, chunk_dest, -1);
+
+ }
+
+ /* adjust the index "start" */
+ cb->desc->start = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, chunk_offset);
+}
+
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/refcount/interface/ia_css_refcount.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/refcount/interface/ia_css_refcount.h
new file mode 100644
index 0000000..20db4de
--- /dev/null
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/refcount/interface/ia_css_refcount.h
@@ -0,0 +1,83 @@
+/*
+ * Support for Intel Camera Imaging ISP subsystem.
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _IA_CSS_REFCOUNT_H_
+#define _IA_CSS_REFCOUNT_H_
+
+#include <type_support.h>
+#include <system_types.h>
+#include <ia_css_err.h>
+
+typedef void (*clear_func)(hrt_vaddress ptr);
+
+/*! \brief Function for initializing refcount list
+ *
+ * \param[in] size Size of the refcount list.
+ * \return ia_css_err
+ */
+extern enum ia_css_err ia_css_refcount_init(uint32_t size);
+
+/*! \brief Function for de-initializing refcount list
+ *
+ * \return None
+ */
+extern void ia_css_refcount_uninit(void);
+
+/*! \brief Function for increasing reference by 1.
+ *
+ * \param[in] id ID of the object.
+ * \param[in] ptr Data of the object (ptr).
+ * \return hrt_vaddress (saved address)
+ */
+extern hrt_vaddress ia_css_refcount_increment(int32_t id, hrt_vaddress ptr);
+
+/*! \brief Function for decrease reference by 1.
+ *
+ * \param[in] id ID of the object.
+ * \param[in] ptr Data of the object (ptr).
+ *
+ * - true, if it is successful.
+ * - false, otherwise.
+ */
+extern bool ia_css_refcount_decrement(int32_t id, hrt_vaddress ptr);
+
+/*! \brief Function to check if reference count is 1.
+ *
+ * \param[in] ptr Data of the object (ptr).
+ *
+ * - true, if it is successful.
+ * - false, otherwise.
+ */
+extern bool ia_css_refcount_is_single(hrt_vaddress ptr);
+
+/*! \brief Function to clear reference list objects.
+ *
+ * \param[in] id ID of the object.
+ * \param[in] clear_func function to be run to free reference objects.
+ *
+ * return None
+ */
+extern void ia_css_refcount_clear(int32_t id,
+ clear_func clear_func_ptr);
+
+/*! \brief Function to verify if object is valid
+ *
+ * \param[in] ptr Data of the object (ptr)
+ *
+ * - true, if valid
+ * - false, if invalid
+ */
+extern bool ia_css_refcount_is_valid(hrt_vaddress ptr);
+
+#endif /* _IA_CSS_REFCOUNT_H_ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/refcount/src/refcount.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/refcount/src/refcount.c
new file mode 100644
index 0000000..05e4bc3
--- /dev/null
+++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/refcount/src/refcount.c
@@ -0,0 +1,281 @@
+/*
+ * Support for Intel Camera Imaging ISP subsystem.
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include "ia_css_refcount.h"
+#include "memory_access/memory_access.h"
+#include "sh_css_defs.h"
+
+#include "platform_support.h"
+
+#include "assert_support.h"
+
+#include "ia_css_debug.h"
+
+/* TODO: enable for other memory aswell
+ now only for hrt_vaddress */
+struct ia_css_refcount_entry {
+ uint32_t count;
+ hrt_vaddress data;
+ int32_t id;
+};
+
+struct ia_css_refcount_list {
+ uint32_t size;
+ struct ia_css_refcount_entry *items;
+};
+
+static struct ia_css_refcount_list myrefcount;
+
+static struct ia_css_refcount_entry *refcount_find_entry(hrt_vaddress ptr,
+ bool firstfree)
+{
+ uint32_t i;
+
+ if (ptr == 0)
+ return NULL;
+ if (myrefcount.items == NULL) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
+ "refcount_find_entry(): Ref count not initiliazed!\n");
+ return NULL;
+ }
+
+ for (i = 0; i < myrefcount.size; i++) {
+
+ if ((&myrefcount.items[i])->data == 0) {
+ if (firstfree) {
+ /* for new entry */
+ return &myrefcount.items[i];
+ }
+ }
+ if ((&myrefcount.items[i])->data == ptr) {
+ /* found entry */
+ return &myrefcount.items[i];
+ }
+ }
+ return NULL;
+}
+
+enum ia_css_err ia_css_refcount_init(uint32_t size)
+{
+ enum ia_css_err err = IA_CSS_SUCCESS;
+
+ if (size == 0) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_init(): Size of 0 for Ref count init!\n");
+ return IA_CSS_ERR_INVALID_ARGUMENTS;
+ }
+ if (myrefcount.items != NULL) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_init(): Ref count is already initialized\n");
+ return IA_CSS_ERR_INTERNAL_ERROR;
+ }
+ myrefcount.items =
+ sh_css_malloc(sizeof(struct ia_css_refcount_entry) * size);
+ if (!myrefcount.items)
+ err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY;
+ if (err == IA_CSS_SUCCESS) {
+ memset(myrefcount.items, 0,
+ sizeof(struct ia_css_refcount_entry) * size);
+ myrefcount.size = size;
+ }
+ return err;
+}
+
+void ia_css_refcount_uninit(void)
+{
+ struct ia_css_refcount_entry *entry;
+ uint32_t i;
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_uninit() entry\n");
+ for (i = 0; i < myrefcount.size; i++) {
+ /* driver verifier tool has issues with &arr[i]
+ and prefers arr + i; as these are actually equivalent
+ the line below uses + i
+ */
+ entry = myrefcount.items + i;
+ if (entry->data != mmgr_NULL) {
+ /* ia_css_debug_dtrace(IA_CSS_DBG_TRACE,
+ "ia_css_refcount_uninit: freeing (%x)\n",
+ entry->data);*/
+ mmgr_free(entry->data);
+ entry->data = mmgr_NULL;
+ entry->count = 0;
+ entry->id = 0;
+ }
+ }
+ sh_css_free(myrefcount.items);
+ myrefcount.items = NULL;
+ myrefcount.size = 0;
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_uninit() leave\n");
+}
+
+hrt_vaddress ia_css_refcount_increment(int32_t id, hrt_vaddress ptr)
+{
+ struct ia_css_refcount_entry *entry;
+
+ if (ptr == mmgr_NULL)
+ return ptr;
+
+ entry = refcount_find_entry(ptr, false);
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_increment(%x) 0x%x\n", id, ptr);
+
+ if (!entry) {
+ entry = refcount_find_entry(ptr, true);
+ assert(entry != NULL);
+ if (entry == NULL)
+ return mmgr_NULL;
+ entry->id = id;
+ }
+
+ if (entry->id != id) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
+ "ia_css_refcount_increment(): Ref count IDS do not match!\n");
+ return mmgr_NULL;
+ }
+
+ if (entry->data == ptr)
+ entry->count += 1;
+ else if (entry->data == mmgr_NULL) {
+ entry->data = ptr;
+ entry->count = 1;
+ } else
+ return mmgr_NULL;
+
+ return ptr;
+}
+
+bool ia_css_refcount_decrement(int32_t id, hrt_vaddress ptr)
+{
+ struct ia_css_refcount_entry *entry;
+
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_decrement(%x) 0x%x\n", id, ptr);
+
+ if (ptr == mmgr_NULL)
+ return false;
+
+ entry = refcount_find_entry(ptr, false);
+
+ if (entry) {
+ if (entry->id != id) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
+ "ia_css_refcount_decrement(): Ref count IDS do not match!\n");
+ return false;
+ }
+ if (entry->count > 0) {
+ entry->count -= 1;
+ if (entry->count == 0) {
+ /* ia_css_debug_dtrace(IA_CSS_DBEUG_TRACE,
+ "ia_css_refcount_decrement: freeing\n");*/
+ mmgr_free(ptr);
+ entry->data = mmgr_NULL;
+ entry->id = 0;
+ }
+ return true;
+ }
+ }
+
+ /* SHOULD NOT HAPPEN: ptr not managed by refcount, or not
+ valid anymore */
+ if (entry)
+ IA_CSS_ERROR("id %x, ptr 0x%x entry %p entry->id %x entry->count %d\n",
+ id, ptr, entry, entry->id, entry->count);
+ else
+ IA_CSS_ERROR("entry NULL\n");
+#ifdef ISP2401
+ assert(false);
+#endif
+
+ return false;
+}
+
+bool ia_css_refcount_is_single(hrt_vaddress ptr)
+{
+ struct ia_css_refcount_entry *entry;
+
+ if (ptr == mmgr_NULL)
+ return false;
+
+ entry = refcount_find_entry(ptr, false);
+
+ if (entry)
+ return (entry->count == 1);
+
+ return true;
+}
+
+void ia_css_refcount_clear(int32_t id, clear_func clear_func_ptr)
+{
+ struct ia_css_refcount_entry *entry;
+ uint32_t i;
+ uint32_t count = 0;
+
+ assert(clear_func_ptr != NULL);
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_refcount_clear(%x)\n",
+ id);
+
+ for (i = 0; i < myrefcount.size; i++) {
+ /* driver verifier tool has issues with &arr[i]
+ and prefers arr + i; as these are actually equivalent
+ the line below uses + i
+ */
+ entry = myrefcount.items + i;
+ if ((entry->data != mmgr_NULL) && (entry->id == id)) {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_clear:"
+ " %x: 0x%x\n", id, entry->data);
+ if (clear_func_ptr) {
+ /* clear using provided function */
+ clear_func_ptr(entry->data);
+ } else {
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_clear: "
+ "using mmgr_free: "
+ "no clear_func\n");
+ mmgr_free(entry->data);
+ }
+#ifndef ISP2401
+
+#else
+ assert(entry->count == 0);
+#endif
+ if (entry->count != 0) {
+ IA_CSS_WARNING("Ref count for entry %x is not zero!", entry->id);
+ }
+ entry->data = mmgr_NULL;
+ entry->count = 0;
+ entry->id = 0;
+ count++;
+ }
+ }
+ ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
+ "ia_css_refcount_clear(%x): cleared %d\n", id,
+ count);
+}
+
+bool ia_css_refcount_is_valid(hrt_vaddress ptr)
+{
+ struct ia_css_refcount_entry *entry;
+
+ if (ptr == mmgr_NULL)
+ return false;
+
+ entry = refcount_find_entry(ptr, false);
+
+ return entry != NULL;
+}
+
OpenPOWER on IntegriCloud