From d6b71b99624cbf3ae36115d4e387477c2c2d500a Mon Sep 17 00:00:00 2001
From: Florian Sylvestre <fsylvestre@baylibre.com>
Date: Fri, 9 Jun 2023 17:35:20 +0200
Subject: [PATCH 22/24] Spider: Add serial communication support

---
 .../config/cortex-a/armv8/spider/config.oil   | 20 ++++
 .../armv8/spider/drivers/serial/serial.c      | 90 ++++++++++++++++++
 .../armv8/spider/drivers/serial/serial.h      | 95 +++++++++++++++++++
 3 files changed, 205 insertions(+)
 create mode 100644 machines/cortex-a/armv8/spider/drivers/serial/serial.c
 create mode 100644 machines/cortex-a/armv8/spider/drivers/serial/serial.h

diff --git a/goil/templates/config/cortex-a/armv8/spider/config.oil b/goil/templates/config/cortex-a/armv8/spider/config.oil
index de105663..918e7477 100755
--- a/goil/templates/config/cortex-a/armv8/spider/config.oil
+++ b/goil/templates/config/cortex-a/armv8/spider/config.oil
@@ -1,5 +1,19 @@
 #includeifexists <buildOptions.oil>
 
+IMPLEMENTATION spider {
+  OS {
+    BOOLEAN [
+      TRUE {
+        ENUM [
+          serial
+        ] LIBRARY[];
+      },
+      FALSE
+    ] BUILD = FALSE;
+
+  };
+};
+
 /*
  * Interrupt sources of the board
  */
@@ -32,6 +46,12 @@ CPU spider {
     CFILE = "tpl_vector_table_ns.s";
   };
 
