Add SPI common library
Bug: 132281443
Change-Id: I961a2e73bb311b2344037b5f7a66b9eb1c1537da
diff --git a/lib/spi/common/include/lib/spi/common/utils.h b/lib/spi/common/include/lib/spi/common/utils.h
new file mode 100644
index 0000000..f9e5fab
--- /dev/null
+++ b/lib/spi/common/include/lib/spi/common/utils.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <lk/compiler.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+__BEGIN_CDECLS
+
+/**
+ * translate_srv_err() - translate SPI error code to LK error code
+ * @srv_err: SPI error code - one of &enum spi_srv_err
+ *
+ * Returns: one of LK error codes
+ */
+int translate_srv_err(uint32_t srv_err);
+
+/**
+ * translate_lk_err() - translate LK error code to SPI error code
+ * @rc: LK error code
+ *
+ * Returns: one of &enum spi_srv_err
+ */
+uint32_t translate_lk_err(int rc);
+
+/**
+ * mem_buf - tracks state of a memory buffer
+ * @buf: pointer to the buffer
+ * @capacity: capacity of @buf
+ * @align: alignment requirement for @buf and @pos
+ * @curr_size: current size of @buf, must not exceed @capacity
+ * @pos: offset to the current position in @buf
+ */
+struct mem_buf {
+ uint8_t* buf;
+ size_t capacity;
+ size_t align;
+ size_t curr_size;
+ size_t pos;
+};
+
+/**
+ * mb_curr_pos() - get current position of memory buffer
+ * @mb: pointer to memory buffer - see &struct mem_buf
+ *
+ * Return: current position of @mb
+ */
+static inline size_t mb_curr_pos(struct mem_buf* mb) {
+ return mb->pos;
+}
+
+/**
+ * mb_rewind_pos() - rewind position of memory buffer back to zero
+ * @mb: pointer to memory buffer - see &struct mem_buf
+ */
+static inline void mb_rewind_pos(struct mem_buf* mb) {
+ mb->pos = 0;
+}
+
+/**
+ * mb_init() - initialize memory buffer
+ * @mb: pointer to memory buffer - see &struct mem_buf
+ * @buf: pointer to the buffer
+ * @cap: capacity of @buf
+ * @align: alignment requirement
+ *
+ * Set initial @curr_size to 0. @buf must be aligned by @align.
+ */
+void mb_init(struct mem_buf* mb, void* buf, size_t cap, size_t align);
+
+/**
+ * mb_destroy() - destroy memory buffer
+ * @mb: pointer to memory buffer - see &struct mem_buf
+ *
+ * After calling this routine, mb_init() is the only valid operation on @mb.
+ * Other operations will return an error.
+ */
+void mb_destroy(struct mem_buf* mb);
+
+/**
+ * mb_resize() - resize memory buffer
+ * @mb: pointer to memory buffer - see &struct mem_buf
+ * @sz: new size of memory buffer in bytes
+ *
+ * Successfully resizing @mb resets @pos to zero. @sz can not exceed capacity of
+ * @mb.
+ *
+ * Return: true on success, false otherwise
+ */
+bool mb_resize(struct mem_buf* mb, size_t sz);
+
+/**
+ * mb_advance_pos() - advance memory buffer position by a given amount
+ * @mb: pointer to memory buffer - see &struct mem_buf
+ * @sz: number of bytes to advance buffer position by
+ *
+ * This routine can only advance @mb's position by a multiple of the alignment
+ * specified by mb_init(). It rounds @sz up to meet the alignment requirement.
+ * Note that as consequence return pointer is also always aligned.
+ *
+ * Return: pointer to current position in memory buffer if possible to advance
+ * position by @size, NULL otherwise
+ */
+void* mb_advance_pos(struct mem_buf* mb, size_t sz);
+
+__END_CDECLS
diff --git a/lib/spi/common/rules.mk b/lib/spi/common/rules.mk
new file mode 100644
index 0000000..f115361
--- /dev/null
+++ b/lib/spi/common/rules.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_SRCS := \
+ $(LOCAL_DIR)/utils.c \
+
+MODULE_DEPS := \
+ trusty/user/base/interface/spi \
+
+include make/module.mk
diff --git a/lib/spi/common/utils.c b/lib/spi/common/utils.c
new file mode 100644
index 0000000..69042ba
--- /dev/null
+++ b/lib/spi/common/utils.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <interface/spi/spi.h>
+#include <lib/spi/common/utils.h>
+#include <lk/macros.h>
+#include <uapi/err.h>
+
+int translate_srv_err(uint32_t srv_err) {
+ switch (srv_err) {
+ case SPI_SRV_NO_ERROR:
+ return NO_ERROR;
+ case SPI_SRV_ERR_BUSY:
+ return ERR_BUSY;
+ case SPI_SRV_ERR_INVALID_ARGS:
+ return ERR_INVALID_ARGS;
+ case SPI_SRV_ERR_NOT_SUPPORTED:
+ return ERR_NOT_SUPPORTED;
+ case SPI_SRV_ERR_NOT_IMPLEMENTED:
+ return ERR_NOT_IMPLEMENTED;
+ case SPI_SRV_ERR_TOO_BIG:
+ return ERR_TOO_BIG;
+ default:
+ return ERR_GENERIC;
+ }
+}
+
+uint32_t translate_lk_err(int rc) {
+ switch (rc) {
+ case NO_ERROR:
+ return SPI_SRV_NO_ERROR;
+ case ERR_BUSY:
+ return SPI_SRV_ERR_BUSY;
+ case ERR_INVALID_ARGS:
+ return SPI_SRV_ERR_INVALID_ARGS;
+ case ERR_NOT_SUPPORTED:
+ return SPI_SRV_ERR_NOT_SUPPORTED;
+ case ERR_NOT_IMPLEMENTED:
+ return SPI_SRV_ERR_NOT_IMPLEMENTED;
+ case ERR_TOO_BIG:
+ return SPI_SRV_ERR_TOO_BIG;
+ default:
+ return SPI_SRV_ERR_GENERIC;
+ }
+}
+
+void mb_init(struct mem_buf* mb, void* buf, size_t sz, size_t align) {
+ assert(align && IS_ALIGNED(buf, align));
+
+ mb->buf = buf;
+ mb->capacity = sz;
+ mb->align = align;
+ mb->curr_size = 0;
+ mb->pos = 0;
+}
+
+void mb_destroy(struct mem_buf* mb) {
+ mb->buf = NULL;
+ mb->capacity = 0;
+ mb->align = 0;
+ mb->curr_size = 0;
+ mb->pos = 0;
+}
+
+static inline bool mb_is_destroyed(struct mem_buf* mb) {
+ return !mb->buf;
+}
+
+bool mb_resize(struct mem_buf* mb, size_t sz) {
+ if (mb_is_destroyed(mb)) {
+ return false;
+ }
+ if (sz <= mb->capacity) {
+ mb->curr_size = sz;
+ mb->pos = 0;
+ return true;
+ }
+ return false;
+}
+
+void* mb_advance_pos(struct mem_buf* mb, size_t sz) {
+ void* p;
+
+ if (mb_is_destroyed(mb)) {
+ return NULL;
+ }
+
+ assert(IS_ALIGNED(mb->pos, mb->align));
+ assert(mb->curr_size >= mb->pos);
+
+ sz = round_up(sz, mb->align);
+
+ if (sz > (mb->curr_size - mb->pos)) {
+ return NULL;
+ }
+
+ p = (void*)(mb->buf + mb->pos);
+ mb->pos += sz;
+ assert(IS_ALIGNED(mb->pos, mb->align));
+ return p;
+}