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;
+}