aboutsummaryrefslogtreecommitdiff
path: root/src/soc/sifive/fu540/spi_internal.h
diff options
context:
space:
mode:
authorXiang Wang <wxjstz@126.com>2019-05-29 15:39:48 +0800
committerPatrick Rudolph <siro@das-labor.org>2019-08-12 08:35:17 +0000
commitf4e158337683640220e3662fd6ca135bd3bad31b (patch)
treeecf48ac9a68ffe399fd64b40986cc53754470651 /src/soc/sifive/fu540/spi_internal.h
parent8adaffcbed6372970f34b85177bd42bb508d03e2 (diff)
soc/sifive/fu540: add code for spi and map flash to memory spaces
SiFive's ZSBL has initialized flash, but only 16MB of space is available. 1. add code for spi 2. add code to map flash to memory spaces Change-Id: I106688c65ac7dd70be7479dc4691797b700682d9 Signed-off-by: Xiang Wang <merle@hardenedlinux.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/33055 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Patrick Rudolph <siro@das-labor.org>
Diffstat (limited to 'src/soc/sifive/fu540/spi_internal.h')
-rw-r--r--src/soc/sifive/fu540/spi_internal.h242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/soc/sifive/fu540/spi_internal.h b/src/soc/sifive/fu540/spi_internal.h
new file mode 100644
index 0000000000..97094c1d8c
--- /dev/null
+++ b/src/soc/sifive/fu540/spi_internal.h
@@ -0,0 +1,242 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 SiFive, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that 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 __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__
+#define __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__
+
+#include <stdint.h>
+
+#define _ASSERT_SIZEOF(type, size) _Static_assert( \
+ sizeof(type) == (size), \
+ #type " must be " #size " bytes wide")
+
+#define FU540_SPI_CSMODE_AUTO 0
+#define FU540_SPI_CSMODE_HOLD 2
+#define FU540_SPI_CSMODE_OFF 3
+
+typedef union {
+ struct {
+ uint32_t pha : 1;
+ uint32_t pol : 1;
+ uint32_t reserved : 30;
+ };
+ uint32_t raw_bits;
+} spi_reg_sckmode;
+_ASSERT_SIZEOF(spi_reg_sckmode, 4);
+
+
+typedef union {
+ struct {
+ uint32_t mode : 2;
+ uint32_t reserved : 30;
+ };
+ uint32_t raw_bits;
+} spi_reg_csmode;
+_ASSERT_SIZEOF(spi_reg_csmode, 4);
+
+
+typedef union {
+ struct {
+ uint32_t cssck : 8;
+ uint32_t reserved0 : 8;
+ uint32_t sckcs : 8;
+ uint32_t reserved1 : 8;
+ };
+ uint32_t raw_bits;
+} spi_reg_delay0;
+_ASSERT_SIZEOF(spi_reg_delay0, 4);
+
+
+typedef union {
+ struct {
+ uint32_t intercs : 8;
+ uint32_t reserved0 : 8;
+ uint32_t interxfr : 8;
+ uint32_t reserved1 : 8;
+ };
+ uint32_t raw_bits;
+} spi_reg_delay1;
+_ASSERT_SIZEOF(spi_reg_delay1, 4);
+
+
+typedef union {
+ struct {
+ uint32_t proto : 2;
+ uint32_t endian : 1;
+ uint32_t dir : 1;
+ uint32_t reserved0 : 12;
+ uint32_t len : 4;
+ uint32_t reserved1 : 12;
+ };
+ uint32_t raw_bits;
+} spi_reg_fmt;
+_ASSERT_SIZEOF(spi_reg_fmt, 4);
+
+
+typedef union {
+ struct {
+ uint32_t data : 8;
+ uint32_t reserved : 23;
+ uint32_t full : 1;
+ };
+ uint32_t raw_bits;
+} spi_reg_txdata;
+_ASSERT_SIZEOF(spi_reg_txdata, 4);
+
+
+typedef union {
+ struct {
+ uint32_t data : 8;
+ uint32_t reserved : 23;
+ uint32_t empty : 1;
+ };
+ uint32_t raw_bits;
+} spi_reg_rxdata;
+_ASSERT_SIZEOF(spi_reg_rxdata, 4);
+
+
+typedef union {
+ struct {
+ uint32_t txmark : 3;
+ uint32_t reserved : 29;
+ };
+ uint32_t raw_bits;
+} spi_reg_txmark;
+_ASSERT_SIZEOF(spi_reg_txmark, 4);
+
+
+typedef union {
+ struct {
+ uint32_t rxmark : 3;
+ uint32_t reserved : 29;
+ };
+ uint32_t raw_bits;
+} spi_reg_rxmark;
+_ASSERT_SIZEOF(spi_reg_rxmark, 4);
+
+
+typedef union {
+ struct {
+ uint32_t en : 1;
+ uint32_t reserved : 31;
+ };
+ uint32_t raw_bits;
+} spi_reg_fctrl;
+_ASSERT_SIZEOF(spi_reg_fctrl, 4);
+
+
+typedef union {
+ struct {
+ uint32_t cmd_en : 1;
+ uint32_t addr_len : 3;
+ uint32_t pad_cnt : 4;
+ uint32_t command_proto : 2;
+ uint32_t addr_proto : 2;
+ uint32_t data_proto : 2;
+ uint32_t reserved : 2;
+ uint32_t command_code : 8;
+ uint32_t pad_code : 8;
+ };
+ uint32_t raw_bits;
+} spi_reg_ffmt;
+_ASSERT_SIZEOF(spi_reg_ffmt, 4);
+
+
+typedef union {
+ struct {
+ uint32_t txwm : 1;
+ uint32_t rxwm : 1;
+ uint32_t reserved : 30;
+ };
+ uint32_t raw_bits;
+} spi_reg_ie;
+typedef spi_reg_ie spi_reg_ip;
+_ASSERT_SIZEOF(spi_reg_ie, 4);
+_ASSERT_SIZEOF(spi_reg_ip, 4);
+
+#undef _ASSERT_SIZEOF
+
+
+/**
+ * SPI control register memory map.
+ *
+ * All functions take a pointer to a SPI device's control registers.
+ */
+struct spi_ctrl {
+ uint32_t sckdiv;
+ spi_reg_sckmode sckmode;
+ uint32_t reserved08;
+ uint32_t reserved0c;
+
+ uint32_t csid;
+ uint32_t csdef;
+ spi_reg_csmode csmode;
+ uint32_t reserved1c;
+
+ uint32_t reserved20;
+ uint32_t reserved24;
+ spi_reg_delay0 delay0;
+ spi_reg_delay1 delay1;
+
+ uint32_t reserved30;
+ uint32_t reserved34;
+ uint32_t reserved38;
+ uint32_t reserved3c;
+
+ spi_reg_fmt fmt;
+ uint32_t reserved44;
+ spi_reg_txdata txdata;
+ spi_reg_rxdata rxdata;
+
+ spi_reg_txmark txmark;
+ spi_reg_rxmark rxmark;
+ uint32_t reserved58;
+ uint32_t reserved5c;
+
+ spi_reg_fctrl fctrl;
+ spi_reg_ffmt ffmt;
+ uint32_t reserved68;
+ uint32_t reserved6c;
+
+ spi_reg_ie ie;
+ spi_reg_ip ip;
+};
+
+/**
+ * Get smallest clock divisor that divides input_khz to a quotient less than or
+ * equal to max_target_khz;
+ */
+static inline unsigned int
+spi_min_clk_divisor(unsigned int input_khz, unsigned int max_target_khz)
+{
+ // f_sck = f_in / (2 * (div + 1)) => div = (f_in / (2*f_sck)) - 1
+ //
+ // The nearest integer solution for div requires rounding up as to not
+ // exceed max_target_khz.
+ //
+ // div = ceil(f_in / (2*f_sck)) - 1
+ // = floor((f_in - 1 + 2*f_sck) / (2*f_sck)) - 1
+ //
+ // This should not overflow as long as (f_in - 1 + 2*f_sck) does not
+ // exceed 2^32 - 1, which is unlikely since we represent frequencies
+ // in kHz.
+ unsigned int quotient =
+ (input_khz + 2 * max_target_khz - 1) / (2 * max_target_khz);
+ // Avoid underflow
+ if (quotient == 0)
+ return 0;
+ return quotient - 1;
+}
+
+#endif /* __SOC_SIFIVE_HIFIVE_U_SPI_INTERNAL_H__ */