测试方式:

 

 

移植补丁

diff --git a/.gitignore b/.gitignore
index 1db11da..7618ae1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,7 @@ sunxi-pio
 version.h
 *.o
 *.swp
+cscope.*
+tags
+.err
+*.fex
diff --git a/aw_spi.h b/aw_spi.h
new file mode 100644
index 0000000..5866523
--- /dev/null
+++ b/aw_spi.h
@@ -0,0 +1,868 @@
+#ifndef __AW_SPI_H__
+#define __AW_SPI_H__
+
+#include <stdint.h>
+
+//typedef unsigned int uint32_t;
+//typedef unsigned short uint16_t;
+//typedef unsigned char uint8_t;
+#ifdef __cplusplus
+extern "C" {
+#endif
+/********************** private ************************************/
+
+/**
+  * @brief Serial Peripheral Interface
+  */
+typedef struct
+{
+    volatile uint32_t RESERVED0;         /* Reserved, 0x00                                        Address offset: 0x00   */
+    volatile uint32_t GCR;               /* SPI Global Control Register,                          Address offset: 0x04   */
+    volatile uint32_t TCR;               /* SPI Transfer Control Register,                        Address offset: 0x08   */
+    volatile uint32_t RESERVED1[1];      /* Reserved, 0x0C                                                               */
+    volatile uint32_t IER;               /* SPI Interrupt Control Register,                       Address offset: 0x10   */
+    volatile uint32_t ISR;               /* SPI Interrupt Status Register,                        Address offset: 0x14   */
+    volatile uint32_t FCR;               /* SPI FIFO Control Register,                            Address offset: 0x18   */
+    volatile uint32_t FSR;               /* SPI FIFO Status Register,                             Address offset: 0x1C   */
+    volatile uint32_t WCR;               /* SPI Wait Clock Counter Register,                      Address offset: 0x20   */
+    volatile uint32_t CCR;               /* SPI Clock Rate Control Register,                      Address offset: 0x24   */
+    
+    volatile uint32_t RESERVED2[2];      /* Reserved, 0x28-0x2C                                                          */
+    volatile uint32_t MBC;               /* SPI Master mode Burst Control Register,               Address offset: 0x30   */
+    volatile uint32_t MTC;               /* SPI Master mode Transmit Counter Register,            Address offset: 0x34   */
+    volatile uint32_t BCC;               /* SPI Burst Control Register,                           Address offset: 0x38   */
+    volatile uint32_t RESERVED4[113];    /* Reserved, 0x3C-0x1FC                                                         */
+    volatile uint32_t TXD;               /* SPI TX Date Register,                                 Address offset: 0x200  */
+    volatile uint32_t RESERVED5[63];     /* Reserved, 0x204-0x2FC                                                        */
+    volatile uint32_t RXD;               /* SPI RX Date Register,                                 Address offset: 0x300  */
+} SPI_T;
+
+/*
+ * @brief SPI Global Control Register
+ */
+#define SPI_CTRL_RST_SHIFT                  (31)
+#define SPI_CTRL_RST_MASK                   (0x1U << SPI_CTRL_RST_SHIFT)
+
+#define SPI_CTRL_TP_EN_SHIFT                (7)
+#define SPI_CTRL_TP_EN_MASK                 (0x1U << SPI_CTRL_TP_EN_SHIFT)
+
+#define SPI_CTRL_MODE_SHIFT                 (1)
+#define SPI_CTRL_MODE_MASK                  (0x1U << SPI_CTRL_MODE_SHIFT)
+typedef enum
+{
+    SPI_CTRL_MODE_SLAVE = 0 << SPI_CTRL_MODE_SHIFT,
+    SPI_CTRL_MODE_MASTER = 1 << SPI_CTRL_MODE_SHIFT
+} SPI_CTRL_Mode;
+
+#define SPI_CTRL_EN_SHIFT                   (0)
+#define SPI_CTRL_EN_MASK                    (0x1U << SPI_CTRL_EN_SHIFT)
+typedef enum
+{
+    SPI_CTRL_EN_DISABLE = 0 << SPI_CTRL_EN_SHIFT,
+    SPI_CTRL_EN_ENABLE = 1 << SPI_CTRL_EN_SHIFT
+} SPI_CTRL_En;
+
+/*
+ * @brief SPI Transfer Control Register
+ */
+#define SPI_TCTRL_XCH_SHIFT                 (31)
+#define SPI_TCTRL_XCH_MASK                  (0x1U << SPI_TCTRL_XCH_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_XCH_IDLE = 0 << SPI_TCTRL_XCH_SHIFT,
+    SPI_TCTRL_XCH_START = 1 << SPI_TCTRL_XCH_SHIFT
+} SPI_TCTRL_Xch;
+
+#define SPI_TCTRL_SDM_SHIFT                 (13)
+#define SPI_TCTRL_SDM_MASK                  (0x1U << SPI_TCTRL_SDM_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_SDM_SAMPLE_NODELAY = 1 << SPI_TCTRL_SDM_SHIFT,
+    SPI_TCTRL_SDM_SAMPLE_DELAY = 0 << SPI_TCTRL_SDM_SHIFT
+} SPI_TCTRL_Sdm;
+
+#define SPI_TCTRL_FBS_SHIFT                 (12)
+#define SPI_TCTRL_FBS_MASK                  (0x1U << SPI_TCTRL_FBS_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_FBS_MSB = 0 << SPI_TCTRL_FBS_SHIFT,
+    SPI_TCTRL_FBS_LSB = 1 << SPI_TCTRL_FBS_SHIFT
+} SPI_TCTRL_Fbs;
+
+#define SPI_TCTRL_SDC_SHIFT                 (11)
+#define SPI_TCTRL_SDC_MASK                  (0x1U << SPI_TCTRL_SDC_SHIFT)
+
+#define SPI_TCTRL_RPSM_SHIFT                (10)
+#define SPI_TCTRL_RPSM_MASK                 (0x1U << SPI_TCTRL_RPSM_SHIFT)
+
+#define SPI_TCTRL_DDB_SHIFT                 (9)
+#define SPI_TCTRL_DDB_MASK                  (0x1U << SPI_TCTRL_DDB_SHIFT)
+
+#define SPI_TCTRL_DHB_SHIFT                 (8)
+#define SPI_TCTRL_DHB_MASK                  (0x1U << SPI_TCTRL_DHB_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_DHB_FULL_DUPLEX = 0 << SPI_TCTRL_DHB_SHIFT,
+    SPI_TCTRL_DHB_HALF_DUPLEX = 1 << SPI_TCTRL_DHB_SHIFT
+} SPI_TCTRL_DHB_Duplex;
+
+#define SPI_TCTRL_SS_LEVEL_SHIFT            (7)
+#define SPI_TCTRL_SS_LEVEL_MASK             (0x1U << SPI_TCTRL_SS_LEVEL_SHIFT)
+
+#define SPI_TCTRL_SS_OWNER_SHIFT            (6)
+#define SPI_TCTRL_SS_OWNER_MASK             (0x1U << SPI_TCTRL_SS_OWNER_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_SS_OWNER_CONTROLLER = 0 << SPI_TCTRL_SS_OWNER_SHIFT,
+    SPI_TCTRL_SS_OWNER_SOFTWARE = 1 << SPI_TCTRL_SS_OWNER_SHIFT
+} SPI_TCTRL_SS_OWNER;
+
+#define SPI_TCTRL_SS_SEL_SHIFT              (4)
+#define SPI_TCTRL_SS_SEL_MASK               (0x3U << SPI_TCTRL_SS_SEL_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_SS_SEL_SS0 = 0 << SPI_TCTRL_SS_SEL_SHIFT,
+    SPI_TCTRL_SS_SEL_SS1 = 1 << SPI_TCTRL_SS_SEL_SHIFT,
+    SPI_TCTRL_SS_SEL_SS2 = 2 << SPI_TCTRL_SS_SEL_SHIFT,
+    SPI_TCTRL_SS_SEL_SS3 = 3 << SPI_TCTRL_SS_SEL_SHIFT
+} SPI_TCTRL_SS_Sel;
+
+#define SPI_TCTRL_SS_CTL_SHIFT              (3)
+#define SPI_TCTRL_SS_CTL_MASK               (0x1U << SPI_TCTRL_SS_CTL_SHIFT)
+
+#define SPI_TCTRL_SPOL_SHIFT                (2)
+#define SPI_TCTRL_SPOL_MASK                 (0x1U << SPI_TCTRL_SPOL_SHIFT)
+
+#define SPI_TCTRL_CPOL_SHIFT                (1)
+#define SPI_TCTRL_CPOL_MASK                 (0x1U << SPI_TCTRL_CPOL_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_CPOL_HIGH = 0 << SPI_TCTRL_CPOL_SHIFT,
+    SPI_TCTRL_CPOL_LOW = 1 << SPI_TCTRL_CPOL_SHIFT
+} SPI_TCTRL_Cpol;
+
+#define SPI_TCTRL_CPHA_SHIFT                (0)
+#define SPI_TCTRL_CPHA_MASK                 (0x1U << SPI_TCTRL_CPHA_SHIFT)
+typedef enum
+{
+    SPI_TCTRL_CPHA_PHASE0  = 0 << SPI_TCTRL_CPHA_SHIFT,
+    SPI_TCTRL_CPHA_PHASE1  = 1 << SPI_TCTRL_CPHA_SHIFT
+} SPI_TCTRL_Cpha;
+
+typedef enum
+{
+    SPI_SCLK_Mode0 = 0 << SPI_TCTRL_CPHA_SHIFT,
+    SPI_SCLK_Mode1 = 1 << SPI_TCTRL_CPHA_SHIFT,
+    SPI_SCLK_Mode2 = 2 << SPI_TCTRL_CPHA_SHIFT,
+    SPI_SCLK_Mode3 = 3 << SPI_TCTRL_CPHA_SHIFT
+} SPI_SCLK_Mode;
+
+/*
+ * @brief SPI Interrupt Control Register
+ */
+#define SPI_IER_SS_INT_EN_SHIFT             (13)
+#define SPI_IER_SS_INT_EN_MASK              (0x1U << SPI_IER_SS_INT_EN_SHIFT)
+
+#define SPI_IER_TC_INT_EN_SHIFT             (12)
+#define SPI_IER_TC_INT_EN_MASK              (0x1U << SPI_IER_TC_INT_EN_SHIFT)
+
+#define SPI_IER_TF_UDR_INT_EN_SHIFT         (11)
+#define SPI_IER_TF_UDR_INT_EN_MASK          (0x1U << SPI_IER_TF_UDR_INT_EN_SHIFT)
+
+#define SPI_IER_TF_OVF_INT_EN_SHIFT         (10)
+#define SPI_IER_TF_OVF_INT_EN_MASK          (0x1U << SPI_IER_TF_OVF_INT_EN_SHIFT)
+
+#define SPI_IER_RF_UDR_INT_EN_SHIFT         (9)
+#define SPI_IER_RF_UDR_INT_EN_MASK          (0x1U << SPI_IER_RF_UDR_INT_EN_SHIFT)
+
+#define SPI_IER_RF_OVF_INT_EN_SHIFT         (8)
+#define SPI_IER_RF_OVF_INT_EN_MASK          (0x1U << SPI_IER_RF_OVF_INT_EN_SHIFT)
+
+#define SPI_IER_TF_FUL_INT_EN_SHIFT         (6)
+#define SPI_IER_TF_FUL_INT_EN_MASK          (0x1U << SPI_IER_TF_FUL_INT_EN_SHIFT)
+
+#define SPI_IER_TX_EMP_INT_EN_SHIFT         (5)
+#define SPI_IER_TX_EMP_INT_EN_MASK          (0x1U << SPI_IER_TX_EMP_INT_EN_SHIFT)
+
+#define SPI_IER_TX_ERQ_INT_EN_SHIFT         (4)
+#define SPI_IER_TX_ERQ_INT_EN_MASK          (0x1U << SPI_IER_TX_ERQ_INT_EN_SHIFT)
+
+#define SPI_IER_RF_FUL_INT_EN_SHIFT         (2)
+#define SPI_IER_RF_FUL_INT_EN_MASK          (0x1U << SPI_IER_RF_FUL_INT_EN_SHIFT)
+
+#define SPI_IER_RX_EMP_INT_EN_SHIFT         (1)
+#define SPI_IER_RX_EMP_INT_EN_MASK          (0x1U << SPI_IER_RX_EMP_INT_EN_SHIFT)
+
+#define SPI_IER_RF_RDY_INT_EN_SHIFT         (0)
+#define SPI_IER_RF_RDY_INT_EN_MASK          (0x1U << SPI_IER_RF_RDY_INT_EN_SHIFT)
+
+/*
+ * @brief SPI Interrupt Status Register
+ */
+#define SPI_STA_SSI_SHIFT                   (13)
+#define SPI_STA_SSI_MASK                    (0x1U << SPI_STA_SSI_SHIFT)
+
+#define SPI_STA_TC_SHIFT                    (12)
+#define SPI_STA_TC_MASK                     (0x1U << SPI_STA_TC_SHIFT)
+
+#define SPI_STA_TF_UDF_SHIFT                (11)
+#define SPI_STA_TF_UDF_MASK                 (0x1U << SPI_STA_TF_UDF_SHIFT)
+
+#define SPI_STA_TF_OVF_SHIFT                (10)
+#define SPI_STA_TF_OVF_MASK                 (0x1U << SPI_STA_TF_OVF_SHIFT)
+
+#define SPI_STA_RX_UDF_SHIFT                (9)
+#define SPI_STA_RX_UDF_MASK                 (0x1U << SPI_STA_RX_UDF_SHIFT)
+
+#define SPI_STA_RX_OVF_SHIFT                (8)
+#define SPI_STA_RX_OVF_MASK                 (0x1U << SPI_STA_RX_OVF_SHIFT)
+
+#define SPI_STA_TX_FULL_SHIFT               (6)
+#define SPI_STA_TX_FULL_MASK                (0x1U << SPI_STA_TX_FULL_SHIFT)
+
+#define SPI_STA_TX_EMP_SHIFT                (5)
+#define SPI_STA_TX_EMP_MASK                 (0x1U << SPI_STA_TX_EMP_SHIFT)
+
+#define SPI_STA_TX_READY_SHIFT              (4)
+#define SPI_STA_TX_READY_MASK               (0x1U << SPI_STA_TX_READY_SHIFT)
+
+#define SPI_STA_RX_FULL_SHIFT               (2)
+#define SPI_STA_RX_FULL_MASK                (0x1U << SPI_STA_RX_FULL_SHIFT)
+
+#define SPI_STA_RX_EMP_SHIFT                (1)
+#define SPI_STA_RX_EMP_MASK                 (0x1U << SPI_STA_RX_EMP_SHIFT)
+
+#define SPI_STA_RX_RDY_SHIFT                (0)
+#define SPI_STA_RX_RDY_MASK                 (0x1U << SPI_STA_RX_RDY_SHIFT)
+
+/*
+ * @brief SPI FIFO Control Register
+ */
+#define SPI_FCTL_TF_RST_SHIFT               (31)
+#define SPI_FCTL_TF_RST_MASK                (0x1U << SPI_FCTL_TF_RST_SHIFT)
+
+#define SPI_FCTL_TF_TEST_EN_SHIFT           (30)
+#define SPI_FCTL_TF_TEST_EN_MASK            (0x1U << SPI_FCTL_TF_TEST_EN_SHIFT)
+
+#define SPI_FCTL_TF_DRQ_EN_SHIFT            (24)
+#define SPI_FCTL_TF_DRQ_EN_MASK             (0x1U << SPI_FCTL_TF_DRQ_EN_SHIFT)
+#define SPI_FCTL_TF_DRQ_EN_BIT              HAL_BIT(24)
+
+#define SPI_FCTL_TX_TRIG_LEVEL_SHIFT        (16)
+#define SPI_FCTL_TX_TRIG_LEVEL_MASK         (0xFFU << SPI_FCTL_TX_TRIG_LEVEL_SHIFT)
+
+#define SPI_FCTL_RF_RST_SHIFT               (15)
+#define SPI_FCTL_RF_RST_MASK                (0x1U << SPI_FCTL_RF_RST_SHIFT)
+
+#define SPI_FCTL_RF_TEST_SHIFT              (14)
+#define SPI_FCTL_RF_TEST_MASK               (0x1U << SPI_FCTL_RF_TEST_SHIFT)
+
+#define SPI_FCTL_RF_DRQ_EN_SHIFT            (8)
+#define SPI_FCTL_RF_DRQ_EN_MASK             (0x1U << SPI_FCTL_RF_DRQ_EN_SHIFT)
+
+#define SPI_FCTL_RX_TRIG_LEVEL_SHIFT        (0)
+#define SPI_FCTL_RX_TRIG_LEVEL_MASK         (0xFFU << SPI_FCTL_RX_TRIG_LEVEL_SHIFT)
+
+/*
+ * @brief SPI FIFO Status Registe
+ */
+#define SPI_FST_TB_WR_SHIFT                 (31)
+#define SPI_FST_TB_WR_MASK                  (0x1U << SPI_FST_TB_WR_SHIFT)
+
+#define SPI_FST_TB_CNT_SHIFT                (28)
+#define SPI_FST_TB_CNT_MASK                 (0x7U << SPI_FST_TB_CNT_SHIFT)
+
+#define SPI_FST_TF_CNT_SHIFT                (16)
+#define SPI_FST_TF_CNT_MASK                 (0xFFU << SPI_FST_TF_CNT_SHIFT)
+
+#define SPI_FST_RB_WR_SHIFT                 (15)
+#define SPI_FST_RB_WR_MASK                  (0x1U << SPI_FST_RB_WR_SHIFT)
+
+#define SPI_FST_RB_CNT_SHIFT                (12)
+#define SPI_FST_RB_CNT_MASK                 (0x7U << SPI_FST_RB_CNT_SHIFT)
+
+#define SPI_FST_RF_CNT_SHIFT                (0)
+#define SPI_FST_RF_CNT_MASK                 (0xFFU << SPI_FST_RF_CNT_SHIFT)
+
+/*
+ * @brief SPI Wait Clock Counter Register
+ */
+#define SPI_WAIT_SWC_SHIFT                  (16)
+#define SPI_WAIT_SWC_MASK                   (0xFU << SPI_WAIT_SWC_SHIFT)
+
+#define SPI_WAIT_WCC_SHIFT                  (0)
+#define SPI_WAIT_WCC_MASK                   (0xFFFFU << SPI_WAIT_WCC_SHIFT)
+
+/*
+ * @brief SPI Clock Rate Control Register
+ */
+#define SPI_CCTR_DRS_SHIFT                  (12)
+#define SPI_CCTR_DRS_MASK                   (0x1U << SPI_CCTR_DRS_SHIFT)
+typedef enum
+{
+    SPI_CCTR_DRS_type_divRate1 = 0 << SPI_CCTR_DRS_SHIFT,
+    SPI_CCTR_DRS_type_divRate2 = 1 << SPI_CCTR_DRS_SHIFT
+} SPI_CCTR_DRS_type;
+
+#define SPI_CCTR_CDR1_SHIFT                 (8)
+#define SPI_CCTR_CDR1_MASK                  (0xFU << SPI_CCTR_CDR1_SHIFT)
+
+#define SPI_CCTR_CDR2_SHIFT                 (0)
+#define SPI_CCTR_CDR2_MASK                  (0xFFU << SPI_CCTR_CDR2_SHIFT)
+
+/*
+ * @brief SPI Master mode Burst Control Register
+ */
+#define SPI_BC_MBC_SHIFT                    (0)
+#define SPI_BC_MBC_MASK                     (0xFFFFFFU << SPI_BC_MBC_SHIFT)
+
+/*
+ * @brief SPI Master mode Transmit Counter Register
+ */
+#define SPI_TC_MWTC_SHIFT                   (0)
+#define SPI_TC_MWTC_MASK                    (0xFFFFFFU << SPI_TC_MWTC_SHIFT)
+
+/*
+ * @brief SPI Burst Control Register
+ */
+#define SPI_BCC_DRM_SHIFT                   (28)
+#define SPI_BCC_DRM_MASK                    (0x1U << SPI_BCC_DRM_SHIFT)
+
+#define SPI_BCC_DBC_SHIFT                   (24)
+#define SPI_BCC_DBC_MASK                    (0xFU << SPI_BCC_DBC_SHIFT)
+
+#define SPI_BCC_STC_SHIFT                   (0)
+#define SPI_BCC_STC_MASK                    (0xFFFFFFU << SPI_BCC_STC_SHIFT)
+
+/*
+ * @brief SPI TX Date Register
+ */
+#define SPI_TXD_SHIFT                       (0)
+#define SPI_TXD_MASK                        (0xFFFFFFFFU << SPI_TXD_SHIFT)
+
+/*
+ * @brief SPI RX Date Register
+ */
+#define SPI_RXD_SHIFT                       (0)
+#define SPI_RXD_MASK                        (0xFFFFFFFFU << SPI_RXD_SHIFT)
+
+/* other */
+#define SPI_FIFO_SIZE                       (64)
+#define SPI_MAX_WAIT_MS (2000)
+#define SPI_SOURCE_CLK (24 * 1000 * 1000)
+
+/* io ops */
+#define HAL_BIT(pos)                        (1U << (pos))
+
+#define HAL_SET_BIT(reg, mask)              ((reg) |= (mask))
+#define HAL_CLR_BIT(reg, mask)              ((reg) &= ~(mask))
+#define HAL_GET_BIT(reg, mask)              ((reg) & (mask))
+#define HAL_GET_BIT_VAL(reg, shift, vmask)  (((reg) >> (shift)) & (vmask))
+
+#define HAL_MODIFY_REG(reg, clr_mask, set_mask) \
+    ((reg) = (((reg) & (~(clr_mask))) | (set_mask)))
+
+/* access LSBs of a 32-bit register (little endian only) */
+#define HAL_REG_32BIT(reg_addr)  (*((volatile uint32_t *)(reg_addr)))
+#define HAL_REG_16BIT(reg_addr)  (*((volatile uint16_t *)(reg_addr)))
+#define HAL_REG_8BIT(reg_addr)   (*((volatile uint8_t  *)(reg_addr)))
+
+#define HAL_WAIT_FOREVER    OS_WAIT_FOREVER
+
+#define HAL_ARRAY_SIZE(a)   (sizeof((a)) / sizeof((a)[0]))
+
+struct aw_spi_cs
+{
+    SPI_TCTRL_SS_Sel cs;
+    int cs_port;
+    int cs_pin;
+    int cs_io_func;
+};
+
+struct aw_spi_init
+{
+    uintptr_t clk;
+    uintptr_t base_addr;
+    uintptr_t irq_num;
+    int mosi_port;
+    int mosi_pin;
+    int mosi_io_func;
+    int miso_port;
+    int miso_pin;
+    int miso_io_func;
+    int ck_port;
+    int ck_pin;
+    int ck_io_func;
+    int wp_port;
+    int wp_pin;
+    int wp_io_func;
+    int hold_port;
+    int hold_pin;
+    int hold_io_func;
+};
+
+/* ------------------------------------------------------------------------------ */
+#define pio_base_addr 	      (0x0300B000)
+#define readl(addr)           (*(volatile unsigned int *)(addr))
+#define writel(value,addr)    (*(volatile unsigned int *)(addr) = (value))
+
+#define GPIOn_CFG_ADDR(base, n)        (base + (n) * 0x24 + 0x00)
+#define GPIOn_DATA_ADDR(base, n)       (base + (n) * 0x24 + 0x10)
+#define GPIOn_DRV_ADDR(base, n)        (base + (n) * 0x24 + 0x14)
+#define GPIOn_PUL_ADDR(base, n)        (base + (n) * 0x24 + 0x1C)
+#define GPIOn_INT_CFG_ADDR(base, n)    (base + 0x200 + (n) * 0x20 + 0x00)
+#define GPIOn_INT_CTRL_ADDR(base, n)   (base + 0x200 + (n) * 0x20 + 0x10)
+#define GPIOn_INT_STA_ADDR(base, n)    (base + 0x200 + (n) * 0x20 + 0x14)
+#define GPIOn_INT_DEB_ADDR(base, n)    (base + 0x200 + (n) * 0x20 + 0x18)
+
+/* IO port */                                                                                                                                         
+enum gpio_port                                                                                                                                        
+{                                                                                                                                                     
+    GPIO_PORT_A = 0,                                                                                                                                  
+    GPIO_PORT_B,                                                                                                                                      
+    GPIO_PORT_C,                                                                                                                                                                               
+    GPIO_PORT_D,                                                                                                                                      
+    GPIO_PORT_E,                                                                                                                                      
+    GPIO_PORT_F,                                                                                                                                      
+    GPIO_PORT_G,                                                                                                                                      
+    GPIO_PORT_H,                                                                                                                                      
+    GPIO_PORT_I,                                                                                                                                      
+    GPIO_PORT_NUM,                                                                                                                                    
+}; 
+
+/* IO pin */
+enum gpio_pin
+{    
+    GPIO_PIN_0 = 0,
+    GPIO_PIN_1,
+    GPIO_PIN_2,
+    GPIO_PIN_3,
+    GPIO_PIN_4,
+    GPIO_PIN_5,
+    GPIO_PIN_6,
+    GPIO_PIN_7,
+    GPIO_PIN_8,
+    GPIO_PIN_9,
+    GPIO_PIN_10,
+    GPIO_PIN_11,
+    GPIO_PIN_12,
+    GPIO_PIN_13,
+    GPIO_PIN_14,
+    GPIO_PIN_15,
+    GPIO_PIN_16,
+    GPIO_PIN_17,
+    GPIO_PIN_18,
+    GPIO_PIN_19,
+    GPIO_PIN_20,
+    GPIO_PIN_21,
+    GPIO_PIN_22,
+    GPIO_PIN_23,
+    GPIO_PIN_NUM,
+}; 
+
+#define IO_INPUT         (0x00)
+#define IO_OUTPUT        (0x01)
+#define IO_DISABLE       (0x07)
+#define IO_FUN_2         (0x02)
+#define IO_FUN_3         (0x03)
+#define IO_FUN_4         (0x04)
+#define IO_FUN_5         (0x05)
+#define IO_FUN_6         (0x06)
+
+#define clk_port        GPIO_PORT_C
+#define hld_port        GPIO_PORT_C
+#define wp_port         GPIO_PORT_C
+#define mosi_port       GPIO_PORT_C
+#define miso_port       GPIO_PORT_C
+#define cs_port         GPIO_PORT_C
+
+#define clk_pin         GPIO_PIN_0
+#define mosi_pin        GPIO_PIN_2
+#define miso_pin        GPIO_PIN_4
+#define wp_pin          GPIO_PIN_15
+#define hld_pin         GPIO_PIN_16
+#define cs_pin          GPIO_PIN_3
+#define cs_sel          SPI_TCTRL_SS_SEL_SS0
+
+#define ck_io_func      IO_FUN_4
+#define hold_io_func    IO_FUN_4
+#define wp_io_func      IO_FUN_4
+#define mosi_io_func    IO_FUN_4
+#define miso_io_func    IO_FUN_4
+#define cs_io_func      IO_FUN_4
+
+static inline __attribute((always_inline)) void gpio_set_func(enum gpio_port port, enum gpio_pin pin, uint8_t func)
+{
+    uintptr_t addr;
+    uint32_t offset;
+    uint32_t data;
+ 
+    addr = GPIOn_CFG_ADDR(pio_base_addr, port) + (pin / 8) * 4;
+    offset = (pin % 8) * 4;                                                                                                                                                                    
+    data = readl(addr);
+    data &= ~(0x7 << offset);
+    data |= func << offset;
+    writel(data, addr);
+}
+static inline __attribute((always_inline)) int gpio_set_value(enum gpio_port port, enum gpio_pin pin, uint8_t value) 
+{
+    uint32_t addr; 
+    uint32_t offset;
+    uint32_t data;
+
+    addr = GPIOn_DATA_ADDR(pio_base_addr, port);
+    offset = pin;
+    
+    data = readl(addr);
+    data &= ~(0x1 << offset);
+    data |= value << offset;
+    writel(data, addr); 
+}
+
+static inline __attribute((always_inline)) void gpio_direction_output(enum gpio_port port, enum gpio_pin pin, int value)
+{
+    volatile uint32_t addr;
+    uint32_t offset;
+    uint32_t data;
+
+    gpio_set_value(port, pin, value); 
+    addr = GPIOn_CFG_ADDR(pio_base_addr, port) + (pin / 8) * 4; 
+    offset = (pin % 8) * 4;
+
+    data = readl(addr); 
+    data &= ~(0x7 << offset);
+    data |= IO_OUTPUT << offset;
+    writel(data, addr);
+}
+
+/* ------------------------------------------------------------------------------ */
+#define SPI_BUS_MAX_CLK    (100 * 1000 * 1000)
+#define SPI_CTR_ADDRESS    (SPI_T *)0x05010000;
+
+static inline __attribute((always_inline)) void SPI_Reset(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->GCR, SPI_CTRL_RST_MASK);
+}
+
+static inline __attribute((always_inline)) void SPI_SetMode(SPI_T *spi, SPI_CTRL_Mode mode)
+{
+    HAL_MODIFY_REG(spi->GCR, SPI_CTRL_MODE_MASK, mode);
+}
+
+static inline __attribute((always_inline)) void SPI_Enable(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->GCR, SPI_CTRL_EN_MASK);
+}
+
+static inline __attribute((always_inline)) void SPI_Disable(SPI_T *spi)
+{
+    HAL_CLR_BIT(spi->GCR, SPI_CTRL_EN_MASK);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_StartTransmit(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->TCR, SPI_TCTRL_XCH_MASK);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_SetFirstTransmitBit(SPI_T *spi, SPI_TCTRL_Fbs bit)
+{
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_FBS_MASK, bit);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_EnableRapidsMode(SPI_T *spi, int delay_sample)
+{
+    HAL_SET_BIT(spi->TCR, SPI_TCTRL_RPSM_MASK);
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_SDC_MASK, delay_sample << SPI_TCTRL_SDC_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_DisableRapidsMode(SPI_T *spi)
+{
+    HAL_CLR_BIT(spi->TCR, SPI_TCTRL_RPSM_MASK);
+}
+
+static inline __attribute((always_inline)) void SPI_SetDuplex(SPI_T *spi, SPI_TCTRL_DHB_Duplex duplex)
+{
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_DHB_MASK, duplex);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_SetCsLevel(SPI_T *spi,  int level)
+{
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_SS_LEVEL_MASK, level << SPI_TCTRL_SS_LEVEL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_ManualChipSelect(SPI_T *spi, SPI_TCTRL_SS_Sel cs)
+{
+    HAL_SET_BIT(spi->TCR, SPI_TCTRL_SS_OWNER_MASK);
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_SS_SEL_MASK, cs);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_AutoChipSelect(SPI_T *spi, SPI_TCTRL_SS_Sel cs, int cs_remain)
+{
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_SS_SEL_MASK, cs);
+    HAL_CLR_BIT(spi->TCR, SPI_TCTRL_SS_OWNER_MASK);
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_SS_CTL_MASK, (!cs_remain) << SPI_TCTRL_SS_CTL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_SetCsIdle(SPI_T *spi, int idle)
+{
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_SPOL_MASK, (!!idle) << SPI_TCTRL_SPOL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_SetSclkMode(SPI_T *spi, SPI_SCLK_Mode mode)
+{
+    HAL_MODIFY_REG(spi->TCR, SPI_TCTRL_CPOL_MASK | SPI_TCTRL_CPHA_MASK, mode);
+}
+
+typedef enum
+{
+    SPI_INT_CS_DESELECT = SPI_IER_SS_INT_EN_MASK,
+    SPI_INT_TRANSFER_COMPLETE = SPI_IER_TC_INT_EN_MASK,
+    SPI_INT_TXFIFO_UNDER_RUN = SPI_IER_TF_UDR_INT_EN_MASK,
+    SPI_INT_TXFIFO_OVERFLOW = SPI_IER_TF_OVF_INT_EN_MASK,
+    SPI_INT_RXFIFO_UNDER_RUN = SPI_IER_RF_UDR_INT_EN_MASK,
+    SPI_INT_RXFIFO_OVERFLOW = SPI_IER_RF_OVF_INT_EN_MASK,
+    SPI_INT_TXFIFO_FULL = SPI_IER_TF_FUL_INT_EN_MASK,
+    SPI_INT_TXFIFO_EMPTY = SPI_IER_TX_EMP_INT_EN_MASK,
+    SPI_INT_TXFIFO_READY = SPI_IER_TX_ERQ_INT_EN_MASK,
+    SPI_INT_RXFIFO_FULL = SPI_IER_RF_FUL_INT_EN_MASK,
+    SPI_INT_RXFIFO_EMPTY = SPI_IER_RX_EMP_INT_EN_MASK,
+    SPI_INT_RXFIFO_READY = SPI_IER_RF_RDY_INT_EN_MASK
+} SPI_Int_Type;
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_EnableInt(SPI_T *spi, SPI_Int_Type type)
+{
+    HAL_SET_BIT(spi->IER, type);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_DisableInt(SPI_T *spi, SPI_Int_Type type)
+{
+    HAL_CLR_BIT(spi->IER, type);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) int SPI_IntState(SPI_T *spi, SPI_Int_Type type)
+{
+    return !!HAL_GET_BIT(spi->ISR, type);
+}
+
+static inline __attribute((always_inline)) int SPI_ClearInt(SPI_T *spi, SPI_Int_Type type)
+{
+    HAL_SET_BIT(spi->ISR, type);
+    return HAL_GET_BIT(spi->ISR, type);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_DebugReadTx(SPI_T *spi, uint32_t *data)
+{
+    // tbc...
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_DebugWriteRx(SPI_T *spi, uint32_t *data)
+{
+    // tbc...
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_ResetTxFifo(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->FCR, SPI_FCTL_TF_RST_MASK);
+    while (HAL_GET_BIT(spi->FCR, SPI_FCTL_TF_RST_MASK) != 0);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_ResetRxFifo(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->FCR, SPI_FCTL_RF_RST_MASK);
+    while (HAL_GET_BIT(spi->FCR, SPI_FCTL_RF_RST_MASK) != 0);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_DMA(SPI_T *spi, int txEn, int rxEn)
+{
+    HAL_MODIFY_REG(spi->FCR,
+                   SPI_FCTL_TF_DRQ_EN_MASK | SPI_FCTL_RF_DRQ_EN_MASK,
+                   ((!!txEn) << SPI_FCTL_TF_DRQ_EN_SHIFT) | ((!!rxEn) << SPI_FCTL_RF_DRQ_EN_SHIFT));
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_SetTxFifoThreshold(SPI_T *spi, uint8_t threshold)
+{
+    HAL_MODIFY_REG(spi->FCR, SPI_FCTL_TX_TRIG_LEVEL_MASK, threshold << SPI_FCTL_TX_TRIG_LEVEL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_SetRxFifoThreshold(SPI_T *spi, uint8_t threshold)
+{
+    HAL_MODIFY_REG(spi->FCR, SPI_FCTL_RX_TRIG_LEVEL_MASK, threshold << SPI_FCTL_RX_TRIG_LEVEL_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) uint8_t SPI_GetTxFifoCounter(SPI_T *spi)
+{
+    return (uint8_t)((spi->FSR & SPI_FST_TF_CNT_MASK) >> SPI_FST_TF_CNT_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) uint8_t SPI_GetRxFifoCounter(SPI_T *spi)
+{
+    return (uint8_t)((spi->FSR & SPI_FST_RF_CNT_MASK) >> SPI_FST_RF_CNT_SHIFT);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_EnableDualMode(SPI_T *spi)
+{
+    HAL_SET_BIT(spi->BCC, SPI_BCC_DRM_MASK);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_DisableDualMode(SPI_T *spi)
+{
+    HAL_CLR_BIT(spi->BCC, SPI_BCC_DRM_MASK);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_SetInterval(SPI_T *spi, uint16_t nSCLK)
+{
+    HAL_MODIFY_REG(spi->WCR, SPI_WAIT_WCC_MASK, nSCLK << SPI_WAIT_WCC_SHIFT);
+}
+
+/*
+ * @brief
+ */
+
+static inline __attribute((always_inline)) void SPI_SetClkDiv(SPI_T *spi, uint16_t div)
+{
+    uint8_t n = 0;
+    if (div < 1)
+    {
+        return;
+    }
+
+    if (div > 2 * (0xFF + 1))
+    {
+        HAL_CLR_BIT(spi->CCR, SPI_CCTR_DRS_MASK);
+        do
+        {
+            div = (div == 1) ? 0 : ((div + 1) / 2);
+            n++;
+        }
+        while (div);
+
+        HAL_MODIFY_REG(spi->CCR, SPI_CCTR_CDR1_MASK, (n & 0x0F) << SPI_CCTR_CDR1_SHIFT);
+    }
+    else
+    {
+        HAL_SET_BIT(spi->CCR, SPI_CCTR_DRS_MASK);
+        n = ((div + 1) / 2) - 1;
+        HAL_MODIFY_REG(spi->CCR, SPI_CCTR_CDR2_MASK, (n & 0xFF) << SPI_CCTR_CDR2_SHIFT);
+    }
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_SetDataSize(SPI_T *spi, uint32_t data_size, uint32_t dummy_size)
+{
+    HAL_MODIFY_REG(spi->MBC, SPI_BC_MBC_MASK, data_size + dummy_size);
+    HAL_MODIFY_REG(spi->MTC, SPI_TC_MWTC_MASK, data_size);
+    HAL_MODIFY_REG(spi->BCC, SPI_BCC_STC_MASK, data_size);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_Write(SPI_T *spi, uint8_t *data)
+{
+    HAL_REG_8BIT(&spi->TXD) = *data;
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) void SPI_Read(SPI_T *spi, uint8_t *data)
+{
+    *data = HAL_REG_8BIT(&spi->RXD);
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) uint8_t *SPI_TxAddress(SPI_T *spi)
+{
+    return (uint8_t *)&spi->TXD;
+}
+
+/*
+ * @brief
+ */
+static inline __attribute((always_inline)) uint8_t *SPI_RxAddress(SPI_T *spi)
+{
+    return (uint8_t *)&spi->RXD;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/fel-remotefunc-compiler.rb b/fel-remotefunc-compiler.rb
old mode 100644
new mode 100755
index 50ea9ea..4824d51
--- a/fel-remotefunc-compiler.rb
+++ b/fel-remotefunc-compiler.rb
@@ -33,8 +33,8 @@ if ARGV.size < 2
   printf("Using this example code inside of sunxi-fel:\n")
   printf("\n")
   printf("    uint32_t a = 1, b = 2, c;\n")
-  printf("    aw_fel_remotefunc_prepare_sum(usb, a, b);\n")
-  printf("    aw_fel_remotefunc_execute(usb, &c);\n")
+  printf("    aw_fel_remotefunc_prepare_sum(dev, a, b);\n")
+  printf("    aw_fel_remotefunc_execute(dev, &c);\n")
   printf("    printf(\"%%d + %%d = %%d\\n\", a, b, c);\n\n")
 
   printf("If the returned result is not needed (a void function), then the second\n")
@@ -122,7 +122,7 @@ out = File.open(ARGV[1], "w")
 out.printf("/* Automatically generated, do not edit! */\n\n")
 
 out.printf("static void\n")
-funcdecl = sprintf("aw_fel_remotefunc_prepare_#{function_name}(libusb_device_handle *usb,")
+funcdecl = sprintf("aw_fel_remotefunc_prepare_#{function_name}(feldev_handle *dev,")
 out.printf("%s\n", funcdecl)
 out.printf("%s", function_args.map {|a|
            " " * funcdecl.index("(") + " uint32_t              " + a }.join(",\n"))
@@ -143,7 +143,7 @@ out.printf("\t};\n")
 out.printf("\tuint32_t args[] = {\n\t\t")
 out.printf("%s\n\t};\n", function_args.join(",\n\t\t"))
 
-out.printf("\taw_fel_remotefunc_prepare(usb, %d, arm_code, sizeof(arm_code), %d, args);\n",
+out.printf("\taw_fel_remotefunc_prepare(dev, %d, arm_code, sizeof(arm_code), %d, args);\n",
            stack_usage[0][:stack_usage], function_args.size)
 
 out.printf("}\n")
diff --git a/fel-remotefunc-spi-data-transfer.h b/fel-remotefunc-spi-data-transfer.h
index c1a64cb..233ef70 100644
--- a/fel-remotefunc-spi-data-transfer.h
+++ b/fel-remotefunc-spi-data-transfer.h
@@ -4,147 +4,147 @@ static void
 aw_fel_remotefunc_prepare_spi_batch_data_transfer(feldev_handle *dev,
                                                   uint32_t              buf,
                                                   uint32_t              spi_ctl_reg,
-                                                  uint32_t              spi_ctl_xch_bitmask,
-                                                  uint32_t              spi_fifo_reg,
-                                                  uint32_t              spi_tx_reg,
-                                                  uint32_t              spi_rx_reg,
-                                                  uint32_t              spi_bc_reg,
-                                                  uint32_t              spi_tc_reg,
-                                                  uint32_t              spi_bcc_reg)
+                                                  uint32_t              unused1,
+                                                  uint32_t              unused2,
+                                                  uint32_t              unused3,
+                                                  uint32_t              unused4,
+                                                  uint32_t              unused5,
+                                                  uint32_t              unused6,
+                                                  uint32_t              unused7)
 {
 	static uint8_t arm_code[] = {
 		0xf0, 0x0f, 0x2d, 0xe9, /*    0:    push     {r4, r5, r6, r7, r8, r9, sl, fp}   */
-		0x18, 0xd0, 0x4d, 0xe2, /*    4:    sub      sp, sp, #24                        */
-		0x38, 0x50, 0x9d, 0xe5, /*    8:    ldr      r5, [sp, #56]                      */
-		0x3c, 0x60, 0x9d, 0xe5, /*    c:    ldr      r6, [sp, #60]                      */
-		0x06, 0x00, 0x8d, 0xe9, /*   10:    stmib    sp, {r1, r2}                       */
-		0x00, 0xa0, 0xd0, 0xe5, /*   14:    ldrb     sl, [r0]                           */
-		0x01, 0x20, 0xd0, 0xe5, /*   18:    ldrb     r2, [r0, #1]                       */
-		0x0a, 0xa4, 0x92, 0xe1, /*   1c:    orrs     sl, r2, sl, lsl #8                 */
-		0x6a, 0x00, 0x00, 0x0a, /*   20:    beq      1d0 <spi_batch_data_transfer+0x1d0> */
-		0xff, 0x2f, 0x0f, 0xe3, /*   24:    movw     r2, #65535                         */
-		0x02, 0x00, 0x5a, 0xe1, /*   28:    cmp      sl, r2                             */
-		0x18, 0x80, 0x8d, 0x02, /*   2c:    addeq    r8, sp, #24                        */
-		0x02, 0x80, 0x80, 0x12, /*   30:    addne    r8, r0, #2                         */
-		0x05, 0xb0, 0xa0, 0x03, /*   34:    moveq    fp, #5                             */
-		0x48, 0xc0, 0x9d, 0xe5, /*   38:    ldr      ip, [sp, #72]                      */
-		0x08, 0xb0, 0x68, 0x05, /*   3c:    strbeq   fp, [r8, #-8]!                     */
-		0x00, 0x10, 0x68, 0xe2, /*   40:    rsb      r1, r8, #0                         */
-		0x40, 0x20, 0x9d, 0xe5, /*   44:    ldr      r2, [sp, #64]                      */
-		0x03, 0x10, 0x01, 0xe2, /*   48:    and      r1, r1, #3                         */
-		0x44, 0xb0, 0x9d, 0xe5, /*   4c:    ldr      fp, [sp, #68]                      */
-		0x0a, 0x70, 0xa0, 0x11, /*   50:    movne    r7, sl                             */
-		0x0c, 0x00, 0x8d, 0x05, /*   54:    streq    r0, [sp, #12]                      */
-		0x3c, 0x00, 0x81, 0xe2, /*   58:    add      r0, r1, #60                        */
-		0x02, 0x70, 0xa0, 0x03, /*   5c:    moveq    r7, #2                             */
-		0x00, 0x00, 0x5c, 0xe3, /*   60:    cmp      ip, #0                             */
-		0x00, 0x70, 0x82, 0xe5, /*   64:    str      r7, [r2]                           */
-		0x08, 0x20, 0xa0, 0xe1, /*   68:    mov      r2, r8                             */
-		0x00, 0x70, 0x8b, 0xe5, /*   6c:    str      r7, [fp]                           */
-		0x00, 0x70, 0x8c, 0x15, /*   70:    strne    r7, [ip]                           */
-		0x07, 0x00, 0x50, 0xe1, /*   74:    cmp      r0, r7                             */
-		0x07, 0x00, 0xa0, 0x21, /*   78:    movcs    r0, r7                             */
-		0x00, 0x40, 0x88, 0xe0, /*   7c:    add      r4, r8, r0                         */
-		0x01, 0xc0, 0xd2, 0xe4, /*   80:    ldrb     ip, [r2], #1                       */
-		0x04, 0x00, 0x52, 0xe1, /*   84:    cmp      r2, r4                             */
-		0x00, 0xc0, 0xc5, 0xe5, /*   88:    strb     ip, [r5]                           */
-		0xfb, 0xff, 0xff, 0x1a, /*   8c:    bne      80 <spi_batch_data_transfer+0x80>  */
-		0x07, 0x00, 0x60, 0xe0, /*   90:    rsb      r0, r0, r7                         */
-		0x00, 0x90, 0x0f, 0xe1, /*   94:    mrs      r9, CPSR                           */
-		0xc0, 0xc0, 0x89, 0xe3, /*   98:    orr      ip, r9, #192                       */
-		0x0c, 0xf0, 0x21, 0xe1, /*   9c:    msr      CPSR_c, ip                         */
-		0x04, 0xc0, 0x9d, 0xe5, /*   a0:    ldr      ip, [sp, #4]                       */
-		0x07, 0x00, 0x51, 0xe1, /*   a4:    cmp      r1, r7                             */
-		0x07, 0x10, 0xa0, 0x21, /*   a8:    movcs    r1, r7                             */
-		0x08, 0xb0, 0x9d, 0xe5, /*   ac:    ldr      fp, [sp, #8]                       */
-		0x00, 0x40, 0x9c, 0xe5, /*   b0:    ldr      r4, [ip]                           */
-		0x01, 0xc0, 0x88, 0xe0, /*   b4:    add      ip, r8, r1                         */
-		0x00, 0xc0, 0x8d, 0xe5, /*   b8:    str      ip, [sp]                           */
-		0x08, 0xc0, 0xa0, 0xe1, /*   bc:    mov      ip, r8                             */
-		0x0b, 0x40, 0x84, 0xe1, /*   c0:    orr      r4, r4, fp                         */
-		0x04, 0xb0, 0x9d, 0xe5, /*   c4:    ldr      fp, [sp, #4]                       */
-		0x00, 0x40, 0x8b, 0xe5, /*   c8:    str      r4, [fp]                           */
-		0x00, 0xb0, 0x9d, 0xe5, /*   cc:    ldr      fp, [sp]                           */
-		0x0b, 0x00, 0x5c, 0xe1, /*   d0:    cmp      ip, fp                             */
-		0x06, 0x00, 0x00, 0x0a, /*   d4:    beq      f4 <spi_batch_data_transfer+0xf4>  */
-		0x00, 0x40, 0x93, 0xe5, /*   d8:    ldr      r4, [r3]                           */
-		0x7f, 0x00, 0x14, 0xe3, /*   dc:    tst      r4, #127                           */
-		0xfc, 0xff, 0xff, 0x0a, /*   e0:    beq      d8 <spi_batch_data_transfer+0xd8>  */
-		0x00, 0x40, 0xd6, 0xe5, /*   e4:    ldrb     r4, [r6]                           */
-		0x01, 0x40, 0xcc, 0xe4, /*   e8:    strb     r4, [ip], #1                       */
-		0x0b, 0x00, 0x5c, 0xe1, /*   ec:    cmp      ip, fp                             */
-		0xf8, 0xff, 0xff, 0x1a, /*   f0:    bne      d8 <spi_batch_data_transfer+0xd8>  */
-		0x07, 0x10, 0x61, 0xe0, /*   f4:    rsb      r1, r1, r7                         */
-		0x03, 0x00, 0x51, 0xe3, /*   f8:    cmp      r1, #3                             */
-		0x12, 0x00, 0x00, 0x9a, /*   fc:    bls      14c <spi_batch_data_transfer+0x14c> */
-		0x00, 0x40, 0x93, 0xe5, /*  100:    ldr      r4, [r3]                           */
-		0x7f, 0xb0, 0x04, 0xe2, /*  104:    and      fp, r4, #127                       */
-		0x54, 0x48, 0xe6, 0xe7, /*  108:    ubfx     r4, r4, #16, #7                    */
-		0x03, 0x00, 0x5b, 0xe3, /*  10c:    cmp      fp, #3                             */
-		0x04, 0x10, 0x41, 0xc2, /*  110:    subgt    r1, r1, #4                         */
-		0x00, 0xb0, 0x96, 0xc5, /*  114:    ldrgt    fp, [r6]                           */
-		0x04, 0xb0, 0x8c, 0xc4, /*  118:    strgt    fp, [ip], #4                       */
-		0x03, 0x00, 0x50, 0xe3, /*  11c:    cmp      r0, #3                             */
-		0x00, 0xb0, 0xa0, 0x93, /*  120:    movls    fp, #0                             */
-		0x01, 0xb0, 0xa0, 0x83, /*  124:    movhi    fp, #1                             */
-		0x3b, 0x00, 0x54, 0xe3, /*  128:    cmp      r4, #59                            */
-		0x00, 0xb0, 0xa0, 0xc3, /*  12c:    movgt    fp, #0                             */
-		0x00, 0x00, 0x5b, 0xe3, /*  130:    cmp      fp, #0                             */
-		0xef, 0xff, 0xff, 0x0a, /*  134:    beq      f8 <spi_batch_data_transfer+0xf8>  */
-		0x04, 0x40, 0x92, 0xe4, /*  138:    ldr      r4, [r2], #4                       */
-		0x03, 0x00, 0x51, 0xe3, /*  13c:    cmp      r1, #3                             */
-		0x04, 0x00, 0x40, 0xe2, /*  140:    sub      r0, r0, #4                         */
-		0x00, 0x40, 0x85, 0xe5, /*  144:    str      r4, [r5]                           */
-		0xec, 0xff, 0xff, 0x8a, /*  148:    bhi      100 <spi_batch_data_transfer+0x100> */
-		0x00, 0x00, 0x51, 0xe3, /*  14c:    cmp      r1, #0                             */
-		0x10, 0x00, 0x00, 0x0a, /*  150:    beq      198 <spi_batch_data_transfer+0x198> */
-		0x00, 0x40, 0x93, 0xe5, /*  154:    ldr      r4, [r3]                           */
-		0x7f, 0x00, 0x14, 0xe3, /*  158:    tst      r4, #127                           */
-		0x54, 0x48, 0xe6, 0xe7, /*  15c:    ubfx     r4, r4, #16, #7                    */
-		0x01, 0x10, 0x41, 0x12, /*  160:    subne    r1, r1, #1                         */
-		0x00, 0xb0, 0xd6, 0x15, /*  164:    ldrbne   fp, [r6]                           */
-		0x01, 0xb0, 0xcc, 0x14, /*  168:    strbne   fp, [ip], #1                       */
-		0x00, 0xb0, 0x90, 0xe2, /*  16c:    adds     fp, r0, #0                         */
-		0x01, 0xb0, 0xa0, 0x13, /*  170:    movne    fp, #1                             */
-		0x3b, 0x00, 0x54, 0xe3, /*  174:    cmp      r4, #59                            */
-		0x00, 0xb0, 0xa0, 0xc3, /*  178:    movgt    fp, #0                             */
-		0x00, 0x00, 0x5b, 0xe3, /*  17c:    cmp      fp, #0                             */
-		0xf1, 0xff, 0xff, 0x0a, /*  180:    beq      14c <spi_batch_data_transfer+0x14c> */
-		0x01, 0x40, 0xd2, 0xe4, /*  184:    ldrb     r4, [r2], #1                       */
-		0x00, 0x00, 0x51, 0xe3, /*  188:    cmp      r1, #0                             */
-		0x01, 0x00, 0x40, 0xe2, /*  18c:    sub      r0, r0, #1                         */
-		0x00, 0x40, 0xc5, 0xe5, /*  190:    strb     r4, [r5]                           */
-		0xee, 0xff, 0xff, 0x1a, /*  194:    bne      154 <spi_batch_data_transfer+0x154> */
-		0x09, 0xf0, 0x21, 0xe1, /*  198:    msr      CPSR_c, r9                         */
-		0xff, 0xcf, 0x0f, 0xe3, /*  19c:    movw     ip, #65535                         */
-		0x0c, 0x00, 0x5a, 0xe1, /*  1a0:    cmp      sl, ip                             */
-		0x07, 0x00, 0x88, 0x10, /*  1a4:    addne    r0, r8, r7                         */
-		0x99, 0xff, 0xff, 0x1a, /*  1a8:    bne      14 <spi_batch_data_transfer+0x14>  */
-		0x11, 0x20, 0xdd, 0xe5, /*  1ac:    ldrb     r2, [sp, #17]                      */
-		0x01, 0x00, 0x12, 0xe3, /*  1b0:    tst      r2, #1                             */
-		0x08, 0x00, 0x00, 0x1a, /*  1b4:    bne      1dc <spi_batch_data_transfer+0x1dc> */
-		0x0c, 0xb0, 0x9d, 0xe5, /*  1b8:    ldr      fp, [sp, #12]                      */
-		0x02, 0x00, 0x8b, 0xe2, /*  1bc:    add      r0, fp, #2                         */
-		0x00, 0xa0, 0xd0, 0xe5, /*  1c0:    ldrb     sl, [r0]                           */
-		0x01, 0x20, 0xd0, 0xe5, /*  1c4:    ldrb     r2, [r0, #1]                       */
-		0x0a, 0xa4, 0x92, 0xe1, /*  1c8:    orrs     sl, r2, sl, lsl #8                 */
-		0x94, 0xff, 0xff, 0x1a, /*  1cc:    bne      24 <spi_batch_data_transfer+0x24>  */
-		0x18, 0xd0, 0x8d, 0xe2, /*  1d0:    add      sp, sp, #24                        */
-		0xf0, 0x0f, 0xbd, 0xe8, /*  1d4:    pop      {r4, r5, r6, r7, r8, r9, sl, fp}   */
-		0x1e, 0xff, 0x2f, 0xe1, /*  1d8:    bx       lr                                 */
-		0x0c, 0x00, 0x9d, 0xe5, /*  1dc:    ldr      r0, [sp, #12]                      */
-		0x8b, 0xff, 0xff, 0xea, /*  1e0:    b        14 <spi_batch_data_transfer+0x14>  */
+		0x08, 0xd0, 0x4d, 0xe2, /*    4:    sub      sp, sp, #8                         */
+		0xff, 0xbf, 0x0f, 0xe3, /*    8:    movw     fp, #65535                         */
+		0x00, 0x30, 0xa0, 0xe3, /*    c:    mov      r3, #0                             */
+		0xb0, 0x30, 0xcd, 0xe1, /*   10:    strh     r3, [sp]                           */
+		0x00, 0x70, 0xd0, 0xe5, /*   14:    ldrb     r7, [r0]                           */
+		0x01, 0x30, 0xd0, 0xe5, /*   18:    ldrb     r3, [r0, #1]                       */
+		0x07, 0x74, 0x93, 0xe1, /*   1c:    orrs     r7, r3, r7, lsl #8                 */
+		0x6c, 0x00, 0x00, 0x0a, /*   20:    beq      1d8 <spi_batch_data_transfer+0x1d8> */
+		0x0b, 0x00, 0x57, 0xe1, /*   24:    cmp      r7, fp                             */
+		0x08, 0x60, 0x8d, 0x02, /*   28:    addeq    r6, sp, #8                         */
+		0x02, 0x60, 0x80, 0x12, /*   2c:    addne    r6, r0, #2                         */
+		0x05, 0x30, 0xa0, 0x03, /*   30:    moveq    r3, #5                             */
+		0x00, 0x90, 0xa0, 0x01, /*   34:    moveq    r9, r0                             */
+		0x08, 0x30, 0x66, 0x05, /*   38:    strbeq   r3, [r6, #-8]!                     */
+		0x02, 0x50, 0xa0, 0x03, /*   3c:    moveq    r5, #2                             */
+		0x07, 0x50, 0xa0, 0x11, /*   40:    movne    r5, r7                             */
+		0x00, 0x80, 0x0f, 0xe1, /*   44:    mrs      r8, CPSR                           */
+		0xc0, 0x30, 0x88, 0xe3, /*   48:    orr      r3, r8, #192                       */
+		0x03, 0xf0, 0x21, 0xe1, /*   4c:    msr      CPSR_c, r3                         */
+		0x08, 0x30, 0x91, 0xe5, /*   50:    ldr      r3, [r1, #8]                       */
+		0x40, 0x30, 0x83, 0xe3, /*   54:    orr      r3, r3, #64                        */
+		0x08, 0x30, 0x81, 0xe5, /*   58:    str      r3, [r1, #8]                       */
+		0x08, 0x30, 0x91, 0xe5, /*   5c:    ldr      r3, [r1, #8]                       */
+		0x30, 0x30, 0xc3, 0xe3, /*   60:    bic      r3, r3, #48                        */
+		0x08, 0x30, 0x81, 0xe5, /*   64:    str      r3, [r1, #8]                       */
+		0x08, 0x30, 0x91, 0xe5, /*   68:    ldr      r3, [r1, #8]                       */
+		0x80, 0x30, 0xc3, 0xe3, /*   6c:    bic      r3, r3, #128                       */
+		0x08, 0x30, 0x81, 0xe5, /*   70:    str      r3, [r1, #8]                       */
+		0x18, 0x30, 0x91, 0xe5, /*   74:    ldr      r3, [r1, #24]                      */
+		0x02, 0x31, 0x83, 0xe3, /*   78:    orr      r3, r3, #-2147483648               */
+		0x18, 0x30, 0x81, 0xe5, /*   7c:    str      r3, [r1, #24]                      */
+		0x18, 0x30, 0x91, 0xe5, /*   80:    ldr      r3, [r1, #24]                      */
+		0x00, 0x00, 0x53, 0xe3, /*   84:    cmp      r3, #0                             */
+		0xfc, 0xff, 0xff, 0xba, /*   88:    blt      80 <spi_batch_data_transfer+0x80>  */
+		0x18, 0x30, 0x91, 0xe5, /*   8c:    ldr      r3, [r1, #24]                      */
+		0x02, 0x39, 0x83, 0xe3, /*   90:    orr      r3, r3, #32768                     */
+		0x18, 0x30, 0x81, 0xe5, /*   94:    str      r3, [r1, #24]                      */
+		0x18, 0x30, 0x91, 0xe5, /*   98:    ldr      r3, [r1, #24]                      */
+		0x02, 0x09, 0x13, 0xe3, /*   9c:    tst      r3, #32768                         */
+		0xfc, 0xff, 0xff, 0x1a, /*   a0:    bne      98 <spi_batch_data_transfer+0x98>  */
+		0x30, 0xc0, 0x91, 0xe5, /*   a4:    ldr      ip, [r1, #48]                      */
+		0x05, 0x40, 0xa0, 0xe1, /*   a8:    mov      r4, r5                             */
+		0x05, 0x00, 0xa0, 0xe1, /*   ac:    mov      r0, r5                             */
+		0x06, 0x20, 0xa0, 0xe1, /*   b0:    mov      r2, r6                             */
+		0xff, 0xc4, 0x0c, 0xe2, /*   b4:    and      ip, ip, #-16777216                 */
+		0x06, 0x30, 0xa0, 0xe1, /*   b8:    mov      r3, r6                             */
+		0x0c, 0xc0, 0x85, 0xe1, /*   bc:    orr      ip, r5, ip                         */
+		0x30, 0xc0, 0x81, 0xe5, /*   c0:    str      ip, [r1, #48]                      */
+		0x34, 0xc0, 0x91, 0xe5, /*   c4:    ldr      ip, [r1, #52]                      */
+		0xff, 0xc4, 0x0c, 0xe2, /*   c8:    and      ip, ip, #-16777216                 */
+		0x0c, 0xc0, 0x85, 0xe1, /*   cc:    orr      ip, r5, ip                         */
+		0x34, 0xc0, 0x81, 0xe5, /*   d0:    str      ip, [r1, #52]                      */
+		0x38, 0xc0, 0x91, 0xe5, /*   d4:    ldr      ip, [r1, #56]                      */
+		0xff, 0xc4, 0x0c, 0xe2, /*   d8:    and      ip, ip, #-16777216                 */
+		0x0c, 0xc0, 0x85, 0xe1, /*   dc:    orr      ip, r5, ip                         */
+		0x38, 0xc0, 0x81, 0xe5, /*   e0:    str      ip, [r1, #56]                      */
+		0x08, 0xc0, 0x91, 0xe5, /*   e4:    ldr      ip, [r1, #8]                       */
+		0x02, 0xc1, 0x8c, 0xe3, /*   e8:    orr      ip, ip, #-2147483648               */
+		0x08, 0xc0, 0x81, 0xe5, /*   ec:    str      ip, [r1, #8]                       */
+		0x00, 0xc0, 0x94, 0xe1, /*   f0:    orrs     ip, r4, r0                         */
+		0x20, 0x00, 0x00, 0x0a, /*   f4:    beq      17c <spi_batch_data_transfer+0x17c> */
+		0x1c, 0xc0, 0x91, 0xe5, /*   f8:    ldr      ip, [r1, #28]                      */
+		0x5c, 0xc8, 0xe7, 0xe7, /*   fc:    ubfx     ip, ip, #16, #8                    */
+		0x3f, 0x00, 0x5c, 0xe3, /*  100:    cmp      ip, #63                            */
+		0x17, 0x00, 0x00, 0x8a, /*  104:    bhi      168 <spi_batch_data_transfer+0x168> */
+		0x00, 0x00, 0x50, 0xe3, /*  108:    cmp      r0, #0                             */
+		0x15, 0x00, 0x00, 0x0a, /*  10c:    beq      168 <spi_batch_data_transfer+0x168> */
+		0xff, 0xa0, 0xa0, 0xe3, /*  110:    mov      sl, #255                           */
+		0x01, 0x00, 0x00, 0xea, /*  114:    b        120 <spi_batch_data_transfer+0x120> */
+		0x00, 0x00, 0x50, 0xe3, /*  118:    cmp      r0, #0                             */
+		0x11, 0x00, 0x00, 0x0a, /*  11c:    beq      168 <spi_batch_data_transfer+0x168> */
+		0x00, 0x00, 0x53, 0xe3, /*  120:    cmp      r3, #0                             */
+		0x01, 0x00, 0x40, 0xe2, /*  124:    sub      r0, r0, #1                         */
+		0x00, 0xa0, 0xd3, 0x15, /*  128:    ldrbne   sl, [r3]                           */
+		0x01, 0x30, 0x83, 0x12, /*  12c:    addne    r3, r3, #1                         */
+		0x00, 0xa2, 0xc1, 0xe5, /*  130:    strb     sl, [r1, #512]                     */
+		0x1c, 0xc0, 0x91, 0xe5, /*  134:    ldr      ip, [r1, #28]                      */
+		0x5c, 0xc8, 0xe7, 0xe7, /*  138:    ubfx     ip, ip, #16, #8                    */
+		0x3f, 0x00, 0x5c, 0xe3, /*  13c:    cmp      ip, #63                            */
+		0xf4, 0xff, 0xff, 0x9a, /*  140:    bls      118 <spi_batch_data_transfer+0x118> */
+		0x1c, 0xc0, 0x91, 0xe5, /*  144:    ldr      ip, [r1, #28]                      */
+		0xff, 0x00, 0x1c, 0xe3, /*  148:    tst      ip, #255                           */
+		0xe7, 0xff, 0xff, 0x0a, /*  14c:    beq      f0 <spi_batch_data_transfer+0xf0>  */
+		0x00, 0xc3, 0xd1, 0xe5, /*  150:    ldrb     ip, [r1, #768]                     */
+		0x00, 0x00, 0x52, 0xe3, /*  154:    cmp      r2, #0                             */
+		0x01, 0x40, 0x44, 0xe2, /*  158:    sub      r4, r4, #1                         */
+		0x7c, 0xc0, 0xef, 0xe6, /*  15c:    uxtb     ip, ip                             */
+		0x00, 0xc0, 0xc2, 0x15, /*  160:    strbne   ip, [r2]                           */
+		0x01, 0x20, 0x82, 0x12, /*  164:    addne    r2, r2, #1                         */
+		0x1c, 0xc0, 0x91, 0xe5, /*  168:    ldr      ip, [r1, #28]                      */
+		0xff, 0x00, 0x1c, 0xe3, /*  16c:    tst      ip, #255                           */
+		0xf6, 0xff, 0xff, 0x1a, /*  170:    bne      150 <spi_batch_data_transfer+0x150> */
+		0x00, 0xc0, 0x94, 0xe1, /*  174:    orrs     ip, r4, r0                         */
+		0xde, 0xff, 0xff, 0x1a, /*  178:    bne      f8 <spi_batch_data_transfer+0xf8>  */
+		0x14, 0x30, 0x91, 0xe5, /*  17c:    ldr      r3, [r1, #20]                      */
+		0x01, 0x0a, 0x13, 0xe3, /*  180:    tst      r3, #4096                          */
+		0xfc, 0xff, 0xff, 0x0a, /*  184:    beq      17c <spi_batch_data_transfer+0x17c> */
+		0x14, 0x30, 0x91, 0xe5, /*  188:    ldr      r3, [r1, #20]                      */
+		0x01, 0x3a, 0x83, 0xe3, /*  18c:    orr      r3, r3, #4096                      */
+		0x14, 0x30, 0x81, 0xe5, /*  190:    str      r3, [r1, #20]                      */
+		0x14, 0x30, 0x91, 0xe5, /*  194:    ldr      r3, [r1, #20]                      */
+		0x08, 0x30, 0x91, 0xe5, /*  198:    ldr      r3, [r1, #8]                       */
+		0x80, 0x30, 0x83, 0xe3, /*  19c:    orr      r3, r3, #128                       */
+		0x08, 0x30, 0x81, 0xe5, /*  1a0:    str      r3, [r1, #8]                       */
+		0x08, 0xf0, 0x21, 0xe1, /*  1a4:    msr      CPSR_c, r8                         */
+		0x0b, 0x00, 0x57, 0xe1, /*  1a8:    cmp      r7, fp                             */
+		0x05, 0x00, 0x86, 0x10, /*  1ac:    addne    r0, r6, r5                         */
+		0x97, 0xff, 0xff, 0x1a, /*  1b0:    bne      14 <spi_batch_data_transfer+0x14>  */
+		0x01, 0x30, 0xdd, 0xe5, /*  1b4:    ldrb     r3, [sp, #1]                       */
+		0x01, 0x00, 0x13, 0xe3, /*  1b8:    tst      r3, #1                             */
+		0x02, 0x00, 0x89, 0x02, /*  1bc:    addeq    r0, r9, #2                         */
+		0x93, 0xff, 0xff, 0x0a, /*  1c0:    beq      14 <spi_batch_data_transfer+0x14>  */
+		0x09, 0x00, 0xa0, 0xe1, /*  1c4:    mov      r0, r9                             */
+		0x00, 0x70, 0xd0, 0xe5, /*  1c8:    ldrb     r7, [r0]                           */
+		0x01, 0x30, 0xd0, 0xe5, /*  1cc:    ldrb     r3, [r0, #1]                       */
+		0x07, 0x74, 0x93, 0xe1, /*  1d0:    orrs     r7, r3, r7, lsl #8                 */
+		0x92, 0xff, 0xff, 0x1a, /*  1d4:    bne      24 <spi_batch_data_transfer+0x24>  */
+		0x08, 0xd0, 0x8d, 0xe2, /*  1d8:    add      sp, sp, #8                         */
+		0xf0, 0x0f, 0xbd, 0xe8, /*  1dc:    pop      {r4, r5, r6, r7, r8, r9, sl, fp}   */
+		0x1e, 0xff, 0x2f, 0xe1, /*  1e0:    bx       lr                                 */
 	};
 	uint32_t args[] = {
 		buf,
 		spi_ctl_reg,
-		spi_ctl_xch_bitmask,
-		spi_fifo_reg,
-		spi_tx_reg,
-		spi_rx_reg,
-		spi_bc_reg,
-		spi_tc_reg,
-		spi_bcc_reg
+		unused1,
+		unused2,
+		unused3,
+		unused4,
+		unused5,
+		unused6,
+		unused7
 	};
-	aw_fel_remotefunc_prepare(dev, 56, arm_code, sizeof(arm_code), 9, args);
+	aw_fel_remotefunc_prepare(dev, 40, arm_code, sizeof(arm_code), 9, args);
 }
diff --git a/fel-spiflash.c b/fel-spiflash.c
index 114affb..5bf362d 100644
--- a/fel-spiflash.c
+++ b/fel-spiflash.c
@@ -81,15 +81,15 @@ spi_flash_info_t default_spi_flash_info = {
 #define SUN4I_SPI0_BC               (0x01C05000 + 0x20)
 #define SUN4I_SPI0_TC               (0x01C05000 + 0x24)
 
-#define SUN6I_SPI0_CCTL             (0x01C68000 + 0x24)
-#define SUN6I_SPI0_GCR              (0x01C68000 + 0x04)
-#define SUN6I_SPI0_TCR              (0x01C68000 + 0x08)
-#define SUN6I_SPI0_FIFO_STA         (0x01C68000 + 0x1C)
-#define SUN6I_SPI0_MBC              (0x01C68000 + 0x30)
-#define SUN6I_SPI0_MTC              (0x01C68000 + 0x34)
-#define SUN6I_SPI0_BCC              (0x01C68000 + 0x38)
-#define SUN6I_SPI0_TXD              (0x01C68000 + 0x200)
-#define SUN6I_SPI0_RXD              (0x01C68000 + 0x300)
+#define SUN6I_SPI0_CCTL             (0x05010000 + 0x24)
+#define SUN6I_SPI0_GCR              (0x05010000 + 0x04)
+#define SUN6I_SPI0_TCR              (0x05010000 + 0x08)
+#define SUN6I_SPI0_FIFO_STA         (0x05010000 + 0x1C)
+#define SUN6I_SPI0_MBC              (0x05010000 + 0x30)
+#define SUN6I_SPI0_MTC              (0x05010000 + 0x34)
+#define SUN6I_SPI0_BCC              (0x05010000 + 0x38)
+#define SUN6I_SPI0_TXD              (0x05010000 + 0x200)
+#define SUN6I_SPI0_RXD              (0x05010000 + 0x300)
 
 #define CCM_SPI0_CLK_DIV_BY_2       (0x1000)
 #define CCM_SPI0_CLK_DIV_BY_4       (0x1001)
@@ -144,21 +144,70 @@ static bool spi0_init(feldev_handle *dev)
 		gpio_set_cfgpin(dev, PC, 2, SUN50I_GPC_SPI0);
 		gpio_set_cfgpin(dev, PC, 3, SUN50I_GPC_SPI0);
 		break;
+	case 0x1817:
+		{
+			uint32_t spi0ctl[9] = { 0x77444444, 0x00007777, 0x00000000, 0x00000000,\
+						0x00000000, 0x00555555, 0x00000000, 0x00001054,\
+						0x00000000 };
+			uint32_t spi0pin_base = 0x0300b048;
+			int i = 0;
+			for(i = 0; i < 9; i ++)
+			{
+				writel(spi0ctl[i], spi0pin_base + 4*i);
+			}
+		}
+		break;
+	case 0x1821:
+		{
+			uint32_t spi0ctl[9] = { 0x47744474, 0x17777777, 0x00000001, 0x00000000,\
+						0x00018000, 0x55555555, 0x00000001, 0x00005140,\
+						0x00000000 };
+			uint32_t spi0pin_base = 0x0300b048;
+			int i = 0;
+			for(i = 0; i < 9; i ++)
+			{
+				writel(spi0ctl[i], spi0pin_base + 4*i);
+			}
+		}
+		break;
 	default: /* Unknown/Unsupported SoC */
 		return false;
 	}
 
-	reg_val = readl(CCM_AHB_GATING0);
-	reg_val |= CCM_AHB_GATE_SPI0;
-	writel(reg_val, CCM_AHB_GATING0);
-
-	/* 24MHz from OSC24M */
-	writel((1 << 31), CCM_SPI0_CLK);
-	/* divide by 4 */
-	writel(CCM_SPI0_CLK_DIV_BY_4, spi_is_sun6i(dev) ? SUN6I_SPI0_CCTL :
-							  SUN4I_SPI0_CCTL);
-
-	if (spi_is_sun6i(dev)) {
+	//printf("%s line %d.\n", __func__, __LINE__);
+	uint32_t ccmu_base = 0x03001000;
+	//uint32_t cpu_ccm = ccmu_base + 0x400;
+	//uint32_t ccmu_axi = ccmu_base + 0x500;
+	//uint32_t CCMU_PSI_AHB1_AHB2_CFG_REG = ccmu_base + 0x510;
+	//uint32_t CCMU_PLL_PERI0_CTRL_REG = ccmu_base + 0x20;
+	//uint32_t CCMU_AHB3_CFG_GREG = ccmu_base + 0x51c;
+	//uint32_t CCMU_APB1_CFG_GREG = ccmu_base + 0x520;
+	uint32_t ccmu_spi0_clk_reg = ccmu_base + 0x940;
+	uint32_t ccmu_spi0_gate_rst = ccmu_base + 0x96c;
+
+	writel(0x8100000b, ccmu_spi0_clk_reg);
+    	//writel(0x8000000b, ccmu_spi0_clk_reg);
+	//writel(0x8200000b, ccmu_spi0_clk_reg);
+	//writel(0x8300000b, ccmu_spi0_clk_reg);
+	//writel(0x8400000b, ccmu_spi0_clk_reg);
+	uint32_t rst_val = readl(ccmu_spi0_gate_rst);
+	rst_val &= ~(1 << 16);
+	writel(rst_val, ccmu_spi0_gate_rst);
+
+	rst_val = readl(ccmu_spi0_gate_rst);
+	rst_val |= (1 << 16);
+	writel(rst_val, ccmu_spi0_gate_rst);
+
+	rst_val = readl(ccmu_spi0_gate_rst);
+	rst_val |= (1 << 0);
+	writel(rst_val, ccmu_spi0_gate_rst);
+
+	//uint32_t clk_reg = readl(ccmu_spi0_clk_reg);
+	//rst_val = readl(ccmu_spi0_gate_rst);
+	//printf("clk_ret = 0x%08x.\n", clk_reg);
+	//printf("rst_val = 0x%08x.\n", rst_val);
+
+	if (0) {
 		/* Deassert SPI0 reset */
 		reg_val = readl(SUN6I_BUS_SOFT_RST_REG0);
 		reg_val |= SUN6I_SPI0_RST;
@@ -169,7 +218,70 @@ static bool spi0_init(feldev_handle *dev)
 		writel(reg_val, SUN6I_SPI0_GCR);
 		/* Wait for completion */
 		while (readl(SUN6I_SPI0_GCR) & (1 << 31)) {}
-	} else {
+	} 
+	else if((dev->soc_info->soc_id == 0x1821) || (dev->soc_info->soc_id == 0x1817))
+	{
+		uint32_t spi0_ctrl = 0x05010000;
+		uint32_t spi0_ctrl_gcr = spi0_ctrl + 0x4;
+		uint32_t spi0_ctrl_tcr = spi0_ctrl + 0x8;
+		uint32_t spi0_ctrl_clk = spi0_ctrl + 0x24;
+		uint32_t spi0_ctrl_clk_ = spi0_ctrl + 0x20;
+		uint32_t spi0_ctrl_fifo = spi0_ctrl + 0x18;
+
+		//soft reset.
+		uint32_t val = readl(spi0_ctrl_gcr);
+		val |= (1 << 31);
+		writel(val, spi0_ctrl_gcr);
+		
+		//enable the bus.
+		val = readl(spi0_ctrl_gcr);
+		val |= (1 << 0);
+		writel(val, spi0_ctrl_gcr);
+		
+		//transer control.
+		val = readl(spi0_ctrl_tcr);
+		val &= ~(0x3 << 4);
+		val |= 0 << 4;
+		writel(val, spi0_ctrl_tcr);
+
+		//set master.
+		val = readl(spi0_ctrl_gcr);
+		val |= (1 << 1);
+		writel(val, spi0_ctrl_gcr);
+		
+		//set clk ctl
+		writel(0x2, spi0_ctrl_clk);
+		writel(0x0, spi0_ctrl_clk_);
+
+		//transer control.
+		val = readl(spi0_ctrl_tcr);
+		val = (0x1 <<  6)|(0x1 <<  7)|(0x1 <<  2);
+		writel(val, spi0_ctrl_tcr);
+		
+		// ss level.
+		val = readl(spi0_ctrl_tcr);
+		val |= (0x1 << 7);
+		writel(val, spi0_ctrl_tcr);
+
+		//enable the tp.
+		val = readl(spi0_ctrl_gcr);
+		val |= (0x1 << 7);
+		writel(val, spi0_ctrl_gcr);
+
+		//transer control owner.
+		/*val = readl(spi0_ctrl_tcr);*/
+		/*val &= ~(0x1 << 6);*/
+		/*writel(val, spi0_ctrl_tcr);*/
+
+		//fifo reset.
+		val = readl(spi0_ctrl_fifo);
+		val |= (0x1 << 15)|(0x1 << 31);
+		val &= ~((0xFF << 0)|(0xFF << 16));
+		val |= (0x40<<16) | 0x01;
+		writel(val, spi0_ctrl_fifo);
+	}
+	else
+	{
 		reg_val = readl(SUN4I_SPI0_CTL);
 		reg_val |= SUN4I_CTL_MASTER;
 		reg_val |= SUN4I_CTL_ENABLE | SUN4I_CTL_TF_RST | SUN4I_CTL_RF_RST;
@@ -203,15 +315,16 @@ static void prepare_spi_batch_data_transfer(feldev_handle *dev, uint32_t buf)
 	if (spi_is_sun6i(dev)) {
 		aw_fel_remotefunc_prepare_spi_batch_data_transfer(dev,
 							    buf,
-							    SUN6I_SPI0_TCR,
-							    SUN6I_TCR_XCH,
-							    SUN6I_SPI0_FIFO_STA,
-							    SUN6I_SPI0_TXD,
-							    SUN6I_SPI0_RXD,
-							    SUN6I_SPI0_MBC,
-							    SUN6I_SPI0_MTC,
-							    SUN6I_SPI0_BCC);
+							    0x05010000,
+							    0,
+							    0,
+							    0,
+							    0,
+							    0,
+							    0,
+							    0);
 	} else {
+		while(1);
 		aw_fel_remotefunc_prepare_spi_batch_data_transfer(dev,
 							    buf,
 							    SUN4I_SPI0_CTL,
@@ -416,7 +529,6 @@ void aw_fel_spiflash_info(feldev_handle *dev)
 	aw_fel_read(dev, dev->soc_info->spl_addr, buf, sizeof(buf));
 
 	restore_sram(dev, backup);
-
 	/* Assume that the MISO pin is either pulled up or down */
 	if (buf[5] == 0x00 || buf[5] == 0xFF) {
 		printf("No SPI flash detected.\n");
@@ -427,6 +539,9 @@ void aw_fel_spiflash_info(feldev_handle *dev)
 	case 0xEF:
 		manufacturer = "Winbond";
 		break;
+	case 0xC2:
+		manufacturer = "Macronix";
+		break;
 	default:
 		manufacturer = "Unknown";
 		break;
diff --git a/fel_spi.c b/fel_spi.c
new file mode 100644
index 0000000..d2441c2
--- /dev/null
+++ b/fel_spi.c
@@ -0,0 +1,81 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "aw_spi.h"
+/*-----------------------------------------------------------------------*/
+void pinctrl_init(void)
+{
+    gpio_direction_output(wp_port, wp_pin, 1);
+    gpio_direction_output(hld_port, hld_pin, 1);
+    gpio_set_func(clk_port, clk_pin, ck_io_func);
+    gpio_set_func(mosi_port, mosi_pin, mosi_io_func);
+    gpio_set_func(miso_port, miso_pin, miso_io_func);
+    gpio_set_func(cs_port, cs_pin, cs_io_func);
+}
+
+void clock_init(void)
+{
+    uint32_t ccmu_base = 0x03001000;
+    //uint32_t cpu_ccm = ccmu_base + 0x400;                                                                                                                                                
+    //uint32_t ccmu_axi = ccmu_base + 0x500;
+    //uint32_t CCMU_PSI_AHB1_AHB2_CFG_REG = ccmu_base + 0x510;
+    //uint32_t CCMU_PLL_PERI0_CTRL_REG = ccmu_base + 0x20;
+    //uint32_t CCMU_AHB3_CFG_GREG = ccmu_base + 0x51c;
+    //uint32_t CCMU_APB1_CFG_GREG = ccmu_base + 0x520;
+    uint32_t ccmu_spi0_clk_reg = ccmu_base + 0x940;
+    uint32_t ccmu_spi0_gate_rst = ccmu_base + 0x96c;
+    
+    writel(0x8100000b, ccmu_spi0_clk_reg);
+    //writel(0x8000000b, ccmu_spi0_clk_reg);
+    //writel(0x8200000b, ccmu_spi0_clk_reg);
+    //writel(0x8300000b, ccmu_spi0_clk_reg);
+    //writel(0x8400000b, ccmu_spi0_clk_reg);
+    uint32_t rst_val = readl(ccmu_spi0_gate_rst);
+    rst_val &= ~(1 << 16);
+    writel(rst_val, ccmu_spi0_gate_rst);
+    
+    rst_val = readl(ccmu_spi0_gate_rst);
+    rst_val |= (1 << 16);
+    writel(rst_val, ccmu_spi0_gate_rst);
+    
+    rst_val = readl(ccmu_spi0_gate_rst);
+    rst_val |= (1 << 0); 
+    writel(rst_val, ccmu_spi0_gate_rst);
+    
+    uint32_t clk_reg = readl(ccmu_spi0_clk_reg);
+    rst_val = readl(ccmu_spi0_gate_rst);
+}
+
+void spi_hw_init(void)
+{
+    //uint32_t spi0_ctrl = 0x05010000;
+    //uint32_t spi0_ctrl_clk = spi0_ctrl + 0x24;
+    //int data_width = 8;
+
+    SPI_T *spi_instance = SPI_CTR_ADDRESS;
+
+    SPI_Disable(spi_instance);
+    SPI_Reset(spi_instance);
+    SPI_ResetRxFifo(spi_instance);
+    SPI_ResetTxFifo(spi_instance);
+
+    SPI_SetDuplex(spi_instance, SPI_TCTRL_DHB_FULL_DUPLEX);
+    SPI_SetMode(spi_instance, SPI_CTRL_MODE_MASTER);
+
+    SPI_SetFirstTransmitBit(spi_instance, SPI_TCTRL_FBS_MSB);
+    SPI_SetSclkMode(spi_instance, SPI_SCLK_Mode0);
+
+    //TODO: set clk div.
+    //writel(0x0002, spi0_ctrl_clk);
+    spi_instance->CCR = 0x02; 
+    SPI_ManualChipSelect(spi_instance, cs_sel);
+    SPI_SetDataSize(spi_instance, 0, 0); 
+    SPI_Enable(spi_instance); 
+}
+
+void spi_configure(void)
+{
+    pinctrl_init();
+    clock_init();
+    spi_hw_init();
+}
diff --git a/soc_info.c b/soc_info.c
index 7728422..dd2493e 100644
--- a/soc_info.c
+++ b/soc_info.c
@@ -34,6 +34,7 @@
  * important too (overwriting them kills FEL). On A10/A13/A20 we can use
  * the SRAM sections A3/A4 (0x8000-0xBFFF) for this purpose.
  */
+ 
 sram_swap_buffers a10_a13_a20_sram_swap_buffers[] = {
 	/* 0x1C00-0x1FFF (IRQ stack) */
 	{ .buf1 = 0x1C00, .buf2 = 0xA400, .size = 0x0400 },
@@ -44,6 +45,16 @@ sram_swap_buffers a10_a13_a20_sram_swap_buffers[] = {
 	{ .size = 0 }  /* End of the table */
 };
 
+sram_swap_buffers v459_r328_sram_swap_buffers[] = {
+	/* 0x1C00-0x1FFF (IRQ stack) */
+	{ .buf1 = 0x32C00, .buf2 = 0x3A400, .size = 0x0400 },
+	/* 0x5C00-0x6FFF (Stack) */
+	{ .buf1 = 0x35C00, .buf2 = 0x3A800, .size = 0x1400 },
+	/* 0x7C00-0x7FFF (Something important) */
+	{ .buf1 = 0x37C00, .buf2 = 0x3BC00, .size = 0x0400 },
+	{ .size = 0 }  /* End of the table */
+};
+
 /*
  * A31 is very similar to A10/A13/A20, except that it has no SRAM at 0x8000.
  * So we use the SRAM section B at 0x20000-0x2FFFF instead. In the FEL mode,
@@ -94,6 +105,7 @@ sram_swap_buffers a80_sram_swap_buffers[] = {
 	{ .size = 0 }  /* End of the table */
 };
 
+extern sram_swap_buffers generic_sram_swap_buffers[]; 
 soc_info_t soc_info_table[] = {
 	{
 		.soc_id       = 0x1623, /* Allwinner A10 */
@@ -207,6 +219,20 @@ soc_info_t soc_info_table[] = {
 		.swap_buffers = a10_a13_a20_sram_swap_buffers,
 		.sid_base     = 0x01C1B000,
 		.sid_offset   = 0x200,
+	},{
+		.soc_id       = 0x1821, /* Allwinner R328 */
+		.name         = "R328",
+		.spl_addr     = 0x20000,
+		.scratch_addr = 0x21000,
+		.thunk_addr   = 0x2a200, .thunk_size = 0x200,
+		.swap_buffers = v459_r328_sram_swap_buffers,
+	},{
+		.soc_id       = 0x1817, /* Allwinner V459 */
+		.name         = "V459",
+		.spl_addr     = 0x20000,
+		.scratch_addr = 0x21000,
+		.thunk_addr   = 0x2a200, .thunk_size = 0x200,
+		.swap_buffers = v459_r328_sram_swap_buffers,
 	},{
 		.swap_buffers = NULL /* End of the table */
 	}
diff --git a/xfer.c b/xfer.c
new file mode 100644
index 0000000..cce8fbe
--- /dev/null
+++ b/xfer.c
@@ -0,0 +1,139 @@
+/*
+ * ===========================================================================================
+ *
+ *       Filename:  xfer.c
+ *
+ *    Description:  mini driver for nor flash on R328.
+ *
+ *        Version:  Melis3.0 
+ *         Create:  2019-11-08 14:00:23
+ *       Revision:  none
+ *       Compiler:  GCC:version 7.2.1 20170904 (release),ARM/embedded-7-branch revision 255204
+ *
+ *         Author:  caozilong@allwinnertech.com
+ *   Organization:  BU1-PSW
+ *  Last Modified:  2019-11-08 14:07:53
+ *
+ * ===========================================================================================
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "aw_spi.h"
+
+static void inline __attribute((always_inline)) xfer(void *buf, uint32_t bufsize, uint32_t spi_reg_base,
+		uint32_t __unused1,
+		uint32_t __unused2,
+		uint32_t __unused3,
+		uint32_t __unused4,
+		uint32_t __unused5,
+		uint32_t __unused6,
+		uint32_t __unused7)
+{
+    const uint8_t *send_ptr = buf;
+    uint8_t *recv_ptr = buf;
+    uint32_t tx_size = bufsize;
+    uint32_t rx_size = bufsize;
+    uint32_t cpsr;
+
+    asm volatile("mrs %0, cpsr" : "=r" (cpsr));
+    asm volatile("msr cpsr_c, %0" :: "r" (cpsr | 0xC0));
+
+    SPI_T *spi_instance = (SPI_T*)spi_reg_base;
+
+    SPI_ManualChipSelect(spi_instance, cs_sel);
+    SPI_SetCsLevel(spi_instance, 0);
+
+    SPI_ResetTxFifo(spi_instance);
+    SPI_ResetRxFifo(spi_instance);
+    SPI_SetDataSize(spi_instance, tx_size, 0); 
+
+    SPI_StartTransmit(spi_instance);
+   
+    while (tx_size > 0 || rx_size > 0)
+    {
+        uint8_t tx_data = 0xFF;
+        uint8_t rx_data = 0xFF;
+    
+        while ((SPI_GetTxFifoCounter(spi_instance) < SPI_FIFO_SIZE) && (tx_size > 0))
+        {
+            if (send_ptr != NULL)
+            {
+                tx_data = *send_ptr++;
+            }
+            SPI_Write(spi_instance, &tx_data);
+            tx_size--;
+        }
+
+        while (SPI_GetRxFifoCounter(spi_instance) > 0)
+        {
+            rx_size--;
+            SPI_Read(spi_instance, &rx_data);
+    
+            if (recv_ptr != NULL)
+            {
+                *recv_ptr++ = rx_data;
+            }
+        }
+    }
+ 
+    if ((tx_size != 0) || (rx_size != 0)) while(1);
+
+    while (SPI_IntState(spi_instance, SPI_INT_TRANSFER_COMPLETE) == 0);
+    SPI_ClearInt(spi_instance, SPI_INT_TRANSFER_COMPLETE);
+    SPI_SetCsLevel(spi_instance, 1);
+    /* Restore CPSR */
+    asm volatile("msr cpsr_c, %0" :: "r" (cpsr));
+}
+
+void spi_batch_data_transfer(uint8_t *buf,uint32_t spi_ctl_reg, uint32_t unused1,
+	uint32_t unused2,
+	uint32_t unused3,
+	uint32_t unused4,
+	uint32_t unused5,
+	uint32_t unused6, 
+	uint32_t unused7)
+{
+    uint8_t wait_for_completion_cmd[2] = {0};
+    uint8_t *backup_buf;
+    uint32_t bufsize;
+
+    while (1) {                                                                                                                                 
+        uint32_t code = (buf[0] << 8) | buf[1];                                                                                                  
+
+        /* End of data */                                                                                                                   
+        if (code == 0)                                                                                                                      
+            return;                                                                                                                     
+
+        if (code == 0xFFFF) {                                                                                                               
+            /* Wait for completion, part 1 */                                                                                           
+            backup_buf = buf;                                                                                                           
+            buf = wait_for_completion_cmd;                                                                                              
+            wait_for_completion_cmd[0] = 0x05;                                                                                          
+            bufsize = 2;                                                                                                                
+        } else {                                                                                                                            
+            /* Normal buffer */                                                                                                         
+            buf += 2;                                                                                                                   
+            bufsize = code;                                                                                                             
+        }                                                                                                                                   
+                                                                                                                                            
+        xfer(buf, bufsize, spi_ctl_reg, unused1,                                                                   
+                                        unused2, unused3, unused4,                                                               
+                                        unused5, unused6, unused7);                                                               
+        if (code == 0xFFFF) {                                                                                                               
+            /* Wait for completion, part 2 */                                                                                           
+            if (wait_for_completion_cmd[1] & 1) {                                                                                       
+                buf = backup_buf;                                                                                                           
+                /* Still busy */                                                                                                    
+                continue;                                                                                                           
+            }                                                                                                                           
+            else {
+                /* Advance to the next code */                                                                                              
+                buf = backup_buf + 2;                                                                                                       
+            }
+        }                                                                                                                                   
+        else {
+            buf += bufsize;                                                                                                                     
+        }
+    }  
+}

结束

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