+  LIBRARY serial {
+    PATH = "cortex-a/armv8/spider/drivers/serial";
+    CHEADER = "serial.h";
+    CFILE = "serial.c";
+  };
+
   POSTBUILD all {
     COMMAND buildhex {
       TYPE = COPIER;
diff --git a/machines/cortex-a/armv8/spider/drivers/serial/serial.c b/machines/cortex-a/armv8/spider/drivers/serial/serial.c
new file mode 100644
index 00000000..6f133f0c
--- /dev/null
+++ b/machines/cortex-a/armv8/spider/drivers/serial/serial.c
@@ -0,0 +1,90 @@
+#include "serial.h"
+
+uint32 Serial_Init(void)
+{
+  volatile uint8  wait_cmpt;
+
+  /* Clear bits TE and RE in HSSCR to 0 */
+  SERIAL_SCR =  SERIAL_SCR_INT_VALUE;
+
+  /* Set bits TFRST and RFRST in FCR to 1 */
+  SERIAL_FCR |= SERIAL_FCR_TFRST_MASK | SERIAL_FCR_RFRS_MASK;
+
+  /* Clear flags ER, DR, BRK, and RDF in FSR */
+  SERIAL_FSR =  SERIAL_FSR_INIT_VALUE;
+
+  /* Clear TO and ORER in LSR,*/
+  SERIAL_LSR =  SERIAL_LSR_INIT_VALUE;
+
+  /* Set bits CKE[1:0] in SCR (leaving other bits cleared to 0) */
+  SERIAL_SCR   =  (SERIAL_SCR & ~SERIAL_SCR_CKE_MASK) | SERIAL_SCR_CKE_INIT_VALUE;
+
+  /* Set data transfer format in HSSMR ( 8 bits, no parity, 1 stop bit, async) */
+  SERIAL_SMR = SERIAL_SMR_INIT_VALUE;
+
+  /* Baud rate setting */
+  SERIAL_BRR = SERIAL_BAUDRATE;
+                      
+#if (SERIAL_BASE_ADDR == SCIF_BASE_ADDR)
+  /* SCIF module used */
+  SERIAL_DL    = SERIAL_DL_SETTING_VALUE;
+  SERIAL_CKS   &= ~(SERIAL_CKS_DIV_MASK | SERIAL_CKS_XIN_MASK);
+#else
+  /* HSCIF module used */
+  /* Sampling rate 8  */
+  SERIAL_SRR = SERIAL_SRR_VAL;
+#endif
+
+  for (wait_cmpt = 0; wait_cmpt < 100; wait_cmpt++)
+  {
+  }
+
+  /* reset-off, tx-fifo, rx-fifo */
+  SERIAL_FCR = SERIAL_FCR_INIT_VALUE;
+
+  /* Enable TE and RE bits*/
+  SERIAL_SCR |= SERIAL_SCR_TE_MASK | SERIAL_SCR_RE_MASK;
+
+  return 1;
+}
+
+void Serial_Tx_Wait(void)
+{
+  /* Wait until TX FIFO is empty */
+  do
+  {
+  } while ((SERIAL_FSR & SERIAL_TX_DONE) != SERIAL_TX_DONE);
+}
+
+uint32 Serial_Tx(uint8 data)
+{
+  Serial_Tx_Wait();
+
+  /* Fill FTDR register with data to send */
+  SERIAL_FTDR = data;
+
+  /* Clear TX status bits */
+  SERIAL_FSR &= ~SERIAL_TX_DONE;
+
+  return 1;
+}
+
+uint8 Serial_Rx(uint8* data)
+{
+  /* Check if data available */
+  if((SERIAL_FSR & SERIAL_FSR_RDF_MASK) != SERIAL_FSR_RDF_MASK)
+    return 0;
+
+  /* Check Data Ready and no break, timeout, overrun nor receive errors */
+  if (((SERIAL_FSR & SERIAL_RX_READY) != 0) || (SERIAL_LSR != 0))
+    return 2;
+
+  /* Get rx data */
+  *data = SERIAL_FRDR;
+  /* Send back data */
+  Serial_Tx(*data);
+  /* Clear RDF flag */
+  SERIAL_FSR &= ~SERIAL_FSR_RDF_MASK;
+
+  return 1;
+}
diff --git a/machines/cortex-a/armv8/spider/drivers/serial/serial.h b/machines/cortex-a/armv8/spider/drivers/serial/serial.h
new file mode 100644
index 00000000..a3256316
--- /dev/null
+++ b/machines/cortex-a/armv8/spider/drivers/serial/serial.h
@@ -0,0 +1,95 @@
+#ifndef SERIAL_H
+#define SERIAL_H
+
+#include "tpl_os.h"
+
+/* SCIF3 */
+#define SCIF_BASE_ADDR                      0xE6C50000
+
+/* HSCIF0 */
+#define HSCIF_BASE_ADDR                     0xE6540000
+
+/* BRR computing:
+ *   HSBRR: Register value = Internal clock / ( Sr * 2^(2*n + 1) * B) * 10^6 -1
+ *   SCBRR: Register value = PCK / ( 64 * 2^(2*n - 1) * B) * 10^6 -1
+ *
+ *   with:
+ *     - PCK: Peripheral module operating frequency (MHz)
+ *     - B: Baudrate
+ *     - Sr: Sampling rate (8 to 32)
+ *     - n: Baudrate generator clock (0 to 3)
+ *
+ *   In our case:  Internal clock = 266, Sr = 8, PCK = 66 and n = 0
+ */
+#define HSBRR_1843200BPS              (uint8)(0x08U)
+#define HSBRR_921600BPS               (uint8)(0x11U)
+#define SCBRR_115200BPS               (uint8)(0x11U)
+
+/* A proper #define must be used between: SCIF_115200BPS, HSCIF_921600BPS and HSCIF_1843200BPS */
+#if defined SCIF_115200BPS
+#define SERIAL_BASE_ADDR                     SCIF_BASE_ADDR
+#define SERIAL_BAUDRATE                      SCBRR_115200BPS
+#elif defined HSCIF_921600BPS
+#define SERIAL_BASE_ADDR                     HSCIF_BASE_ADDR
+#define SERIAL_BAUDRATE                      HSBRR_921600BPS
+#elif defined HSCIF_1843200BPS
+#define SERIAL_BASE_ADDR                     HSCIF_BASE_ADDR
+#define SERIAL_BAUDRATE                      HSBRR_1843200BPS
+#else
+#error "No baudrate defined for serial communication"
+#endif
+
+#define SERIAL_SMR        (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x00))
+#define SERIAL_BRR        (*(volatile uint8  *)(SERIAL_BASE_ADDR + 0x04))
+#define SERIAL_SCR        (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x08))
+#define SERIAL_FTDR       (*(volatile uint8  *)(SERIAL_BASE_ADDR + 0x0C))
+#define SERIAL_FSR        (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x10))
+#define SERIAL_FRDR       (*(volatile uint8  *)(SERIAL_BASE_ADDR + 0x14))
+#define SERIAL_FCR        (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x18))
+#define SERIAL_FDR        (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x1C))
+#define SERIAL_SPTR       (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x20))
+#define SERIAL_LSR        (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x24))
+#define SERIAL_DL         (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x30)) /* Only used by SCIF */
+#define SERIAL_CKS        (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x34)) /* Only used by SCIF */
+#define SERIAL_SRR        (*(volatile uint16 *)(SERIAL_BASE_ADDR + 0x40)) /* Only used by HSCIF */
+
+#define SERIAL_SMR_INIT_VALUE       (0x0000U)
+
+#define SERIAL_SCR_INT_VALUE        (0x0000U)
+#define SERIAL_SCR_CKE_MASK         (3U << 0)
+#define SERIAL_SCR_CKE_BRG_VALUE    (0x0002U)
+#define SERIAL_SCR_CKE_INIT_VALUE   (0x0000U)
+#define SERIAL_SCR_RE_MASK          (1U << 4)
+#define SERIAL_SCR_TE_MASK          (1U << 5)
+
+#define SERIAL_FSR_INIT_VALUE       (0x0000U)
+#define SERIAL_FSR_DR_MASK          (1U << 0)
+#define SERIAL_FSR_RDF_MASK         (1U << 1)
+#define SERIAL_FSR_BRK_MASK         (1U << 4)
+#define SERIAL_FSR_TDFE_MASK        (1U << 5)
+#define SERIAL_FSR_TEND_MASK        (1U << 6)
+#define SERIAL_FSR_ER_MASK          (1U << 7)
+#define SERIAL_RX_READY             (SERIAL_FSR_DR_MASK | SERIAL_FSR_BRK_MASK | SERIAL_FSR_ER_MASK)
+#define SERIAL_TX_DONE              (SERIAL_FSR_TDFE_MASK | SERIAL_FSR_TEND_MASK)
+
+#define SERIAL_FCR_INIT_VALUE       (0x0000U)
+#define SERIAL_FCR_TFRST_MASK       (1U << 2)
+#define SERIAL_FCR_RFRS_MASK        (1U << 1)
+
+#define SERIAL_LSR_INIT_VALUE       (0x0000U)
+
+#define SERIAL_DL_SETTING_VALUE     (0x0008U)
+
+#define SERIAL_CKS_DIV_MASK         (1U << 15)
+#define SERIAL_CKS_XIN_MASK         (1U << 14)
+
+#define SERIAL_SRR_SRE              (1U << 15)
+#define SERIAL_SRR_SRCYC8           (7U << 0)
+#define SERIAL_SRR_VAL              (SERIAL_SRR_SRE | SERIAL_SRR_SRCYC8)
+
+uint32 Serial_Init(void);
+void Serial_Tx_Wait(void);
+uint32 Serial_Tx(uint8 data);
+uint8  Serial_Rx(uint8* data);
+
+#endif
-- 
2.25.1

