ext qmsi: Update to QMSI 1.1-Beta
QMSI 1.1 Beta is available on Github:
https://github.com/01org/qmsi/releases/tag/v1.1.0-beta
Update the QMSI drop we maintain in Zephyr and
keep the modification to qm_soc_regs.h introduced on commit
6b88a6b945
"ext qmsi: Add USB base and interrupt defines" since
that patch hasn't made into the QMSI 1.1-Beta release in time.
Also, fix the build where needed:
- add hard dependency from qm_i2c to qm_dma
- fix spi_qmsi_ss.c due to new parameter naming
- fix adc_qmsi.c and adc_qmsi_ss.c due to a new parameter
Change-Id: I01388c787f5ee6ee97fece2e42b24a717522207f
Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
Signed-off-by: Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
This commit is contained in:
parent
19fa82ab91
commit
abd7496225
54 changed files with 2647 additions and 1180 deletions
|
@ -110,6 +110,7 @@ static int adc_qmsi_read(struct device *dev, struct adc_seq_table *seq_tbl)
|
||||||
{
|
{
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
qm_adc_xfer_t xfer;
|
qm_adc_xfer_t xfer;
|
||||||
|
qm_adc_status_t status;
|
||||||
|
|
||||||
struct adc_info *info = dev->driver_data;
|
struct adc_info *info = dev->driver_data;
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ static int adc_qmsi_read(struct device *dev, struct adc_seq_table *seq_tbl)
|
||||||
* register to check if the number of samples required has been
|
* register to check if the number of samples required has been
|
||||||
* captured
|
* captured
|
||||||
*/
|
*/
|
||||||
if (qm_adc_convert(QM_ADC_0, &xfer) != 0) {
|
if (qm_adc_convert(QM_ADC_0, &xfer, &status) != 0) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
adc_unlock(info);
|
adc_unlock(info);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -116,6 +116,7 @@ static int adc_qmsi_ss_read(struct device *dev, struct adc_seq_table *seq_tbl)
|
||||||
{
|
{
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
qm_ss_adc_xfer_t xfer;
|
qm_ss_adc_xfer_t xfer;
|
||||||
|
qm_ss_adc_status_t status;
|
||||||
|
|
||||||
struct adc_info *info = dev->driver_data;
|
struct adc_info *info = dev->driver_data;
|
||||||
|
|
||||||
|
@ -154,7 +155,7 @@ static int adc_qmsi_ss_read(struct device *dev, struct adc_seq_table *seq_tbl)
|
||||||
* register to check if the number of samples required has been
|
* register to check if the number of samples required has been
|
||||||
* captured
|
* captured
|
||||||
*/
|
*/
|
||||||
if (qm_ss_adc_convert(QM_SS_ADC_0, &xfer) != 0) {
|
if (qm_ss_adc_convert(QM_SS_ADC_0, &xfer, &status) != 0) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
adc_unlock(info);
|
adc_unlock(info);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -56,6 +56,7 @@ config I2C_QMSI_SS
|
||||||
config I2C_QMSI
|
config I2C_QMSI
|
||||||
bool "QMSI I2C driver"
|
bool "QMSI I2C driver"
|
||||||
depends on I2C && QMSI
|
depends on I2C && QMSI
|
||||||
|
select DMA_QMSI
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
This option enable the QMSI I2C driver.
|
This option enable the QMSI I2C driver.
|
||||||
|
|
|
@ -169,7 +169,7 @@ static int ss_spi_qmsi_transceive(struct device *dev,
|
||||||
xfer->rx_len = rx_buf_len / dfs;
|
xfer->rx_len = rx_buf_len / dfs;
|
||||||
xfer->tx = (uint8_t *)tx_buf;
|
xfer->tx = (uint8_t *)tx_buf;
|
||||||
xfer->tx_len = tx_buf_len / dfs;
|
xfer->tx_len = tx_buf_len / dfs;
|
||||||
xfer->data = dev;
|
xfer->callback_data = dev;
|
||||||
xfer->callback = spi_qmsi_callback;
|
xfer->callback = spi_qmsi_callback;
|
||||||
|
|
||||||
if (tx_buf_len == 0) {
|
if (tx_buf_len == 0) {
|
||||||
|
|
|
@ -8,8 +8,8 @@ Microcontroller products. It currently support the following SoCs:
|
||||||
- Intel® Quark™ D2000 Microcontroller
|
- Intel® Quark™ D2000 Microcontroller
|
||||||
- Intel® Quark™ SE Microcontroller
|
- Intel® Quark™ SE Microcontroller
|
||||||
|
|
||||||
The current version supported in Zephyr is QMSI 1.1.0 See
|
The current version supported in Zephyr is QMSI 1.1.0-Beta. See:
|
||||||
|
|
||||||
https://github.com/01org/qmsi/releases/tag/v1.1.0
|
https://github.com/01org/qmsi/releases/tag/v1.1.0-beta
|
||||||
|
|
||||||
for more details.
|
for more details.
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
#include <x86intrin.h>
|
#include <x86intrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "soc_watch.h"
|
||||||
|
|
||||||
#if (QM_SENSOR) && (!UNIT_TEST)
|
#if (QM_SENSOR) && (!UNIT_TEST)
|
||||||
/* Timestamp counter for Sensor Subsystem is 32bit. */
|
/* Timestamp counter for Sensor Subsystem is 32bit. */
|
||||||
#define get_ticks() __builtin_arc_lr(QM_SS_TSC_BASE + QM_SS_TIMER_COUNT)
|
#define get_ticks() __builtin_arc_lr(QM_SS_TSC_BASE + QM_SS_TIMER_COUNT)
|
||||||
|
@ -51,7 +53,7 @@ static uint32_t ticks_per_us = SYS_TICKS_PER_US_32MHZ;
|
||||||
|
|
||||||
int clk_sys_set_mode(const clk_sys_mode_t mode, const clk_sys_div_t div)
|
int clk_sys_set_mode(const clk_sys_mode_t mode, const clk_sys_div_t div)
|
||||||
{
|
{
|
||||||
QM_CHECK(div <= CLK_SYS_DIV_NUM, -EINVAL);
|
QM_CHECK(div < CLK_SYS_DIV_NUM, -EINVAL);
|
||||||
QM_CHECK(mode <= CLK_SYS_CRYSTAL_OSC, -EINVAL);
|
QM_CHECK(mode <= CLK_SYS_CRYSTAL_OSC, -EINVAL);
|
||||||
uint16_t trim = 0;
|
uint16_t trim = 0;
|
||||||
|
|
||||||
|
@ -158,6 +160,9 @@ int clk_sys_set_mode(const clk_sys_mode_t mode, const clk_sys_div_t div)
|
||||||
QM_SCSS_CCU->ccu_sys_clk_ctl |= QM_CCU_SYS_CLK_DIV_EN;
|
QM_SCSS_CCU->ccu_sys_clk_ctl |= QM_CCU_SYS_CLK_DIV_EN;
|
||||||
ticks_per_us = (sys_ticks_per_us > 0 ? sys_ticks_per_us : 1);
|
ticks_per_us = (sys_ticks_per_us > 0 ? sys_ticks_per_us : 1);
|
||||||
|
|
||||||
|
/* Log any clock changes. */
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_OSC0_CFG1);
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_SYS_CLK_CTL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,11 +178,26 @@ int clk_trim_read(uint32_t *const value)
|
||||||
|
|
||||||
int clk_trim_apply(const uint32_t value)
|
int clk_trim_apply(const uint32_t value)
|
||||||
{
|
{
|
||||||
|
/* Enable trim mode */
|
||||||
|
QM_SCSS_CCU->osc0_cfg0 |= BIT(1);
|
||||||
|
|
||||||
/* Apply trim code */
|
/* Apply trim code */
|
||||||
QM_SCSS_CCU->osc0_cfg1 &= ~OSC0_CFG1_FTRIMOTP_MASK;
|
QM_SCSS_CCU->osc0_cfg1 &= ~OSC0_CFG1_FTRIMOTP_MASK;
|
||||||
QM_SCSS_CCU->osc0_cfg1 |=
|
QM_SCSS_CCU->osc0_cfg1 |=
|
||||||
(value << OSC0_CFG1_FTRIMOTP_OFFS) & OSC0_CFG1_FTRIMOTP_MASK;
|
(value << OSC0_CFG1_FTRIMOTP_OFFS) & OSC0_CFG1_FTRIMOTP_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recommended wait time after setting up the trim code
|
||||||
|
* is 200us. Minimum wait time is 100us.
|
||||||
|
* The delay is running from of the silicon oscillator
|
||||||
|
* which is been trimmed. This induces a lack of precision
|
||||||
|
* in the delay.
|
||||||
|
*/
|
||||||
|
clk_sys_udelay(200);
|
||||||
|
|
||||||
|
/* Disable trim mode */
|
||||||
|
QM_SCSS_CCU->osc0_cfg0 &= ~BIT(1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,6 +290,9 @@ int clk_periph_enable(const clk_periph_t clocks)
|
||||||
|
|
||||||
QM_SCSS_CCU->ccu_periph_clk_gate_ctl |= clocks;
|
QM_SCSS_CCU->ccu_periph_clk_gate_ctl |= clocks;
|
||||||
|
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||||
|
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +302,9 @@ int clk_periph_disable(const clk_periph_t clocks)
|
||||||
|
|
||||||
QM_SCSS_CCU->ccu_periph_clk_gate_ctl &= ~clocks;
|
QM_SCSS_CCU->ccu_periph_clk_gate_ctl &= ~clocks;
|
||||||
|
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||||
|
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,10 +159,6 @@ static int dma_channel_disable(const qm_dma_t dma,
|
||||||
timeout_us--;
|
timeout_us--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(chan_reg->cfg_low & QM_DMA_CFG_L_FIFO_EMPTY_MASK)) {
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable the channel and wait to confirm that it has been disabled. */
|
/* Disable the channel and wait to confirm that it has been disabled. */
|
||||||
misc_reg->chan_en_low = (channel_mask << QM_DMA_MISC_CHAN_EN_WE_OFFSET);
|
misc_reg->chan_en_low = (channel_mask << QM_DMA_MISC_CHAN_EN_WE_OFFSET);
|
||||||
|
|
||||||
|
|
|
@ -267,12 +267,14 @@ int qm_adc_set_config(const qm_adc_t adc, const qm_adc_config_t *const cfg);
|
||||||
*
|
*
|
||||||
* @param[in] adc Which ADC to read.
|
* @param[in] adc Which ADC to read.
|
||||||
* @param[in,out] xfer Channel and sample info. This must not be NULL.
|
* @param[in,out] xfer Channel and sample info. This must not be NULL.
|
||||||
|
* @param[out] status Get status of the ADC device.
|
||||||
*
|
*
|
||||||
* @return Standard errno return type for QMSI.
|
* @return Standard errno return type for QMSI.
|
||||||
* @retval 0 on success.
|
* @retval 0 on success.
|
||||||
* @retval Negative @ref errno for possible error codes.
|
* @retval Negative @ref errno for possible error codes.
|
||||||
*/
|
*/
|
||||||
int qm_adc_convert(const qm_adc_t adc, qm_adc_xfer_t *const xfer);
|
int qm_adc_convert(const qm_adc_t adc, qm_adc_xfer_t *const xfer,
|
||||||
|
qm_adc_status_t *const status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously read values from the ADC.
|
* Asynchronously read values from the ADC.
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
#include "qm_common.h"
|
#include "qm_common.h"
|
||||||
#include "qm_soc_regs.h"
|
#include "qm_soc_regs.h"
|
||||||
|
#include "qm_interrupt.h"
|
||||||
/**
|
/**
|
||||||
* Flash controller.
|
* Flash controller.
|
||||||
*
|
*
|
||||||
|
|
|
@ -58,9 +58,9 @@
|
||||||
/**
|
/**
|
||||||
* QM I2C addressing type.
|
* QM I2C addressing type.
|
||||||
*/
|
*/
|
||||||
typedef enum{
|
typedef enum {
|
||||||
QM_I2C_7_BIT = 0, /**< 7-bit mode. */
|
QM_I2C_7_BIT = 0, /**< 7-bit mode. */
|
||||||
QM_I2C_10_BIT /**< 10-bit mode. */
|
QM_I2C_10_BIT /**< 10-bit mode. */
|
||||||
} qm_i2c_addr_t;
|
} qm_i2c_addr_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,7 +68,7 @@ typedef enum{
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_I2C_MASTER, /**< Master mode. */
|
QM_I2C_MASTER, /**< Master mode. */
|
||||||
QM_I2C_SLAVE /**< Slave mode. */
|
QM_I2C_SLAVE /**< Slave mode. */
|
||||||
} qm_i2c_mode_t;
|
} qm_i2c_mode_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -84,27 +84,27 @@ typedef enum {
|
||||||
* I2C status type.
|
* I2C status type.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_I2C_IDLE = 0, /**< Controller idle. */
|
QM_I2C_IDLE = 0, /**< Controller idle. */
|
||||||
QM_I2C_TX_ABRT_7B_ADDR_NOACK = BIT(0), /**< 7-bit address noack. */
|
QM_I2C_TX_ABRT_7B_ADDR_NOACK = BIT(0), /**< 7-bit address noack. */
|
||||||
QM_I2C_TX_ABRT_10ADDR1_NOACK = BIT(1), /**< 10-bit address noack. */
|
QM_I2C_TX_ABRT_10ADDR1_NOACK = BIT(1), /**< 10-bit address noack. */
|
||||||
QM_I2C_TX_ABRT_10ADDR2_NOACK = BIT(2), /**< 10-bit second address
|
QM_I2C_TX_ABRT_10ADDR2_NOACK = BIT(2), /**< 10-bit second address
|
||||||
byte address noack. */
|
byte address noack. */
|
||||||
QM_I2C_TX_ABRT_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
QM_I2C_TX_ABRT_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
||||||
QM_I2C_TX_ABRT_GCALL_NOACK = BIT(4), /**< General call noack. */
|
QM_I2C_TX_ABRT_GCALL_NOACK = BIT(4), /**< General call noack. */
|
||||||
QM_I2C_TX_ABRT_GCALL_READ = BIT(5), /**< Read after general call. */
|
QM_I2C_TX_ABRT_GCALL_READ = BIT(5), /**< Read after general call. */
|
||||||
QM_I2C_TX_ABRT_HS_ACKDET = BIT(6), /**< High Speed master ID ACK. */
|
QM_I2C_TX_ABRT_HS_ACKDET = BIT(6), /**< High Speed master ID ACK. */
|
||||||
QM_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
QM_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
||||||
QM_I2C_TX_ABRT_HS_NORSTRT = BIT(8), /**< High Speed with restart
|
QM_I2C_TX_ABRT_HS_NORSTRT = BIT(8), /**< High Speed with restart
|
||||||
disabled. */
|
disabled. */
|
||||||
QM_I2C_TX_ABRT_10B_RD_NORSTRT = BIT(10), /**< 10-bit address read and
|
QM_I2C_TX_ABRT_10B_RD_NORSTRT = BIT(10), /**< 10-bit address read and
|
||||||
restart disabled. */
|
restart disabled. */
|
||||||
QM_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
QM_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
||||||
QM_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
QM_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
||||||
QM_I2C_TX_ABRT_SLVFLUSH_TXFIFO = BIT(13), /**< Slave flush tx FIFO. */
|
QM_I2C_TX_ABRT_SLVFLUSH_TXFIFO = BIT(13), /**< Slave flush tx FIFO. */
|
||||||
QM_I2C_TX_ABRT_SLV_ARBLOST = BIT(14), /**< Slave lost bus. */
|
QM_I2C_TX_ABRT_SLV_ARBLOST = BIT(14), /**< Slave lost bus. */
|
||||||
QM_I2C_TX_ABRT_SLVRD_INTX = BIT(15), /**< Slave read completion. */
|
QM_I2C_TX_ABRT_SLVRD_INTX = BIT(15), /**< Slave read completion. */
|
||||||
QM_I2C_TX_ABRT_USER_ABRT = BIT(16), /**< User abort. */
|
QM_I2C_TX_ABRT_USER_ABRT = BIT(16), /**< User abort. */
|
||||||
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
||||||
} qm_i2c_status_t;
|
} qm_i2c_status_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -135,7 +135,7 @@ typedef struct {
|
||||||
bool stop; /**< Generate master STOP. */
|
bool stop; /**< Generate master STOP. */
|
||||||
void (*callback)(void *data, int rc, qm_i2c_status_t status,
|
void (*callback)(void *data, int rc, qm_i2c_status_t status,
|
||||||
uint32_t len); /**< Callback. */
|
uint32_t len); /**< Callback. */
|
||||||
void *callback_data; /**< Callback identifier. */
|
void *callback_data; /**< Callback identifier. */
|
||||||
} qm_i2c_transfer_t;
|
} qm_i2c_transfer_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -217,8 +217,8 @@ int qm_i2c_master_write(const qm_i2c_t i2c, const uint16_t slave_addr,
|
||||||
* @retval Negative @ref errno for possible error codes.
|
* @retval Negative @ref errno for possible error codes.
|
||||||
*/
|
*/
|
||||||
int qm_i2c_master_read(const qm_i2c_t i2c, const uint16_t slave_addr,
|
int qm_i2c_master_read(const qm_i2c_t i2c, const uint16_t slave_addr,
|
||||||
uint8_t *const data, uint32_t len,
|
uint8_t *const data, uint32_t len, const bool stop,
|
||||||
const bool stop, qm_i2c_status_t *const status);
|
qm_i2c_status_t *const status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interrupt based master transfer on I2C.
|
* Interrupt based master transfer on I2C.
|
||||||
|
@ -228,8 +228,9 @@ int qm_i2c_master_read(const qm_i2c_t i2c, const uint16_t slave_addr,
|
||||||
*
|
*
|
||||||
* @param[in] i2c Which I2C to transfer from.
|
* @param[in] i2c Which I2C to transfer from.
|
||||||
* @param[in] xfer Transfer structure includes write / read buffers, length,
|
* @param[in] xfer Transfer structure includes write / read buffers, length,
|
||||||
* user callback function and the callback context. This must
|
* user callback function and the callback context.
|
||||||
* not be NULL.
|
* The structure must not be NULL and must be kept valid until
|
||||||
|
* the transfer is complete.
|
||||||
* @param[in] slave_addr Address of slave to transfer data with.
|
* @param[in] slave_addr Address of slave to transfer data with.
|
||||||
*
|
*
|
||||||
* @return Standard errno return type for QMSI.
|
* @return Standard errno return type for QMSI.
|
||||||
|
|
|
@ -115,7 +115,7 @@ void _qm_irq_setup(uint32_t irq, uint16_t register_offset);
|
||||||
* @param[in] isr ISR to register to given IRQ.
|
* @param[in] isr ISR to register to given IRQ.
|
||||||
*/
|
*/
|
||||||
#if (UNIT_TEST)
|
#if (UNIT_TEST)
|
||||||
#define qm_int_vector_request(vector, isr)
|
void qm_int_vector_request(uint32_t vector, qm_isr_t isr);
|
||||||
#else
|
#else
|
||||||
#if (__iamcu__)
|
#if (__iamcu__)
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -69,6 +69,7 @@ QM_ISR_DECLARE(qm_adc_pwr_0_isr);
|
||||||
* @endcode if IRQ based calibration is used.
|
* @endcode if IRQ based calibration is used.
|
||||||
*/
|
*/
|
||||||
QM_ISR_DECLARE(qm_ss_adc_0_cal_isr);
|
QM_ISR_DECLARE(qm_ss_adc_0_cal_isr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ISR for SS ADC 0 mode change interrupt.
|
* ISR for SS ADC 0 mode change interrupt.
|
||||||
*
|
*
|
||||||
|
@ -79,6 +80,7 @@ QM_ISR_DECLARE(qm_ss_adc_0_cal_isr);
|
||||||
QM_ISR_DECLARE(qm_ss_adc_0_pwr_isr);
|
QM_ISR_DECLARE(qm_ss_adc_0_pwr_isr);
|
||||||
|
|
||||||
#endif /* QUARK_SE */
|
#endif /* QUARK_SE */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ISR for Always-on Periodic Timer 0 interrupt.
|
* ISR for Always-on Periodic Timer 0 interrupt.
|
||||||
*
|
*
|
||||||
|
|
|
@ -111,7 +111,7 @@ typedef void (*qm_mbox_callback_t)(void *data);
|
||||||
* @retval Negative @ref errno for possible error codes.
|
* @retval Negative @ref errno for possible error codes.
|
||||||
*/
|
*/
|
||||||
int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch, qm_mbox_callback_t mpr_cb,
|
int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch, qm_mbox_callback_t mpr_cb,
|
||||||
void *cb_data, const bool irq_en);
|
void *cb_data, const bool irq_en);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write to a specified mailbox channel.
|
* Write to a specified mailbox channel.
|
||||||
|
@ -125,7 +125,7 @@ int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch, qm_mbox_callback_t mpr_cb,
|
||||||
* @retval Negative @ref errno for possible error codes.
|
* @retval Negative @ref errno for possible error codes.
|
||||||
*/
|
*/
|
||||||
int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch,
|
int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch,
|
||||||
const qm_mbox_msg_t *const msg);
|
const qm_mbox_msg_t *const msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read specified mailbox channel.
|
* Read specified mailbox channel.
|
||||||
|
@ -151,7 +151,7 @@ int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const msg);
|
||||||
* @retval Negative @ref errno for possible error codes.
|
* @retval Negative @ref errno for possible error codes.
|
||||||
*/
|
*/
|
||||||
int qm_mbox_ch_get_status(const qm_mbox_ch_t mbox_ch,
|
int qm_mbox_ch_get_status(const qm_mbox_ch_t mbox_ch,
|
||||||
qm_mbox_ch_status_t *const status);
|
qm_mbox_ch_status_t *const status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acknowledge the data arrival.
|
* Acknowledge the data arrival.
|
||||||
|
|
|
@ -54,6 +54,7 @@ typedef enum {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
qm_pic_timer_mode_t mode; /**< Operation mode. */
|
qm_pic_timer_mode_t mode; /**< Operation mode. */
|
||||||
bool int_en; /**< Interrupt enable. */
|
bool int_en; /**< Interrupt enable. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User callback.
|
* User callback.
|
||||||
*
|
*
|
||||||
|
|
|
@ -59,6 +59,7 @@ typedef struct {
|
||||||
uint32_t init_val; /**< Initial value in RTC clocks. */
|
uint32_t init_val; /**< Initial value in RTC clocks. */
|
||||||
bool alarm_en; /**< Alarm enable. */
|
bool alarm_en; /**< Alarm enable. */
|
||||||
uint32_t alarm_val; /**< Alarm value in RTC clocks. */
|
uint32_t alarm_val; /**< Alarm value in RTC clocks. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User callback.
|
* User callback.
|
||||||
*
|
*
|
||||||
|
@ -75,6 +76,13 @@ typedef struct {
|
||||||
* an alarm is required. If the alarm is enabled, register an ISR with the user
|
* an alarm is required. If the alarm is enabled, register an ISR with the user
|
||||||
* defined callback function.
|
* defined callback function.
|
||||||
*
|
*
|
||||||
|
* The RTC clock resides in a different clock domain
|
||||||
|
* to the system clock.
|
||||||
|
* It takes 3-4 RTC ticks for a system clock write to propagate
|
||||||
|
* to the RTC domain.
|
||||||
|
* If an entry to sleep is initiated without waiting for the
|
||||||
|
* transaction to complete the SOC will not wake from sleep.
|
||||||
|
*
|
||||||
* @param[in] rtc RTC index.
|
* @param[in] rtc RTC index.
|
||||||
* @param[in] cfg New RTC configuration. This must not be NULL.
|
* @param[in] cfg New RTC configuration. This must not be NULL.
|
||||||
*
|
*
|
||||||
|
@ -90,6 +98,13 @@ int qm_rtc_set_config(const qm_rtc_t rtc, const qm_rtc_config_t *const cfg);
|
||||||
* Set a new RTC alarm value after an alarm, that has been set using the
|
* Set a new RTC alarm value after an alarm, that has been set using the
|
||||||
* qm_rtc_set_config function, has expired and a new alarm value is required.
|
* qm_rtc_set_config function, has expired and a new alarm value is required.
|
||||||
*
|
*
|
||||||
|
* The RTC clock resides in a different clock domain
|
||||||
|
* to the system clock.
|
||||||
|
* It takes 3-4 RTC ticks for a system clock write to propagate
|
||||||
|
* to the RTC domain.
|
||||||
|
* If an entry to sleep is initiated without waiting for the
|
||||||
|
* transaction to complete the SOC will not wake from sleep.
|
||||||
|
*
|
||||||
* @param[in] rtc RTC index.
|
* @param[in] rtc RTC index.
|
||||||
* @param[in] alarm_val Value to set alarm to.
|
* @param[in] alarm_val Value to set alarm to.
|
||||||
*
|
*
|
||||||
|
|
|
@ -99,7 +99,9 @@ typedef enum {
|
||||||
/**
|
/**
|
||||||
* SPI slave select type.
|
* SPI slave select type.
|
||||||
*
|
*
|
||||||
* QM_SPI_SS_DISABLED prevents the controller from starting a transfer.
|
* Slave selects can combined by logical OR if multiple slaves are selected
|
||||||
|
* during one transfer. Setting only QM_SPI_SS_DISABLED prevents the controller
|
||||||
|
* from starting the transfer.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_SPI_SS_DISABLED = 0, /**< Slave select disable. */
|
QM_SPI_SS_DISABLED = 0, /**< Slave select disable. */
|
||||||
|
@ -139,8 +141,8 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *tx; /**< Write data. */
|
uint8_t *tx; /**< Write data. */
|
||||||
uint16_t tx_len; /**< Write data Length. */
|
|
||||||
uint8_t *rx; /**< Read data. */
|
uint8_t *rx; /**< Read data. */
|
||||||
|
uint16_t tx_len; /**< Write data Length. */
|
||||||
uint16_t rx_len; /**< Read buffer length. */
|
uint16_t rx_len; /**< Read buffer length. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -152,8 +154,8 @@ typedef struct {
|
||||||
* @param[in] data The callback user data.
|
* @param[in] data The callback user data.
|
||||||
* @param[in] error 0 on success.
|
* @param[in] error 0 on success.
|
||||||
* Negative @ref errno for possible error codes.
|
* Negative @ref errno for possible error codes.
|
||||||
* @param[in] status SPI driver status.
|
* @param[in] status SPI driver status.
|
||||||
* @param[in] len Length of the SPI transfer if successful, 0
|
* @param[in] len Length of the SPI transfer if successful, 0
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
void (*callback)(void *data, int error, qm_spi_status_t status,
|
void (*callback)(void *data, int error, qm_spi_status_t status,
|
||||||
|
@ -166,8 +168,8 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t *tx; /**< Write Data. */
|
uint8_t *tx; /**< Write Data. */
|
||||||
uint16_t tx_len; /**< Write Data Length. */
|
|
||||||
uint8_t *rx; /**< Read Data. */
|
uint8_t *rx; /**< Read Data. */
|
||||||
|
uint16_t tx_len; /**< Write Data Length. */
|
||||||
uint16_t rx_len; /**< Receive Data Length. */
|
uint16_t rx_len; /**< Receive Data Length. */
|
||||||
} qm_spi_transfer_t;
|
} qm_spi_transfer_t;
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,8 @@ int qm_uart_write_buffer(const qm_uart_t uart, const uint8_t *const data,
|
||||||
* @param[in] uart UART index.
|
* @param[in] uart UART index.
|
||||||
* @param[in] xfer Structure containing pre-allocated
|
* @param[in] xfer Structure containing pre-allocated
|
||||||
* write buffer and callback functions.
|
* write buffer and callback functions.
|
||||||
* This must not be NULL.
|
* The structure must not be NULL and must be kept valid until
|
||||||
|
* the transfer is complete.
|
||||||
*
|
*
|
||||||
* @return Standard errno return type for QMSI.
|
* @return Standard errno return type for QMSI.
|
||||||
* @retval 0 on success.
|
* @retval 0 on success.
|
||||||
|
@ -349,7 +350,8 @@ int qm_uart_irq_write(const qm_uart_t uart,
|
||||||
* @param[in] uart UART index.
|
* @param[in] uart UART index.
|
||||||
* @param[in] xfer Structure containing pre-allocated read
|
* @param[in] xfer Structure containing pre-allocated read
|
||||||
* buffer and callback functions.
|
* buffer and callback functions.
|
||||||
* This must not be NULL.
|
* The structure must not be NULL and must be kept valid until
|
||||||
|
* the transfer is complete.
|
||||||
*
|
*
|
||||||
* @return Standard errno return type for QMSI.
|
* @return Standard errno return type for QMSI.
|
||||||
* @retval 0 on success.
|
* @retval 0 on success.
|
||||||
|
@ -424,6 +426,10 @@ int qm_uart_dma_channel_config(
|
||||||
* QM_DMA_MEMORY_TO_PERIPHERAL to be used on this UART, calling
|
* QM_DMA_MEMORY_TO_PERIPHERAL to be used on this UART, calling
|
||||||
* qm_uart_dma_channel_config(). The transfer length is limited to 4KB.
|
* qm_uart_dma_channel_config(). The transfer length is limited to 4KB.
|
||||||
*
|
*
|
||||||
|
* Note that this function uses the UART TX FIFO empty interrupt and therefore,
|
||||||
|
* in addition to the DMA interrupts, the ISR of the corresponding UART must be
|
||||||
|
* registered before using this function.
|
||||||
|
*
|
||||||
* @param[in] uart UART index.
|
* @param[in] uart UART index.
|
||||||
* @param[in] xfer Structure containing a pre-allocated write buffer
|
* @param[in] xfer Structure containing a pre-allocated write buffer
|
||||||
* and callback functions.
|
* and callback functions.
|
||||||
|
|
163
ext/hal/qmsi/drivers/include/soc_watch.h
Normal file
163
ext/hal/qmsi/drivers/include/soc_watch.h
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Intel Corporation
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOC_WATCH_H__
|
||||||
|
#define __SOC_WATCH_H__
|
||||||
|
|
||||||
|
/* This file relies on the SOC being defined, which comes from qm_soc_regs.h */
|
||||||
|
#include "qm_soc_regs.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SoC Watch (Energy Analyzer).
|
||||||
|
*
|
||||||
|
* @defgroup group SOC_WATCH
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qm_common.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To activate the functionality in this file, compile with
|
||||||
|
* SOC_WATCH_ENABLE=1 on the make command line.
|
||||||
|
*
|
||||||
|
* Accurate timestamping through sleep modes also requires:
|
||||||
|
* + board design: provide an RTC crystal
|
||||||
|
* + application : don't reset or disable the RTC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Power profiling events enumeration.
|
||||||
|
*
|
||||||
|
* In order to maintain binary compatibility, only SOCW_EVENT_MAX should
|
||||||
|
* ever be altered: new events should be inserted before SOCW_EVENT_MAX,
|
||||||
|
* and SOCW_EVENT_MAX incremented. Add events, do not replace them.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
SOCW_EVENT_HALT = 0, /**< CPU Halt. */
|
||||||
|
SOCW_EVENT_INTERRUPT = 1, /**< CPU interrupt generated. */
|
||||||
|
SOCW_EVENT_SLEEP = 2, /**< Sleep mode entered. */
|
||||||
|
SOCW_EVENT_REGISTER = 3, /**< SOC register altered. */
|
||||||
|
SOCW_EVENT_APP = 4, /**< Application-defined event. */
|
||||||
|
SOCW_EVENT_MAX = 5 /**< End of events sentinel. */
|
||||||
|
} soc_watch_event_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register ID enumeration.
|
||||||
|
*
|
||||||
|
* The Register Event stores a register ID enumeration instead of a
|
||||||
|
* register address in order to save space. Registers can be added,
|
||||||
|
* but they should not be deleted, in order to preserve compatibility
|
||||||
|
* with different versions of the post-processor.
|
||||||
|
*
|
||||||
|
* Note that most of these names mirror the names used elsewhere in
|
||||||
|
* the QMSI code, although these are upper case, while the register
|
||||||
|
* pointer names are in lower case. That's one clue for identifying
|
||||||
|
* where logging calls should to be added: wherever you see one of the
|
||||||
|
* named registers below being written, you should consider that write
|
||||||
|
* may need a corresponding SoC Watch logging call.
|
||||||
|
*/
|
||||||
|
#if (QUARK_D2000)
|
||||||
|
typedef enum {
|
||||||
|
/* Clock rate registers */
|
||||||
|
SOCW_REG_OSC0_CFG1 = 0, /**< 0x000 OSC0_CFG1 register. */
|
||||||
|
SOCW_REG_CCU_LP_CLK_CTL = 1, /**< 0x02C Clock Control register.*/
|
||||||
|
SOCW_REG_CCU_SYS_CLK_CTL = 2, /**< 0x038 System Clock Control. */
|
||||||
|
/* Clock gating registers. */
|
||||||
|
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL = 3, /**< 0x018 Perip Clock Gate Ctl.*/
|
||||||
|
SOCW_REG_CCU_EXT_CLK_CTL = 4, /**< 0x024 CCU Ext Clock Gate Ctl.*/
|
||||||
|
/* Registers affecting power consumption */
|
||||||
|
SOCW_REG_CMP_PWR = 5, /**< 0x30C Comprtr Power Enable. */
|
||||||
|
SOCW_REG_PMUX_PULLUP = 6, /**< 0x900 Pin Mux Pullup. */
|
||||||
|
SOCW_REG_PMUX_SLEW = 7, /**< 0x910 Pin Mux Slew. */
|
||||||
|
SOCW_REG_PMUX_IN_EN = 8, /**< 0x920 Pin Mux In Enable. */
|
||||||
|
SOCW_REG_MAX, /**< Register enum sentinel. */
|
||||||
|
} soc_watch_reg_t;
|
||||||
|
|
||||||
|
#elif(QUARK_SE)
|
||||||
|
typedef enum {
|
||||||
|
/* Clock rate registers */
|
||||||
|
SOCW_REG_OSC0_CFG1 = 0, /**< 0x000 OSC0_CFG1 register. */
|
||||||
|
SOCW_REG_CCU_LP_CLK_CTL = 1, /**< 0x02C Clock Control register. */
|
||||||
|
SOCW_REG_CCU_SYS_CLK_CTL = 2, /**< 0x038 System Clock Control. */
|
||||||
|
/* Clock gating registers. */
|
||||||
|
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL = 3, /**< 0x018 Perip Clock Gate Ctl.*/
|
||||||
|
SOCW_REG_CCU_SS_PERIPH_CLK_GATE_CTL = 4, /**< 0x0028 SS PCL Gate Ctl.*/
|
||||||
|
SOCW_REG_CCU_EXT_CLK_CTL = 5, /**< 0x024 CCU Ext Clock Gate Ctl.*/
|
||||||
|
/* Registers affecting power consumption */
|
||||||
|
SOCW_REG_CMP_PWR = 6, /**< 0x30C Comparator Power Enable. */
|
||||||
|
SOCW_REG_SLP_CFG = 7, /**< 0x550 Sleep Configuration. */
|
||||||
|
SOCW_REG_PMUX_PULLUP0 = 8, /**< 0x900 Pin Mux Pullup. */
|
||||||
|
SOCW_REG_PMUX_PULLUP1 = 9, /**< 0x904 Pin Mux Pullup. */
|
||||||
|
SOCW_REG_PMUX_PULLUP2 = 10, /**< 0x908 Pin Mux Pullup. */
|
||||||
|
SOCW_REG_PMUX_PULLUP3 = 11, /**< 0x90c Pin Mux Pullup. */
|
||||||
|
SOCW_REG_PMUX_SLEW0 = 12, /**< 0x910 Pin Mux Slew. */
|
||||||
|
SOCW_REG_PMUX_SLEW1 = 13, /**< 0x914 Pin Mux Slew. */
|
||||||
|
SOCW_REG_PMUX_SLEW2 = 14, /**< 0x918 Pin Mux Slew. */
|
||||||
|
SOCW_REG_PMUX_SLEW3 = 15, /**< 0x91c Pin Mux Slew. */
|
||||||
|
SOCW_REG_PMUX_IN_EN0 = 16, /**< 0x920 Pin Mux In Enable. */
|
||||||
|
SOCW_REG_PMUX_IN_EN1 = 17, /**< 0x924 Pin Mux In Enable. */
|
||||||
|
SOCW_REG_PMUX_IN_EN2 = 18, /**< 0x928 Pin Mux In Enable. */
|
||||||
|
SOCW_REG_PMUX_IN_EN3 = 19, /**< 0x92c Pin Mux In Enable. */
|
||||||
|
SOCW_REG_MAX, /**< Register enum sentinel. */
|
||||||
|
} soc_watch_reg_t;
|
||||||
|
#endif /* QUARK_SE */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a power profile event.
|
||||||
|
*
|
||||||
|
* Log an event related to power management. This should be things like
|
||||||
|
* halts, or register reads which cause us to go to low power states, or
|
||||||
|
* register reads that affect the clock rate, or other clock gating.
|
||||||
|
*
|
||||||
|
* @param[in] event_id The Event ID of the profile event.
|
||||||
|
* @param[in] ev_data A parameter to the event ID (if the event needs one).
|
||||||
|
*/
|
||||||
|
void soc_watch_log_event(soc_watch_event_t event_id, uintptr_t ev_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log an application event via the power profile logger.
|
||||||
|
*
|
||||||
|
* This allows applications layered on top of QMSI to log their own
|
||||||
|
* events. The subtype identifies the type of data for the user, and
|
||||||
|
* 'data' is the actual information being logged.
|
||||||
|
*
|
||||||
|
* @param[in] event_id The Event ID of the profile event.
|
||||||
|
* @param[in] ev_subtype A 1-byte user-defined event_id.
|
||||||
|
* @param[in] ev_data A parameter to the event ID (if the event needs one).
|
||||||
|
*
|
||||||
|
* @returns Nothing.
|
||||||
|
*/
|
||||||
|
void soc_watch_log_app_event(soc_watch_event_t event_id, uint8_t ev_subtype,
|
||||||
|
uintptr_t ev_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* __SOC_WATCH_H__ */
|
|
@ -50,7 +50,7 @@
|
||||||
static uint8_t sample_window[QM_ADC_NUM];
|
static uint8_t sample_window[QM_ADC_NUM];
|
||||||
static qm_adc_resolution_t resolution[QM_ADC_NUM];
|
static qm_adc_resolution_t resolution[QM_ADC_NUM];
|
||||||
|
|
||||||
static qm_adc_xfer_t irq_xfer[QM_ADC_NUM];
|
static qm_adc_xfer_t *irq_xfer[QM_ADC_NUM];
|
||||||
static uint32_t count[QM_ADC_NUM];
|
static uint32_t count[QM_ADC_NUM];
|
||||||
static bool dummy_conversion = false;
|
static bool dummy_conversion = false;
|
||||||
|
|
||||||
|
@ -79,10 +79,10 @@ static void qm_adc_isr_handler(const qm_adc_t adc)
|
||||||
/* Disable all interrupts. */
|
/* Disable all interrupts. */
|
||||||
QM_ADC[adc].adc_intr_enable = 0;
|
QM_ADC[adc].adc_intr_enable = 0;
|
||||||
/* Call the user callback. */
|
/* Call the user callback. */
|
||||||
if (irq_xfer[adc].callback) {
|
if (irq_xfer[adc]->callback) {
|
||||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data,
|
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
|
||||||
-EIO, QM_ADC_OVERFLOW,
|
-EIO, QM_ADC_OVERFLOW,
|
||||||
QM_ADC_TRANSFER);
|
QM_ADC_TRANSFER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,16 +94,16 @@ static void qm_adc_isr_handler(const qm_adc_t adc)
|
||||||
/* Calculate the number of samples to read. */
|
/* Calculate the number of samples to read. */
|
||||||
samples_to_read = QM_ADC[adc].adc_fifo_count;
|
samples_to_read = QM_ADC[adc].adc_fifo_count;
|
||||||
if (samples_to_read >
|
if (samples_to_read >
|
||||||
(irq_xfer[adc].samples_len - count[adc])) {
|
(irq_xfer[adc]->samples_len - count[adc])) {
|
||||||
samples_to_read =
|
samples_to_read =
|
||||||
irq_xfer[adc].samples_len - count[adc];
|
irq_xfer[adc]->samples_len - count[adc];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy data out of FIFO. The sample must be shifted right by
|
/* Copy data out of FIFO. The sample must be shifted right by
|
||||||
* 2, 4 or 6 bits for 10, 8 and 6 bit resolution respectively
|
* 2, 4 or 6 bits for 10, 8 and 6 bit resolution respectively
|
||||||
* to get the correct value. */
|
* to get the correct value. */
|
||||||
for (i = 0; i < samples_to_read; i++) {
|
for (i = 0; i < samples_to_read; i++) {
|
||||||
irq_xfer[adc].samples[count[adc]] =
|
irq_xfer[adc]->samples[count[adc]] =
|
||||||
(QM_ADC[adc].adc_sample >>
|
(QM_ADC[adc].adc_sample >>
|
||||||
(2 * (3 - resolution[adc])));
|
(2 * (3 - resolution[adc])));
|
||||||
count[adc]++;
|
count[adc]++;
|
||||||
|
@ -111,15 +111,15 @@ static void qm_adc_isr_handler(const qm_adc_t adc)
|
||||||
|
|
||||||
/* Check if we have the requested number of samples, stop the
|
/* Check if we have the requested number of samples, stop the
|
||||||
* conversion and call the user callback function. */
|
* conversion and call the user callback function. */
|
||||||
if (count[adc] == irq_xfer[adc].samples_len) {
|
if (count[adc] == irq_xfer[adc]->samples_len) {
|
||||||
/* Stop the transfer. */
|
/* Stop the transfer. */
|
||||||
QM_ADC[adc].adc_cmd = QM_ADC_CMD_STOP_CONT;
|
QM_ADC[adc].adc_cmd = QM_ADC_CMD_STOP_CONT;
|
||||||
/* Disable all interrupts. */
|
/* Disable all interrupts. */
|
||||||
QM_ADC[adc].adc_intr_enable = 0;
|
QM_ADC[adc].adc_intr_enable = 0;
|
||||||
/* Call the user callback. */
|
/* Call the user callback. */
|
||||||
if (irq_xfer[adc].callback) {
|
if (irq_xfer[adc]->callback) {
|
||||||
irq_xfer[adc].callback(
|
irq_xfer[adc]->callback(
|
||||||
irq_xfer[adc].callback_data, 0,
|
irq_xfer[adc]->callback_data, 0,
|
||||||
QM_ADC_COMPLETE, QM_ADC_TRANSFER);
|
QM_ADC_COMPLETE, QM_ADC_TRANSFER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ static void qm_adc_isr_handler(const qm_adc_t adc)
|
||||||
|
|
||||||
/* Call the user callback if it is set. */
|
/* Call the user callback if it is set. */
|
||||||
if (cal_callback[adc]) {
|
if (cal_callback[adc]) {
|
||||||
cal_callback[adc](irq_xfer[adc].callback_data, 0,
|
cal_callback[adc](irq_xfer[adc]->callback_data, 0,
|
||||||
QM_ADC_IDLE, QM_ADC_CAL_COMPLETE);
|
QM_ADC_IDLE, QM_ADC_CAL_COMPLETE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ static void qm_adc_isr_handler(const qm_adc_t adc)
|
||||||
|
|
||||||
/* Call the user callback if it is set. */
|
/* Call the user callback if it is set. */
|
||||||
if (mode_callback[adc]) {
|
if (mode_callback[adc]) {
|
||||||
mode_callback[adc](irq_xfer[adc].callback_data, 0,
|
mode_callback[adc](irq_xfer[adc]->callback_data, 0,
|
||||||
QM_ADC_IDLE, QM_ADC_MODE_CHANGED);
|
QM_ADC_IDLE, QM_ADC_MODE_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ static void qm_adc_pwr_0_isr_handler(const qm_adc_t adc)
|
||||||
} else {
|
} else {
|
||||||
/* Call the user callback function */
|
/* Call the user callback function */
|
||||||
if (mode_callback[adc]) {
|
if (mode_callback[adc]) {
|
||||||
mode_callback[adc](irq_xfer[adc].callback_data, 0,
|
mode_callback[adc](irq_xfer[adc]->callback_data, 0,
|
||||||
QM_ADC_IDLE, QM_ADC_MODE_CHANGED);
|
QM_ADC_IDLE, QM_ADC_MODE_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ int qm_adc_irq_calibrate(const qm_adc_t adc,
|
||||||
cal_callback[adc] = callback;
|
cal_callback[adc] = callback;
|
||||||
cal_callback_data[adc] = callback_data;
|
cal_callback_data[adc] = callback_data;
|
||||||
|
|
||||||
/* Clear and enable the command complete interupt. */
|
/* Clear and enable the command complete interrupt. */
|
||||||
QM_ADC[adc].adc_intr_status = QM_ADC_INTR_STATUS_CC;
|
QM_ADC[adc].adc_intr_status = QM_ADC_INTR_STATUS_CC;
|
||||||
QM_ADC[adc].adc_intr_enable |= QM_ADC_INTR_ENABLE_CC;
|
QM_ADC[adc].adc_intr_enable |= QM_ADC_INTR_ENABLE_CC;
|
||||||
|
|
||||||
|
@ -369,7 +369,8 @@ int qm_adc_set_config(const qm_adc_t adc, const qm_adc_config_t *const cfg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qm_adc_convert(const qm_adc_t adc, qm_adc_xfer_t *xfer)
|
int qm_adc_convert(const qm_adc_t adc, qm_adc_xfer_t *xfer,
|
||||||
|
qm_adc_status_t *const status)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
|
@ -399,6 +400,10 @@ int qm_adc_convert(const qm_adc_t adc, qm_adc_xfer_t *xfer)
|
||||||
while (QM_ADC[adc].adc_fifo_count != xfer->samples_len)
|
while (QM_ADC[adc].adc_fifo_count != xfer->samples_len)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
*status = QM_ADC_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the value into the data structure. The sample must be shifted
|
/* Read the value into the data structure. The sample must be shifted
|
||||||
* right by 2, 4 or 6 bits for 10, 8 and 6 bit resolution respectively
|
* right by 2, 4 or 6 bits for 10, 8 and 6 bit resolution respectively
|
||||||
* to get the correct value. */
|
* to get the correct value. */
|
||||||
|
@ -428,7 +433,7 @@ int qm_adc_irq_convert(const qm_adc_t adc, qm_adc_xfer_t *xfer)
|
||||||
setup_seq_table(adc, xfer);
|
setup_seq_table(adc, xfer);
|
||||||
|
|
||||||
/* Copy the xfer struct so we can get access from the ISR. */
|
/* Copy the xfer struct so we can get access from the ISR. */
|
||||||
memcpy(&irq_xfer[adc], xfer, sizeof(qm_adc_xfer_t));
|
irq_xfer[adc] = xfer;
|
||||||
|
|
||||||
/* Clear all pending interrupts. */
|
/* Clear all pending interrupts. */
|
||||||
QM_ADC[adc].adc_intr_status = QM_ADC_INTR_STATUS_CC |
|
QM_ADC[adc].adc_intr_status = QM_ADC_INTR_STATUS_CC |
|
||||||
|
|
|
@ -85,7 +85,7 @@ int qm_aonc_disable(const qm_scss_aon_t aonc)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qm_aonc_get_value(const qm_scss_aon_t aonc, uint32_t * const val)
|
int qm_aonc_get_value(const qm_scss_aon_t aonc, uint32_t *const val)
|
||||||
{
|
{
|
||||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||||
QM_CHECK(val != NULL, -EINVAL);
|
QM_CHECK(val != NULL, -EINVAL);
|
||||||
|
|
|
@ -354,7 +354,7 @@ int qm_dma_transfer_terminate(const qm_dma_t dma,
|
||||||
|
|
||||||
/* The channel is disabled and the transfer complete callback is
|
/* The channel is disabled and the transfer complete callback is
|
||||||
* triggered. This callback provides the client with the data length
|
* triggered. This callback provides the client with the data length
|
||||||
* transfered before the transfer was stopped. */
|
* transferred before the transfer was stopped. */
|
||||||
return_code = dma_channel_disable(dma, channel_id);
|
return_code = dma_channel_disable(dma, channel_id);
|
||||||
if (!return_code) {
|
if (!return_code) {
|
||||||
chan_cfg = &dma_channel_config[dma][channel_id];
|
chan_cfg = &dma_channel_config[dma][channel_id];
|
||||||
|
|
|
@ -86,6 +86,58 @@ int qm_fpr_set_config(const qm_flash_t flash, const qm_fpr_id_t id,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (QM_SENSOR)
|
||||||
|
int qm_fpr_set_violation_policy(const qm_fpr_viol_mode_t mode,
|
||||||
|
const qm_flash_t flash,
|
||||||
|
qm_fpr_callback_t callback_fn, void *data)
|
||||||
|
{
|
||||||
|
QM_CHECK(mode <= FPR_VIOL_MODE_PROBE, -EINVAL);
|
||||||
|
QM_CHECK(flash < QM_FLASH_NUM, -EINVAL);
|
||||||
|
volatile uint32_t *int_flash_controller_mask =
|
||||||
|
&QM_SCSS_INT->int_flash_controller_0_mask;
|
||||||
|
|
||||||
|
/* interrupt mode */
|
||||||
|
if (FPR_VIOL_MODE_INTERRUPT == mode) {
|
||||||
|
|
||||||
|
callback[flash] = callback_fn;
|
||||||
|
callback_data[flash] = data;
|
||||||
|
|
||||||
|
int_flash_controller_mask[flash] &=
|
||||||
|
~QM_INT_FLASH_CONTROLLER_SS_MASK;
|
||||||
|
int_flash_controller_mask[flash] |=
|
||||||
|
QM_INT_FLASH_CONTROLLER_SS_HALT_MASK;
|
||||||
|
|
||||||
|
QM_SCSS_SS->ss_cfg &= ~QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* probe or reset mode */
|
||||||
|
else {
|
||||||
|
int_flash_controller_mask[flash] |=
|
||||||
|
QM_INT_FLASH_CONTROLLER_SS_MASK;
|
||||||
|
int_flash_controller_mask[flash] &=
|
||||||
|
~QM_INT_FLASH_CONTROLLER_SS_HALT_MASK;
|
||||||
|
|
||||||
|
if (FPR_VIOL_MODE_PROBE == mode) {
|
||||||
|
|
||||||
|
/* When an enabled host halt interrupt occurs, this bit
|
||||||
|
* determines if the interrupt event triggers a warm
|
||||||
|
* reset
|
||||||
|
* or an entry into Probe Mode.
|
||||||
|
* 0b : Warm Reset
|
||||||
|
* 1b : Probe Mode Entry
|
||||||
|
*/
|
||||||
|
QM_SCSS_SS->ss_cfg |=
|
||||||
|
QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
|
} else {
|
||||||
|
QM_SCSS_SS->ss_cfg &=
|
||||||
|
~QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* QM_SENSOR */
|
||||||
|
|
||||||
int qm_fpr_set_violation_policy(const qm_fpr_viol_mode_t mode,
|
int qm_fpr_set_violation_policy(const qm_fpr_viol_mode_t mode,
|
||||||
const qm_flash_t flash,
|
const qm_flash_t flash,
|
||||||
qm_fpr_callback_t callback_fn, void *data)
|
qm_fpr_callback_t callback_fn, void *data)
|
||||||
|
@ -109,13 +161,9 @@ int qm_fpr_set_violation_policy(const qm_fpr_viol_mode_t mode,
|
||||||
qm_irq_unmask(QM_IRQ_FLASH_1);
|
qm_irq_unmask(QM_IRQ_FLASH_1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if defined(QM_SENSOR)
|
|
||||||
int_flash_controller_mask[flash] |=
|
|
||||||
QM_INT_FLASH_CONTROLLER_SS_HALT_MASK;
|
|
||||||
#else /* QM_SENSOR */
|
|
||||||
int_flash_controller_mask[flash] |=
|
int_flash_controller_mask[flash] |=
|
||||||
QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK;
|
QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK;
|
||||||
#endif /* QM_SENSOR */
|
|
||||||
|
|
||||||
QM_SCSS_PMU->p_sts &= ~QM_P_STS_HALT_INTERRUPT_REDIRECTION;
|
QM_SCSS_PMU->p_sts &= ~QM_P_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
}
|
}
|
||||||
|
@ -130,13 +178,9 @@ int qm_fpr_set_violation_policy(const qm_fpr_viol_mode_t mode,
|
||||||
qm_irq_mask(QM_IRQ_FLASH_1);
|
qm_irq_mask(QM_IRQ_FLASH_1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if defined(QM_SENSOR)
|
|
||||||
int_flash_controller_mask[flash] &=
|
|
||||||
~QM_INT_FLASH_CONTROLLER_SS_HALT_MASK;
|
|
||||||
#else /* QM_SENSOR */
|
|
||||||
int_flash_controller_mask[flash] &=
|
int_flash_controller_mask[flash] &=
|
||||||
~QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK;
|
~QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK;
|
||||||
#endif /* QM_SENSOR */
|
|
||||||
|
|
||||||
if (FPR_VIOL_MODE_PROBE == mode) {
|
if (FPR_VIOL_MODE_PROBE == mode) {
|
||||||
|
|
||||||
|
@ -156,3 +200,4 @@ int qm_fpr_set_violation_policy(const qm_fpr_viol_mode_t mode,
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* QM_SENSOR */
|
||||||
|
|
|
@ -45,6 +45,25 @@ static void gpio_isr(const qm_gpio_t gpio)
|
||||||
{
|
{
|
||||||
const uint32_t int_status = QM_GPIO[gpio]->gpio_intstatus;
|
const uint32_t int_status = QM_GPIO[gpio]->gpio_intstatus;
|
||||||
|
|
||||||
|
#if (QUARK_D2000)
|
||||||
|
/*
|
||||||
|
* If the SoC is in deep sleep mode, all the clocks are gated, if the
|
||||||
|
* interrupt source is cleared before the oscillators are ungated, the
|
||||||
|
* oscillators return to a powered down state and the SoC will not
|
||||||
|
* return to an active state then.
|
||||||
|
*/
|
||||||
|
if ((QM_SCSS_GP->gps1 & QM_SCSS_GP_POWER_STATES_MASK) ==
|
||||||
|
QM_SCSS_GP_POWER_STATE_DEEP_SLEEP) {
|
||||||
|
/* Return the oscillators to an active state. */
|
||||||
|
QM_SCSS_CCU->osc0_cfg1 &= ~QM_OSC0_PD;
|
||||||
|
QM_SCSS_CCU->osc1_cfg0 &= ~QM_OSC1_PD;
|
||||||
|
|
||||||
|
/* HYB_OSC_PD_LATCH_EN = 1, RTC_OSC_PD_LATCH_EN=1 */
|
||||||
|
QM_SCSS_CCU->ccu_lp_clk_ctl |=
|
||||||
|
(QM_HYB_OSC_PD_LATCH_EN | QM_RTC_OSC_PD_LATCH_EN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (callback[gpio]) {
|
if (callback[gpio]) {
|
||||||
(*callback[gpio])(callback_data[gpio], int_status);
|
(*callback[gpio])(callback_data[gpio], int_status);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@
|
||||||
#define SPK_LEN_FS_FSP (2)
|
#define SPK_LEN_FS_FSP (2)
|
||||||
|
|
||||||
/* number of retries before giving up on disabling the controller */
|
/* number of retries before giving up on disabling the controller */
|
||||||
#define MAX_T_POLL_COUNT (100)
|
#define I2C_POLL_COUNT (1000000)
|
||||||
#define TI2C_POLL_MICROSECOND (10000)
|
#define I2C_POLL_MICROSECOND (1)
|
||||||
|
|
||||||
#ifndef UNIT_TEST
|
#ifndef UNIT_TEST
|
||||||
#if (QUARK_SE)
|
#if (QUARK_SE)
|
||||||
|
@ -49,9 +49,9 @@ qm_i2c_reg_t *qm_i2c[QM_I2C_NUM] = {(qm_i2c_reg_t *)QM_I2C_0_BASE};
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static qm_i2c_transfer_t i2c_transfer[QM_I2C_NUM];
|
static const qm_i2c_transfer_t *i2c_transfer[QM_I2C_NUM];
|
||||||
static uint32_t i2c_write_pos[QM_I2C_NUM], i2c_read_pos[QM_I2C_NUM],
|
static uint32_t i2c_write_pos[QM_I2C_NUM], i2c_read_pos[QM_I2C_NUM],
|
||||||
i2c_read_buffer_remaining[QM_I2C_NUM];
|
i2c_read_cmd_send[QM_I2C_NUM];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I2C DMA controller configuration descriptor.
|
* I2C DMA controller configuration descriptor.
|
||||||
|
@ -61,12 +61,13 @@ typedef struct {
|
||||||
qm_dma_t dma_controller_id;
|
qm_dma_t dma_controller_id;
|
||||||
qm_dma_channel_id_t dma_tx_channel_id; /* TX channel ID */
|
qm_dma_channel_id_t dma_tx_channel_id; /* TX channel ID */
|
||||||
qm_dma_transfer_t dma_tx_transfer_config; /* Configuration for TX */
|
qm_dma_transfer_t dma_tx_transfer_config; /* Configuration for TX */
|
||||||
volatile bool ongoing_dma_tx_operation; /* Keep track of ongoing TX */
|
|
||||||
qm_dma_channel_id_t dma_rx_channel_id; /* RX channel ID */
|
qm_dma_channel_id_t dma_rx_channel_id; /* RX channel ID */
|
||||||
qm_dma_transfer_t dma_rx_transfer_config; /* Configuration for RX */
|
qm_dma_transfer_t dma_rx_transfer_config; /* Configuration for RX */
|
||||||
/* Configuration for writing READ commands during an RX operation */
|
/* Configuration for writing READ commands during an RX operation */
|
||||||
qm_dma_transfer_t dma_cmd_transfer_config;
|
qm_dma_transfer_t dma_cmd_transfer_config;
|
||||||
|
volatile bool ongoing_dma_tx_operation; /* Keep track of ongoing TX */
|
||||||
volatile bool ongoing_dma_rx_operation; /* Keep track of oingoing RX*/
|
volatile bool ongoing_dma_rx_operation; /* Keep track of oingoing RX*/
|
||||||
|
int multimaster_abort_status;
|
||||||
} i2c_dma_context_t;
|
} i2c_dma_context_t;
|
||||||
|
|
||||||
/* DMA context */
|
/* DMA context */
|
||||||
|
@ -96,9 +97,12 @@ static int controller_disable(const qm_i2c_t i2c);
|
||||||
|
|
||||||
static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
||||||
{
|
{
|
||||||
|
const qm_i2c_transfer_t *const transfer = i2c_transfer[i2c];
|
||||||
uint32_t ic_data_cmd = 0, count_tx = (QM_I2C_FIFO_SIZE - TX_TL);
|
uint32_t ic_data_cmd = 0, count_tx = (QM_I2C_FIFO_SIZE - TX_TL);
|
||||||
qm_i2c_status_t status = 0;
|
qm_i2c_status_t status = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
uint32_t read_buffer_remaining = transfer->rx_len - i2c_read_pos[i2c];
|
||||||
|
uint32_t write_buffer_remaining = transfer->tx_len - i2c_write_pos[i2c];
|
||||||
|
|
||||||
qm_i2c_reg_t *const controller = QM_I2C[i2c];
|
qm_i2c_reg_t *const controller = QM_I2C[i2c];
|
||||||
|
|
||||||
|
@ -120,12 +124,24 @@ static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
||||||
controller->ic_intr_mask = QM_I2C_IC_INTR_MASK_ALL;
|
controller->ic_intr_mask = QM_I2C_IC_INTR_MASK_ALL;
|
||||||
|
|
||||||
rc = (status & QM_I2C_TX_ABRT_USER_ABRT) ? -ECANCELED : -EIO;
|
rc = (status & QM_I2C_TX_ABRT_USER_ABRT) ? -ECANCELED : -EIO;
|
||||||
if (i2c_transfer[i2c].callback) {
|
|
||||||
/* NOTE: currently 0 is returned for length but we
|
if ((i2c_dma_context[i2c].ongoing_dma_rx_operation == true) ||
|
||||||
* may revisit that soon
|
(i2c_dma_context[i2c].ongoing_dma_tx_operation == true)) {
|
||||||
|
/* If in DMA mode, raise a flag and stop the channels */
|
||||||
|
i2c_dma_context[i2c].multimaster_abort_status = rc;
|
||||||
|
/* When terminating the DMA transfer, the DMA controller
|
||||||
|
* calls the TX or RX callback, which will trigger the
|
||||||
|
* error callback. This will disable the I2C controller
|
||||||
*/
|
*/
|
||||||
i2c_transfer[i2c].callback(
|
qm_i2c_dma_transfer_terminate(i2c);
|
||||||
i2c_transfer[i2c].callback_data, rc, status, 0);
|
} else {
|
||||||
|
if (transfer->callback) {
|
||||||
|
/* NOTE: currently 0 is returned for length but
|
||||||
|
* we may revisit that soon
|
||||||
|
*/
|
||||||
|
transfer->callback(transfer->callback_data, rc,
|
||||||
|
status, 0);
|
||||||
|
}
|
||||||
controller_disable(i2c);
|
controller_disable(i2c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,39 +149,38 @@ static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
||||||
/* RX read from buffer */
|
/* RX read from buffer */
|
||||||
if (controller->ic_intr_stat & QM_I2C_IC_INTR_STAT_RX_FULL) {
|
if (controller->ic_intr_stat & QM_I2C_IC_INTR_STAT_RX_FULL) {
|
||||||
|
|
||||||
while (i2c_read_buffer_remaining[i2c] && controller->ic_rxflr) {
|
while (read_buffer_remaining && controller->ic_rxflr) {
|
||||||
i2c_transfer[i2c].rx[i2c_read_pos[i2c]] =
|
transfer->rx[i2c_read_pos[i2c]] =
|
||||||
controller->ic_data_cmd;
|
controller->ic_data_cmd;
|
||||||
i2c_read_buffer_remaining[i2c]--;
|
read_buffer_remaining--;
|
||||||
i2c_read_pos[i2c]++;
|
i2c_read_pos[i2c]++;
|
||||||
|
|
||||||
if (i2c_read_buffer_remaining[i2c] == 0) {
|
if (read_buffer_remaining == 0) {
|
||||||
/* mask rx full interrupt if transfer
|
/* mask rx full interrupt if transfer
|
||||||
* complete
|
* complete
|
||||||
*/
|
*/
|
||||||
controller->ic_intr_mask &=
|
controller->ic_intr_mask &=
|
||||||
~QM_I2C_IC_INTR_MASK_RX_FULL;
|
~QM_I2C_IC_INTR_MASK_RX_FULL;
|
||||||
|
|
||||||
if (i2c_transfer[i2c].stop) {
|
if (transfer->stop) {
|
||||||
controller_disable(i2c);
|
controller_disable(i2c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c_transfer[i2c].callback) {
|
if (transfer->callback) {
|
||||||
i2c_transfer[i2c].callback(
|
transfer->callback(
|
||||||
i2c_transfer[i2c].callback_data, 0,
|
transfer->callback_data, 0,
|
||||||
QM_I2C_IDLE, i2c_read_pos[i2c]);
|
QM_I2C_IDLE, i2c_read_pos[i2c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c_read_buffer_remaining[i2c] > 0 &&
|
if (read_buffer_remaining > 0 &&
|
||||||
i2c_read_buffer_remaining[i2c] < (RX_TL + 1)) {
|
read_buffer_remaining < (RX_TL + 1)) {
|
||||||
/* Adjust the RX threshold so the next 'RX_FULL'
|
/* Adjust the RX threshold so the next 'RX_FULL'
|
||||||
* interrupt is generated when all the remaining
|
* interrupt is generated when all the remaining
|
||||||
* data are received.
|
* data are received.
|
||||||
*/
|
*/
|
||||||
controller->ic_rx_tl =
|
controller->ic_rx_tl = read_buffer_remaining - 1;
|
||||||
i2c_read_buffer_remaining[i2c] - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX_FULL INTR is autocleared when the buffer
|
/* RX_FULL INTR is autocleared when the buffer
|
||||||
|
@ -176,9 +191,8 @@ static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
||||||
if (controller->ic_intr_stat & QM_I2C_IC_INTR_STAT_TX_EMPTY) {
|
if (controller->ic_intr_stat & QM_I2C_IC_INTR_STAT_TX_EMPTY) {
|
||||||
|
|
||||||
if ((controller->ic_status & QM_I2C_IC_STATUS_TFE) &&
|
if ((controller->ic_status & QM_I2C_IC_STATUS_TFE) &&
|
||||||
(i2c_transfer[i2c].tx != NULL) &&
|
(transfer->tx != NULL) && (write_buffer_remaining == 0) &&
|
||||||
(i2c_transfer[i2c].tx_len == 0) &&
|
(read_buffer_remaining == 0)) {
|
||||||
(i2c_transfer[i2c].rx_len == 0)) {
|
|
||||||
|
|
||||||
controller->ic_intr_mask &=
|
controller->ic_intr_mask &=
|
||||||
~QM_I2C_IC_INTR_MASK_TX_EMPTY;
|
~QM_I2C_IC_INTR_MASK_TX_EMPTY;
|
||||||
|
@ -186,33 +200,31 @@ static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
||||||
/* if this is not a combined
|
/* if this is not a combined
|
||||||
* transaction, disable the controller now
|
* transaction, disable the controller now
|
||||||
*/
|
*/
|
||||||
if ((i2c_read_buffer_remaining[i2c] == 0) &&
|
if (transfer->stop) {
|
||||||
i2c_transfer[i2c].stop) {
|
|
||||||
controller_disable(i2c);
|
controller_disable(i2c);
|
||||||
|
|
||||||
/* callback */
|
/* callback */
|
||||||
if (i2c_transfer[i2c].callback) {
|
if (transfer->callback) {
|
||||||
i2c_transfer[i2c].callback(
|
transfer->callback(
|
||||||
i2c_transfer[i2c].callback_data, 0,
|
transfer->callback_data, 0,
|
||||||
QM_I2C_IDLE, i2c_write_pos[i2c]);
|
QM_I2C_IDLE, i2c_write_pos[i2c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((count_tx) && i2c_transfer[i2c].tx_len) {
|
while ((count_tx) && write_buffer_remaining) {
|
||||||
count_tx--;
|
count_tx--;
|
||||||
|
write_buffer_remaining--;
|
||||||
|
|
||||||
/* write command -IC_DATA_CMD[8] = 0 */
|
/* write command -IC_DATA_CMD[8] = 0 */
|
||||||
/* fill IC_DATA_CMD[7:0] with the data */
|
/* fill IC_DATA_CMD[7:0] with the data */
|
||||||
ic_data_cmd = i2c_transfer[i2c].tx[i2c_write_pos[i2c]];
|
ic_data_cmd = transfer->tx[i2c_write_pos[i2c]];
|
||||||
i2c_transfer[i2c].tx_len--;
|
|
||||||
|
|
||||||
/* if transfer is a combined transfer, only
|
/* if transfer is a combined transfer, only
|
||||||
* send stop at
|
* send stop at
|
||||||
* end of the transfer sequence */
|
* end of the transfer sequence */
|
||||||
if (i2c_transfer[i2c].stop &&
|
if (transfer->stop && (write_buffer_remaining == 0) &&
|
||||||
(i2c_transfer[i2c].tx_len == 0) &&
|
(read_buffer_remaining == 0)) {
|
||||||
(i2c_transfer[i2c].rx_len == 0)) {
|
|
||||||
|
|
||||||
ic_data_cmd |= QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL;
|
ic_data_cmd |= QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL;
|
||||||
}
|
}
|
||||||
|
@ -230,18 +242,15 @@ static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
||||||
count_tx = QM_I2C_FIFO_SIZE -
|
count_tx = QM_I2C_FIFO_SIZE -
|
||||||
(controller->ic_txflr + controller->ic_rxflr + 1);
|
(controller->ic_txflr + controller->ic_rxflr + 1);
|
||||||
|
|
||||||
while (i2c_transfer[i2c].rx_len &&
|
while (i2c_read_cmd_send[i2c] &&
|
||||||
(i2c_transfer[i2c].tx_len == 0) && count_tx) {
|
(write_buffer_remaining == 0) && count_tx) {
|
||||||
count_tx--;
|
count_tx--;
|
||||||
i2c_transfer[i2c].rx_len--;
|
i2c_read_cmd_send[i2c]--;
|
||||||
|
|
||||||
/* if transfer is a combined transfer, only
|
/* If transfer is a combined transfer, only send stop at
|
||||||
* send stop at
|
* end of the transfer sequence
|
||||||
* end of
|
*/
|
||||||
* the transfer sequence */
|
if (transfer->stop && (i2c_read_cmd_send[i2c] == 0)) {
|
||||||
if (i2c_transfer[i2c].stop &&
|
|
||||||
(i2c_transfer[i2c].rx_len == 0) &&
|
|
||||||
(i2c_transfer[i2c].tx_len == 0)) {
|
|
||||||
controller->ic_data_cmd =
|
controller->ic_data_cmd =
|
||||||
QM_I2C_IC_DATA_CMD_READ |
|
QM_I2C_IC_DATA_CMD_READ |
|
||||||
QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL;
|
QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL;
|
||||||
|
@ -252,8 +261,8 @@ static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generate a tx_empty interrupt when tx fifo is fully empty */
|
/* generate a tx_empty interrupt when tx fifo is fully empty */
|
||||||
if ((i2c_transfer[i2c].tx_len == 0) &&
|
if ((write_buffer_remaining == 0) &&
|
||||||
(i2c_transfer[i2c].rx_len == 0)) {
|
(read_buffer_remaining == 0)) {
|
||||||
controller->ic_tx_tl = 0;
|
controller->ic_tx_tl = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,7 +324,7 @@ int qm_i2c_set_config(const qm_i2c_t i2c, const qm_i2c_config_t *const cfg)
|
||||||
|
|
||||||
/* disable controller */
|
/* disable controller */
|
||||||
if (controller_disable(i2c)) {
|
if (controller_disable(i2c)) {
|
||||||
return -EAGAIN;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cfg->mode) {
|
switch (cfg->mode) {
|
||||||
|
@ -430,6 +439,7 @@ int qm_i2c_set_speed(const qm_i2c_t i2c, const qm_i2c_speed_t speed,
|
||||||
ic_con |= QM_I2C_IC_CON_SPEED_SS;
|
ic_con |= QM_I2C_IC_CON_SPEED_SS;
|
||||||
controller->ic_ss_scl_lcnt = lo_cnt;
|
controller->ic_ss_scl_lcnt = lo_cnt;
|
||||||
controller->ic_ss_scl_hcnt = hi_cnt;
|
controller->ic_ss_scl_hcnt = hi_cnt;
|
||||||
|
controller->ic_fs_spklen = SPK_LEN_SS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QM_I2C_SPEED_FAST:
|
case QM_I2C_SPEED_FAST:
|
||||||
|
@ -437,6 +447,7 @@ int qm_i2c_set_speed(const qm_i2c_t i2c, const qm_i2c_speed_t speed,
|
||||||
ic_con |= QM_I2C_IC_CON_SPEED_FS_FSP;
|
ic_con |= QM_I2C_IC_CON_SPEED_FS_FSP;
|
||||||
controller->ic_fs_scl_lcnt = lo_cnt;
|
controller->ic_fs_scl_lcnt = lo_cnt;
|
||||||
controller->ic_fs_scl_hcnt = hi_cnt;
|
controller->ic_fs_scl_hcnt = hi_cnt;
|
||||||
|
controller->ic_fs_spklen = SPK_LEN_FS_FSP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +528,7 @@ int qm_i2c_master_write(const qm_i2c_t i2c, const uint16_t slave_addr,
|
||||||
/* disable controller */
|
/* disable controller */
|
||||||
if (true == stop) {
|
if (true == stop) {
|
||||||
if (controller_disable(i2c)) {
|
if (controller_disable(i2c)) {
|
||||||
ret = -EIO;
|
ret = -EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,7 +601,7 @@ int qm_i2c_master_read(const qm_i2c_t i2c, const uint16_t slave_addr,
|
||||||
/* disable controller */
|
/* disable controller */
|
||||||
if (true == stop) {
|
if (true == stop) {
|
||||||
if (controller_disable(i2c)) {
|
if (controller_disable(i2c)) {
|
||||||
ret = -EIO;
|
ret = -EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,8 +634,8 @@ int qm_i2c_master_irq_transfer(const qm_i2c_t i2c,
|
||||||
|
|
||||||
i2c_write_pos[i2c] = 0;
|
i2c_write_pos[i2c] = 0;
|
||||||
i2c_read_pos[i2c] = 0;
|
i2c_read_pos[i2c] = 0;
|
||||||
i2c_read_buffer_remaining[i2c] = xfer->rx_len;
|
i2c_read_cmd_send[i2c] = xfer->rx_len;
|
||||||
memcpy(&i2c_transfer[i2c], xfer, sizeof(i2c_transfer[i2c]));
|
i2c_transfer[i2c] = xfer;
|
||||||
|
|
||||||
/* set threshold */
|
/* set threshold */
|
||||||
controller->ic_tx_tl = TX_TL;
|
controller->ic_tx_tl = TX_TL;
|
||||||
|
@ -666,12 +677,15 @@ static void controller_enable(const qm_i2c_t i2c)
|
||||||
QM_I2C_IC_ENABLE_STATUS_IC_EN))
|
QM_I2C_IC_ENABLE_STATUS_IC_EN))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* be sure that all interrupts flag are cleared */
|
||||||
|
controller->ic_clr_intr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int controller_disable(const qm_i2c_t i2c)
|
static int controller_disable(const qm_i2c_t i2c)
|
||||||
{
|
{
|
||||||
qm_i2c_reg_t *const controller = QM_I2C[i2c];
|
qm_i2c_reg_t *const controller = QM_I2C[i2c];
|
||||||
int poll_count = MAX_T_POLL_COUNT;
|
int poll_count = I2C_POLL_COUNT;
|
||||||
|
|
||||||
/* disable controller */
|
/* disable controller */
|
||||||
controller->ic_enable &= ~QM_I2C_IC_ENABLE_CONTROLLER_EN;
|
controller->ic_enable &= ~QM_I2C_IC_ENABLE_CONTROLLER_EN;
|
||||||
|
@ -679,7 +693,7 @@ static int controller_disable(const qm_i2c_t i2c)
|
||||||
/* wait until controller is disabled */
|
/* wait until controller is disabled */
|
||||||
while ((controller->ic_enable_status & QM_I2C_IC_ENABLE_STATUS_IC_EN) &&
|
while ((controller->ic_enable_status & QM_I2C_IC_ENABLE_STATUS_IC_EN) &&
|
||||||
poll_count--) {
|
poll_count--) {
|
||||||
clk_sys_udelay(TI2C_POLL_MICROSECOND);
|
clk_sys_udelay(I2C_POLL_MICROSECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns 0 if ok, meaning controller is disabled */
|
/* returns 0 if ok, meaning controller is disabled */
|
||||||
|
@ -718,26 +732,18 @@ int qm_i2c_dma_transfer_terminate(const qm_i2c_t i2c)
|
||||||
rc = qm_dma_transfer_terminate(
|
rc = qm_dma_transfer_terminate(
|
||||||
i2c_dma_context[i2c].dma_controller_id,
|
i2c_dma_context[i2c].dma_controller_id,
|
||||||
i2c_dma_context[i2c].dma_tx_channel_id);
|
i2c_dma_context[i2c].dma_tx_channel_id);
|
||||||
/* Then disable DMA transmit */
|
|
||||||
QM_I2C[i2c]->ic_dma_cr &= ~QM_I2C_IC_DMA_CR_TX_ENABLE;
|
|
||||||
i2c_dma_context[i2c].ongoing_dma_tx_operation = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == 0) {
|
if (i2c_dma_context[i2c].ongoing_dma_rx_operation) {
|
||||||
if (i2c_dma_context[i2c].ongoing_dma_rx_operation) {
|
/* First terminate the DMA transfer */
|
||||||
/* First terminate the DMA transfer */
|
rc |= qm_dma_transfer_terminate(
|
||||||
rc = qm_dma_transfer_terminate(
|
i2c_dma_context[i2c].dma_controller_id,
|
||||||
i2c_dma_context[i2c].dma_controller_id,
|
i2c_dma_context[i2c].dma_rx_channel_id);
|
||||||
i2c_dma_context[i2c].dma_rx_channel_id);
|
|
||||||
/* Then disable DMA receive */
|
|
||||||
QM_I2C[i2c]->ic_dma_cr &= ~QM_I2C_IC_DMA_CR_RX_ENABLE;
|
|
||||||
i2c_dma_context[i2c].ongoing_dma_rx_operation = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And terminate the I2C transfer */
|
/* Check if any of the calls failed */
|
||||||
if (rc == 0) {
|
if (rc != 0) {
|
||||||
QM_I2C[i2c]->ic_enable |= QM_I2C_IC_ENABLE_CONTROLLER_ABORT;
|
rc = -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -749,6 +755,7 @@ int qm_i2c_dma_transfer_terminate(const qm_i2c_t i2c)
|
||||||
static void i2c_dma_transfer_error_callback(uint32_t i2c, int error_code,
|
static void i2c_dma_transfer_error_callback(uint32_t i2c, int error_code,
|
||||||
uint32_t len)
|
uint32_t len)
|
||||||
{
|
{
|
||||||
|
const qm_i2c_transfer_t *const transfer = i2c_transfer[i2c];
|
||||||
qm_i2c_status_t status;
|
qm_i2c_status_t status;
|
||||||
|
|
||||||
if (error_code != 0) {
|
if (error_code != 0) {
|
||||||
|
@ -764,12 +771,16 @@ static void i2c_dma_transfer_error_callback(uint32_t i2c, int error_code,
|
||||||
i2c_dma_context[i2c].ongoing_dma_rx_operation = false;
|
i2c_dma_context[i2c].ongoing_dma_rx_operation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Wait until the controller is done and disable it */
|
||||||
|
while (!(QM_I2C[i2c]->ic_status & QM_I2C_IC_STATUS_TFE)) {
|
||||||
|
}
|
||||||
|
controller_disable(i2c);
|
||||||
|
|
||||||
/* If the user has provided a callback, let's call it */
|
/* If the user has provided a callback, let's call it */
|
||||||
if (i2c_transfer[i2c].callback != NULL) {
|
if (transfer->callback != NULL) {
|
||||||
qm_i2c_get_status(i2c, &status);
|
qm_i2c_get_status(i2c, &status);
|
||||||
i2c_transfer[i2c].callback(
|
transfer->callback(transfer->callback_data, error_code,
|
||||||
i2c_transfer[i2c].callback_data, error_code, status,
|
status, len);
|
||||||
len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -785,8 +796,10 @@ static void i2c_dma_transmit_callback(void *callback_context, uint32_t len,
|
||||||
qm_i2c_status_t status;
|
qm_i2c_status_t status;
|
||||||
|
|
||||||
qm_i2c_t i2c = ((i2c_dma_context_t *)callback_context)->i2c;
|
qm_i2c_t i2c = ((i2c_dma_context_t *)callback_context)->i2c;
|
||||||
|
const qm_i2c_transfer_t *const transfer = i2c_transfer[i2c];
|
||||||
|
|
||||||
if (error_code == 0) {
|
if ((error_code == 0) &&
|
||||||
|
(i2c_dma_context[i2c].multimaster_abort_status == 0)) {
|
||||||
/* Disable DMA transmit */
|
/* Disable DMA transmit */
|
||||||
QM_I2C[i2c]->ic_dma_cr &= ~QM_I2C_IC_DMA_CR_TX_ENABLE;
|
QM_I2C[i2c]->ic_dma_cr &= ~QM_I2C_IC_DMA_CR_TX_ENABLE;
|
||||||
i2c_dma_context[i2c].ongoing_dma_tx_operation = false;
|
i2c_dma_context[i2c].ongoing_dma_tx_operation = false;
|
||||||
|
@ -805,8 +818,8 @@ static void i2c_dma_transmit_callback(void *callback_context, uint32_t len,
|
||||||
|
|
||||||
/* Check if we must issue a stop condition and it's not
|
/* Check if we must issue a stop condition and it's not
|
||||||
a combined transaction */
|
a combined transaction */
|
||||||
if ((i2c_transfer[i2c].stop == true) &&
|
if ((transfer->stop == true) &&
|
||||||
(i2c_transfer[i2c].rx_len == 0)) {
|
(transfer->rx_len == 0)) {
|
||||||
data_command |=
|
data_command |=
|
||||||
QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL;
|
QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL;
|
||||||
}
|
}
|
||||||
|
@ -816,12 +829,12 @@ static void i2c_dma_transmit_callback(void *callback_context, uint32_t len,
|
||||||
|
|
||||||
/* Check if there is a pending read operation, meaning
|
/* Check if there is a pending read operation, meaning
|
||||||
this is a combined transaction */
|
this is a combined transaction */
|
||||||
if (i2c_transfer[i2c].rx_len > 0) {
|
if (transfer->rx_len > 0) {
|
||||||
i2c_start_dma_read(i2c);
|
i2c_start_dma_read(i2c);
|
||||||
} else {
|
} else {
|
||||||
/* Let's disable the I2C controller if we are
|
/* Let's disable the I2C controller if we are
|
||||||
done */
|
done */
|
||||||
if (i2c_transfer[i2c].stop == true) {
|
if (transfer->stop == true) {
|
||||||
/* This callback is called when DMA is
|
/* This callback is called when DMA is
|
||||||
done, but I2C can still be
|
done, but I2C can still be
|
||||||
transmitting, so let's wait
|
transmitting, so let's wait
|
||||||
|
@ -834,15 +847,21 @@ static void i2c_dma_transmit_callback(void *callback_context, uint32_t len,
|
||||||
/* If user provided a callback, it'll be called
|
/* If user provided a callback, it'll be called
|
||||||
only if this is a TX only operation, not in a
|
only if this is a TX only operation, not in a
|
||||||
combined transaction */
|
combined transaction */
|
||||||
if (i2c_transfer[i2c].callback != NULL) {
|
if (transfer->callback != NULL) {
|
||||||
qm_i2c_get_status(i2c, &status);
|
qm_i2c_get_status(i2c, &status);
|
||||||
i2c_transfer[i2c].callback(
|
transfer->callback(
|
||||||
i2c_transfer[i2c].callback_data,
|
transfer->callback_data, error_code,
|
||||||
error_code, status, len);
|
status, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* If error code is 0, a multimaster arbitration loss has
|
||||||
|
happened, so use it as error code */
|
||||||
|
if (error_code == 0) {
|
||||||
|
error_code =
|
||||||
|
i2c_dma_context[i2c].multimaster_abort_status;
|
||||||
|
}
|
||||||
i2c_dma_transfer_error_callback(i2c, error_code, len);
|
i2c_dma_transfer_error_callback(i2c, error_code, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -856,26 +875,31 @@ static void i2c_dma_receive_callback(void *callback_context, uint32_t len,
|
||||||
qm_i2c_status_t status;
|
qm_i2c_status_t status;
|
||||||
|
|
||||||
qm_i2c_t i2c = ((i2c_dma_context_t *)callback_context)->i2c;
|
qm_i2c_t i2c = ((i2c_dma_context_t *)callback_context)->i2c;
|
||||||
|
const qm_i2c_transfer_t *const transfer = i2c_transfer[i2c];
|
||||||
|
|
||||||
if (error_code == 0) {
|
if ((error_code == 0) &&
|
||||||
|
(i2c_dma_context[i2c].multimaster_abort_status == 0)) {
|
||||||
/* Disable DMA receive */
|
/* Disable DMA receive */
|
||||||
QM_I2C[i2c]->ic_dma_cr &= ~QM_I2C_IC_DMA_CR_RX_ENABLE;
|
QM_I2C[i2c]->ic_dma_cr &= ~QM_I2C_IC_DMA_CR_RX_ENABLE;
|
||||||
i2c_dma_context[i2c].ongoing_dma_rx_operation = false;
|
i2c_dma_context[i2c].ongoing_dma_rx_operation = false;
|
||||||
|
|
||||||
/* Let's disable the I2C controller if we are done */
|
/* Let's disable the I2C controller if we are done */
|
||||||
if (i2c_transfer[i2c].stop == true) {
|
if (transfer->stop == true) {
|
||||||
controller_disable(i2c);
|
controller_disable(i2c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the user has provided a callback, let's call it */
|
/* If the user has provided a callback, let's call it */
|
||||||
if (i2c_transfer[i2c].callback != NULL) {
|
if (transfer->callback != NULL) {
|
||||||
qm_i2c_get_status(i2c, &status);
|
qm_i2c_get_status(i2c, &status);
|
||||||
i2c_transfer[i2c].callback(
|
transfer->callback(transfer->callback_data, error_code,
|
||||||
i2c_transfer[i2c].callback_data, error_code, status,
|
status, len);
|
||||||
len);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i2c_dma_transfer_error_callback(i2c, error_code, len);
|
/* Only call the error callback on RX error. Arbitration loss
|
||||||
|
errors are handled on the TX callback */
|
||||||
|
if (error_code != 0) {
|
||||||
|
i2c_dma_transfer_error_callback(i2c, error_code, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -994,18 +1018,21 @@ int qm_i2c_master_dma_transfer(const qm_i2c_t i2c,
|
||||||
QM_CHECK(0 == xfer->rx_len ? xfer->tx_len != 0 : 1, -EINVAL);
|
QM_CHECK(0 == xfer->rx_len ? xfer->tx_len != 0 : 1, -EINVAL);
|
||||||
|
|
||||||
/* Disable all IRQs but the TX abort one */
|
/* Disable all IRQs but the TX abort one */
|
||||||
QM_I2C[i2c]->ic_intr_mask = QM_I2C_IC_INTR_STAT_TX_ABRT;
|
QM_I2C[i2c]->ic_intr_mask = QM_I2C_IC_INTR_MASK_TX_ABORT;
|
||||||
|
|
||||||
/* write slave address to TAR */
|
/* write slave address to TAR */
|
||||||
QM_I2C[i2c]->ic_tar = slave_addr;
|
QM_I2C[i2c]->ic_tar = slave_addr;
|
||||||
|
|
||||||
memcpy(&i2c_transfer[i2c], xfer, sizeof(i2c_transfer[i2c]));
|
i2c_read_cmd_send[i2c] = xfer->rx_len;
|
||||||
|
i2c_transfer[i2c] = xfer;
|
||||||
|
|
||||||
/* Set DMA TX and RX waterlevels to 0, to make sure no data is lost */
|
/* Set DMA TX and RX waterlevels to 0, to make sure no data is lost */
|
||||||
/* NOTE: This can be optimized for performance */
|
/* NOTE: This can be optimized for performance */
|
||||||
QM_I2C[i2c]->ic_dma_rdlr = 0;
|
QM_I2C[i2c]->ic_dma_rdlr = 0;
|
||||||
QM_I2C[i2c]->ic_dma_tdlr = 0;
|
QM_I2C[i2c]->ic_dma_tdlr = 0;
|
||||||
|
|
||||||
|
i2c_dma_context[i2c].multimaster_abort_status = 0;
|
||||||
|
|
||||||
/* Setup RX if something to receive */
|
/* Setup RX if something to receive */
|
||||||
if (xfer->rx_len > 0) {
|
if (xfer->rx_len > 0) {
|
||||||
i2c_dma_context[i2c].dma_rx_transfer_config.block_size =
|
i2c_dma_context[i2c].dma_rx_transfer_config.block_size =
|
||||||
|
|
|
@ -158,6 +158,16 @@ void _qm_irq_setup(uint32_t irq, uint16_t register_offset)
|
||||||
void _qm_register_isr(uint32_t vector, qm_isr_t isr)
|
void _qm_register_isr(uint32_t vector, qm_isr_t isr)
|
||||||
{
|
{
|
||||||
#if (QM_SENSOR)
|
#if (QM_SENSOR)
|
||||||
|
/* Invalidate the i-cache line which contains the IRQ vector. This
|
||||||
|
* will bypass i-cache and set vector with the good ISR. */
|
||||||
|
__builtin_arc_sr((uint32_t)&__ivt_vect_table[0] + (vector * 4),
|
||||||
|
QM_SS_AUX_IC_IVIL);
|
||||||
|
/* All SR accesses to the IC_IVIL register must be followed by three
|
||||||
|
* NOP instructions, see chapter 3.3.59 in the datasheet
|
||||||
|
* "ARC_V2_ProgrammersReference.pdf" */
|
||||||
|
__builtin_arc_nop();
|
||||||
|
__builtin_arc_nop();
|
||||||
|
__builtin_arc_nop();
|
||||||
__ivt_vect_table[vector] = isr;
|
__ivt_vect_table[vector] = isr;
|
||||||
#else
|
#else
|
||||||
idt_set_intr_gate_desc(vector, (uint32_t)isr);
|
idt_set_intr_gate_desc(vector, (uint32_t)isr);
|
||||||
|
@ -180,7 +190,7 @@ static void ss_register_irq(unsigned int vector)
|
||||||
/* Edge sensitive. */
|
/* Edge sensitive. */
|
||||||
__builtin_arc_sr(vector, QM_SS_AUX_IRQ_SELECT);
|
__builtin_arc_sr(vector, QM_SS_AUX_IRQ_SELECT);
|
||||||
__builtin_arc_sr(QM_SS_IRQ_EDGE_SENSITIVE,
|
__builtin_arc_sr(QM_SS_IRQ_EDGE_SENSITIVE,
|
||||||
QM_SS_AUX_IRQ_TRIGER);
|
QM_SS_AUX_IRQ_TRIGGER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -131,8 +131,8 @@ int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch, qm_mbox_callback_t mpr_cb,
|
||||||
int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch,
|
int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch,
|
||||||
const qm_mbox_msg_t *const data)
|
const qm_mbox_msg_t *const data)
|
||||||
{
|
{
|
||||||
qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_SCSS_MAILBOX +
|
qm_mailbox_t *const mbox_reg =
|
||||||
mbox_ch;
|
(qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch;
|
||||||
|
|
||||||
/* Check if the previous message has been consumed. */
|
/* Check if the previous message has been consumed. */
|
||||||
if (!(mbox_reg->ch_ctrl & QM_MBOX_TRIGGER_CH_INT)) {
|
if (!(mbox_reg->ch_ctrl & QM_MBOX_TRIGGER_CH_INT)) {
|
||||||
|
@ -152,7 +152,8 @@ int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch,
|
||||||
|
|
||||||
int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const data)
|
int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const data)
|
||||||
{
|
{
|
||||||
qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch;
|
qm_mailbox_t *const mbox_reg =
|
||||||
|
(qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch;
|
||||||
|
|
||||||
/* Read data from the mailbox channel and clear bit 31 of the
|
/* Read data from the mailbox channel and clear bit 31 of the
|
||||||
* control word. */
|
* control word. */
|
||||||
|
@ -176,9 +177,9 @@ int qm_mbox_ch_get_status(const qm_mbox_ch_t mbox_ch,
|
||||||
qm_mbox_ch_status_t *const status)
|
qm_mbox_ch_status_t *const status)
|
||||||
{
|
{
|
||||||
QM_CHECK(mbox_ch < QM_MBOX_CH_NUM, -EINVAL);
|
QM_CHECK(mbox_ch < QM_MBOX_CH_NUM, -EINVAL);
|
||||||
qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_SCSS_MAILBOX +
|
qm_mailbox_t *const mbox_reg =
|
||||||
mbox_ch;
|
(qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch;
|
||||||
*status = mbox_reg->ch_sts &QM_MBOX_CH_STATUS_MASK;
|
*status = mbox_reg->ch_sts & QM_MBOX_CH_STATUS_MASK;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,14 +58,61 @@ int qm_mpr_set_config(const qm_mpr_id_t id, const qm_mpr_config_t *const cfg)
|
||||||
/* MPR Upper bound 16:10 */
|
/* MPR Upper bound 16:10 */
|
||||||
((cfg->up_bound & ADDRESS_MASK_7_BIT) << QM_MPR_UP_BOUND_OFFSET)
|
((cfg->up_bound & ADDRESS_MASK_7_BIT) << QM_MPR_UP_BOUND_OFFSET)
|
||||||
/* MPR Lower bound 6:0 */
|
/* MPR Lower bound 6:0 */
|
||||||
|
|
| cfg->low_bound;
|
||||||
cfg->low_bound;
|
|
||||||
|
|
||||||
/* enable/lock */
|
/* enable/lock */
|
||||||
QM_MPR->mpr_cfg[id] |= (cfg->en_lock_mask << QM_MPR_EN_LOCK_OFFSET);
|
QM_MPR->mpr_cfg[id] |= (cfg->en_lock_mask << QM_MPR_EN_LOCK_OFFSET);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#if (QM_SENSOR)
|
||||||
|
int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
|
||||||
|
qm_mpr_callback_t callback_fn,
|
||||||
|
void *callback_data)
|
||||||
|
{
|
||||||
|
QM_CHECK(mode <= MPR_VIOL_MODE_PROBE, -EINVAL);
|
||||||
|
/* interrupt mode */
|
||||||
|
if (MPR_VIOL_MODE_INTERRUPT == mode) {
|
||||||
|
callback = callback_fn;
|
||||||
|
callback_data = callback_data;
|
||||||
|
|
||||||
|
/* unmask interrupt */
|
||||||
|
QM_SCSS_INT->int_sram_controller_mask &=
|
||||||
|
~QM_INT_SRAM_CONTROLLER_SS_MASK;
|
||||||
|
|
||||||
|
QM_SCSS_INT->int_sram_controller_mask |=
|
||||||
|
QM_INT_SRAM_CONTROLLER_SS_HALT_MASK;
|
||||||
|
|
||||||
|
QM_SCSS_SS->ss_cfg &= ~QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* probe or reset mode */
|
||||||
|
else {
|
||||||
|
/* mask interrupt */
|
||||||
|
QM_SCSS_INT->int_sram_controller_mask |=
|
||||||
|
QM_INT_SRAM_CONTROLLER_SS_MASK;
|
||||||
|
|
||||||
|
QM_SCSS_INT->int_sram_controller_mask &=
|
||||||
|
~QM_INT_SRAM_CONTROLLER_SS_HALT_MASK;
|
||||||
|
|
||||||
|
if (MPR_VIOL_MODE_PROBE == mode) {
|
||||||
|
|
||||||
|
/* When an enabled host halt interrupt occurs, this bit
|
||||||
|
* determines if the interrupt event triggers a warm
|
||||||
|
* reset
|
||||||
|
* or an entry into Probe Mode.
|
||||||
|
* 0b : Warm Reset
|
||||||
|
* 1b : Probe Mode Entry
|
||||||
|
*/
|
||||||
|
QM_SCSS_SS->ss_cfg |=
|
||||||
|
QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
|
} else {
|
||||||
|
QM_SCSS_SS->ss_cfg &=
|
||||||
|
~QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
|
int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
|
||||||
qm_mpr_callback_t callback_fn,
|
qm_mpr_callback_t callback_fn,
|
||||||
void *callback_data)
|
void *callback_data)
|
||||||
|
@ -78,26 +125,18 @@ int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
|
||||||
|
|
||||||
/* unmask interrupt */
|
/* unmask interrupt */
|
||||||
qm_irq_unmask(QM_IRQ_SRAM);
|
qm_irq_unmask(QM_IRQ_SRAM);
|
||||||
#if defined(QM_SENSOR)
|
|
||||||
QM_SCSS_INT->int_sram_controller_mask |=
|
|
||||||
QM_INT_SRAM_CONTROLLER_SS_HALT_MASK;
|
|
||||||
#else /* QM_SENSOR */
|
|
||||||
QM_SCSS_INT->int_sram_controller_mask |=
|
QM_SCSS_INT->int_sram_controller_mask |=
|
||||||
QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK;
|
QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK;
|
||||||
#endif /* QM_SENSOR */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* probe or reset mode */
|
/* probe or reset mode */
|
||||||
else {
|
else {
|
||||||
/* mask interrupt */
|
/* mask interrupt */
|
||||||
qm_irq_mask(QM_IRQ_SRAM);
|
qm_irq_mask(QM_IRQ_SRAM);
|
||||||
#if defined(QM_SENSOR)
|
|
||||||
QM_SCSS_INT->int_sram_controller_mask &=
|
|
||||||
~QM_INT_SRAM_CONTROLLER_SS_HALT_MASK;
|
|
||||||
#else /* QM_SENSOR */
|
|
||||||
QM_SCSS_INT->int_sram_controller_mask &=
|
QM_SCSS_INT->int_sram_controller_mask &=
|
||||||
~QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK;
|
~QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK;
|
||||||
#endif /* QM_SENSOR */
|
|
||||||
|
|
||||||
if (MPR_VIOL_MODE_PROBE == mode) {
|
if (MPR_VIOL_MODE_PROBE == mode) {
|
||||||
|
|
||||||
|
@ -110,12 +149,11 @@ int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
|
||||||
*/
|
*/
|
||||||
QM_SCSS_PMU->p_sts |=
|
QM_SCSS_PMU->p_sts |=
|
||||||
QM_P_STS_HALT_INTERRUPT_REDIRECTION;
|
QM_P_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
else {
|
|
||||||
QM_SCSS_PMU->p_sts &=
|
QM_SCSS_PMU->p_sts &=
|
||||||
~QM_P_STS_HALT_INTERRUPT_REDIRECTION;
|
~QM_P_STS_HALT_INTERRUPT_REDIRECTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* QM_SENSOR */
|
|
@ -37,6 +37,33 @@ QM_ISR_DECLARE(qm_rtc_isr_0)
|
||||||
/* Disable RTC interrupt */
|
/* Disable RTC interrupt */
|
||||||
QM_RTC[QM_RTC_0].rtc_ccr &= ~QM_RTC_CCR_INTERRUPT_ENABLE;
|
QM_RTC[QM_RTC_0].rtc_ccr &= ~QM_RTC_CCR_INTERRUPT_ENABLE;
|
||||||
|
|
||||||
|
#if (QUARK_D2000)
|
||||||
|
/*
|
||||||
|
* If the SoC is in deep sleep mode, all the clocks are gated, if the
|
||||||
|
* interrupt source is cleared before the oscillators are ungated, the
|
||||||
|
* oscillators return to a powered down state and the SoC will not
|
||||||
|
* return to an active state then.
|
||||||
|
*/
|
||||||
|
if ((QM_SCSS_GP->gps1 & QM_SCSS_GP_POWER_STATES_MASK) ==
|
||||||
|
QM_SCSS_GP_POWER_STATE_DEEP_SLEEP) {
|
||||||
|
/* Return the oscillators to an active state. */
|
||||||
|
QM_SCSS_CCU->osc0_cfg1 &=
|
||||||
|
~QM_OSC0_PD; /* power on the oscillator. */
|
||||||
|
QM_SCSS_CCU->osc1_cfg0 &=
|
||||||
|
~QM_OSC1_PD; /* power on crystal oscillator. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* datasheet 9.1.2 Low Power State to Active
|
||||||
|
*
|
||||||
|
* FW to program HYB_OSC_PD_LATCH_EN = 1, RTC_OSC_PD_LATCH_EN=1
|
||||||
|
* so that OSC0_PD and OSC1_PD values directly control the
|
||||||
|
* oscillators in active state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
QM_SCSS_CCU->ccu_lp_clk_ctl |=
|
||||||
|
(QM_HYB_OSC_PD_LATCH_EN | QM_RTC_OSC_PD_LATCH_EN);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (callback[QM_RTC_0]) {
|
if (callback[QM_RTC_0]) {
|
||||||
(callback[QM_RTC_0])(callback_data[QM_RTC_0]);
|
(callback[QM_RTC_0])(callback_data[QM_RTC_0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,17 @@
|
||||||
|
|
||||||
/* SPI DMA transmit watermark level. When the number of valid data entries in
|
/* SPI DMA transmit watermark level. When the number of valid data entries in
|
||||||
* the transmit FIFO is equal to or below this field value, dma_tx_req is
|
* the transmit FIFO is equal to or below this field value, dma_tx_req is
|
||||||
* generated. The burst length has to fit in the remaining space of the transmit
|
* generated. The destination burst length has to fit in the remaining space
|
||||||
* FIFO, i.e. the burst length cannot be bigger than (16 - watermark level). */
|
* of the transmit FIFO, thus it must be <= (SPI_FIFOS_DEPTH - TDLR).
|
||||||
#define SPI_DMATDLR_DMATDL (0x03)
|
* For optimal results it must be set to that delta so we can ensure the number
|
||||||
|
* of DMA transactions (bursts) needed are minimal, leading to a better bus
|
||||||
|
* utilization.
|
||||||
|
*
|
||||||
|
* With that in mind, here we choose 4 frames as a watermark level (TDLR) so we
|
||||||
|
* can end up with a valid value for SPI_DMA_WRITE_BURST_LENGTH of 4 frames,
|
||||||
|
* still adhering to the above (FIFOS_DEPTH - TDLR = 4).
|
||||||
|
*/
|
||||||
|
#define SPI_DMATDLR_DMATDL (0x4)
|
||||||
#define SPI_DMA_WRITE_BURST_LENGTH QM_DMA_BURST_TRANS_LENGTH_4
|
#define SPI_DMA_WRITE_BURST_LENGTH QM_DMA_BURST_TRANS_LENGTH_4
|
||||||
|
|
||||||
/* SPI DMA receive watermark level. When the number of valid data entries in the
|
/* SPI DMA receive watermark level. When the number of valid data entries in the
|
||||||
|
@ -50,13 +58,21 @@
|
||||||
* 0 1
|
* 0 1
|
||||||
* 3 4
|
* 3 4
|
||||||
* 7 (highest) 8
|
* 7 (highest) 8
|
||||||
|
*
|
||||||
|
* By keeping SPI_DMA_READ_BURST_LENGTH = RDLR + 1, we have optimal results
|
||||||
|
* since it reduces the number of DMA transactions, leading to a better bus
|
||||||
|
* utilization.
|
||||||
|
*
|
||||||
|
* Note that, unlike we do for IRQ transfers, there is no need to adjust the
|
||||||
|
* watermark level (RDLR for DMA transfers, RXFTLR for IRQ ones) during or at
|
||||||
|
* the start of the DMA transaction, if rx_len < RDLR. This is done
|
||||||
|
* automatically
|
||||||
|
* by the SPI DMA interface when it decides between burst or single transactions
|
||||||
|
* through means of the BLOCK_TS and SRC_MSIZE ratio.
|
||||||
*/
|
*/
|
||||||
#define SPI_DMARDLR_DMARDL (0x03)
|
#define SPI_DMARDLR_DMARDL (0x03)
|
||||||
#define SPI_DMA_READ_BURST_LENGTH QM_DMA_BURST_TRANS_LENGTH_4
|
#define SPI_DMA_READ_BURST_LENGTH QM_DMA_BURST_TRANS_LENGTH_4
|
||||||
|
|
||||||
/* Arbitrary byte sent in RX-only mode. */
|
|
||||||
#define SPI_RX_ONLY_DUMMY_BYTE (0xf0)
|
|
||||||
|
|
||||||
/* DMA transfer information, relevant on callback invocations from the DMA
|
/* DMA transfer information, relevant on callback invocations from the DMA
|
||||||
* driver. */
|
* driver. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -81,7 +97,7 @@ qm_spi_reg_t *qm_spi_controllers[QM_SPI_NUM] = {
|
||||||
static const qm_spi_async_transfer_t *spi_async_transfer[QM_SPI_NUM];
|
static const qm_spi_async_transfer_t *spi_async_transfer[QM_SPI_NUM];
|
||||||
static volatile uint16_t tx_counter[QM_SPI_NUM], rx_counter[QM_SPI_NUM];
|
static volatile uint16_t tx_counter[QM_SPI_NUM], rx_counter[QM_SPI_NUM];
|
||||||
static uint8_t dfs[QM_SPI_NUM];
|
static uint8_t dfs[QM_SPI_NUM];
|
||||||
static const uint32_t tx_dummy_frame = SPI_RX_ONLY_DUMMY_BYTE;
|
static const uint32_t tx_dummy_frame = 0;
|
||||||
static qm_spi_tmode_t tmode[QM_SPI_NUM];
|
static qm_spi_tmode_t tmode[QM_SPI_NUM];
|
||||||
/* DMA (memory to SPI controller) callback information. */
|
/* DMA (memory to SPI controller) callback information. */
|
||||||
static dma_context_t dma_context_tx[QM_SPI_NUM];
|
static dma_context_t dma_context_tx[QM_SPI_NUM];
|
||||||
|
@ -220,8 +236,7 @@ static void handle_spi_interrupt(const qm_spi_t spi)
|
||||||
if (int_status & QM_SPI_ISR_RXOIS) {
|
if (int_status & QM_SPI_ISR_RXOIS) {
|
||||||
if (transfer->callback) {
|
if (transfer->callback) {
|
||||||
transfer->callback(transfer->callback_data, -EIO,
|
transfer->callback(transfer->callback_data, -EIO,
|
||||||
QM_SPI_RX_OVERFLOW,
|
QM_SPI_RX_OVERFLOW, rx_counter[spi]);
|
||||||
rx_counter[spi]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
controller->rxoicr;
|
controller->rxoicr;
|
||||||
|
@ -361,8 +376,6 @@ int qm_spi_transfer(const qm_spi_t spi, const qm_spi_transfer_t *const xfer,
|
||||||
uint8_t *rx_buffer = xfer->rx;
|
uint8_t *rx_buffer = xfer->rx;
|
||||||
const uint8_t *tx_buffer = xfer->tx;
|
const uint8_t *tx_buffer = xfer->tx;
|
||||||
|
|
||||||
int frames;
|
|
||||||
|
|
||||||
/* RX Only transfers need a dummy byte to be sent for starting.
|
/* RX Only transfers need a dummy byte to be sent for starting.
|
||||||
* This is covered by the databook on page 42.
|
* This is covered by the databook on page 42.
|
||||||
*/
|
*/
|
||||||
|
@ -381,33 +394,21 @@ int qm_spi_transfer(const qm_spi_t spi, const qm_spi_transfer_t *const xfer,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (i_rx && controller->rxflr) {
|
if (i_rx && (controller->sr & QM_SPI_SR_RFNE)) {
|
||||||
read_frame(spi, rx_buffer);
|
read_frame(spi, rx_buffer);
|
||||||
rx_buffer += dfs[spi];
|
rx_buffer += dfs[spi];
|
||||||
i_rx--;
|
i_rx--;
|
||||||
}
|
}
|
||||||
|
|
||||||
frames =
|
if (i_tx && (controller->sr & QM_SPI_SR_TFNF)) {
|
||||||
SPI_FIFOS_DEPTH - controller->txflr - controller->rxflr - 1;
|
|
||||||
while (i_tx && frames) {
|
|
||||||
write_frame(spi, tx_buffer);
|
write_frame(spi, tx_buffer);
|
||||||
tx_buffer += dfs[spi];
|
tx_buffer += dfs[spi];
|
||||||
i_tx--;
|
i_tx--;
|
||||||
frames--;
|
|
||||||
}
|
|
||||||
/* Databook page 43 says we always need to busy-wait until the
|
|
||||||
* controller is ready again after writing frames to the TX
|
|
||||||
* FIFO.
|
|
||||||
*
|
|
||||||
* That is only needed for TX or TX_RX transfer modes.
|
|
||||||
*/
|
|
||||||
if (tmode[spi] == QM_SPI_TMOD_TX_RX ||
|
|
||||||
tmode[spi] == QM_SPI_TMOD_TX) {
|
|
||||||
wait_for_controller(controller);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
wait_for_controller(controller);
|
||||||
|
|
||||||
controller->ssienr = 0; /** Disable SPI Device */
|
controller->ssienr = 0; /* Disable SPI Device */
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -548,12 +549,10 @@ static void spi_dma_callback(void *callback_context, uint32_t len,
|
||||||
/* TX transfer. */
|
/* TX transfer. */
|
||||||
frames_expected = transfer->tx_len;
|
frames_expected = transfer->tx_len;
|
||||||
cb_pending_alternate_p = &dma_context_rx[spi].cb_pending;
|
cb_pending_alternate_p = &dma_context_rx[spi].cb_pending;
|
||||||
} else if (dma_context_p == &dma_context_rx[spi]) {
|
} else {
|
||||||
/* RX tranfer. */
|
/* RX transfer. */
|
||||||
frames_expected = transfer->rx_len;
|
frames_expected = transfer->rx_len;
|
||||||
cb_pending_alternate_p = &dma_context_tx[spi].cb_pending;
|
cb_pending_alternate_p = &dma_context_tx[spi].cb_pending;
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QM_ASSERT(cb_pending_alternate_p);
|
QM_ASSERT(cb_pending_alternate_p);
|
||||||
|
@ -598,7 +597,6 @@ int qm_spi_dma_channel_config(
|
||||||
QM_CHECK(dma_ctrl_id < QM_DMA_NUM, -EINVAL);
|
QM_CHECK(dma_ctrl_id < QM_DMA_NUM, -EINVAL);
|
||||||
QM_CHECK(dma_channel_id < QM_DMA_CHANNEL_NUM, -EINVAL);
|
QM_CHECK(dma_channel_id < QM_DMA_CHANNEL_NUM, -EINVAL);
|
||||||
|
|
||||||
int ret = -EINVAL;
|
|
||||||
dma_context_t *dma_context_p = NULL;
|
dma_context_t *dma_context_p = NULL;
|
||||||
qm_dma_channel_config_t dma_chan_cfg = {0};
|
qm_dma_channel_config_t dma_chan_cfg = {0};
|
||||||
dma_chan_cfg.handshake_polarity = QM_DMA_HANDSHAKE_POLARITY_HIGH;
|
dma_chan_cfg.handshake_polarity = QM_DMA_HANDSHAKE_POLARITY_HIGH;
|
||||||
|
@ -630,21 +628,14 @@ int qm_spi_dma_channel_config(
|
||||||
|
|
||||||
switch (dma_channel_direction) {
|
switch (dma_channel_direction) {
|
||||||
case QM_DMA_MEMORY_TO_PERIPHERAL:
|
case QM_DMA_MEMORY_TO_PERIPHERAL:
|
||||||
switch (spi) {
|
|
||||||
case QM_SPI_MST_0:
|
|
||||||
dma_chan_cfg.handshake_interface =
|
|
||||||
DMA_HW_IF_SPI_MASTER_0_TX;
|
|
||||||
break;
|
|
||||||
#if (QUARK_SE)
|
#if (QUARK_SE)
|
||||||
case QM_SPI_MST_1:
|
dma_chan_cfg.handshake_interface =
|
||||||
dma_chan_cfg.handshake_interface =
|
(QM_SPI_MST_0 == spi) ? DMA_HW_IF_SPI_MASTER_0_TX
|
||||||
DMA_HW_IF_SPI_MASTER_1_TX;
|
: DMA_HW_IF_SPI_MASTER_1_TX;
|
||||||
break;
|
#else
|
||||||
|
dma_chan_cfg.handshake_interface = DMA_HW_IF_SPI_MASTER_0_TX;
|
||||||
#endif
|
#endif
|
||||||
default:
|
|
||||||
/* Slave SPI is not supported. */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The DMA burst length has to fit in the space remaining in the
|
/* The DMA burst length has to fit in the space remaining in the
|
||||||
* TX FIFO after the watermark level, DMATDLR. */
|
* TX FIFO after the watermark level, DMATDLR. */
|
||||||
|
@ -656,22 +647,14 @@ int qm_spi_dma_channel_config(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QM_DMA_PERIPHERAL_TO_MEMORY:
|
case QM_DMA_PERIPHERAL_TO_MEMORY:
|
||||||
switch (spi) {
|
|
||||||
case QM_SPI_MST_0:
|
|
||||||
dma_chan_cfg.handshake_interface =
|
|
||||||
DMA_HW_IF_SPI_MASTER_0_RX;
|
|
||||||
break;
|
|
||||||
#if (QUARK_SE)
|
|
||||||
case QM_SPI_MST_1:
|
|
||||||
dma_chan_cfg.handshake_interface =
|
|
||||||
DMA_HW_IF_SPI_MASTER_1_RX;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
/* Slave SPI is not supported. */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#if (QUARK_SE)
|
||||||
|
dma_chan_cfg.handshake_interface =
|
||||||
|
(QM_SPI_MST_0 == spi) ? DMA_HW_IF_SPI_MASTER_0_RX
|
||||||
|
: DMA_HW_IF_SPI_MASTER_1_RX;
|
||||||
|
#else
|
||||||
|
dma_chan_cfg.handshake_interface = DMA_HW_IF_SPI_MASTER_0_RX;
|
||||||
|
#endif
|
||||||
/* The DMA burst length has to match the value of the receive
|
/* The DMA burst length has to match the value of the receive
|
||||||
* watermark level, DMARDLR + 1. */
|
* watermark level, DMARDLR + 1. */
|
||||||
dma_chan_cfg.source_burst_length = SPI_DMA_READ_BURST_LENGTH;
|
dma_chan_cfg.source_burst_length = SPI_DMA_READ_BURST_LENGTH;
|
||||||
|
@ -693,12 +676,6 @@ int qm_spi_dma_channel_config(
|
||||||
QM_ASSERT(dma_context_p);
|
QM_ASSERT(dma_context_p);
|
||||||
dma_chan_cfg.callback_context = dma_context_p;
|
dma_chan_cfg.callback_context = dma_context_p;
|
||||||
|
|
||||||
ret = qm_dma_channel_set_config(dma_ctrl_id, dma_channel_id,
|
|
||||||
&dma_chan_cfg);
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* To be used on received DMA callback. */
|
/* To be used on received DMA callback. */
|
||||||
dma_context_p->spi_id = spi;
|
dma_context_p->spi_id = spi;
|
||||||
dma_context_p->dma_channel_id = dma_channel_id;
|
dma_context_p->dma_channel_id = dma_channel_id;
|
||||||
|
@ -706,7 +683,8 @@ int qm_spi_dma_channel_config(
|
||||||
/* To be used on transfer setup. */
|
/* To be used on transfer setup. */
|
||||||
dma_core[spi] = dma_ctrl_id;
|
dma_core[spi] = dma_ctrl_id;
|
||||||
|
|
||||||
return 0;
|
return qm_dma_channel_set_config(dma_ctrl_id, dma_channel_id,
|
||||||
|
&dma_chan_cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int qm_spi_dma_transfer(const qm_spi_t spi,
|
int qm_spi_dma_transfer(const qm_spi_t spi,
|
||||||
|
|
|
@ -47,17 +47,20 @@ typedef struct {
|
||||||
const qm_uart_transfer_t *xfer; /**< User transfer structure. */
|
const qm_uart_transfer_t *xfer; /**< User transfer structure. */
|
||||||
} dma_context_t;
|
} dma_context_t;
|
||||||
|
|
||||||
/* UART Callback pointers. */
|
/**
|
||||||
static uart_client_callback_t write_callback[QM_UART_NUM];
|
* Parameters returned by DMA driver on DMA transfer complete callback.
|
||||||
static uart_client_callback_t read_callback[QM_UART_NUM];
|
*/
|
||||||
|
typedef volatile struct {
|
||||||
/* User callback data. */
|
void *context; /**< Pointer to dma_context_t struct. */
|
||||||
static void *write_data[QM_UART_NUM], *read_data[QM_UART_NUM];
|
uint32_t len; /**< Amount of data successfully transferred. */
|
||||||
|
int error_code; /**< Error code of failed transfer. */
|
||||||
|
} dma_callback_par_t;
|
||||||
|
|
||||||
/* Buffer pointers to store transmit / receive data for UART */
|
/* Buffer pointers to store transmit / receive data for UART */
|
||||||
static uint8_t *write_buffer[QM_UART_NUM], *read_buffer[QM_UART_NUM];
|
static uint32_t write_pos[QM_UART_NUM];
|
||||||
static uint32_t write_pos[QM_UART_NUM], write_len[QM_UART_NUM];
|
static uint32_t read_pos[QM_UART_NUM];
|
||||||
static uint32_t read_pos[QM_UART_NUM], read_len[QM_UART_NUM];
|
static const qm_uart_transfer_t *uart_read_transfer[QM_UART_NUM];
|
||||||
|
static const qm_uart_transfer_t *uart_write_transfer[QM_UART_NUM];
|
||||||
|
|
||||||
/* DMA (memory to UART) callback information. */
|
/* DMA (memory to UART) callback information. */
|
||||||
static dma_context_t dma_context_tx[QM_UART_NUM];
|
static dma_context_t dma_context_tx[QM_UART_NUM];
|
||||||
|
@ -65,21 +68,34 @@ static dma_context_t dma_context_tx[QM_UART_NUM];
|
||||||
static dma_context_t dma_context_rx[QM_UART_NUM];
|
static dma_context_t dma_context_rx[QM_UART_NUM];
|
||||||
/* DMA core being used by each UART. */
|
/* DMA core being used by each UART. */
|
||||||
static qm_dma_t dma_core[QM_UART_NUM];
|
static qm_dma_t dma_core[QM_UART_NUM];
|
||||||
|
/* DMA callback parameters returned by DMA driver (TX transfers). */
|
||||||
|
static dma_callback_par_t dma_delayed_callback_par[QM_UART_NUM];
|
||||||
|
|
||||||
static bool is_read_xfer_complete(const qm_uart_t uart)
|
static bool is_read_xfer_complete(const qm_uart_t uart)
|
||||||
{
|
{
|
||||||
return read_pos[uart] >= read_len[uart];
|
const qm_uart_transfer_t *const transfer = uart_read_transfer[uart];
|
||||||
|
|
||||||
|
return read_pos[uart] >= transfer->data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_write_xfer_complete(const qm_uart_t uart)
|
static bool is_write_xfer_complete(const qm_uart_t uart)
|
||||||
{
|
{
|
||||||
return write_pos[uart] >= write_len[uart];
|
const qm_uart_transfer_t *const transfer = uart_write_transfer[uart];
|
||||||
|
|
||||||
|
return write_pos[uart] >= transfer->data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void uart_client_callback(void *data, int error, qm_uart_status_t status,
|
||||||
|
uint32_t len);
|
||||||
|
|
||||||
static void qm_uart_isr_handler(const qm_uart_t uart)
|
static void qm_uart_isr_handler(const qm_uart_t uart)
|
||||||
{
|
{
|
||||||
qm_uart_reg_t *const regs = QM_UART[uart];
|
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||||
uint8_t interrupt_id = regs->iir_fcr & QM_UART_IIR_IID_MASK;
|
uint8_t interrupt_id = regs->iir_fcr & QM_UART_IIR_IID_MASK;
|
||||||
|
const qm_uart_transfer_t *const read_transfer =
|
||||||
|
uart_read_transfer[uart];
|
||||||
|
const qm_uart_transfer_t *const write_transfer =
|
||||||
|
uart_write_transfer[uart];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Interrupt ID priority levels (from highest to lowest):
|
* Interrupt ID priority levels (from highest to lowest):
|
||||||
|
@ -89,6 +105,22 @@ static void qm_uart_isr_handler(const qm_uart_t uart)
|
||||||
*/
|
*/
|
||||||
switch (interrupt_id) {
|
switch (interrupt_id) {
|
||||||
case QM_UART_IIR_THR_EMPTY:
|
case QM_UART_IIR_THR_EMPTY:
|
||||||
|
|
||||||
|
if (dma_delayed_callback_par[uart].context) {
|
||||||
|
/*
|
||||||
|
* A DMA TX transfer just completed, disable interrupt
|
||||||
|
* and invoke client callback.
|
||||||
|
*/
|
||||||
|
regs->ier_dlh &= ~QM_UART_IER_ETBEI;
|
||||||
|
|
||||||
|
uart_client_callback(
|
||||||
|
dma_delayed_callback_par[uart].context,
|
||||||
|
dma_delayed_callback_par[uart].error_code,
|
||||||
|
QM_UART_IDLE, dma_delayed_callback_par[uart].len);
|
||||||
|
dma_delayed_callback_par[uart].context = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_write_xfer_complete(uart)) {
|
if (is_write_xfer_complete(uart)) {
|
||||||
regs->ier_dlh &= ~QM_UART_IER_ETBEI;
|
regs->ier_dlh &= ~QM_UART_IER_ETBEI;
|
||||||
/*
|
/*
|
||||||
|
@ -99,10 +131,10 @@ static void qm_uart_isr_handler(const qm_uart_t uart)
|
||||||
* complete.
|
* complete.
|
||||||
*/
|
*/
|
||||||
regs->scr |= BIT(0);
|
regs->scr |= BIT(0);
|
||||||
if (write_callback[uart]) {
|
if (write_transfer->callback) {
|
||||||
write_callback[uart](write_data[uart], 0,
|
write_transfer->callback(
|
||||||
QM_UART_IDLE,
|
write_transfer->callback_data, 0,
|
||||||
write_pos[uart]);
|
QM_UART_IDLE, write_pos[uart]);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -116,7 +148,7 @@ static void qm_uart_isr_handler(const qm_uart_t uart)
|
||||||
: QM_UART_FIFO_HALF_DEPTH;
|
: QM_UART_FIFO_HALF_DEPTH;
|
||||||
while (count-- && !is_write_xfer_complete(uart)) {
|
while (count-- && !is_write_xfer_complete(uart)) {
|
||||||
regs->rbr_thr_dll =
|
regs->rbr_thr_dll =
|
||||||
write_buffer[uart][write_pos[uart]++];
|
write_transfer->data[write_pos[uart]++];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -148,14 +180,14 @@ static void qm_uart_isr_handler(const qm_uart_t uart)
|
||||||
* in the future.
|
* in the future.
|
||||||
*/
|
*/
|
||||||
if (lsr & QM_UART_LSR_ERROR_BITS) {
|
if (lsr & QM_UART_LSR_ERROR_BITS) {
|
||||||
if (read_callback[uart]) {
|
if (read_transfer->callback) {
|
||||||
read_callback[uart](
|
read_transfer->callback(
|
||||||
read_data[uart], -EIO,
|
read_transfer->callback_data, -EIO,
|
||||||
lsr & QM_UART_LSR_ERROR_BITS, 0);
|
lsr & QM_UART_LSR_ERROR_BITS, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lsr & QM_UART_LSR_DR) {
|
if (lsr & QM_UART_LSR_DR) {
|
||||||
read_buffer[uart][read_pos[uart]++] =
|
read_transfer->data[read_pos[uart]++] =
|
||||||
regs->rbr_thr_dll;
|
regs->rbr_thr_dll;
|
||||||
} else {
|
} else {
|
||||||
/* No more data in the RX FIFO */
|
/* No more data in the RX FIFO */
|
||||||
|
@ -170,24 +202,24 @@ static void qm_uart_isr_handler(const qm_uart_t uart)
|
||||||
*/
|
*/
|
||||||
regs->ier_dlh &=
|
regs->ier_dlh &=
|
||||||
~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
|
~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
|
||||||
if (read_callback[uart]) {
|
if (read_transfer->callback) {
|
||||||
read_callback[uart](read_data[uart], 0,
|
read_transfer->callback(
|
||||||
QM_UART_IDLE,
|
read_transfer->callback_data, 0,
|
||||||
read_pos[uart]);
|
QM_UART_IDLE, read_pos[uart]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QM_UART_IIR_RECV_LINE_STATUS:
|
case QM_UART_IIR_RECV_LINE_STATUS:
|
||||||
if (read_callback[uart]) {
|
if (read_transfer->callback) {
|
||||||
/*
|
/*
|
||||||
* NOTE: Returned len is 0 for now, this might change
|
* NOTE: Returned len is 0 for now, this might change
|
||||||
* in the future.
|
* in the future.
|
||||||
*/
|
*/
|
||||||
read_callback[uart](read_data[uart], -EIO,
|
read_transfer->callback(
|
||||||
regs->lsr & QM_UART_LSR_ERROR_BITS,
|
read_transfer->callback_data, -EIO,
|
||||||
0);
|
regs->lsr & QM_UART_LSR_ERROR_BITS, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -363,10 +395,7 @@ int qm_uart_irq_write(const qm_uart_t uart,
|
||||||
qm_uart_reg_t *const regs = QM_UART[uart];
|
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||||
|
|
||||||
write_pos[uart] = 0;
|
write_pos[uart] = 0;
|
||||||
write_len[uart] = xfer->data_len;
|
uart_write_transfer[uart] = xfer;
|
||||||
write_buffer[uart] = xfer->data;
|
|
||||||
write_callback[uart] = xfer->callback;
|
|
||||||
write_data[uart] = xfer->callback_data;
|
|
||||||
|
|
||||||
/* Set threshold */
|
/* Set threshold */
|
||||||
regs->iir_fcr =
|
regs->iir_fcr =
|
||||||
|
@ -386,10 +415,7 @@ int qm_uart_irq_read(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
|
||||||
qm_uart_reg_t *const regs = QM_UART[uart];
|
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||||
|
|
||||||
read_pos[uart] = 0;
|
read_pos[uart] = 0;
|
||||||
read_len[uart] = xfer->data_len;
|
uart_read_transfer[uart] = xfer;
|
||||||
read_buffer[uart] = xfer->data;
|
|
||||||
read_callback[uart] = xfer->callback;
|
|
||||||
read_data[uart] = xfer->callback_data;
|
|
||||||
|
|
||||||
/* Set threshold */
|
/* Set threshold */
|
||||||
regs->iir_fcr =
|
regs->iir_fcr =
|
||||||
|
@ -409,14 +435,14 @@ int qm_uart_irq_write_terminate(const qm_uart_t uart)
|
||||||
QM_CHECK(uart < QM_UART_NUM, -EINVAL);
|
QM_CHECK(uart < QM_UART_NUM, -EINVAL);
|
||||||
|
|
||||||
qm_uart_reg_t *const regs = QM_UART[uart];
|
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||||
|
const qm_uart_transfer_t *const transfer = uart_write_transfer[uart];
|
||||||
|
|
||||||
/* Disable TX holding reg empty interrupt. */
|
/* Disable TX holding reg empty interrupt. */
|
||||||
regs->ier_dlh &= ~QM_UART_IER_ETBEI;
|
regs->ier_dlh &= ~QM_UART_IER_ETBEI;
|
||||||
if (write_callback[uart]) {
|
if (transfer->callback) {
|
||||||
write_callback[uart](write_data[uart], -ECANCELED, QM_UART_IDLE,
|
transfer->callback(transfer->callback_data, -ECANCELED,
|
||||||
write_pos[uart]);
|
QM_UART_IDLE, write_pos[uart]);
|
||||||
}
|
}
|
||||||
write_len[uart] = 0;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -426,28 +452,71 @@ int qm_uart_irq_read_terminate(const qm_uart_t uart)
|
||||||
QM_CHECK(uart < QM_UART_NUM, -EINVAL);
|
QM_CHECK(uart < QM_UART_NUM, -EINVAL);
|
||||||
|
|
||||||
qm_uart_reg_t *const regs = QM_UART[uart];
|
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||||
|
const qm_uart_transfer_t *const transfer = uart_read_transfer[uart];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable both 'Receiver Data Available' and 'Receiver Line Status'
|
* Disable both 'Receiver Data Available' and 'Receiver Line Status'
|
||||||
* interrupts.
|
* interrupts.
|
||||||
*/
|
*/
|
||||||
regs->ier_dlh &= ~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
|
regs->ier_dlh &= ~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
|
||||||
if (read_callback[uart]) {
|
if (transfer->callback) {
|
||||||
read_callback[uart](read_data[uart], -ECANCELED, QM_UART_IDLE,
|
transfer->callback(transfer->callback_data, -ECANCELED,
|
||||||
read_pos[uart]);
|
QM_UART_IDLE, read_pos[uart]);
|
||||||
}
|
}
|
||||||
read_len[uart] = 0;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DMA driver invoked callback. */
|
/*
|
||||||
|
* Called by the DMA driver when the whole TX buffer has been written to the TX
|
||||||
|
* FIFO (write transfers) or the expected amount of data has been read from the
|
||||||
|
* RX FIFO (read transfers).
|
||||||
|
*/
|
||||||
static void uart_dma_callback(void *callback_context, uint32_t len,
|
static void uart_dma_callback(void *callback_context, uint32_t len,
|
||||||
int error_code)
|
int error_code)
|
||||||
{
|
{
|
||||||
QM_ASSERT(callback_context);
|
QM_ASSERT(callback_context);
|
||||||
const qm_uart_transfer_t *const xfer =
|
/*
|
||||||
((dma_context_t *)callback_context)->xfer;
|
* On TX transfers, the DMA driver invokes this function as soon as all
|
||||||
|
* data has been written to the TX FIFO, but we still need to wait until
|
||||||
|
* everything has been written to the shift register (TX FIFO empty
|
||||||
|
* interrupt) before the client callback is invoked.
|
||||||
|
*/
|
||||||
|
if (callback_context >= (void *)&dma_context_tx[0] &&
|
||||||
|
callback_context <= (void *)&dma_context_tx[QM_UART_NUM - 1]) {
|
||||||
|
/*
|
||||||
|
* callback_context is within dma_context_tx array so this is a
|
||||||
|
* TX transfer, we extract the uart index from the position in
|
||||||
|
* the array.
|
||||||
|
*/
|
||||||
|
const qm_uart_t uart =
|
||||||
|
(dma_context_t *)callback_context - dma_context_tx;
|
||||||
|
QM_ASSERT(callback_context == (void *)&dma_context_tx[uart]);
|
||||||
|
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||||
|
|
||||||
|
dma_delayed_callback_par[uart].context = callback_context;
|
||||||
|
dma_delayed_callback_par[uart].len = len;
|
||||||
|
dma_delayed_callback_par[uart].error_code = error_code;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change the threshold level to trigger an interrupt when the
|
||||||
|
* TX FIFO is empty and enable the TX FIFO empty interrupt.
|
||||||
|
*/
|
||||||
|
regs->iir_fcr =
|
||||||
|
(QM_UART_FCR_FIFOE | QM_UART_FCR_TX_0_RX_1_2_THRESHOLD);
|
||||||
|
regs->ier_dlh |= QM_UART_IER_ETBEI;
|
||||||
|
} else {
|
||||||
|
/* RX transfer. */
|
||||||
|
uart_client_callback(callback_context, error_code, QM_UART_IDLE,
|
||||||
|
len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Invoke the UART client callback. */
|
||||||
|
static void uart_client_callback(void *data, int error, qm_uart_status_t status,
|
||||||
|
uint32_t len)
|
||||||
|
{
|
||||||
|
const qm_uart_transfer_t *const xfer = ((dma_context_t *)data)->xfer;
|
||||||
QM_ASSERT(xfer);
|
QM_ASSERT(xfer);
|
||||||
const uart_client_callback_t client_callback = xfer->callback;
|
const uart_client_callback_t client_callback = xfer->callback;
|
||||||
void *const client_data = xfer->callback_data;
|
void *const client_data = xfer->callback_data;
|
||||||
|
@ -457,19 +526,19 @@ static void uart_dma_callback(void *callback_context, uint32_t len,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error_code) {
|
if (error) {
|
||||||
/*
|
/*
|
||||||
* Transfer failed, pass to client the error code returned by
|
* Transfer failed, pass to client the error code returned by
|
||||||
* the DMA driver.
|
* the DMA driver.
|
||||||
*/
|
*/
|
||||||
client_callback(client_data, error_code, QM_UART_IDLE, 0);
|
client_callback(client_data, error, status, 0);
|
||||||
} else if (len == client_expected_len) {
|
} else if (len == client_expected_len) {
|
||||||
/* Transfer completed successfully. */
|
/* Transfer completed successfully. */
|
||||||
client_callback(client_data, 0, QM_UART_IDLE, len);
|
client_callback(client_data, 0, status, len);
|
||||||
} else {
|
} else {
|
||||||
QM_ASSERT(len < client_expected_len);
|
QM_ASSERT(len < client_expected_len);
|
||||||
/* Transfer cancelled. */
|
/* Transfer cancelled. */
|
||||||
client_callback(client_data, -ECANCELED, QM_UART_IDLE, len);
|
client_callback(client_data, -ECANCELED, status, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,16 +565,9 @@ int qm_uart_dma_channel_config(
|
||||||
|
|
||||||
switch (dma_channel_direction) {
|
switch (dma_channel_direction) {
|
||||||
case QM_DMA_MEMORY_TO_PERIPHERAL:
|
case QM_DMA_MEMORY_TO_PERIPHERAL:
|
||||||
switch (uart) {
|
dma_chan_cfg.handshake_interface = (QM_UART_0 == uart)
|
||||||
case QM_UART_0:
|
? DMA_HW_IF_UART_A_TX
|
||||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_UART_A_TX;
|
: DMA_HW_IF_UART_B_TX;
|
||||||
break;
|
|
||||||
case QM_UART_1:
|
|
||||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_UART_B_TX;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The DMA driver needs a pointer to the DMA context structure
|
* The DMA driver needs a pointer to the DMA context structure
|
||||||
|
@ -516,16 +578,9 @@ int qm_uart_dma_channel_config(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QM_DMA_PERIPHERAL_TO_MEMORY:
|
case QM_DMA_PERIPHERAL_TO_MEMORY:
|
||||||
switch (uart) {
|
dma_chan_cfg.handshake_interface = (QM_UART_0 == uart)
|
||||||
case QM_UART_0:
|
? DMA_HW_IF_UART_A_RX
|
||||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_UART_A_RX;
|
: DMA_HW_IF_UART_B_RX;
|
||||||
break;
|
|
||||||
case QM_UART_1:
|
|
||||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_UART_B_RX;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The DMA driver needs a pointer to the DMA context structure
|
* The DMA driver needs a pointer to the DMA context structure
|
||||||
|
|
|
@ -33,7 +33,7 @@ uint32_t qm_ver_rom(void)
|
||||||
{
|
{
|
||||||
volatile uint32_t *ver_pointer;
|
volatile uint32_t *ver_pointer;
|
||||||
|
|
||||||
ver_pointer = (uint32_t*)ROM_VERSION_ADDRESS;
|
ver_pointer = (uint32_t *)ROM_VERSION_ADDRESS;
|
||||||
|
|
||||||
return *ver_pointer;
|
return *ver_pointer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qm_wdt.h"
|
#include "qm_wdt.h"
|
||||||
|
#include "soc_watch.h"
|
||||||
|
|
||||||
#define QM_WDT_RELOAD_VALUE (0x76)
|
#define QM_WDT_RELOAD_VALUE (0x76)
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ static void *callback_data[QM_WDT_NUM];
|
||||||
QM_ISR_DECLARE(qm_wdt_isr_0)
|
QM_ISR_DECLARE(qm_wdt_isr_0)
|
||||||
{
|
{
|
||||||
if (callback[QM_WDT_0]) {
|
if (callback[QM_WDT_0]) {
|
||||||
callback[QM_WDT_0](callback_data);
|
callback[QM_WDT_0](callback_data[QM_WDT_0]);
|
||||||
}
|
}
|
||||||
QM_ISR_EOI(QM_IRQ_WDT_0_VECTOR);
|
QM_ISR_EOI(QM_IRQ_WDT_0_VECTOR);
|
||||||
}
|
}
|
||||||
|
@ -58,6 +59,8 @@ int qm_wdt_start(const qm_wdt_t wdt)
|
||||||
#else
|
#else
|
||||||
#error("Unsupported / unspecified processor detected.");
|
#error("Unsupported / unspecified processor detected.");
|
||||||
#endif
|
#endif
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||||
|
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||||
|
|
||||||
QM_SCSS_PERIPHERAL->periph_cfg0 |= BIT(1);
|
QM_SCSS_PERIPHERAL->periph_cfg0 |= BIT(1);
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#define __QM_SS_ADC_H__
|
#define __QM_SS_ADC_H__
|
||||||
|
|
||||||
#include "qm_common.h"
|
#include "qm_common.h"
|
||||||
|
#include "qm_soc_regs.h"
|
||||||
#include "qm_sensor_regs.h"
|
#include "qm_sensor_regs.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,7 +172,9 @@ int qm_ss_adc_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode);
|
||||||
/**
|
/**
|
||||||
* Switch operating mode of SS ADC.
|
* Switch operating mode of SS ADC.
|
||||||
*
|
*
|
||||||
* This call is non-blocking and will call the user callback on completion.
|
* This call is non-blocking and will call the user callback on completion. An
|
||||||
|
* interrupt will not be generated if the user requests the same mode the ADC
|
||||||
|
* is currently in (default mode on boot is deep power down).
|
||||||
*
|
*
|
||||||
* @param[in] adc Which ADC to enable.
|
* @param[in] adc Which ADC to enable.
|
||||||
* @param[in] mode ADC operating mode.
|
* @param[in] mode ADC operating mode.
|
||||||
|
@ -273,12 +276,14 @@ int qm_ss_adc_set_config(const qm_ss_adc_t adc,
|
||||||
*
|
*
|
||||||
* @param[in] adc Which ADC to read.
|
* @param[in] adc Which ADC to read.
|
||||||
* @param[in,out] xfer Channel and sample info. This must not be NULL.
|
* @param[in,out] xfer Channel and sample info. This must not be NULL.
|
||||||
|
* @param[out] status Get status of the adc device.
|
||||||
*
|
*
|
||||||
* @return Standard errno return type for QMSI.
|
* @return Standard errno return type for QMSI.
|
||||||
* @retval 0 on success.
|
* @retval 0 on success.
|
||||||
* @retval Negative @ref errno for possible error codes.
|
* @retval Negative @ref errno for possible error codes.
|
||||||
*/
|
*/
|
||||||
int qm_ss_adc_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *const xfer);
|
int qm_ss_adc_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *const xfer,
|
||||||
|
qm_ss_adc_status_t *const status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously read values from the SS ADC.
|
* Asynchronously read values from the SS ADC.
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
* GPIO SS pin states.
|
* GPIO SS pin states.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_SS_GPIO_LOW, /**< Pin level high. */
|
QM_SS_GPIO_LOW, /**< Pin level high. */
|
||||||
QM_SS_GPIO_HIGH, /**< Pin level low. */
|
QM_SS_GPIO_HIGH, /**< Pin level low. */
|
||||||
QM_SS_GPIO_STATE_NUM
|
QM_SS_GPIO_STATE_NUM
|
||||||
} qm_ss_gpio_state_t;
|
} qm_ss_gpio_state_t;
|
||||||
|
@ -60,6 +60,7 @@ typedef struct {
|
||||||
uint32_t int_type; /**< Interrupt type, 0b: level; 1b: edge. */
|
uint32_t int_type; /**< Interrupt type, 0b: level; 1b: edge. */
|
||||||
uint32_t int_polarity; /**< Interrupt polarity, 0b: low, 1b: high. */
|
uint32_t int_polarity; /**< Interrupt polarity, 0b: low, 1b: high. */
|
||||||
uint32_t int_debounce; /**< Debounce on/off. */
|
uint32_t int_debounce; /**< Debounce on/off. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User callback.
|
* User callback.
|
||||||
*
|
*
|
||||||
|
@ -95,14 +96,15 @@ int qm_ss_gpio_set_config(const qm_ss_gpio_t gpio,
|
||||||
*
|
*
|
||||||
* @param[in] gpio SS GPIO port index.
|
* @param[in] gpio SS GPIO port index.
|
||||||
* @param[in] pin Pin of SS GPIO port to read.
|
* @param[in] pin Pin of SS GPIO port to read.
|
||||||
* @param[out] state QM_GPIO_LOW for low or QM_GPIO_HIGH for high. This must not be NULL.
|
* @param[out] state QM_GPIO_LOW for low or QM_GPIO_HIGH for high. This must not
|
||||||
|
* be NULL.
|
||||||
*
|
*
|
||||||
* @return Standard errno return type for QMSI.
|
* @return Standard errno return type for QMSI.
|
||||||
* @retval 0 on success.
|
* @retval 0 on success.
|
||||||
* @retval Negative @ref errno for possible error codes.
|
* @retval Negative @ref errno for possible error codes.
|
||||||
*/
|
*/
|
||||||
int qm_ss_gpio_read_pin(const qm_ss_gpio_t gpio, const uint8_t pin,
|
int qm_ss_gpio_read_pin(const qm_ss_gpio_t gpio, const uint8_t pin,
|
||||||
qm_ss_gpio_state_t *const state);
|
qm_ss_gpio_state_t *const state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a single pin on a given SS GPIO port.
|
* Set a single pin on a given SS GPIO port.
|
||||||
|
|
|
@ -71,32 +71,32 @@
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_SS_I2C_7_BIT = 0, /**< 7-bit mode. */
|
QM_SS_I2C_7_BIT = 0, /**< 7-bit mode. */
|
||||||
QM_SS_I2C_10_BIT /**< 10-bit mode. */
|
QM_SS_I2C_10_BIT /**< 10-bit mode. */
|
||||||
} qm_ss_i2c_addr_t;
|
} qm_ss_i2c_addr_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* QM SS I2C Speed Type.
|
* QM SS I2C Speed Type.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_SS_I2C_SPEED_STD = 1, /**< Standard mode (100 Kbps). */
|
QM_SS_I2C_SPEED_STD = 1, /**< Standard mode (100 Kbps). */
|
||||||
QM_SS_I2C_SPEED_FAST = 2 /**< Fast mode (400 Kbps). */
|
QM_SS_I2C_SPEED_FAST = 2 /**< Fast mode (400 Kbps). */
|
||||||
} qm_ss_i2c_speed_t;
|
} qm_ss_i2c_speed_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* QM SS I2C status type.
|
* QM SS I2C status type.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_I2C_IDLE = 0, /**< Controller idle. */
|
QM_I2C_IDLE = 0, /**< Controller idle. */
|
||||||
QM_I2C_TX_ABRT_7B_ADDR_NOACK = BIT(0), /**< 7-bit address noack. */
|
QM_I2C_TX_ABRT_7B_ADDR_NOACK = BIT(0), /**< 7-bit address noack. */
|
||||||
QM_I2C_TX_ABRT_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
QM_I2C_TX_ABRT_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
||||||
QM_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
QM_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
||||||
QM_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
QM_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
||||||
QM_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
QM_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
||||||
QM_I2C_TX_ABRT_SLVFLUSH_TXFIFO = BIT(13), /**< Slave flush tx FIFO. */
|
QM_I2C_TX_ABRT_SLVFLUSH_TXFIFO = BIT(13), /**< Slave flush tx FIFO. */
|
||||||
QM_I2C_TX_ABRT_SLV_ARBLOST = BIT(14), /**< Slave lost bus. */
|
QM_I2C_TX_ABRT_SLV_ARBLOST = BIT(14), /**< Slave lost bus. */
|
||||||
QM_I2C_TX_ABRT_SLVRD_INTX = BIT(15), /**< Slave read completion. */
|
QM_I2C_TX_ABRT_SLVRD_INTX = BIT(15), /**< Slave read completion. */
|
||||||
QM_I2C_TX_ABRT_USER_ABRT = BIT(16), /**< User abort. */
|
QM_I2C_TX_ABRT_USER_ABRT = BIT(16), /**< User abort. */
|
||||||
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
||||||
} qm_ss_i2c_status_t;
|
} qm_ss_i2c_status_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,6 +120,7 @@ typedef struct {
|
||||||
uint8_t *rx; /**< Read data. */
|
uint8_t *rx; /**< Read data. */
|
||||||
uint32_t rx_len; /**< Read buffer length. */
|
uint32_t rx_len; /**< Read buffer length. */
|
||||||
bool stop; /**< Generate master STOP. */
|
bool stop; /**< Generate master STOP. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User callback.
|
* User callback.
|
||||||
*
|
*
|
||||||
|
@ -230,8 +231,9 @@ int qm_ss_i2c_master_read(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
|
||||||
*
|
*
|
||||||
* @param[in] i2c Which I2C to transfer from.
|
* @param[in] i2c Which I2C to transfer from.
|
||||||
* @param[in] xfer Transfer structure includes write / read data and length,
|
* @param[in] xfer Transfer structure includes write / read data and length,
|
||||||
* user callback function and the callback context.
|
* user callback function and the callback context.
|
||||||
* This must not be NULL.
|
* The structure must not be NULL and must be kept valid until
|
||||||
|
* the transfer is complete.
|
||||||
* @param[in] slave_addr Address of slave to transfer data with.
|
* @param[in] slave_addr Address of slave to transfer data with.
|
||||||
*
|
*
|
||||||
* @return Standard errno return type for QMSI.
|
* @return Standard errno return type for QMSI.
|
||||||
|
|
|
@ -110,14 +110,16 @@ typedef enum {
|
||||||
/**
|
/**
|
||||||
* SPI slave select type.
|
* SPI slave select type.
|
||||||
*
|
*
|
||||||
* Slave selects can be combined by logical OR.
|
* Slave selects can combined by logical OR if multiple slaves are selected
|
||||||
|
* during one transfer. Setting only QM_SS_SPI_SS_DISABLED prevents the
|
||||||
|
* controller from starting the transfer.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_SS_SPI_SS_NONE = 0, /**< No slave select. */
|
QM_SS_SPI_SS_DISABLED = 0, /**< Slave select disable. */
|
||||||
QM_SS_SPI_SS_0 = BIT(0), /**< Slave select 0. */
|
QM_SS_SPI_SS_0 = BIT(0), /**< Slave select 0. */
|
||||||
QM_SS_SPI_SS_1 = BIT(1), /**< Slave select 1. */
|
QM_SS_SPI_SS_1 = BIT(1), /**< Slave select 1. */
|
||||||
QM_SS_SPI_SS_2 = BIT(2), /**< Slave select 2. */
|
QM_SS_SPI_SS_2 = BIT(2), /**< Slave select 2. */
|
||||||
QM_SS_SPI_SS_3 = BIT(3), /**< Slave select 3. */
|
QM_SS_SPI_SS_3 = BIT(3), /**< Slave select 3. */
|
||||||
} qm_ss_spi_slave_select_t;
|
} qm_ss_spi_slave_select_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,7 +171,7 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
void (*callback)(void *data, int error, qm_ss_spi_status_t status,
|
void (*callback)(void *data, int error, qm_ss_spi_status_t status,
|
||||||
uint16_t len);
|
uint16_t len);
|
||||||
void *data; /**< Callback user data. */
|
void *callback_data; /**< Callback user data. */
|
||||||
} qm_ss_spi_async_transfer_t;
|
} qm_ss_spi_async_transfer_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
* Sensor Subsystem Timer Configuration Type.
|
* Sensor Subsystem Timer Configuration Type.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool watchdog_mode; /**< Watchdog mode. */
|
bool watchdog_mode; /**< Watchdog mode. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increments in run state only.
|
* Increments in run state only.
|
||||||
|
@ -55,8 +55,9 @@ typedef struct {
|
||||||
* running state.
|
* running state.
|
||||||
*/
|
*/
|
||||||
bool inc_run_only;
|
bool inc_run_only;
|
||||||
bool int_en; /**< Interrupt enable. */
|
bool int_en; /**< Interrupt enable. */
|
||||||
uint32_t count; /**< Final count value. */
|
uint32_t count; /**< Final count value. */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User callback.
|
* User callback.
|
||||||
*
|
*
|
||||||
|
|
|
@ -43,11 +43,11 @@
|
||||||
#define QM_SS_ADC_CMD_START_CAL (3)
|
#define QM_SS_ADC_CMD_START_CAL (3)
|
||||||
#define QM_SS_ADC_CMD_LOAD_CAL (4)
|
#define QM_SS_ADC_CMD_LOAD_CAL (4)
|
||||||
|
|
||||||
/* Mode change delay is clock speed * 5. */
|
/* Mode change delay is (clock speed * 5). */
|
||||||
#define CALCULATE_DELAY() (clk_sys_get_ticks_per_us() * 5)
|
#define CALCULATE_DELAY() (clk_sys_get_ticks_per_us() * 5)
|
||||||
|
|
||||||
static uint32_t adc_base[QM_SS_ADC_NUM] = {QM_SS_ADC_BASE};
|
static uint32_t adc_base[QM_SS_ADC_NUM] = {QM_SS_ADC_BASE};
|
||||||
static qm_ss_adc_xfer_t irq_xfer[QM_SS_ADC_NUM];
|
static qm_ss_adc_xfer_t *irq_xfer[QM_SS_ADC_NUM];
|
||||||
|
|
||||||
static uint8_t sample_window[QM_SS_ADC_NUM];
|
static uint8_t sample_window[QM_SS_ADC_NUM];
|
||||||
static qm_ss_adc_resolution_t resolution[QM_SS_ADC_NUM];
|
static qm_ss_adc_resolution_t resolution[QM_SS_ADC_NUM];
|
||||||
|
@ -65,7 +65,10 @@ static void *cal_callback_data[QM_SS_ADC_NUM];
|
||||||
|
|
||||||
static void dummy_conversion(uint32_t controller);
|
static void dummy_conversion(uint32_t controller);
|
||||||
|
|
||||||
static bool first_mode_callback_ignored[QM_SS_ADC_NUM] = {false};
|
/* As the mode change interrupt is always asserted when the requested mode
|
||||||
|
* matches the current mode, an interrupt will be triggered whenever it is
|
||||||
|
* unmasked, which may need to be suppressed. */
|
||||||
|
static volatile bool ignore_spurious_interrupt[QM_SS_ADC_NUM] = {true};
|
||||||
static qm_ss_adc_mode_t requested_mode[QM_SS_ADC_NUM];
|
static qm_ss_adc_mode_t requested_mode[QM_SS_ADC_NUM];
|
||||||
|
|
||||||
static void enable_adc(void)
|
static void enable_adc(void)
|
||||||
|
@ -87,8 +90,8 @@ static void qm_ss_adc_isr_handler(const qm_ss_adc_t adc)
|
||||||
|
|
||||||
/* Calculate the number of samples to read. */
|
/* Calculate the number of samples to read. */
|
||||||
samples_to_read = FIFO_INTERRUPT_THRESHOLD;
|
samples_to_read = FIFO_INTERRUPT_THRESHOLD;
|
||||||
if (samples_to_read > (irq_xfer[adc].samples_len - count[adc])) {
|
if (samples_to_read > (irq_xfer[adc]->samples_len - count[adc])) {
|
||||||
samples_to_read = irq_xfer[adc].samples_len - count[adc];
|
samples_to_read = irq_xfer[adc]->samples_len - count[adc];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the samples into the array. */
|
/* Read the samples into the array. */
|
||||||
|
@ -97,7 +100,7 @@ static void qm_ss_adc_isr_handler(const qm_ss_adc_t adc)
|
||||||
QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET,
|
QM_SS_REG_AUX_OR(controller + QM_SS_ADC_SET,
|
||||||
QM_SS_ADC_SET_POP_RX);
|
QM_SS_ADC_SET_POP_RX);
|
||||||
/* Read the sample in the array. */
|
/* Read the sample in the array. */
|
||||||
irq_xfer[adc].samples[count[adc]] =
|
irq_xfer[adc]->samples[count[adc]] =
|
||||||
(__builtin_arc_lr(controller + QM_SS_ADC_SAMPLE) >>
|
(__builtin_arc_lr(controller + QM_SS_ADC_SAMPLE) >>
|
||||||
(ADC_SAMPLE_SHIFT - resolution[adc]));
|
(ADC_SAMPLE_SHIFT - resolution[adc]));
|
||||||
count[adc]++;
|
count[adc]++;
|
||||||
|
@ -106,7 +109,7 @@ static void qm_ss_adc_isr_handler(const qm_ss_adc_t adc)
|
||||||
QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
|
QM_SS_REG_AUX_OR(controller + QM_SS_ADC_CTRL,
|
||||||
QM_SS_ADC_CTRL_CLR_DATA_A);
|
QM_SS_ADC_CTRL_CLR_DATA_A);
|
||||||
|
|
||||||
if (count[adc] == irq_xfer[adc].samples_len) {
|
if (count[adc] == irq_xfer[adc]->samples_len) {
|
||||||
/* Stop the sequencer. */
|
/* Stop the sequencer. */
|
||||||
QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_CTRL,
|
QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_CTRL,
|
||||||
QM_SS_ADC_CTRL_SEQ_START);
|
QM_SS_ADC_CTRL_SEQ_START);
|
||||||
|
@ -116,10 +119,10 @@ static void qm_ss_adc_isr_handler(const qm_ss_adc_t adc)
|
||||||
QM_SS_ADC_CTRL_MSK_ALL_INT);
|
QM_SS_ADC_CTRL_MSK_ALL_INT);
|
||||||
|
|
||||||
/* Call the user callback. */
|
/* Call the user callback. */
|
||||||
if (irq_xfer[adc].callback) {
|
if (irq_xfer[adc]->callback) {
|
||||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data, 0,
|
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data, 0,
|
||||||
QM_SS_ADC_COMPLETE,
|
QM_SS_ADC_COMPLETE,
|
||||||
QM_SS_ADC_TRANSFER);
|
QM_SS_ADC_TRANSFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable the ADC. */
|
/* Disable the ADC. */
|
||||||
|
@ -144,24 +147,24 @@ static void qm_ss_adc_isr_err_handler(const qm_ss_adc_t adc)
|
||||||
|
|
||||||
/* Call the user callback and pass it the status code. */
|
/* Call the user callback and pass it the status code. */
|
||||||
if (intstat & QM_SS_ADC_INTSTAT_OVERFLOW) {
|
if (intstat & QM_SS_ADC_INTSTAT_OVERFLOW) {
|
||||||
if (irq_xfer[adc].callback) {
|
if (irq_xfer[adc]->callback) {
|
||||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data,
|
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
|
||||||
-EIO, QM_SS_ADC_OVERFLOW,
|
-EIO, QM_SS_ADC_OVERFLOW,
|
||||||
QM_SS_ADC_TRANSFER);
|
QM_SS_ADC_TRANSFER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (intstat & QM_SS_ADC_INTSTAT_UNDERFLOW) {
|
if (intstat & QM_SS_ADC_INTSTAT_UNDERFLOW) {
|
||||||
if (irq_xfer[adc].callback) {
|
if (irq_xfer[adc]->callback) {
|
||||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data,
|
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
|
||||||
-EIO, QM_SS_ADC_UNDERFLOW,
|
-EIO, QM_SS_ADC_UNDERFLOW,
|
||||||
QM_SS_ADC_TRANSFER);
|
QM_SS_ADC_TRANSFER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (intstat & QM_SS_ADC_INTSTAT_SEQERROR) {
|
if (intstat & QM_SS_ADC_INTSTAT_SEQERROR) {
|
||||||
if (irq_xfer[adc].callback) {
|
if (irq_xfer[adc]->callback) {
|
||||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data,
|
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
|
||||||
-EIO, QM_SS_ADC_SEQERROR,
|
-EIO, QM_SS_ADC_SEQERROR,
|
||||||
QM_SS_ADC_TRANSFER);
|
QM_SS_ADC_TRANSFER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,8 +185,8 @@ static void qm_ss_adc_isr_pwr_handler(const qm_ss_adc_t adc)
|
||||||
/* The IRQ associated with the mode change fires an interrupt as soon
|
/* The IRQ associated with the mode change fires an interrupt as soon
|
||||||
* as it is enabled so it is necessary to ignore it the first time the
|
* as it is enabled so it is necessary to ignore it the first time the
|
||||||
* ISR runs. */
|
* ISR runs. */
|
||||||
if (!first_mode_callback_ignored[adc]) {
|
if (ignore_spurious_interrupt[adc]) {
|
||||||
first_mode_callback_ignored[adc] = true;
|
ignore_spurious_interrupt[adc] = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +218,7 @@ static void qm_ss_adc_isr_cal_handler(const qm_ss_adc_t adc)
|
||||||
disable_adc();
|
disable_adc();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ISR for SS ADC 0 Data avaliable. */
|
/* ISR for SS ADC 0 Data available. */
|
||||||
QM_ISR_DECLARE(qm_ss_adc_0_isr)
|
QM_ISR_DECLARE(qm_ss_adc_0_isr)
|
||||||
{
|
{
|
||||||
qm_ss_adc_isr_handler(QM_SS_ADC_0);
|
qm_ss_adc_isr_handler(QM_SS_ADC_0);
|
||||||
|
@ -382,12 +385,17 @@ int qm_ss_adc_set_config(const qm_ss_adc_t adc,
|
||||||
|
|
||||||
int qm_ss_adc_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode)
|
int qm_ss_adc_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode)
|
||||||
{
|
{
|
||||||
uint32_t creg, delay;
|
uint32_t creg, delay, intstat;
|
||||||
uint32_t controller = adc_base[adc];
|
uint32_t controller = adc_base[adc];
|
||||||
|
|
||||||
QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
|
QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
|
||||||
QM_CHECK(mode <= QM_SS_ADC_MODE_NORM_NO_CAL, -EINVAL);
|
QM_CHECK(mode <= QM_SS_ADC_MODE_NORM_NO_CAL, -EINVAL);
|
||||||
|
|
||||||
|
/* Save the state of the mode interrupt mask. */
|
||||||
|
intstat = QM_SCSS_INT->int_adc_pwr_mask & QM_INT_ADC_PWR_MASK;
|
||||||
|
/* Mask the ADC mode change interrupt. */
|
||||||
|
QM_SCSS_INT->int_adc_pwr_mask |= QM_INT_ADC_PWR_MASK;
|
||||||
|
|
||||||
/* Calculate the delay. */
|
/* Calculate the delay. */
|
||||||
delay = CALCULATE_DELAY();
|
delay = CALCULATE_DELAY();
|
||||||
|
|
||||||
|
@ -403,6 +411,12 @@ int qm_ss_adc_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode)
|
||||||
QM_SS_ADC_PWR_MODE_STS)) {
|
QM_SS_ADC_PWR_MODE_STS)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Restore the state of the mode change interrupt mask if necessary. */
|
||||||
|
if (!intstat) {
|
||||||
|
ignore_spurious_interrupt[adc] = true;
|
||||||
|
QM_SCSS_INT->int_adc_pwr_mask &= ~(QM_INT_ADC_PWR_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
/* Perform a dummy conversion if transitioning to Normal Mode. */
|
/* Perform a dummy conversion if transitioning to Normal Mode. */
|
||||||
if ((mode >= QM_SS_ADC_MODE_NORM_CAL)) {
|
if ((mode >= QM_SS_ADC_MODE_NORM_CAL)) {
|
||||||
dummy_conversion(controller);
|
dummy_conversion(controller);
|
||||||
|
@ -440,9 +454,14 @@ int qm_ss_adc_irq_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode,
|
||||||
|
|
||||||
int qm_ss_adc_calibrate(const qm_ss_adc_t adc __attribute__((unused)))
|
int qm_ss_adc_calibrate(const qm_ss_adc_t adc __attribute__((unused)))
|
||||||
{
|
{
|
||||||
uint32_t creg;
|
uint32_t creg, intstat;
|
||||||
QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
|
QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
|
||||||
|
|
||||||
|
/* Save the state of the calibration interrupt mask. */
|
||||||
|
intstat = QM_SCSS_INT->int_adc_calib_mask & QM_INT_ADC_CALIB_MASK;
|
||||||
|
/* Mask the ADC calibration interrupt. */
|
||||||
|
QM_SCSS_INT->int_adc_calib_mask |= QM_INT_ADC_CALIB_MASK;
|
||||||
|
|
||||||
/* Enable the ADC. */
|
/* Enable the ADC. */
|
||||||
enable_adc();
|
enable_adc();
|
||||||
|
|
||||||
|
@ -458,13 +477,21 @@ int qm_ss_adc_calibrate(const qm_ss_adc_t adc __attribute__((unused)))
|
||||||
QM_SS_ADC_CAL_ACK)) {
|
QM_SS_ADC_CAL_ACK)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the calibration request reg. */
|
/* Clear the calibration request reg and wait for it to complete. */
|
||||||
QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
|
QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
|
||||||
QM_SS_ADC_CAL_REQ);
|
QM_SS_ADC_CAL_REQ);
|
||||||
|
while (__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
|
||||||
|
QM_SS_ADC_CAL_ACK) {
|
||||||
|
}
|
||||||
|
|
||||||
/* Disable the ADC. */
|
/* Disable the ADC. */
|
||||||
disable_adc();
|
disable_adc();
|
||||||
|
|
||||||
|
/* Restore the state of the calibration interrupt mask if necessary. */
|
||||||
|
if (!intstat) {
|
||||||
|
QM_SCSS_INT->int_adc_calib_mask &= ~(QM_INT_ADC_CALIB_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,11 +523,16 @@ int qm_ss_adc_irq_calibrate(const qm_ss_adc_t adc,
|
||||||
int qm_ss_adc_set_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
int qm_ss_adc_set_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
||||||
const qm_ss_adc_calibration_t cal_data)
|
const qm_ss_adc_calibration_t cal_data)
|
||||||
{
|
{
|
||||||
uint32_t creg;
|
uint32_t creg, intstat;
|
||||||
|
|
||||||
QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
|
QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
|
||||||
QM_CHECK(cal_data <= QM_SS_ADC_CAL_MAX, -EINVAL);
|
QM_CHECK(cal_data <= QM_SS_ADC_CAL_MAX, -EINVAL);
|
||||||
|
|
||||||
|
/* Save the state of the calibration interrupt mask. */
|
||||||
|
intstat = QM_SCSS_INT->int_adc_calib_mask & QM_INT_ADC_CALIB_MASK;
|
||||||
|
/* Mask the ADC calibration interrupt. */
|
||||||
|
QM_SCSS_INT->int_adc_calib_mask |= QM_INT_ADC_CALIB_MASK;
|
||||||
|
|
||||||
/* Issue the load calibrate command. */
|
/* Issue the load calibrate command. */
|
||||||
creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||||
creg &= ~(QM_SS_ADC_CAL_VAL_SET_MASK | QM_SS_ADC_CAL_CMD_MASK |
|
creg &= ~(QM_SS_ADC_CAL_VAL_SET_MASK | QM_SS_ADC_CAL_CMD_MASK |
|
||||||
|
@ -515,9 +547,17 @@ int qm_ss_adc_set_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
||||||
QM_SS_ADC_CAL_ACK)) {
|
QM_SS_ADC_CAL_ACK)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the calibration request reg. */
|
/* Clear the calibration request reg and wait for it to complete. */
|
||||||
QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
|
QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
|
||||||
QM_SS_ADC_CAL_REQ);
|
QM_SS_ADC_CAL_REQ);
|
||||||
|
while (__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
|
||||||
|
QM_SS_ADC_CAL_ACK) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the state of the calibration interrupt mask if necessary. */
|
||||||
|
if (!intstat) {
|
||||||
|
QM_SCSS_INT->int_adc_calib_mask &= ~(QM_INT_ADC_CALIB_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -535,7 +575,8 @@ int qm_ss_adc_get_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qm_ss_adc_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer)
|
int qm_ss_adc_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer,
|
||||||
|
qm_ss_adc_status_t *const status)
|
||||||
{
|
{
|
||||||
uint32_t reg, i;
|
uint32_t reg, i;
|
||||||
uint32_t controller = adc_base[adc];
|
uint32_t controller = adc_base[adc];
|
||||||
|
@ -581,6 +622,9 @@ int qm_ss_adc_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer)
|
||||||
|
|
||||||
/* Return if we get an error (UNDERFLOW, OVERFLOW, SEQ_ERROR). */
|
/* Return if we get an error (UNDERFLOW, OVERFLOW, SEQ_ERROR). */
|
||||||
if (res > 1) {
|
if (res > 1) {
|
||||||
|
if (status) {
|
||||||
|
*status = res;
|
||||||
|
}
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,7 +669,7 @@ int qm_ss_adc_irq_convert(const qm_ss_adc_t adc, qm_ss_adc_xfer_t *xfer)
|
||||||
setup_seq_table(adc, xfer, false);
|
setup_seq_table(adc, xfer, false);
|
||||||
|
|
||||||
/* Copy the xfer struct so we can get access from the ISR. */
|
/* Copy the xfer struct so we can get access from the ISR. */
|
||||||
memcpy(&irq_xfer[adc], xfer, sizeof(qm_ss_adc_xfer_t));
|
irq_xfer[adc] = xfer;
|
||||||
|
|
||||||
/* Set count back to 0. */
|
/* Set count back to 0. */
|
||||||
count[adc] = 0;
|
count[adc] = 0;
|
||||||
|
|
|
@ -125,7 +125,7 @@ int qm_ss_gpio_clear_pin(const qm_ss_gpio_t gpio, const uint8_t pin)
|
||||||
}
|
}
|
||||||
|
|
||||||
int qm_ss_gpio_set_pin_state(const qm_ss_gpio_t gpio, const uint8_t pin,
|
int qm_ss_gpio_set_pin_state(const qm_ss_gpio_t gpio, const uint8_t pin,
|
||||||
const qm_ss_gpio_state_t state)
|
const qm_ss_gpio_state_t state)
|
||||||
{
|
{
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
QM_CHECK(gpio < QM_SS_GPIO_NUM, -EINVAL);
|
QM_CHECK(gpio < QM_SS_GPIO_NUM, -EINVAL);
|
||||||
|
|
|
@ -26,14 +26,19 @@
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "qm_ss_i2c.h"
|
||||||
|
#include "clk.h"
|
||||||
|
|
||||||
#define SPK_LEN_SS (1)
|
#define SPK_LEN_SS (1)
|
||||||
#define SPK_LEN_FS (2)
|
#define SPK_LEN_FS (2)
|
||||||
#define TX_TL (2)
|
#define TX_TL (2)
|
||||||
#define RX_TL (5)
|
#define RX_TL (5)
|
||||||
|
|
||||||
#include <string.h>
|
/* number of retries before giving up on disabling the controller */
|
||||||
#include "qm_ss_i2c.h"
|
#define I2C_POLL_COUNT (1000000)
|
||||||
#include "clk.h"
|
#define I2C_POLL_MICROSECOND (1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: There are a number of differences between this Sensor Subsystem I2C
|
* NOTE: There are a number of differences between this Sensor Subsystem I2C
|
||||||
|
@ -59,19 +64,22 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static uint32_t i2c_base[QM_SS_I2C_NUM] = {QM_SS_I2C_0_BASE, QM_SS_I2C_1_BASE};
|
static uint32_t i2c_base[QM_SS_I2C_NUM] = {QM_SS_I2C_0_BASE, QM_SS_I2C_1_BASE};
|
||||||
static qm_ss_i2c_transfer_t i2c_transfer[QM_SS_I2C_NUM];
|
static const qm_ss_i2c_transfer_t *i2c_transfer[QM_SS_I2C_NUM];
|
||||||
static uint32_t i2c_write_pos[QM_SS_I2C_NUM], i2c_read_pos[QM_SS_I2C_NUM],
|
static uint32_t i2c_write_pos[QM_SS_I2C_NUM], i2c_read_pos[QM_SS_I2C_NUM],
|
||||||
i2c_read_buffer_remaining[QM_SS_I2C_NUM];
|
i2c_read_cmd_send[QM_SS_I2C_NUM];
|
||||||
|
|
||||||
static void controller_enable(const qm_ss_i2c_t i2c);
|
static void controller_enable(const qm_ss_i2c_t i2c);
|
||||||
static void controller_disable(const qm_ss_i2c_t i2c);
|
static int controller_disable(const qm_ss_i2c_t i2c);
|
||||||
|
|
||||||
static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
||||||
{
|
{
|
||||||
|
const qm_ss_i2c_transfer_t *const transfer = i2c_transfer[i2c];
|
||||||
uint32_t controller = i2c_base[i2c], data_cmd = 0,
|
uint32_t controller = i2c_base[i2c], data_cmd = 0,
|
||||||
count_tx = (QM_SS_I2C_FIFO_SIZE - TX_TL);
|
count_tx = (QM_SS_I2C_FIFO_SIZE - TX_TL);
|
||||||
qm_ss_i2c_status_t status = 0;
|
qm_ss_i2c_status_t status = 0;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
uint32_t read_buffer_remaining = transfer->rx_len - i2c_read_pos[i2c];
|
||||||
|
uint32_t write_buffer_remaining = transfer->tx_len - i2c_write_pos[i2c];
|
||||||
|
|
||||||
/* Check for errors */
|
/* Check for errors */
|
||||||
QM_ASSERT(!(__builtin_arc_lr(controller + QM_SS_I2C_INTR_STAT) &
|
QM_ASSERT(!(__builtin_arc_lr(controller + QM_SS_I2C_INTR_STAT) &
|
||||||
|
@ -101,27 +109,29 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
||||||
|
|
||||||
rc = (status & QM_I2C_TX_ABRT_USER_ABRT) ? -ECANCELED : -EIO;
|
rc = (status & QM_I2C_TX_ABRT_USER_ABRT) ? -ECANCELED : -EIO;
|
||||||
|
|
||||||
if (i2c_transfer[i2c].callback) {
|
if (i2c_transfer[i2c]->callback) {
|
||||||
i2c_transfer[i2c].callback(
|
i2c_transfer[i2c]->callback(
|
||||||
i2c_transfer[i2c].callback_data, rc, status, 0);
|
i2c_transfer[i2c]->callback_data, rc, status, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
controller_disable(i2c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX read from buffer */
|
/* RX read from buffer */
|
||||||
if ((__builtin_arc_lr(controller + QM_SS_I2C_INTR_STAT) &
|
if ((__builtin_arc_lr(controller + QM_SS_I2C_INTR_STAT) &
|
||||||
QM_SS_I2C_INTR_STAT_RX_FULL)) {
|
QM_SS_I2C_INTR_STAT_RX_FULL)) {
|
||||||
|
|
||||||
while (i2c_read_buffer_remaining[i2c] &&
|
while (read_buffer_remaining &&
|
||||||
(__builtin_arc_lr(controller + QM_SS_I2C_RXFLR))) {
|
(__builtin_arc_lr(controller + QM_SS_I2C_RXFLR))) {
|
||||||
__builtin_arc_sr(QM_SS_I2C_DATA_CMD_POP,
|
__builtin_arc_sr(QM_SS_I2C_DATA_CMD_POP,
|
||||||
controller + QM_SS_I2C_DATA_CMD);
|
controller + QM_SS_I2C_DATA_CMD);
|
||||||
/* IC_DATA_CMD[7:0] contains received data */
|
/* IC_DATA_CMD[7:0] contains received data */
|
||||||
i2c_transfer[i2c].rx[i2c_read_pos[i2c]] =
|
i2c_transfer[i2c]->rx[i2c_read_pos[i2c]] =
|
||||||
__builtin_arc_lr(controller + QM_SS_I2C_DATA_CMD);
|
__builtin_arc_lr(controller + QM_SS_I2C_DATA_CMD);
|
||||||
i2c_read_buffer_remaining[i2c]--;
|
read_buffer_remaining--;
|
||||||
i2c_read_pos[i2c]++;
|
i2c_read_pos[i2c]++;
|
||||||
|
|
||||||
if (i2c_read_buffer_remaining[i2c] == 0) {
|
if (read_buffer_remaining == 0) {
|
||||||
/* mask rx full interrupt if transfer
|
/* mask rx full interrupt if transfer
|
||||||
* complete
|
* complete
|
||||||
*/
|
*/
|
||||||
|
@ -129,19 +139,19 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
||||||
(controller + QM_SS_I2C_INTR_MASK),
|
(controller + QM_SS_I2C_INTR_MASK),
|
||||||
QM_SS_I2C_INTR_MASK_RX_FULL);
|
QM_SS_I2C_INTR_MASK_RX_FULL);
|
||||||
|
|
||||||
if (i2c_transfer[i2c].stop) {
|
if (i2c_transfer[i2c]->stop) {
|
||||||
controller_disable(i2c);
|
controller_disable(i2c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i2c_transfer[i2c].callback) {
|
if (i2c_transfer[i2c]->callback) {
|
||||||
i2c_transfer[i2c].callback(
|
i2c_transfer[i2c]->callback(
|
||||||
i2c_transfer[i2c].callback_data, 0,
|
i2c_transfer[i2c]->callback_data, 0,
|
||||||
QM_I2C_IDLE, i2c_read_pos[i2c]);
|
QM_I2C_IDLE, i2c_read_pos[i2c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i2c_read_buffer_remaining[i2c] > 0 &&
|
if (read_buffer_remaining > 0 &&
|
||||||
i2c_read_buffer_remaining[i2c] < (RX_TL + 1)) {
|
read_buffer_remaining < (RX_TL + 1)) {
|
||||||
/* Adjust the RX threshold so the next 'RX_FULL'
|
/* Adjust the RX threshold so the next 'RX_FULL'
|
||||||
* interrupt is generated when all the remaining
|
* interrupt is generated when all the remaining
|
||||||
* data are received.
|
* data are received.
|
||||||
|
@ -149,7 +159,7 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
||||||
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_TL),
|
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_TL),
|
||||||
QM_SS_I2C_TL_RX_TL_MASK);
|
QM_SS_I2C_TL_RX_TL_MASK);
|
||||||
QM_SS_REG_AUX_OR((controller + QM_SS_I2C_TL),
|
QM_SS_REG_AUX_OR((controller + QM_SS_I2C_TL),
|
||||||
(i2c_read_buffer_remaining[i2c] - 1));
|
(read_buffer_remaining - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX_FULL INTR is autocleared when the buffer
|
/* RX_FULL INTR is autocleared when the buffer
|
||||||
|
@ -162,9 +172,9 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
||||||
|
|
||||||
if ((__builtin_arc_lr(controller + QM_SS_I2C_STATUS) &
|
if ((__builtin_arc_lr(controller + QM_SS_I2C_STATUS) &
|
||||||
QM_SS_I2C_STATUS_TFE) &&
|
QM_SS_I2C_STATUS_TFE) &&
|
||||||
(i2c_transfer[i2c].tx != NULL) &&
|
(i2c_transfer[i2c]->tx != NULL) &&
|
||||||
(i2c_transfer[i2c].tx_len == 0) &&
|
(write_buffer_remaining == 0) &&
|
||||||
(i2c_transfer[i2c].rx_len == 0)) {
|
(read_buffer_remaining == 0)) {
|
||||||
|
|
||||||
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_INTR_MASK),
|
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_INTR_MASK),
|
||||||
QM_SS_I2C_INTR_MASK_TX_EMPTY);
|
QM_SS_I2C_INTR_MASK_TX_EMPTY);
|
||||||
|
@ -172,34 +182,33 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
||||||
/* if this is not a combined
|
/* if this is not a combined
|
||||||
* transaction, disable the controller now
|
* transaction, disable the controller now
|
||||||
*/
|
*/
|
||||||
if ((i2c_read_buffer_remaining[i2c] == 0) &&
|
if (i2c_transfer[i2c]->stop) {
|
||||||
i2c_transfer[i2c].stop) {
|
|
||||||
controller_disable(i2c);
|
controller_disable(i2c);
|
||||||
|
|
||||||
/* callback */
|
/* callback */
|
||||||
if (i2c_transfer[i2c].callback) {
|
if (i2c_transfer[i2c]->callback) {
|
||||||
i2c_transfer[i2c].callback(
|
i2c_transfer[i2c]->callback(
|
||||||
i2c_transfer[i2c].callback_data, 0,
|
i2c_transfer[i2c]->callback_data, 0,
|
||||||
QM_I2C_IDLE, i2c_write_pos[i2c]);
|
QM_I2C_IDLE, i2c_write_pos[i2c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((count_tx) && i2c_transfer[i2c].tx_len) {
|
while ((count_tx) && write_buffer_remaining) {
|
||||||
count_tx--;
|
count_tx--;
|
||||||
|
write_buffer_remaining--;
|
||||||
|
|
||||||
/* write command -IC_DATA_CMD[8] = 0 */
|
/* write command -IC_DATA_CMD[8] = 0 */
|
||||||
/* fill IC_DATA_CMD[7:0] with the data */
|
/* fill IC_DATA_CMD[7:0] with the data */
|
||||||
data_cmd = QM_SS_I2C_DATA_CMD_PUSH |
|
data_cmd = QM_SS_I2C_DATA_CMD_PUSH |
|
||||||
i2c_transfer[i2c].tx[i2c_write_pos[i2c]];
|
i2c_transfer[i2c]->tx[i2c_write_pos[i2c]];
|
||||||
i2c_transfer[i2c].tx_len--;
|
|
||||||
|
|
||||||
/* if transfer is a combined transfer, only
|
/* if transfer is a combined transfer, only
|
||||||
* send stop at
|
* send stop at
|
||||||
* end of the transfer sequence */
|
* end of the transfer sequence */
|
||||||
if (i2c_transfer[i2c].stop &&
|
if (i2c_transfer[i2c]->stop &&
|
||||||
(i2c_transfer[i2c].tx_len == 0) &&
|
(read_buffer_remaining == 0) &&
|
||||||
(i2c_transfer[i2c].rx_len == 0)) {
|
(write_buffer_remaining == 0)) {
|
||||||
|
|
||||||
data_cmd |= QM_SS_I2C_DATA_CMD_STOP;
|
data_cmd |= QM_SS_I2C_DATA_CMD_STOP;
|
||||||
}
|
}
|
||||||
|
@ -220,18 +229,17 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
||||||
(__builtin_arc_lr(controller + QM_SS_I2C_TXFLR) +
|
(__builtin_arc_lr(controller + QM_SS_I2C_TXFLR) +
|
||||||
(__builtin_arc_lr(controller + QM_SS_I2C_RXFLR) + 1));
|
(__builtin_arc_lr(controller + QM_SS_I2C_RXFLR) + 1));
|
||||||
|
|
||||||
while (i2c_transfer[i2c].rx_len &&
|
while (i2c_read_cmd_send[i2c] &&
|
||||||
(i2c_transfer[i2c].tx_len == 0) && count_tx) {
|
(write_buffer_remaining == 0) && count_tx) {
|
||||||
count_tx--;
|
count_tx--;
|
||||||
i2c_transfer[i2c].rx_len--;
|
i2c_read_cmd_send[i2c]--;
|
||||||
|
|
||||||
/* if transfer is a combined transfer, only
|
/* if transfer is a combined transfer, only
|
||||||
* send stop at
|
* send stop at
|
||||||
* end of
|
* end of
|
||||||
* the transfer sequence */
|
* the transfer sequence */
|
||||||
if (i2c_transfer[i2c].stop &&
|
if (i2c_transfer[i2c]->stop &&
|
||||||
(i2c_transfer[i2c].rx_len == 0) &&
|
(i2c_read_cmd_send[i2c] == 0)) {
|
||||||
(i2c_transfer[i2c].tx_len == 0)) {
|
|
||||||
|
|
||||||
__builtin_arc_sr((QM_SS_I2C_DATA_CMD_CMD |
|
__builtin_arc_sr((QM_SS_I2C_DATA_CMD_CMD |
|
||||||
QM_SS_I2C_DATA_CMD_PUSH |
|
QM_SS_I2C_DATA_CMD_PUSH |
|
||||||
|
@ -249,8 +257,8 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
||||||
|
|
||||||
/* generate a tx_empty interrupt when tx fifo is fully
|
/* generate a tx_empty interrupt when tx fifo is fully
|
||||||
* empty */
|
* empty */
|
||||||
if ((i2c_transfer[i2c].tx_len == 0) &&
|
if ((write_buffer_remaining == 0) &&
|
||||||
(i2c_transfer[i2c].rx_len == 0)) {
|
(read_buffer_remaining == 0)) {
|
||||||
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_TL),
|
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_TL),
|
||||||
QM_SS_I2C_TL_TX_TL_MASK);
|
QM_SS_I2C_TL_TX_TL_MASK);
|
||||||
}
|
}
|
||||||
|
@ -297,7 +305,9 @@ int qm_ss_i2c_set_config(const qm_ss_i2c_t i2c,
|
||||||
controller + QM_SS_I2C_INTR_MASK);
|
controller + QM_SS_I2C_INTR_MASK);
|
||||||
|
|
||||||
/* disable controller */
|
/* disable controller */
|
||||||
controller_disable(i2c);
|
if (controller_disable(i2c)) {
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
/* set mode */
|
/* set mode */
|
||||||
con |= QM_SS_I2C_CON_RESTART_EN |
|
con |= QM_SS_I2C_CON_RESTART_EN |
|
||||||
|
@ -379,7 +389,7 @@ int qm_ss_i2c_set_speed(const qm_ss_i2c_t i2c, const qm_ss_i2c_speed_t speed,
|
||||||
lo_cnt > QM_SS_I2C_IC_LCNT_MIN,
|
lo_cnt > QM_SS_I2C_IC_LCNT_MIN,
|
||||||
-EINVAL);
|
-EINVAL);
|
||||||
|
|
||||||
con &= ~QM_SS_I2C_CON_SPEED_MASK;
|
con &= ~(QM_SS_I2C_CON_SPEED_MASK | QM_SS_I2C_CON_SPKLEN_MASK);
|
||||||
|
|
||||||
full_cnt = (lo_cnt & QM_SS_I2C_SS_FS_SCL_CNT_16BIT_MASK) |
|
full_cnt = (lo_cnt & QM_SS_I2C_SS_FS_SCL_CNT_16BIT_MASK) |
|
||||||
(hi_cnt & QM_SS_I2C_SS_FS_SCL_CNT_16BIT_MASK)
|
(hi_cnt & QM_SS_I2C_SS_FS_SCL_CNT_16BIT_MASK)
|
||||||
|
@ -387,12 +397,14 @@ int qm_ss_i2c_set_speed(const qm_ss_i2c_t i2c, const qm_ss_i2c_speed_t speed,
|
||||||
|
|
||||||
switch (speed) {
|
switch (speed) {
|
||||||
case QM_SS_I2C_SPEED_STD:
|
case QM_SS_I2C_SPEED_STD:
|
||||||
con |= QM_SS_I2C_CON_SPEED_SS;
|
con |= (QM_SS_I2C_CON_SPEED_SS |
|
||||||
|
(SPK_LEN_SS << QM_SS_I2C_CON_SPKLEN_OFFSET));
|
||||||
__builtin_arc_sr(full_cnt, controller + QM_SS_I2C_SS_SCL_CNT);
|
__builtin_arc_sr(full_cnt, controller + QM_SS_I2C_SS_SCL_CNT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QM_SS_I2C_SPEED_FAST:
|
case QM_SS_I2C_SPEED_FAST:
|
||||||
con |= QM_SS_I2C_CON_SPEED_FS;
|
con |= (QM_SS_I2C_CON_SPEED_FS |
|
||||||
|
(SPK_LEN_FS << QM_SS_I2C_CON_SPKLEN_OFFSET));
|
||||||
__builtin_arc_sr(full_cnt, controller + QM_SS_I2C_FS_SCL_CNT);
|
__builtin_arc_sr(full_cnt, controller + QM_SS_I2C_FS_SCL_CNT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -480,7 +492,9 @@ int qm_ss_i2c_master_write(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
|
||||||
|
|
||||||
/* disable controller */
|
/* disable controller */
|
||||||
if (true == stop) {
|
if (true == stop) {
|
||||||
controller_disable(i2c);
|
if (controller_disable(i2c)) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status != NULL) {
|
if (status != NULL) {
|
||||||
|
@ -550,7 +564,8 @@ int qm_ss_i2c_master_read(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
|
||||||
|
|
||||||
/* wait until rx fifo is empty, indicating pop is complete*/
|
/* wait until rx fifo is empty, indicating pop is complete*/
|
||||||
while ((__builtin_arc_lr(controller + QM_SS_I2C_STATUS) &
|
while ((__builtin_arc_lr(controller + QM_SS_I2C_STATUS) &
|
||||||
QM_SS_I2C_STATUS_RFNE));
|
QM_SS_I2C_STATUS_RFNE))
|
||||||
|
;
|
||||||
|
|
||||||
/* IC_DATA_CMD[7:0] contains received data */
|
/* IC_DATA_CMD[7:0] contains received data */
|
||||||
*d = __builtin_arc_lr(controller + QM_SS_I2C_DATA_CMD);
|
*d = __builtin_arc_lr(controller + QM_SS_I2C_DATA_CMD);
|
||||||
|
@ -559,7 +574,9 @@ int qm_ss_i2c_master_read(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
|
||||||
|
|
||||||
/* disable controller */
|
/* disable controller */
|
||||||
if (true == stop) {
|
if (true == stop) {
|
||||||
controller_disable(i2c);
|
if (controller_disable(i2c)) {
|
||||||
|
ret = -EBUSY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status != NULL) {
|
if (status != NULL) {
|
||||||
|
@ -595,8 +612,8 @@ int qm_ss_i2c_master_irq_transfer(const qm_ss_i2c_t i2c,
|
||||||
|
|
||||||
i2c_write_pos[i2c] = 0;
|
i2c_write_pos[i2c] = 0;
|
||||||
i2c_read_pos[i2c] = 0;
|
i2c_read_pos[i2c] = 0;
|
||||||
i2c_read_buffer_remaining[i2c] = xfer->rx_len;
|
i2c_read_cmd_send[i2c] = xfer->rx_len;
|
||||||
memcpy(&i2c_transfer[i2c], xfer, sizeof(i2c_transfer[i2c]));
|
i2c_transfer[i2c] = xfer;
|
||||||
|
|
||||||
/* set threshold */
|
/* set threshold */
|
||||||
if (xfer->rx_len > 0 && xfer->rx_len < (RX_TL + 1)) {
|
if (xfer->rx_len > 0 && xfer->rx_len < (RX_TL + 1)) {
|
||||||
|
@ -643,22 +660,30 @@ static void controller_enable(const qm_ss_i2c_t i2c)
|
||||||
QM_SS_I2C_ENABLE_STATUS_IC_EN))
|
QM_SS_I2C_ENABLE_STATUS_IC_EN))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear all interruption flags */
|
||||||
|
__builtin_arc_sr(QM_SS_I2C_INTR_CLR_ALL,
|
||||||
|
controller + QM_SS_I2C_INTR_CLR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void controller_disable(const qm_ss_i2c_t i2c)
|
static int controller_disable(const qm_ss_i2c_t i2c)
|
||||||
{
|
{
|
||||||
uint32_t controller = i2c_base[i2c];
|
uint32_t controller = i2c_base[i2c];
|
||||||
if (__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
|
int poll_count = I2C_POLL_COUNT;
|
||||||
QM_SS_I2C_ENABLE_STATUS_IC_EN) {
|
|
||||||
/* disable controller */
|
|
||||||
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_CON),
|
|
||||||
QM_SS_I2C_CON_ENABLE);
|
|
||||||
|
|
||||||
/* wait until controller is disabled */
|
/* disable controller */
|
||||||
while ((__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
|
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_CON), QM_SS_I2C_CON_ENABLE);
|
||||||
QM_SS_I2C_ENABLE_STATUS_IC_EN))
|
|
||||||
;
|
/* wait until controller is disabled */
|
||||||
|
while ((__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
|
||||||
|
QM_SS_I2C_ENABLE_STATUS_IC_EN) &&
|
||||||
|
poll_count--) {
|
||||||
|
clk_sys_udelay(I2C_POLL_MICROSECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* returns 0 if ok, meaning controller is disabled */
|
||||||
|
return (__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
|
||||||
|
QM_SS_I2C_ENABLE_STATUS_IC_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
int qm_ss_i2c_irq_transfer_terminate(const qm_ss_i2c_t i2c)
|
int qm_ss_i2c_irq_transfer_terminate(const qm_ss_i2c_t i2c)
|
||||||
|
|
|
@ -38,13 +38,11 @@
|
||||||
|
|
||||||
static uint32_t base[QM_SS_SPI_NUM] = {QM_SS_SPI_0_BASE, QM_SS_SPI_1_BASE};
|
static uint32_t base[QM_SS_SPI_NUM] = {QM_SS_SPI_0_BASE, QM_SS_SPI_1_BASE};
|
||||||
|
|
||||||
static const qm_ss_spi_async_transfer_t *transfer[QM_SS_SPI_NUM];
|
static const qm_ss_spi_async_transfer_t *spi_async_transfer[QM_SS_SPI_NUM];
|
||||||
static uint32_t rx_c[QM_SS_SPI_NUM];
|
static uint32_t rx_c[QM_SS_SPI_NUM];
|
||||||
static uint32_t tx_c[QM_SS_SPI_NUM];
|
static uint32_t tx_c[QM_SS_SPI_NUM];
|
||||||
static uint8_t *rx_p[QM_SS_SPI_NUM];
|
|
||||||
static uint8_t *tx_p[QM_SS_SPI_NUM];
|
|
||||||
|
|
||||||
static uint16_t dummy_frame;
|
static const uint16_t dummy_frame = 0;
|
||||||
|
|
||||||
/* Private Functions */
|
/* Private Functions */
|
||||||
static void spi_disable(const qm_ss_spi_t spi)
|
static void spi_disable(const qm_ss_spi_t spi)
|
||||||
|
@ -57,7 +55,7 @@ static void spi_disable(const qm_ss_spi_t spi)
|
||||||
__builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_CLR_INTR);
|
__builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_CLR_INTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __inline__ void fifo_write(const qm_ss_spi_t spi, void *data,
|
static __inline__ void fifo_write(const qm_ss_spi_t spi, const void *data,
|
||||||
uint8_t size)
|
uint8_t size)
|
||||||
{
|
{
|
||||||
uint32_t dr;
|
uint32_t dr;
|
||||||
|
@ -211,7 +209,7 @@ int qm_ss_spi_transfer(const qm_ss_spi_t spi,
|
||||||
tx_cnt--;
|
tx_cnt--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Wait for last byte transfered */
|
/* Wait for last byte transferred */
|
||||||
while (__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY)
|
while (__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -231,20 +229,22 @@ int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi,
|
||||||
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
|
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
|
||||||
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
||||||
QM_SS_SPI_CTRL_TMOD_OFFS);
|
QM_SS_SPI_CTRL_TMOD_OFFS);
|
||||||
|
uint8_t bytes = BYTES_PER_FRAME(ctrl);
|
||||||
|
|
||||||
QM_CHECK(tmode == QM_SS_SPI_TMOD_TX_RX ? (xfer->tx_len == xfer->rx_len)
|
QM_CHECK(tmode == QM_SS_SPI_TMOD_TX_RX ? (xfer->tx_len == xfer->rx_len)
|
||||||
: 1,
|
: 1,
|
||||||
-EINVAL);
|
-EINVAL);
|
||||||
|
|
||||||
transfer[spi] = xfer;
|
spi_async_transfer[spi] = xfer;
|
||||||
tx_c[spi] = xfer->tx_len;
|
tx_c[spi] = xfer->tx_len;
|
||||||
rx_c[spi] = xfer->rx_len;
|
rx_c[spi] = xfer->rx_len;
|
||||||
tx_p[spi] = xfer->tx;
|
|
||||||
rx_p[spi] = xfer->rx;
|
/* Set NDF (Number of Data Frames) in RX or EEPROM Read mode. (-1) */
|
||||||
/* RX only transfers need a dummy frame byte to be sent. */
|
if (tmode == QM_SS_SPI_TMOD_RX || tmode == QM_SS_SPI_TMOD_EEPROM_READ) {
|
||||||
if (tmode == QM_SS_SPI_TMOD_RX) {
|
ctrl &= ~QM_SS_SPI_CTRL_NDF_MASK;
|
||||||
tx_p[spi] = (uint8_t *)&dummy_frame;
|
ctrl |= ((xfer->rx_len - 1) << QM_SS_SPI_CTRL_NDF_OFFS) &
|
||||||
tx_c[spi] = 1;
|
QM_SS_SPI_CTRL_NDF_MASK;
|
||||||
|
__builtin_arc_sr(ctrl, base[spi] + QM_SS_SPI_CTRL);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ftlr =
|
uint32_t ftlr =
|
||||||
|
@ -256,35 +256,44 @@ int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi,
|
||||||
|
|
||||||
/* Unmask all interrupts */
|
/* Unmask all interrupts */
|
||||||
__builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_INTR_MASK);
|
__builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_INTR_MASK);
|
||||||
|
|
||||||
/* Enable SPI device */
|
/* Enable SPI device */
|
||||||
QM_SS_REG_AUX_OR(base[spi] + QM_SS_SPI_SPIEN, QM_SS_SPI_SPIEN_EN);
|
QM_SS_REG_AUX_OR(base[spi] + QM_SS_SPI_SPIEN, QM_SS_SPI_SPIEN_EN);
|
||||||
|
|
||||||
|
/* RX only transfers need a dummy frame byte to be sent. */
|
||||||
|
if (tmode == QM_SS_SPI_TMOD_RX) {
|
||||||
|
fifo_write(spi, (uint8_t *)&dummy_frame, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qm_ss_spi_transfer_terminate(const qm_ss_spi_t spi)
|
int qm_ss_spi_transfer_terminate(const qm_ss_spi_t spi)
|
||||||
{
|
{
|
||||||
QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL);
|
QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL);
|
||||||
|
const qm_ss_spi_async_transfer_t *const transfer =
|
||||||
|
spi_async_transfer[spi];
|
||||||
|
|
||||||
spi_disable(spi);
|
spi_disable(spi);
|
||||||
|
|
||||||
if (transfer[spi]->callback) {
|
if (transfer->callback) {
|
||||||
uint32_t len = 0;
|
uint32_t len = 0;
|
||||||
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
|
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
|
||||||
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
||||||
QM_SS_SPI_CTRL_TMOD_OFFS);
|
QM_SS_SPI_CTRL_TMOD_OFFS);
|
||||||
if (tmode == QM_SS_SPI_TMOD_TX ||
|
if (tmode == QM_SS_SPI_TMOD_TX ||
|
||||||
tmode == QM_SS_SPI_TMOD_TX_RX) {
|
tmode == QM_SS_SPI_TMOD_TX_RX) {
|
||||||
len = transfer[spi]->tx_len - tx_c[spi];
|
len = transfer->tx_len - tx_c[spi];
|
||||||
} else {
|
} else {
|
||||||
len = transfer[spi]->rx_len - rx_c[spi];
|
len = transfer->rx_len - rx_c[spi];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NOTE: change this to return controller-specific code
|
* NOTE: change this to return controller-specific code
|
||||||
* 'user aborted'.
|
* 'user aborted'.
|
||||||
*/
|
*/
|
||||||
transfer[spi]->callback(transfer[spi]->data, -ECANCELED,
|
transfer->callback(transfer->callback_data, -ECANCELED,
|
||||||
QM_SS_SPI_IDLE, (uint16_t)len);
|
QM_SS_SPI_IDLE, (uint16_t)len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -293,14 +302,17 @@ int qm_ss_spi_transfer_terminate(const qm_ss_spi_t spi)
|
||||||
static void handle_spi_err_interrupt(const qm_ss_spi_t spi)
|
static void handle_spi_err_interrupt(const qm_ss_spi_t spi)
|
||||||
{
|
{
|
||||||
uint32_t intr_stat = __builtin_arc_lr(base[spi] + QM_SS_SPI_INTR_STAT);
|
uint32_t intr_stat = __builtin_arc_lr(base[spi] + QM_SS_SPI_INTR_STAT);
|
||||||
spi_disable(spi);
|
const qm_ss_spi_async_transfer_t *const transfer =
|
||||||
QM_ASSERT((intr_stat &
|
spi_async_transfer[spi];
|
||||||
(QM_SS_SPI_INTR_STAT_TXOI | QM_SS_SPI_INTR_STAT_RXFI)) == 0);
|
|
||||||
|
|
||||||
if ((intr_stat & QM_SS_SPI_INTR_RXOI) && transfer[spi]->callback) {
|
spi_disable(spi);
|
||||||
transfer[spi]->callback(transfer[spi]->data, -EIO,
|
QM_ASSERT((intr_stat & QM_SS_SPI_INTR_STAT_TXOI) == 0);
|
||||||
QM_SS_SPI_RX_OVERFLOW,
|
QM_ASSERT((intr_stat & QM_SS_SPI_INTR_STAT_RXUI) == 0);
|
||||||
transfer[spi]->rx_len - rx_c[spi]);
|
|
||||||
|
if ((intr_stat & QM_SS_SPI_INTR_RXOI) && transfer->callback) {
|
||||||
|
transfer->callback(transfer->callback_data, -EIO,
|
||||||
|
QM_SS_SPI_RX_OVERFLOW,
|
||||||
|
transfer->rx_len - rx_c[spi]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,14 +326,24 @@ static void handle_spi_tx_interrupt(const qm_ss_spi_t spi)
|
||||||
uint8_t bytes = BYTES_PER_FRAME(ctrl);
|
uint8_t bytes = BYTES_PER_FRAME(ctrl);
|
||||||
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
||||||
QM_SS_SPI_CTRL_TMOD_OFFS);
|
QM_SS_SPI_CTRL_TMOD_OFFS);
|
||||||
|
const qm_ss_spi_async_transfer_t *const transfer =
|
||||||
|
spi_async_transfer[spi];
|
||||||
|
|
||||||
|
/* Jump to the right position of TX buffer.
|
||||||
|
* If no bytes were transmitted before, we start from the beginning,
|
||||||
|
* otherwise we jump to the next frame to be sent.
|
||||||
|
*/
|
||||||
|
const uint8_t *tx_buffer =
|
||||||
|
transfer->tx + ((transfer->tx_len - tx_c[spi]) * bytes);
|
||||||
|
|
||||||
if (tx_c[spi] == 0 &&
|
if (tx_c[spi] == 0 &&
|
||||||
!(__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY)) {
|
!(__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY)) {
|
||||||
if (tmode == QM_SS_SPI_TMOD_TX) {
|
if (tmode == QM_SS_SPI_TMOD_TX) {
|
||||||
spi_disable(spi);
|
spi_disable(spi);
|
||||||
if (transfer[spi]->callback) {
|
if (transfer->callback) {
|
||||||
transfer[spi]->callback(transfer[spi]->data, 0,
|
transfer->callback(transfer->callback_data, 0,
|
||||||
QM_SS_SPI_IDLE,
|
QM_SS_SPI_IDLE,
|
||||||
transfer[spi]->tx_len);
|
transfer->tx_len);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QM_SS_REG_AUX_NAND(base[spi] + QM_SS_SPI_INTR_MASK,
|
QM_SS_REG_AUX_NAND(base[spi] + QM_SS_SPI_INTR_MASK,
|
||||||
|
@ -334,8 +356,8 @@ static void handle_spi_tx_interrupt(const qm_ss_spi_t spi)
|
||||||
uint32_t txflr = __builtin_arc_lr(base[spi] + QM_SS_SPI_TXFLR);
|
uint32_t txflr = __builtin_arc_lr(base[spi] + QM_SS_SPI_TXFLR);
|
||||||
int32_t cnt = FIFO_SIZE - rxflr - txflr - 1;
|
int32_t cnt = FIFO_SIZE - rxflr - txflr - 1;
|
||||||
while (tx_c[spi] && cnt > 0) {
|
while (tx_c[spi] && cnt > 0) {
|
||||||
fifo_write(spi, tx_p[spi], bytes);
|
fifo_write(spi, tx_buffer, bytes);
|
||||||
tx_p[spi] += bytes;
|
tx_buffer += bytes;
|
||||||
tx_c[spi]--;
|
tx_c[spi]--;
|
||||||
cnt--;
|
cnt--;
|
||||||
}
|
}
|
||||||
|
@ -349,10 +371,21 @@ static void handle_spi_rx_interrupt(const qm_ss_spi_t spi)
|
||||||
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
|
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
|
||||||
/* Calculate number of bytes per frame (1 or 2)*/
|
/* Calculate number of bytes per frame (1 or 2)*/
|
||||||
uint8_t bytes = BYTES_PER_FRAME(ctrl);
|
uint8_t bytes = BYTES_PER_FRAME(ctrl);
|
||||||
|
const qm_ss_spi_async_transfer_t *const transfer =
|
||||||
|
spi_async_transfer[spi];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Jump to the right position of RX buffer.
|
||||||
|
* If no bytes were received before, we start from the beginning,
|
||||||
|
* otherwise we jump to the next available frame position.
|
||||||
|
*/
|
||||||
|
uint8_t *rx_buffer =
|
||||||
|
transfer->rx + ((transfer->rx_len - rx_c[spi]) * bytes);
|
||||||
|
|
||||||
while (__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_RFNE &&
|
while (__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_RFNE &&
|
||||||
rx_c[spi]) {
|
rx_c[spi]) {
|
||||||
fifo_read(spi, rx_p[spi], bytes);
|
fifo_read(spi, rx_buffer, bytes);
|
||||||
rx_p[spi] += bytes;
|
rx_buffer += bytes;
|
||||||
rx_c[spi]--;
|
rx_c[spi]--;
|
||||||
}
|
}
|
||||||
/* Set new FIFO threshold or complete transfer */
|
/* Set new FIFO threshold or complete transfer */
|
||||||
|
@ -366,10 +399,9 @@ static void handle_spi_rx_interrupt(const qm_ss_spi_t spi)
|
||||||
__builtin_arc_sr(ftlr, base[spi] + QM_SS_SPI_FTLR);
|
__builtin_arc_sr(ftlr, base[spi] + QM_SS_SPI_FTLR);
|
||||||
} else {
|
} else {
|
||||||
spi_disable(spi);
|
spi_disable(spi);
|
||||||
if (transfer[spi]->callback) {
|
if (transfer->callback) {
|
||||||
transfer[spi]->callback(transfer[spi]->data, 0,
|
transfer->callback(transfer->callback_data, 0,
|
||||||
QM_SS_SPI_IDLE,
|
QM_SS_SPI_IDLE, transfer->rx_len);
|
||||||
transfer[spi]->rx_len);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
44
ext/hal/qmsi/drivers/sensor/sensor.mk
Normal file
44
ext/hal/qmsi/drivers/sensor/sensor.mk
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016, Intel Corporation
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions and the following disclaimer in the documentation
|
||||||
|
# and/or other materials provided with the distribution.
|
||||||
|
# 3. Neither the name of the Intel Corporation nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from this
|
||||||
|
# software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
SENSOR_DIR = $(BASE_DIR)/drivers/sensor
|
||||||
|
OBJ_DIRS += $(SENSOR_DIR)/$(BUILD)/$(SOC)/$(TARGET)
|
||||||
|
SENSOR_SOURCES = $(wildcard $(SENSOR_DIR)/*.c)
|
||||||
|
OBJECTS += $(addprefix $(DRV_DIR)/$(BUILD)/$(SOC)/$(TARGET)/$(OBJ)/,$(notdir $(SENSOR_SOURCES:.c=.o)))
|
||||||
|
|
||||||
|
### Flags
|
||||||
|
CFLAGS += -I$(SENSOR_DIR)
|
||||||
|
CFLAGS += -I$(SENSOR_DIR)/include
|
||||||
|
CFLAGS += -I$(BASE_DIR)/soc/$(SOC_ROOT_DIR)/include
|
||||||
|
|
||||||
|
### Build C files
|
||||||
|
$(DRV_DIR)/$(BUILD)/$(SOC)/$(TARGET)/$(OBJ)/%.o: $(SENSOR_DIR)/%.c
|
||||||
|
$(call mkdir, $(DRV_DIR)/$(BUILD)/$(SOC)/$(TARGET)/$(OBJ))
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
|
@ -28,6 +28,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ss_power_states.h"
|
#include "ss_power_states.h"
|
||||||
|
#include "qm_isr.h"
|
||||||
|
#include "qm_sensor_regs.h"
|
||||||
|
|
||||||
/* Sensor Subsystem sleep operand definition.
|
/* Sensor Subsystem sleep operand definition.
|
||||||
* Only a subset applies as internal sensor RTC
|
* Only a subset applies as internal sensor RTC
|
||||||
|
@ -58,6 +60,14 @@
|
||||||
*/
|
*/
|
||||||
void ss_power_cpu_ss1(const ss_power_cpu_ss1_mode_t mode)
|
void ss_power_cpu_ss1(const ss_power_cpu_ss1_mode_t mode)
|
||||||
{
|
{
|
||||||
|
/* The sensor cannot be woken up with an edge triggered
|
||||||
|
* interrupt from the RTC.
|
||||||
|
* Switch to Level triggered interrupts and restore
|
||||||
|
* the setting after when waking up.
|
||||||
|
*/
|
||||||
|
__builtin_arc_sr(QM_IRQ_RTC_0_VECTOR, QM_SS_AUX_IRQ_SELECT);
|
||||||
|
__builtin_arc_sr(QM_SS_IRQ_LEVEL_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER);
|
||||||
|
|
||||||
/* Enter SS1 */
|
/* Enter SS1 */
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case SS_POWER_CPU_SS1_TIMER_OFF:
|
case SS_POWER_CPU_SS1_TIMER_OFF:
|
||||||
|
@ -73,6 +83,10 @@ void ss_power_cpu_ss1(const ss_power_cpu_ss1_mode_t mode)
|
||||||
: "i"(QM_SS_SLEEP_MODE_CORE_OFF));
|
: "i"(QM_SS_SLEEP_MODE_CORE_OFF));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Restore the RTC to edge interrupt after when waking up. */
|
||||||
|
__builtin_arc_sr(QM_IRQ_RTC_0_VECTOR, QM_SS_AUX_IRQ_SELECT);
|
||||||
|
__builtin_arc_sr(QM_SS_IRQ_EDGE_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enter SS2 :
|
/* Enter SS2 :
|
||||||
|
@ -81,8 +95,20 @@ void ss_power_cpu_ss1(const ss_power_cpu_ss1_mode_t mode)
|
||||||
*/
|
*/
|
||||||
void ss_power_cpu_ss2(void)
|
void ss_power_cpu_ss2(void)
|
||||||
{
|
{
|
||||||
|
/* The sensor cannot be woken up with an edge triggered
|
||||||
|
* interrupt from the RTC.
|
||||||
|
* Switch to Level triggered interrupts and restore
|
||||||
|
* the setting after when waking up.
|
||||||
|
*/
|
||||||
|
__builtin_arc_sr(QM_IRQ_RTC_0_VECTOR, QM_SS_AUX_IRQ_SELECT);
|
||||||
|
__builtin_arc_sr(QM_SS_IRQ_LEVEL_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER);
|
||||||
|
|
||||||
/* Enter SS2 */
|
/* Enter SS2 */
|
||||||
__asm__ __volatile__("sleep %0"
|
__asm__ __volatile__("sleep %0"
|
||||||
:
|
:
|
||||||
: "i"(QM_SS_SLEEP_MODE_CORE_TIMERS_RTC_OFF));
|
: "i"(QM_SS_SLEEP_MODE_CORE_TIMERS_RTC_OFF));
|
||||||
|
|
||||||
|
/* Restore the RTC to edge interrupt after when waking up. */
|
||||||
|
__builtin_arc_sr(QM_IRQ_RTC_0_VECTOR, QM_SS_AUX_IRQ_SELECT);
|
||||||
|
__builtin_arc_sr(QM_SS_IRQ_EDGE_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER);
|
||||||
}
|
}
|
||||||
|
|
355
ext/hal/qmsi/drivers/soc_watch.c
Normal file
355
ext/hal/qmsi/drivers/soc_watch.c
Normal file
|
@ -0,0 +1,355 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016, Intel Corporation
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SoC Watch - QMSI power profiler
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (SOC_WATCH_ENABLE) && (!QM_SENSOR)
|
||||||
|
|
||||||
|
#include <x86intrin.h>
|
||||||
|
#include "qm_common.h"
|
||||||
|
#include "qm_soc_regs.h"
|
||||||
|
#include "qm_interrupt.h"
|
||||||
|
#include "soc_watch.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define a macro for exposing some functions and other definitions
|
||||||
|
* only when unit testing. If we're not unit testing, then declare
|
||||||
|
* them as static, so that their declarations are hidden to normal
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
#if (UNIT_TEST)
|
||||||
|
#define NONUTSTATIC
|
||||||
|
#else
|
||||||
|
#define NONUTSTATIC static
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Event strings" table, describing message structures.
|
||||||
|
* The first character is the event code to write to the data file.
|
||||||
|
* The 2nd and subsequent characters describe how to format the record's
|
||||||
|
* data. Note that the ordering here needs to agree with the
|
||||||
|
* enumeration list in qmsw_stub.h.
|
||||||
|
*
|
||||||
|
* Table characters:
|
||||||
|
* + First char = event code to write into the result file.
|
||||||
|
* + T = TSC Timestamp (Hi-res timestamp)
|
||||||
|
* + t = RTC Timestamp (lo-res timestamp)
|
||||||
|
* + 1 = interpret ev_data as a 1-byte value
|
||||||
|
* + 4 = interpret ev_data as a 4-byte value
|
||||||
|
* + R = Using ev_data as a register enumeration, read that register,
|
||||||
|
* + and put that 4-byte value into the data file.
|
||||||
|
* + L = Trigger an RTC timestamp Later
|
||||||
|
*/
|
||||||
|
NONUTSTATIC const char *ev_strs[] = {
|
||||||
|
"HT", /* Halt event */
|
||||||
|
"IT1", /* Interrupt event */
|
||||||
|
"STtL", /* Sleep event */
|
||||||
|
"RT1R", /* Register read event: Timestamp, reg enum, reg value*/
|
||||||
|
"UTs4", /* User event: timestamp, subtype, data value. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This list of registers corresponds to the SoC Watch register ID
|
||||||
|
* enumeration in soc_watch.h, and MUST STAY IN AGREEMENT with that
|
||||||
|
* list, since that enumeration is used to index this list.
|
||||||
|
*
|
||||||
|
* To record a register value, the SoC Watch code indexes into this
|
||||||
|
* array, and reads the corresponding address found in that slot.
|
||||||
|
*/
|
||||||
|
#if (QUARK_D2000)
|
||||||
|
static const uint32_t *platform_regs[] = {
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->osc0_cfg1),
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_lp_clk_ctl),
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_sys_clk_ctl),
|
||||||
|
/* Clock Gating Registers */
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_periph_clk_gate_ctl),
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_ext_clock_ctl),
|
||||||
|
/* Power Consumption regs */
|
||||||
|
(uint32_t *)(&QM_SCSS_CMP->cmp_pwr),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en)};
|
||||||
|
#elif(QUARK_SE)
|
||||||
|
static const uint32_t *platform_regs[] = {
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->osc0_cfg1),
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_lp_clk_ctl),
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_sys_clk_ctl),
|
||||||
|
/* Clock Gating Registers */
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_periph_clk_gate_ctl),
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_ss_periph_clk_gate_ctl),
|
||||||
|
(uint32_t *)(&QM_SCSS_CCU->ccu_ext_clock_ctl),
|
||||||
|
/* Power Consumption regs */
|
||||||
|
(uint32_t *)(&QM_SCSS_CMP->cmp_pwr), (uint32_t *)(&QM_SCSS_PMU->slp_cfg),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup[1]),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup[2]),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup[3]),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew[1]),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew[2]),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew[3]),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en[1]),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en[2]),
|
||||||
|
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en[3])};
|
||||||
|
#endif /* QUARK_SE */
|
||||||
|
|
||||||
|
/* Define VERBOSE to turn on printf-based logging */
|
||||||
|
#ifdef VERBOSE
|
||||||
|
#define SOC_WATCH_TRACE QM_PRINTF
|
||||||
|
#else
|
||||||
|
#define SOC_WATCH_TRACE(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mlog routines -- low-level memory debug logging.
|
||||||
|
* Only enable if there's a need to debug this module.
|
||||||
|
*/
|
||||||
|
#ifdef MLOG_ENABLE
|
||||||
|
#define MLOG(e) mlog(e)
|
||||||
|
#define MLOG_BYTE(b) mlog_byte(b)
|
||||||
|
#define MLOG_SIZE 512 /* Must be a power of 2 */
|
||||||
|
static uint8_t mlog_events[MLOG_SIZE];
|
||||||
|
static uint16_t mlog_idx = 0;
|
||||||
|
void mlog(uint8_t event)
|
||||||
|
{
|
||||||
|
mlog_events[++mlog_idx % (MLOG_SIZE)] = event;
|
||||||
|
}
|
||||||
|
void mlog_byte(uint8_t byte)
|
||||||
|
{
|
||||||
|
const char c[] = {"0123456789ABCDEF"};
|
||||||
|
MLOG(c[byte >> 4]);
|
||||||
|
MLOG(c[byte & 4]);
|
||||||
|
}
|
||||||
|
#else /* !MLOG_ENABLE */
|
||||||
|
#define MLOG(event)
|
||||||
|
#define MLOG_BYTE(b)
|
||||||
|
#endif /* !MLOG_ENABLE */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CONFIGURABLE: Set this to control the number of bytes of RAM you
|
||||||
|
* want to dedicate to event buffering. The larger the buffer,
|
||||||
|
* the fewer (expensive) flushes we will have to do. The smaller,
|
||||||
|
* the lower the memory cost, but the more flushes you will do.
|
||||||
|
*/
|
||||||
|
#define SOC_WATCH_EVENT_BUFFER_SIZE (256) /* Measured in bytes */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Power profiling event data buffer. Symbol must be globally
|
||||||
|
* visible, so that it can be seen by external tools.
|
||||||
|
*/
|
||||||
|
struct sw_profiling_event_buffer {
|
||||||
|
uint8_t eb_idx; /* Index of next byte to be written */
|
||||||
|
uint8_t eb_size; /* Buffer size == SOC_WATCH_EVENT_BUFFER_SIZE */
|
||||||
|
uint8_t event_data[SOC_WATCH_EVENT_BUFFER_SIZE - 2]; /* Event data -
|
||||||
|
sizeof(idx + size) */
|
||||||
|
} soc_watch_event_buffer = {0, SOC_WATCH_EVENT_BUFFER_SIZE - 1, {0}};
|
||||||
|
|
||||||
|
/* High water mark, i.e. "start trying to flush" point. */
|
||||||
|
#define SW_EB_HIGH_WATER (((SOC_WATCH_EVENT_BUFFER_SIZE - 2) * 7) >> 3)
|
||||||
|
|
||||||
|
NONUTSTATIC int soc_watch_buffer_full(void)
|
||||||
|
{
|
||||||
|
return (soc_watch_event_buffer.eb_idx >= SW_EB_HIGH_WATER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag used by the JTAG data extraction routine. During setup, a HW
|
||||||
|
* watchpoint is placed on this address. During the flush routine,
|
||||||
|
* software writes to it, causing the HW watchpoint to fire, and
|
||||||
|
* OpenOCD to extract the data. This symbol MUST be globally visible
|
||||||
|
* in order for JTAG data transfer to work.
|
||||||
|
*/
|
||||||
|
volatile uint8_t soc_watch_flush_flag = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* soc_watch_event_buffer_flush -- Trigger the data buffer flush.
|
||||||
|
*/
|
||||||
|
static void soc_watch_event_buffer_flush(void)
|
||||||
|
{
|
||||||
|
/* Figure out if we can successfully flush the data out.
|
||||||
|
* If we're sleeping, the JTAG query will fail.
|
||||||
|
*/
|
||||||
|
#if (QUARK_D2000)
|
||||||
|
/**
|
||||||
|
* If the "we're going to sleep" bit is set, parts of the
|
||||||
|
* SOC are already asleep, and transferring data over
|
||||||
|
* the JTAG port is not always reliable. So defer transferring
|
||||||
|
* the data until later.
|
||||||
|
* @TODO: Determine if there is also a sensitivity to the
|
||||||
|
* clock rate.
|
||||||
|
*/
|
||||||
|
MLOG('F');
|
||||||
|
if (QM_SCSS_PMU->aon_vr & QM_AON_VR_VREG_SEL) {
|
||||||
|
MLOG('-');
|
||||||
|
return; /* We would only send junk, so don't flush. */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
soc_watch_flush_flag = 1; /* Trigger the data extract brkpt */
|
||||||
|
soc_watch_event_buffer.eb_idx = 0;
|
||||||
|
MLOG('+');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store a byte in the event buffer. */
|
||||||
|
static void eb_write_char(uint8_t data)
|
||||||
|
{
|
||||||
|
SOC_WATCH_TRACE("c%d:0x%x [0]=%x\n", soc_watch_event_buffer.eb_idx,
|
||||||
|
data, soc_watch_event_buffer.event_data[0]);
|
||||||
|
soc_watch_event_buffer.event_data[soc_watch_event_buffer.eb_idx++] =
|
||||||
|
data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store a word in the event buffer. */
|
||||||
|
static void eb_write_uint32(uint32_t *data)
|
||||||
|
{
|
||||||
|
uint32_t *uip = (uint32_t *)&soc_watch_event_buffer
|
||||||
|
.event_data[soc_watch_event_buffer.eb_idx];
|
||||||
|
*uip = *data;
|
||||||
|
SOC_WATCH_TRACE("I%d:0x%x\n", soc_watch_event_buffer.eb_idx, *data);
|
||||||
|
soc_watch_event_buffer.eb_idx += sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Log an event with one parameter. */
|
||||||
|
void soc_watch_log_event(soc_watch_event_t event_id, uintptr_t ev_data)
|
||||||
|
{
|
||||||
|
soc_watch_log_app_event(event_id, 0, ev_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log an event with two parameters, where the subtype comes from
|
||||||
|
* the user. Note that what actually makes this an 'application event' is
|
||||||
|
* the event_id, not the fact that it is coming in via this interface.
|
||||||
|
*/
|
||||||
|
void soc_watch_log_app_event(soc_watch_event_t event_id, uint8_t ev_subtype,
|
||||||
|
uintptr_t ev_data)
|
||||||
|
{
|
||||||
|
static uint8_t record_rtc = 0;
|
||||||
|
const uint32_t *rtc_ctr = (uint32_t *)&QM_RTC->rtc_ccr;
|
||||||
|
const char *cp;
|
||||||
|
uint64_t tsc = __builtin_ia32_rdtsc(); /* Grab hi-res timestamp */
|
||||||
|
uint32_t rtc_val = *rtc_ctr;
|
||||||
|
|
||||||
|
#define AVG_EVENT_SIZE 8 /* Size of a typical message in bytes. */
|
||||||
|
|
||||||
|
MLOG('[');
|
||||||
|
qm_irq_disable();
|
||||||
|
/* TODO: We know exactly how many bytes of storage we need,
|
||||||
|
* since we know the event code. So don't do an "AVG" size thing
|
||||||
|
* here--use the exact size!
|
||||||
|
*/
|
||||||
|
if ((soc_watch_event_buffer.eb_idx + AVG_EVENT_SIZE) <=
|
||||||
|
soc_watch_event_buffer.eb_size) {
|
||||||
|
|
||||||
|
/* Map a halt event to a sleep event where appropriate. */
|
||||||
|
#if (QUARK_D2000)
|
||||||
|
if (event_id == SOCW_EVENT_HALT) {
|
||||||
|
if (QM_SCSS_PMU->aon_vr & QM_AON_VR_VREG_SEL) {
|
||||||
|
event_id = SOCW_EVENT_SLEEP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Record the RTC of the waking event, if it's rousing us from
|
||||||
|
* sleep. */
|
||||||
|
if (record_rtc) {
|
||||||
|
eb_write_char('t');
|
||||||
|
eb_write_uint32((uint32_t *)(&rtc_val)); /* Timestamp */
|
||||||
|
record_rtc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_id >= SOCW_EVENT_MAX) {
|
||||||
|
SOC_WATCH_TRACE("Unknown event id: 0x%x\n", event_id);
|
||||||
|
MLOG('?');
|
||||||
|
qm_irq_enable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cp = ev_strs[event_id]; /* Look up event string */
|
||||||
|
SOC_WATCH_TRACE("%c", *cp);
|
||||||
|
MLOG(*cp);
|
||||||
|
eb_write_char(*cp); /* Write event code */
|
||||||
|
while (*++cp) {
|
||||||
|
switch (*cp) {
|
||||||
|
case 'T':
|
||||||
|
eb_write_uint32((uint32_t *)(&tsc)); /* Hi-res
|
||||||
|
Timestamp */
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
eb_write_uint32(
|
||||||
|
(uint32_t *)(&rtc_val)); /* Lo-res
|
||||||
|
Timestamp */
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
record_rtc = 1;
|
||||||
|
break;
|
||||||
|
case 'R': /* Register data value */
|
||||||
|
eb_write_uint32(
|
||||||
|
(uint32_t *)platform_regs[ev_data]);
|
||||||
|
break;
|
||||||
|
case '4': /* 32-bit data value */
|
||||||
|
eb_write_uint32((uint32_t *)&ev_data);
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
/* Register ID */
|
||||||
|
eb_write_char(((uint32_t)ev_data) & 0xff);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
/* Event subtype */
|
||||||
|
eb_write_char(((uint32_t)ev_subtype) & 0xff);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SOC_WATCH_TRACE(
|
||||||
|
"Unknown string char: 0x%x on string "
|
||||||
|
"0x%x\n",
|
||||||
|
*cp, event_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is an interrupt which roused the CPU out of a sleep state,
|
||||||
|
* don't flush the buffer. (Due to a bug in OpenOCD, doing so will
|
||||||
|
* clear the HW watchpoint, ensuring no further flushes are seen by
|
||||||
|
* OpenOCD.)
|
||||||
|
*/
|
||||||
|
if ((soc_watch_buffer_full()) && (event_id != SOCW_EVENT_INTERRUPT)) {
|
||||||
|
SOC_WATCH_TRACE("\n --- FLUSH: idx= %d ---\n",
|
||||||
|
soc_watch_event_buffer.eb_idx);
|
||||||
|
soc_watch_event_buffer_flush();
|
||||||
|
}
|
||||||
|
MLOG(':');
|
||||||
|
MLOG_BYTE(soc_watch_event_buffer.eb_idx);
|
||||||
|
qm_irq_enable();
|
||||||
|
MLOG(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !(defined(SOC_WATCH) && (!QM_SENSOR)) */
|
|
@ -55,15 +55,21 @@ struct interrupt_frame;
|
||||||
|
|
||||||
#define REG_VAL(addr) (*((volatile uint32_t *)addr))
|
#define REG_VAL(addr) (*((volatile uint32_t *)addr))
|
||||||
|
|
||||||
|
/* QM_ASSERT is not currently available for Zephyr. */
|
||||||
|
#define ASSERT_EXCLUDE (ZEPHYR_OS)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In our reference implementation, by default DEBUG enables QM_PUTS and
|
* In our reference implementation, by default DEBUG enables QM_PUTS and
|
||||||
* QM_ASSERT but not QM_PRINTF.
|
* QM_ASSERT but not QM_PRINTF.
|
||||||
* User can modify this block to customise the default DEBUG configuration.
|
* User can modify this block to customise the default DEBUG configuration.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if (DEBUG)
|
#if (DEBUG)
|
||||||
|
#if !ASSERT_EXCLUDE
|
||||||
#ifndef ASSERT_ENABLE
|
#ifndef ASSERT_ENABLE
|
||||||
#define ASSERT_ENABLE (1)
|
#define ASSERT_ENABLE (1)
|
||||||
#endif
|
#endif
|
||||||
|
#endif /* ASSERT_EXCLUDE */
|
||||||
#ifndef PUTS_ENABLE
|
#ifndef PUTS_ENABLE
|
||||||
#define PUTS_ENABLE (1)
|
#define PUTS_ENABLE (1)
|
||||||
#endif
|
#endif
|
||||||
|
@ -112,7 +118,8 @@ void stdout_uart_setup(uint32_t baud_divisors);
|
||||||
#endif /* PRINTF_ENABLE || PUTS_ENABLE || ASSERT_ENABLE */
|
#endif /* PRINTF_ENABLE || PUTS_ENABLE || ASSERT_ENABLE */
|
||||||
|
|
||||||
#if (PRINTF_ENABLE)
|
#if (PRINTF_ENABLE)
|
||||||
#define QM_PRINTF(...) printf(__VA_ARGS__)
|
int pico_printf(const char *format, ...);
|
||||||
|
#define QM_PRINTF(...) pico_printf(__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define QM_PRINTF(...)
|
#define QM_PRINTF(...)
|
||||||
#endif /* PRINTF_ENABLE */
|
#endif /* PRINTF_ENABLE */
|
||||||
|
@ -146,7 +153,7 @@ void stdout_uart_setup(uint32_t baud_divisors);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stdout UART intialization is enabled by default. Use this switch if you wish
|
* Stdout UART initialization is enabled by default. Use this switch if you wish
|
||||||
* to disable it (e.g. if the UART is already initialized by an application
|
* to disable it (e.g. if the UART is already initialized by an application
|
||||||
* running on the other core).
|
* running on the other core).
|
||||||
*/
|
*/
|
||||||
|
@ -266,4 +273,39 @@ void stdout_uart_setup(uint32_t baud_divisors);
|
||||||
#define QM_VER_STRINGIFY(major, minor, patch) \
|
#define QM_VER_STRINGIFY(major, minor, patch) \
|
||||||
QM_STRINGIFY(major) "." QM_STRINGIFY(minor) "." QM_STRINGIFY(patch)
|
QM_STRINGIFY(major) "." QM_STRINGIFY(minor) "." QM_STRINGIFY(patch)
|
||||||
|
|
||||||
|
#if (SOC_WATCH_ENABLE) && (!QM_SENSOR)
|
||||||
|
/**
|
||||||
|
* Front-end macro for logging a SoC Watch event. When SOC_WATCH_ENABLE
|
||||||
|
* is not set to 1, the macro expands to nothing, there is no overhead.
|
||||||
|
*
|
||||||
|
* @param[in] event_id The Event ID of the profile event.
|
||||||
|
* @param[in] ev_data A parameter to the event ID (if the event needs one).
|
||||||
|
*
|
||||||
|
* @returns Nothing.
|
||||||
|
*/
|
||||||
|
#define SOC_WATCH_LOG_EVENT(event, param) \
|
||||||
|
do { \
|
||||||
|
soc_watch_log_event(event, param); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Front-end macro for logging application events via the power profiler
|
||||||
|
* logger. When SOC_WATCH_ENABLE is not set to 1, the macro expands to
|
||||||
|
* nothing, there is no overhead.
|
||||||
|
*
|
||||||
|
* @param[in] event_id The Event ID of the profile event.
|
||||||
|
* @param[in] ev_subtype A 1-byte user-defined event_id.
|
||||||
|
* @param[in] ev_data A parameter to the event ID (if the event needs one).
|
||||||
|
*
|
||||||
|
* @returns Nothing.
|
||||||
|
*/
|
||||||
|
#define SOC_WATCH_LOG_APP_EVENT(event, subtype, param) \
|
||||||
|
do { \
|
||||||
|
soc_watch_log_app_event(event, subtype, param); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define SOC_WATCH_LOG_EVENT(event, param)
|
||||||
|
#define SOC_WATCH_LOG_APP_EVENT(event, subtype, param)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __QM_COMMON_H__ */
|
#endif /* __QM_COMMON_H__ */
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2016, Intel Corporation
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Intel Corporation nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from this
|
|
||||||
* software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SPINLOCK_H__
|
|
||||||
#define __SPINLOCK_H__
|
|
||||||
|
|
||||||
#include "qm_soc_regs.h"
|
|
||||||
/*
|
|
||||||
* Single, shared spinlock which can be used for synchronization between the
|
|
||||||
* Lakemont and ARC cores.
|
|
||||||
* The Spinlock lock size and position in RAM must be same on both cores.
|
|
||||||
*/
|
|
||||||
#if (QUARK_SE)
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
volatile char flag[2];
|
|
||||||
volatile char turn;
|
|
||||||
} spinlock_t;
|
|
||||||
|
|
||||||
extern spinlock_t __esram_lock_start;
|
|
||||||
void spinlock_lock(spinlock_t *lock);
|
|
||||||
void spinlock_unlock(spinlock_t *lock);
|
|
||||||
|
|
||||||
#define QM_SPINLOCK_LOCK() spinlock_lock(&__esram_lock_start)
|
|
||||||
#define QM_SPINLOCK_UNLOCK() spinlock_unlock(&__esram_lock_start)
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define QM_SPINLOCK_LOCK()
|
|
||||||
#define QM_SPINLOCK_UNLOCK()
|
|
||||||
|
|
||||||
#endif /* defined(QM_QUARK_SE) */
|
|
||||||
|
|
||||||
#endif /* __SPINLOCK_H__ */
|
|
|
@ -30,13 +30,15 @@
|
||||||
#include "power_states.h"
|
#include "power_states.h"
|
||||||
#include "clk.h"
|
#include "clk.h"
|
||||||
#include "qm_comparator.h"
|
#include "qm_comparator.h"
|
||||||
|
#include "qm_isr.h"
|
||||||
#include "qm_adc.h"
|
#include "qm_adc.h"
|
||||||
|
|
||||||
#include "rar.h"
|
#include "rar.h"
|
||||||
|
#include "soc_watch.h"
|
||||||
|
|
||||||
void cpu_halt(void)
|
void power_cpu_halt(void)
|
||||||
{
|
{
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_HALT, 0);
|
||||||
__asm__ __volatile__("hlt");
|
__asm__ __volatile__("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +57,7 @@ static void clear_all_pending_interrupts(void)
|
||||||
QM_GPIO[QM_GPIO_0]->gpio_porta_eoi = -1;
|
QM_GPIO[QM_GPIO_0]->gpio_porta_eoi = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void soc_sleep(void)
|
void power_soc_sleep(void)
|
||||||
{
|
{
|
||||||
/* Variables to save register values. */
|
/* Variables to save register values. */
|
||||||
uint32_t ac_power_save;
|
uint32_t ac_power_save;
|
||||||
|
@ -79,6 +81,8 @@ void soc_sleep(void)
|
||||||
* Mask registers.
|
* Mask registers.
|
||||||
*/
|
*/
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_WAKE_PROBE_MODE_MASK;
|
QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_WAKE_PROBE_MODE_MASK;
|
||||||
|
/* Enable all wake sources as interrupts. */
|
||||||
|
QM_SCSS_CCU->wake_mask = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that powering down of oscillators is delayed by hardware until
|
* Ensure that powering down of oscillators is delayed by hardware until
|
||||||
|
@ -93,10 +97,9 @@ void soc_sleep(void)
|
||||||
* frequency than RTC clock.
|
* frequency than RTC clock.
|
||||||
*/
|
*/
|
||||||
/* CCU_LP_CLK_CTL.CCU_EXIT_TO_HYBOSC */
|
/* CCU_LP_CLK_CTL.CCU_EXIT_TO_HYBOSC */
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl |= QM_CCU_EXIT_TO_HYBOSC;
|
QM_SCSS_CCU->ccu_lp_clk_ctl |=
|
||||||
|
QM_CCU_EXIT_TO_HYBOSC | QM_CCU_MEM_HALT_EN | QM_CCU_CPU_HALT_EN;
|
||||||
/* Power down hybrid oscillator after HALT instruction is executed. */
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);
|
||||||
QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_PD;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only the following peripherals can be used as a wakeup source:
|
* Only the following peripherals can be used as a wakeup source:
|
||||||
|
@ -124,7 +127,7 @@ void soc_sleep(void)
|
||||||
* CCU_SYS_CLK_CTL.CCU_SYS_CLK_SEL to RTC Oscillator.
|
* CCU_SYS_CLK_CTL.CCU_SYS_CLK_SEL to RTC Oscillator.
|
||||||
*/
|
*/
|
||||||
/* Enter SoC sleep mode. */
|
/* Enter SoC sleep mode. */
|
||||||
cpu_halt();
|
power_cpu_halt();
|
||||||
|
|
||||||
/* From here on, restore the SoC to an active state. */
|
/* From here on, restore the SoC to an active state. */
|
||||||
/* Set the RAR to normal mode. */
|
/* Set the RAR to normal mode. */
|
||||||
|
@ -137,6 +140,8 @@ void soc_sleep(void)
|
||||||
QM_SCSS_CCU->ccu_sys_clk_ctl |=
|
QM_SCSS_CCU->ccu_sys_clk_ctl |=
|
||||||
QM_CCU_SYS_CLK_DIV_EN | QM_CCU_RTC_CLK_DIV_EN;
|
QM_CCU_SYS_CLK_DIV_EN | QM_CCU_RTC_CLK_DIV_EN;
|
||||||
|
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_SYS_CLK_CTL);
|
||||||
|
|
||||||
/* Wait for the XTAL or SI oscillator to stabilise. */
|
/* Wait for the XTAL or SI oscillator to stabilise. */
|
||||||
while (!(QM_SCSS_CCU->osc0_stat1 &
|
while (!(QM_SCSS_CCU->osc0_stat1 &
|
||||||
(QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {
|
(QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {
|
||||||
|
@ -145,12 +150,14 @@ void soc_sleep(void)
|
||||||
/* Restore original clocking, ADC, analog comparator states. */
|
/* Restore original clocking, ADC, analog comparator states. */
|
||||||
QM_SCSS_CCU->osc0_cfg1 = osc0_cfg_save;
|
QM_SCSS_CCU->osc0_cfg1 = osc0_cfg_save;
|
||||||
QM_SCSS_CCU->ccu_periph_clk_gate_ctl = clk_gate_save;
|
QM_SCSS_CCU->ccu_periph_clk_gate_ctl = clk_gate_save;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_OSC0_CFG1);
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||||
|
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||||
QM_SCSS_CMP->cmp_pwr = ac_power_save;
|
QM_SCSS_CMP->cmp_pwr = ac_power_save;
|
||||||
QM_ADC->adc_op_mode = adc_mode_save;
|
QM_ADC->adc_op_mode = adc_mode_save;
|
||||||
}
|
}
|
||||||
|
|
||||||
void soc_deep_sleep(void)
|
void power_soc_deep_sleep(const power_wake_event_t wake_event)
|
||||||
{
|
{
|
||||||
/* Variables to save register values. */
|
/* Variables to save register values. */
|
||||||
uint32_t ac_power_save;
|
uint32_t ac_power_save;
|
||||||
|
@ -170,9 +177,23 @@ void soc_deep_sleep(void)
|
||||||
/* Clear any pending interrupts. */
|
/* Clear any pending interrupts. */
|
||||||
clear_all_pending_interrupts();
|
clear_all_pending_interrupts();
|
||||||
|
|
||||||
/* Only clear the comparator wake mask bit. */
|
/*
|
||||||
QM_SCSS_CCU->wake_mask =
|
* Clear the wake mask bits. Default behaviour is to wake from GPIO /
|
||||||
SET_ALL_BITS & ~QM_CCU_WAKE_MASK_COMPARATOR_BIT;
|
* comparator.
|
||||||
|
*/
|
||||||
|
switch (wake_event) {
|
||||||
|
case POWER_WAKE_FROM_RTC:
|
||||||
|
QM_SCSS_CCU->wake_mask =
|
||||||
|
SET_ALL_BITS & ~QM_CCU_WAKE_MASK_RTC_BIT;
|
||||||
|
break;
|
||||||
|
case POWER_WAKE_FROM_GPIO_COMP:
|
||||||
|
default:
|
||||||
|
QM_SCSS_CCU->wake_mask = SET_ALL_BITS &
|
||||||
|
~(QM_CCU_WAKE_MASK_COMPARATOR_BIT |
|
||||||
|
QM_CCU_WAKE_MASK_GPIO_BIT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
QM_SCSS_GP->gps1 |= QM_SCSS_GP_POWER_STATE_DEEP_SLEEP;
|
QM_SCSS_GP->gps1 |= QM_SCSS_GP_POWER_STATE_DEEP_SLEEP;
|
||||||
|
|
||||||
qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_DEEP_PWR_DOWN);
|
qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_DEEP_PWR_DOWN);
|
||||||
|
@ -186,15 +207,20 @@ void soc_deep_sleep(void)
|
||||||
|
|
||||||
/* Disable external clocks. */
|
/* Disable external clocks. */
|
||||||
QM_SCSS_CCU->ccu_ext_clock_ctl = 0;
|
QM_SCSS_CCU->ccu_ext_clock_ctl = 0;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_EXT_CLK_CTL);
|
||||||
|
|
||||||
/* Set slew rate of all pins to 12mA. */
|
/* Set slew rate of all pins to 12mA. */
|
||||||
QM_SCSS_PMUX->pmux_slew[0] = 0;
|
QM_SCSS_PMUX->pmux_slew[0] = 0;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_PMUX_SLEW);
|
||||||
|
|
||||||
/* Disable RTC. */
|
if (wake_event != POWER_WAKE_FROM_RTC) {
|
||||||
QM_SCSS_CCU->osc1_cfg0 &= ~QM_OSC1_PD;
|
/* Disable RTC. */
|
||||||
|
QM_SCSS_CCU->osc1_cfg0 &= ~QM_OSC1_PD;
|
||||||
|
|
||||||
/* Set system clock source to hyb osc, 4 MHz, scaled down to 32 kHz. */
|
/* Set system clock source to
|
||||||
clk_sys_set_mode(CLK_SYS_HYB_OSC_4MHZ, CLK_SYS_DIV_128);
|
* Silicon Oscillator 4 MHz, scaled down to 32 kHz. */
|
||||||
|
clk_sys_set_mode(CLK_SYS_HYB_OSC_4MHZ, CLK_SYS_DIV_128);
|
||||||
|
}
|
||||||
|
|
||||||
/* Power down the oscillator after the halt instruction is executed. */
|
/* Power down the oscillator after the halt instruction is executed. */
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_HYB_OSC_PD_LATCH_EN;
|
QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_HYB_OSC_PD_LATCH_EN;
|
||||||
|
@ -204,6 +230,7 @@ void soc_deep_sleep(void)
|
||||||
*/
|
*/
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl |=
|
QM_SCSS_CCU->ccu_lp_clk_ctl |=
|
||||||
QM_CCU_EXIT_TO_HYBOSC | QM_CCU_MEM_HALT_EN | QM_CCU_CPU_HALT_EN;
|
QM_CCU_EXIT_TO_HYBOSC | QM_CCU_MEM_HALT_EN | QM_CCU_CPU_HALT_EN;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);
|
||||||
|
|
||||||
/* Power down hybrid oscillator. */
|
/* Power down hybrid oscillator. */
|
||||||
QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_PD;
|
QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_PD;
|
||||||
|
@ -244,8 +271,16 @@ void soc_deep_sleep(void)
|
||||||
/* Set the RAR to retention mode. */
|
/* Set the RAR to retention mode. */
|
||||||
rar_set_mode(RAR_RETENTION);
|
rar_set_mode(RAR_RETENTION);
|
||||||
|
|
||||||
|
if (wake_event == POWER_WAKE_FROM_RTC) {
|
||||||
|
/* Start running on the rtc clock */
|
||||||
|
clk_sys_set_mode(CLK_SYS_RTC_OSC, CLK_SYS_DIV_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable all peripheral clocks. */
|
||||||
|
clk_periph_disable(CLK_PERIPH_REGISTER | CLK_PERIPH_CLK);
|
||||||
|
|
||||||
/* Enter SoC deep sleep mode. */
|
/* Enter SoC deep sleep mode. */
|
||||||
cpu_halt();
|
power_cpu_halt();
|
||||||
|
|
||||||
/* We are now exiting from deep sleep mode. */
|
/* We are now exiting from deep sleep mode. */
|
||||||
/* Set the RAR to normal mode. */
|
/* Set the RAR to normal mode. */
|
||||||
|
@ -297,6 +332,7 @@ void soc_deep_sleep(void)
|
||||||
while (!(QM_SCSS_CCU->osc0_stat1 &
|
while (!(QM_SCSS_CCU->osc0_stat1 &
|
||||||
(QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {
|
(QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {
|
||||||
};
|
};
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_SYS_CLK_CTL);
|
||||||
|
|
||||||
/* Re-enable clocks. */
|
/* Re-enable clocks. */
|
||||||
clk_periph_enable(CLK_PERIPH_REGISTER);
|
clk_periph_enable(CLK_PERIPH_REGISTER);
|
||||||
|
@ -309,6 +345,9 @@ void soc_deep_sleep(void)
|
||||||
QM_SCSS_CCU->ccu_periph_clk_gate_ctl = clk_gate_save;
|
QM_SCSS_CCU->ccu_periph_clk_gate_ctl = clk_gate_save;
|
||||||
QM_SCSS_CCU->osc1_cfg0 = osc1_cfg_save;
|
QM_SCSS_CCU->osc1_cfg0 = osc1_cfg_save;
|
||||||
|
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_OSC0_CFG1);
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||||
|
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||||
QM_SCSS_CMP->cmp_pwr = ac_power_save;
|
QM_SCSS_CMP->cmp_pwr = ac_power_save;
|
||||||
QM_ADC->adc_op_mode = adc_mode_save;
|
QM_ADC->adc_op_mode = adc_mode_save;
|
||||||
|
|
||||||
|
@ -316,6 +355,10 @@ void soc_deep_sleep(void)
|
||||||
QM_SCSS_CCU->ccu_ext_clock_ctl = ext_clock_save;
|
QM_SCSS_CCU->ccu_ext_clock_ctl = ext_clock_save;
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl = lp_clk_save;
|
QM_SCSS_CCU->ccu_lp_clk_ctl = lp_clk_save;
|
||||||
|
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_PMUX_SLEW);
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_EXT_CLK_CTL);
|
||||||
|
|
||||||
QM_SCSS_CCU->wake_mask = SET_ALL_BITS;
|
QM_SCSS_CCU->wake_mask = SET_ALL_BITS;
|
||||||
QM_SCSS_GP->gps1 &= ~QM_SCSS_GP_POWER_STATE_DEEP_SLEEP;
|
QM_SCSS_GP->gps1 &= ~QM_SCSS_GP_POWER_STATE_DEEP_SLEEP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,78 @@ typedef union {
|
||||||
#define QM_FLASH_TRIM_PRESENT_MASK (0xFC00)
|
#define QM_FLASH_TRIM_PRESENT_MASK (0xFC00)
|
||||||
#define QM_FLASH_TRIM_PRESENT (0x7C00)
|
#define QM_FLASH_TRIM_PRESENT (0x7C00)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bootloader data
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** The flash controller where BL-Data is stored. */
|
||||||
|
#define BL_DATA_FLASH_CONTROLLER QM_FLASH_0
|
||||||
|
/** The flash region where BL-Data is stored. */
|
||||||
|
#define BL_DATA_FLASH_REGION QM_FLASH_REGION_DATA
|
||||||
|
/** The flash address where the BL-Data Section starts. */
|
||||||
|
#define BL_DATA_FLASH_REGION_BASE QM_FLASH_REGION_DATA_0_BASE
|
||||||
|
/** The flash page where the BL-Data Section starts. */
|
||||||
|
#define BL_DATA_SECTION_BASE_PAGE (0)
|
||||||
|
|
||||||
|
/** The size (in pages) of the System flash region of Quark D2000. */
|
||||||
|
#define QM_FLASH_REGION_SYS_0_PAGES (16)
|
||||||
|
|
||||||
|
/** The size of each flash partition for Lakemont application code. */
|
||||||
|
#if (BL_CONFIG_DUAL_BANK)
|
||||||
|
#define BL_PARTITION_SIZE_LMT (QM_FLASH_REGION_SYS_0_PAGES / 2)
|
||||||
|
#else /* !BL_CONFIG_DUAL_BANK */
|
||||||
|
#define BL_PARTITION_SIZE_LMT (QM_FLASH_REGION_SYS_0_PAGES)
|
||||||
|
#endif /* BL_CONFIG_DUAL_BANK */
|
||||||
|
|
||||||
|
/** Number of boot targets. */
|
||||||
|
#define BL_BOOT_TARGETS_NUM (1)
|
||||||
|
|
||||||
|
#define BL_TARGET_IDX_LMT (0)
|
||||||
|
|
||||||
|
#define BL_PARTITION_IDX_LMT0 (0)
|
||||||
|
#define BL_PARTITION_IDX_LMT1 (1)
|
||||||
|
|
||||||
|
#define BL_TARGET_0_LMT \
|
||||||
|
{ \
|
||||||
|
.active_partition_idx = BL_PARTITION_IDX_LMT0, .svn = 0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BL_PARTITION_0_LMT0 \
|
||||||
|
{ \
|
||||||
|
.target_idx = BL_TARGET_IDX_LMT, .controller = QM_FLASH_0, \
|
||||||
|
.first_page = 0, .num_pages = BL_PARTITION_SIZE_LMT, \
|
||||||
|
.start_addr = (uint32_t *)QM_FLASH_REGION_SYS_0_BASE, \
|
||||||
|
.is_consistent = true, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BL_PARTITION_1_LMT1 \
|
||||||
|
{ \
|
||||||
|
.target_idx = BL_TARGET_IDX_LMT, .controller = QM_FLASH_0, \
|
||||||
|
.first_page = BL_PARTITION_SIZE_LMT, \
|
||||||
|
.num_pages = BL_PARTITION_SIZE_LMT, \
|
||||||
|
.start_addr = \
|
||||||
|
(uint_32_t *)QM_FLASH_REGION_SYS_0_BASE + \
|
||||||
|
(BL_PARTITION_SIZE_LMT * QM_FLAH_PAGE_SIZE_DWORDS), \
|
||||||
|
.is_consistent = true, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BL_TARGET_LIST \
|
||||||
|
{ \
|
||||||
|
BL_TARGET_0_LMT \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (BL_CONFIG_DUAL_BANK)
|
||||||
|
#define BL_PARTITION_LIST \
|
||||||
|
{ \
|
||||||
|
BL_PARTITION_0_LMT0, BL_PARTITION_1_LMT1 \
|
||||||
|
}
|
||||||
|
#else /* !BL_CONFIG_DUAL_BANK */
|
||||||
|
#define BL_PARTITION_LIST \
|
||||||
|
{ \
|
||||||
|
BL_PARTITION_0_LMT0 \
|
||||||
|
}
|
||||||
|
#endif /* BL_CONFIG_DUAL_BANK */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -40,12 +40,20 @@
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wake source for deep sleep mode type.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
POWER_WAKE_FROM_GPIO_COMP, /**< Use GPIO / Comparator as wake source. */
|
||||||
|
POWER_WAKE_FROM_RTC, /**< Use RTC as wake source. */
|
||||||
|
} power_wake_event_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put CPU in halt state.
|
* Put CPU in halt state.
|
||||||
*
|
*
|
||||||
* Halts the CPU until next interrupt or reset.
|
* Halts the CPU until next interrupt or reset.
|
||||||
*/
|
*/
|
||||||
void cpu_halt(void);
|
void power_cpu_halt(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put SoC to sleep.
|
* Put SoC to sleep.
|
||||||
|
@ -68,15 +76,19 @@ void cpu_halt(void);
|
||||||
* - RTC
|
* - RTC
|
||||||
* - Low power comparators
|
* - Low power comparators
|
||||||
*/
|
*/
|
||||||
void soc_sleep();
|
void power_soc_sleep();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Put SoC to deep sleep.
|
* Put SoC to deep sleep.
|
||||||
*
|
*
|
||||||
* Enter into deep sleep mode. All clocks are gated. The only way to return
|
* Enter into deep sleep mode. All clocks are gated. The Wake source for this
|
||||||
* from this is to have an interrupt trigger on the low power comparators.
|
* function depends on the input parameter, POWER_WAKE_FROM_GPIO_COMP will
|
||||||
|
* enable waking from GPIO or comparator pins and POWER_WAKE_FROM_RTC will
|
||||||
|
* enable waking from the RTC.
|
||||||
|
*
|
||||||
|
* @param[in] wake_source Select wake source for deep sleep mode.
|
||||||
*/
|
*/
|
||||||
void soc_deep_sleep();
|
void power_soc_deep_sleep(const power_wake_event_t wake_event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
|
|
|
@ -33,10 +33,10 @@
|
||||||
#include "qm_common.h"
|
#include "qm_common.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Quark Microcontroller D2000 Register file.
|
* Quark D2000 SoC Registers.
|
||||||
*
|
|
||||||
* @brief Quark Microcontroller D2000 Registers.
|
|
||||||
*
|
*
|
||||||
|
* @defgroup groupQUARKD2000SEREG SoC Registers (D2000)
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define QUARK_D2000 (1)
|
#define QUARK_D2000 (1)
|
||||||
|
@ -44,10 +44,11 @@
|
||||||
#define HAS_MVIC (1)
|
#define HAS_MVIC (1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup groupD2000REG Quark D2000 Registers
|
* @name System Core
|
||||||
@{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** System Core register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t osc0_cfg0; /**< Hybrid Oscillator Configuration 0 */
|
QM_RW uint32_t osc0_cfg0; /**< Hybrid Oscillator Configuration 0 */
|
||||||
QM_RW uint32_t osc0_stat1; /**< Hybrid Oscillator status 1 */
|
QM_RW uint32_t osc0_stat1; /**< Hybrid Oscillator status 1 */
|
||||||
|
@ -79,7 +80,6 @@ qm_scss_ccu_reg_t test_scss_ccu;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_CCU_BASE (0xB0800000)
|
#define QM_SCSS_CCU_BASE (0xB0800000)
|
||||||
/** system control subsystem clock control unit register block */
|
|
||||||
#define QM_SCSS_CCU ((qm_scss_ccu_reg_t *)QM_SCSS_CCU_BASE)
|
#define QM_SCSS_CCU ((qm_scss_ccu_reg_t *)QM_SCSS_CCU_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -88,16 +88,16 @@ qm_scss_ccu_reg_t test_scss_ccu;
|
||||||
#define QM_OSC0_PD BIT(2)
|
#define QM_OSC0_PD BIT(2)
|
||||||
#define QM_OSC1_PD BIT(1)
|
#define QM_OSC1_PD BIT(1)
|
||||||
|
|
||||||
/* Enable Crystal oscillator*/
|
/* Enable Crystal oscillator. */
|
||||||
#define QM_OSC0_EN_CRYSTAL BIT(0)
|
#define QM_OSC0_EN_CRYSTAL BIT(0)
|
||||||
|
|
||||||
/* Crystal oscillator parameters */
|
/* Crystal oscillator parameters. */
|
||||||
#define OSC0_CFG1_OSC0_FADJ_XTAL_MASK (0x000F0000)
|
#define OSC0_CFG1_OSC0_FADJ_XTAL_MASK (0x000F0000)
|
||||||
#define OSC0_CFG1_OSC0_FADJ_XTAL_OFFS (16)
|
#define OSC0_CFG1_OSC0_FADJ_XTAL_OFFS (16)
|
||||||
#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_MASK (0x00600000)
|
#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_MASK (0x00600000)
|
||||||
#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_OFFS (21)
|
#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_OFFS (21)
|
||||||
|
|
||||||
/* Silicon Oscillator parameters */
|
/* Silicon Oscillator parameters. */
|
||||||
#define OSC0_CFG1_FTRIMOTP_MASK (0x3FF00000)
|
#define OSC0_CFG1_FTRIMOTP_MASK (0x3FF00000)
|
||||||
#define OSC0_CFG1_FTRIMOTP_OFFS (20)
|
#define OSC0_CFG1_FTRIMOTP_OFFS (20)
|
||||||
#define OSC0_CFG1_SI_FREQ_SEL_MASK (0x00000300)
|
#define OSC0_CFG1_SI_FREQ_SEL_MASK (0x00000300)
|
||||||
|
@ -106,36 +106,44 @@ qm_scss_ccu_reg_t test_scss_ccu;
|
||||||
#define QM_OSC0_LOCK_SI BIT(0)
|
#define QM_OSC0_LOCK_SI BIT(0)
|
||||||
#define QM_OSC0_LOCK_XTAL BIT(1)
|
#define QM_OSC0_LOCK_XTAL BIT(1)
|
||||||
#define QM_OSC0_EN_SI_OSC BIT(1)
|
#define QM_OSC0_EN_SI_OSC BIT(1)
|
||||||
|
|
||||||
#define QM_SI_OSC_1V2_MODE BIT(0)
|
#define QM_SI_OSC_1V2_MODE BIT(0)
|
||||||
|
|
||||||
|
/** Peripheral clock divider control */
|
||||||
|
#define QM_CCU_PERIPH_PCLK_DIV_OFFSET (1)
|
||||||
|
#define QM_CCU_PERIPH_PCLK_DIV_EN BIT(0)
|
||||||
|
|
||||||
|
/* System clock control */
|
||||||
#define QM_CCU_SYS_CLK_SEL BIT(0)
|
#define QM_CCU_SYS_CLK_SEL BIT(0)
|
||||||
#define QM_CCU_PERIPH_CLK_EN BIT(1)
|
#define QM_CCU_PERIPH_CLK_EN BIT(1)
|
||||||
#define QM_CCU_ADC_CLK_DIV_OFFSET (16)
|
#define QM_CCU_ADC_CLK_DIV_OFFSET (16)
|
||||||
#define QM_CCU_ADC_CLK_DIV_DEF_MASK (0xFC00FFFF)
|
#define QM_CCU_ADC_CLK_DIV_DEF_MASK (0xFC00FFFF)
|
||||||
#define QM_CCU_PERIPH_PCLK_DIV_DEF_MASK (0xFFFFFFF8)
|
#define QM_CCU_PERIPH_PCLK_DIV_DEF_MASK (0xFFFFFFF8)
|
||||||
#define QM_CCU_PERIPH_PCLK_DIV_OFFSET (1)
|
#define QM_CCU_RTC_CLK_EN BIT(1)
|
||||||
#define QM_CCU_PERIPH_PCLK_DIV_EN BIT(0)
|
#define QM_CCU_RTC_CLK_DIV_EN BIT(2)
|
||||||
#define QM_CCU_SYS_CLK_DIV_EN BIT(7)
|
#define QM_CCU_SYS_CLK_DIV_EN BIT(7)
|
||||||
#define QM_CCU_SYS_CLK_DIV_MASK (0x00000700)
|
#define QM_CCU_SYS_CLK_DIV_MASK (0x00000700)
|
||||||
#define QM_CCU_SYS_CLK_DIV_DEF_MASK (0xFFFFF47F)
|
|
||||||
#define QM_OSC0_SI_FREQ_SEL_DEF_MASK (0xFFFFFCFF)
|
#define QM_OSC0_SI_FREQ_SEL_DEF_MASK (0xFFFFFCFF)
|
||||||
|
#define QM_CCU_SYS_CLK_DIV_DEF_MASK (0xFFFFF47F)
|
||||||
#define QM_OSC0_SI_FREQ_SEL_4MHZ (3 >> 8)
|
#define QM_OSC0_SI_FREQ_SEL_4MHZ (3 >> 8)
|
||||||
#define QM_CCU_RTC_CLK_DIV_EN BIT(2)
|
|
||||||
#define QM_CCU_EXTERN_DIV_OFFSET (3)
|
#define QM_CCU_EXTERN_DIV_OFFSET (3)
|
||||||
#define QM_CCU_EXT_CLK_DIV_EN BIT(2)
|
#define QM_CCU_EXT_CLK_DIV_EN BIT(2)
|
||||||
#define QM_CCU_GPIO_DB_DIV_OFFSET (2)
|
#define QM_CCU_GPIO_DB_DIV_OFFSET (2)
|
||||||
#define QM_CCU_GPIO_DB_CLK_DIV_EN BIT(1)
|
#define QM_CCU_GPIO_DB_CLK_DIV_EN BIT(1)
|
||||||
|
#define QM_CCU_GPIO_DB_CLK_EN BIT(0)
|
||||||
#define QM_CCU_RTC_CLK_DIV_OFFSET (3)
|
#define QM_CCU_RTC_CLK_DIV_OFFSET (3)
|
||||||
#define QM_CCU_SYS_CLK_DIV_OFFSET (8)
|
#define QM_CCU_SYS_CLK_DIV_OFFSET (8)
|
||||||
#define QM_CCU_RTC_CLK_EN BIT(1)
|
|
||||||
#define QM_CCU_GPIO_DB_CLK_DIV_DEF_MASK (0xFFFFFFE1)
|
#define QM_CCU_GPIO_DB_CLK_DIV_DEF_MASK (0xFFFFFFE1)
|
||||||
#define QM_CCU_EXT_CLK_DIV_DEF_MASK (0xFFFFFFE3)
|
#define QM_CCU_EXT_CLK_DIV_DEF_MASK (0xFFFFFFE3)
|
||||||
#define QM_CCU_RTC_CLK_DIV_DEF_MASK (0xFFFFFF83)
|
#define QM_CCU_RTC_CLK_DIV_DEF_MASK (0xFFFFFF83)
|
||||||
#define QM_CCU_DMA_CLK_EN BIT(6)
|
#define QM_CCU_DMA_CLK_EN BIT(6)
|
||||||
|
#define QM_CCU_WAKE_MASK_RTC_BIT BIT(2)
|
||||||
|
#define QM_CCU_WAKE_MASK_GPIO_BIT BIT(15)
|
||||||
#define QM_CCU_WAKE_MASK_COMPARATOR_BIT BIT(14)
|
#define QM_CCU_WAKE_MASK_COMPARATOR_BIT BIT(14)
|
||||||
|
#define QM_CCU_WAKE_MASK_GPIO_BIT BIT(15)
|
||||||
|
|
||||||
#define QM_CCU_GPIO_DB_CLK_EN BIT(0)
|
|
||||||
#define QM_HYB_OSC_PD_LATCH_EN BIT(14)
|
#define QM_HYB_OSC_PD_LATCH_EN BIT(14)
|
||||||
#define QM_RTC_OSC_PD_LATCH_EN BIT(15)
|
#define QM_RTC_OSC_PD_LATCH_EN BIT(15)
|
||||||
#define QM_CCU_EXIT_TO_HYBOSC BIT(4)
|
#define QM_CCU_EXIT_TO_HYBOSC BIT(4)
|
||||||
|
@ -144,16 +152,24 @@ qm_scss_ccu_reg_t test_scss_ccu;
|
||||||
|
|
||||||
#define QM_WAKE_PROBE_MODE_MASK BIT(13)
|
#define QM_WAKE_PROBE_MODE_MASK BIT(13)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name General Purpose
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** General Purpose register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t gps0; /**< General Purpose Sticky Registers */
|
QM_RW uint32_t gps0; /**< General Purpose Sticky Register 0 */
|
||||||
QM_RW uint32_t gps1; /**< General Purpose Sticky Registers */
|
QM_RW uint32_t gps1; /**< General Purpose Sticky Register 1 */
|
||||||
QM_RW uint32_t gps2; /**< General Purpose Sticky Registers */
|
QM_RW uint32_t gps2; /**< General Purpose Sticky Register 2 */
|
||||||
QM_RW uint32_t gps3; /**< General Purpose Sticky Registers */
|
QM_RW uint32_t gps3; /**< General Purpose Sticky Register 3 */
|
||||||
QM_RW uint32_t reserved;
|
QM_RW uint32_t reserved;
|
||||||
QM_RW uint32_t gp0; /**< General Purpose Scratchpad Registers */
|
QM_RW uint32_t gp0; /**< General Purpose Scratchpad Register 0 */
|
||||||
QM_RW uint32_t gp1; /**< General Purpose Scratchpad Registers */
|
QM_RW uint32_t gp1; /**< General Purpose Scratchpad Register 1 */
|
||||||
QM_RW uint32_t gp2; /**< General Purpose Scratchpad Registers */
|
QM_RW uint32_t gp2; /**< General Purpose Scratchpad Register 2 */
|
||||||
QM_RW uint32_t gp3; /**< General Purpose Scratchpad Registers */
|
QM_RW uint32_t gp3; /**< General Purpose Scratchpad Register 3 */
|
||||||
QM_RW uint32_t reserved1[3];
|
QM_RW uint32_t reserved1[3];
|
||||||
QM_RW uint32_t wo_sp; /**< Write-One-to-Set Scratchpad Register */
|
QM_RW uint32_t wo_sp; /**< Write-One-to-Set Scratchpad Register */
|
||||||
QM_RW uint32_t
|
QM_RW uint32_t
|
||||||
|
@ -166,21 +182,28 @@ qm_scss_gp_reg_t test_scss_gp;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_GP_BASE (0xB0800100)
|
#define QM_SCSS_GP_BASE (0xB0800100)
|
||||||
/** system control subsystem general purpose register block */
|
|
||||||
#define QM_SCSS_GP ((qm_scss_gp_reg_t *)QM_SCSS_GP_BASE)
|
#define QM_SCSS_GP ((qm_scss_gp_reg_t *)QM_SCSS_GP_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QM_SCSS_GP_POWER_STATES_MASK (BIT(6) | BIT(7) | BIT(8) | BIT(9))
|
#define QM_SCSS_GP_POWER_STATES_MASK (BIT(6) | BIT(7) | BIT(8) | BIT(9))
|
||||||
#define QM_SCSS_GP_POWER_STATE_DEEP_SLEEP BIT(6)
|
#define QM_SCSS_GP_POWER_STATE_DEEP_SLEEP BIT(6)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Comparator
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Comparator register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t cmp_en; /**< Comparator enable */
|
QM_RW uint32_t cmp_en; /**< Comparator enable. */
|
||||||
QM_RW uint32_t cmp_ref_sel; /**< Comparator reference select */
|
QM_RW uint32_t cmp_ref_sel; /**< Comparator reference select. */
|
||||||
QM_RW uint32_t
|
QM_RW uint32_t
|
||||||
cmp_ref_pol; /**< Comparator reference polarity select register */
|
cmp_ref_pol; /**< Comparator reference polarity select register. */
|
||||||
QM_RW uint32_t cmp_pwr; /**< Comparator power enable register */
|
QM_RW uint32_t cmp_pwr; /**< Comparator power enable register. */
|
||||||
QM_RW uint32_t reserved[6];
|
QM_RW uint32_t reserved[6];
|
||||||
QM_RW uint32_t cmp_stat_clr; /**< Comparator clear register */
|
QM_RW uint32_t cmp_stat_clr; /**< Comparator clear register. */
|
||||||
} qm_scss_cmp_reg_t;
|
} qm_scss_cmp_reg_t;
|
||||||
|
|
||||||
#if (UNIT_TEST)
|
#if (UNIT_TEST)
|
||||||
|
@ -189,12 +212,19 @@ qm_scss_cmp_reg_t test_scss_cmp;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_CMP_BASE (0xB0800300)
|
#define QM_SCSS_CMP_BASE (0xB0800300)
|
||||||
/** system control subsystem comparators register block */
|
|
||||||
#define QM_SCSS_CMP ((qm_scss_cmp_reg_t *)QM_SCSS_CMP_BASE)
|
#define QM_SCSS_CMP ((qm_scss_cmp_reg_t *)QM_SCSS_CMP_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QM_AC_HP_COMPARATORS_MASK (0x7FFC0)
|
#define QM_AC_HP_COMPARATORS_MASK (0x7FFC0)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Interrupt
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Interrupt register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t int_i2c_mst_0_mask; /**< Interrupt Routing Mask 0 */
|
QM_RW uint32_t int_i2c_mst_0_mask; /**< Interrupt Routing Mask 0 */
|
||||||
QM_RW uint32_t reserved[2]; /* There is a hole in the address space. */
|
QM_RW uint32_t reserved[2]; /* There is a hole in the address space. */
|
||||||
|
@ -244,17 +274,23 @@ qm_scss_int_reg_t test_scss_int;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_INT_BASE (0xB0800448)
|
#define QM_SCSS_INT_BASE (0xB0800448)
|
||||||
/** system control subsystem Interrupt masking register block */
|
|
||||||
#define QM_SCSS_INT ((qm_scss_int_reg_t *)QM_SCSS_INT_BASE)
|
#define QM_SCSS_INT ((qm_scss_int_reg_t *)QM_SCSS_INT_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QM_INT_TIMER_HOST_HALT_MASK BIT(0)
|
#define QM_INT_TIMER_HOST_HALT_MASK BIT(0)
|
||||||
|
|
||||||
#define QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK BIT(16)
|
#define QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK BIT(16)
|
||||||
#define QM_INT_SRAM_CONTROLLER_HOST_MASK BIT(0)
|
#define QM_INT_SRAM_CONTROLLER_HOST_MASK BIT(0)
|
||||||
#define QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK BIT(16)
|
#define QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK BIT(16)
|
||||||
#define QM_INT_FLASH_CONTROLLER_HOST_MASK BIT(0)
|
#define QM_INT_FLASH_CONTROLLER_HOST_MASK BIT(0)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Power Management
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Power Management register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t aon_vr; /**< AON Voltage Regulator */
|
QM_RW uint32_t aon_vr; /**< AON Voltage Regulator */
|
||||||
QM_RW uint32_t reserved[5];
|
QM_RW uint32_t reserved[5];
|
||||||
|
@ -274,12 +310,18 @@ qm_scss_pmu_reg_t test_scss_pmu;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_PMU_BASE (0xB0800540)
|
#define QM_SCSS_PMU_BASE (0xB0800540)
|
||||||
/** system control subsystem power management register block */
|
|
||||||
#define QM_SCSS_PMU ((qm_scss_pmu_reg_t *)QM_SCSS_PMU_BASE)
|
#define QM_SCSS_PMU ((qm_scss_pmu_reg_t *)QM_SCSS_PMU_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QM_P_STS_HALT_INTERRUPT_REDIRECTION BIT(26)
|
#define QM_P_STS_HALT_INTERRUPT_REDIRECTION BIT(26)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Always-on controllers.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#define QM_AON_VR_ROK_BUF_VREG_MASK BIT(9)
|
#define QM_AON_VR_ROK_BUF_VREG_MASK BIT(9)
|
||||||
#define QM_AON_VR_VREG_SEL BIT(8)
|
#define QM_AON_VR_VREG_SEL BIT(8)
|
||||||
#define QM_AON_VR_PASS_CODE (0x9DC4 << 16)
|
#define QM_AON_VR_PASS_CODE (0x9DC4 << 16)
|
||||||
|
@ -288,20 +330,19 @@ qm_scss_pmu_reg_t test_scss_pmu;
|
||||||
#define QM_AON_VR_VSEL_1V8 (0x10)
|
#define QM_AON_VR_VSEL_1V8 (0x10)
|
||||||
#define QM_AON_VR_VSTRB BIT(5)
|
#define QM_AON_VR_VSTRB BIT(5)
|
||||||
|
|
||||||
/**
|
/** Number of SCSS Always-on controllers. */
|
||||||
* Number of SCSS Always on controllers.
|
|
||||||
*/
|
|
||||||
typedef enum { QM_SCSS_AON_0 = 0, QM_SCSS_AON_NUM } qm_scss_aon_t;
|
typedef enum { QM_SCSS_AON_0 = 0, QM_SCSS_AON_NUM } qm_scss_aon_t;
|
||||||
|
|
||||||
|
/** Always-on Controller register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t aonc_cnt; /**< Always on counter register */
|
QM_RW uint32_t aonc_cnt; /**< Always-on counter register. */
|
||||||
QM_RW uint32_t aonc_cfg; /**< Always on counter enable */
|
QM_RW uint32_t aonc_cfg; /**< Always-on counter enable. */
|
||||||
QM_RW uint32_t aonpt_cnt; /**< Always on periodic timer */
|
QM_RW uint32_t aonpt_cnt; /**< Always-on periodic timer. */
|
||||||
QM_RW uint32_t
|
QM_RW uint32_t
|
||||||
aonpt_stat; /**< Always on periodic timer status register */
|
aonpt_stat; /**< Always-on periodic timer status register. */
|
||||||
QM_RW uint32_t aonpt_ctrl; /**< Always on periodic timer control */
|
QM_RW uint32_t aonpt_ctrl; /**< Always-on periodic timer control. */
|
||||||
QM_RW uint32_t
|
QM_RW uint32_t
|
||||||
aonpt_cfg; /**< Always on periodic timer configuration register */
|
aonpt_cfg; /**< Always-on periodic timer configuration register. */
|
||||||
} qm_scss_aon_reg_t;
|
} qm_scss_aon_reg_t;
|
||||||
|
|
||||||
#if (UNIT_TEST)
|
#if (UNIT_TEST)
|
||||||
|
@ -310,10 +351,17 @@ qm_scss_aon_reg_t test_scss_aon;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_AON_BASE (0xB0800700)
|
#define QM_SCSS_AON_BASE (0xB0800700)
|
||||||
/** system control subsystem always on register block */
|
|
||||||
#define QM_SCSS_AON ((qm_scss_aon_reg_t *)QM_SCSS_AON_BASE)
|
#define QM_SCSS_AON ((qm_scss_aon_reg_t *)QM_SCSS_AON_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Peripheral Registers
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Peripheral Registers register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t periph_cfg0; /**< Peripheral Configuration */
|
QM_RW uint32_t periph_cfg0; /**< Peripheral Configuration */
|
||||||
QM_RW uint32_t reserved[2];
|
QM_RW uint32_t reserved[2];
|
||||||
|
@ -326,10 +374,17 @@ qm_scss_peripheral_reg_t test_scss_peripheral;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_PERIPHERAL_BASE (0xB0800804)
|
#define QM_SCSS_PERIPHERAL_BASE (0xB0800804)
|
||||||
/** system control subsystem peripheral register block */
|
|
||||||
#define QM_SCSS_PERIPHERAL ((qm_scss_peripheral_reg_t *)QM_SCSS_PERIPHERAL_BASE)
|
#define QM_SCSS_PERIPHERAL ((qm_scss_peripheral_reg_t *)QM_SCSS_PERIPHERAL_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Pin MUX
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Pin MUX register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t pmux_pullup[1]; /**< Pin Mux Pullup */
|
QM_RW uint32_t pmux_pullup[1]; /**< Pin Mux Pullup */
|
||||||
QM_RW uint32_t reserved[3];
|
QM_RW uint32_t reserved[3];
|
||||||
|
@ -352,10 +407,17 @@ qm_scss_pmux_reg_t test_scss_pmux;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_PMUX_BASE (0xB0800900)
|
#define QM_SCSS_PMUX_BASE (0xB0800900)
|
||||||
/** system control subsystem pin muxing register block */
|
|
||||||
#define QM_SCSS_PMUX ((qm_scss_pmux_reg_t *)QM_SCSS_PMUX_BASE)
|
#define QM_SCSS_PMUX ((qm_scss_pmux_reg_t *)QM_SCSS_PMUX_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ID
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Information register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t id; /**< Identification Register */
|
QM_RW uint32_t id; /**< Identification Register */
|
||||||
QM_RW uint32_t rev; /**< Revision Register */
|
QM_RW uint32_t rev; /**< Revision Register */
|
||||||
|
@ -371,11 +433,17 @@ qm_scss_info_reg_t test_scss_info;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define QM_SCSS_INFO_BASE (0xB0801000)
|
#define QM_SCSS_INFO_BASE (0xB0801000)
|
||||||
/** system control subsystem pin muxing register block */
|
|
||||||
#define QM_SCSS_INFO ((qm_scss_info_reg_t *)QM_SCSS_INFO_BASE)
|
#define QM_SCSS_INFO ((qm_scss_info_reg_t *)QM_SCSS_INFO_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** IRQs and interrupt vectors.
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name IRQs and Interrupts
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* IRQs and interrupt vectors.
|
||||||
*
|
*
|
||||||
* The vector numbers must be defined without arithmetic expressions nor
|
* The vector numbers must be defined without arithmetic expressions nor
|
||||||
* parentheses because they are expanded as token concatenation.
|
* parentheses because they are expanded as token concatenation.
|
||||||
|
@ -383,93 +451,93 @@ qm_scss_info_reg_t test_scss_info;
|
||||||
|
|
||||||
#define QM_INT_VECTOR_DOUBLE_FAULT 8
|
#define QM_INT_VECTOR_DOUBLE_FAULT 8
|
||||||
|
|
||||||
#define QM_IRQ_RTC_0 (2)
|
#define QM_IRQ_RTC_0 2
|
||||||
#define QM_IRQ_RTC_0_MASK_OFFSET (12)
|
#define QM_IRQ_RTC_0_MASK_OFFSET 12
|
||||||
#define QM_IRQ_RTC_0_VECTOR 34
|
#define QM_IRQ_RTC_0_VECTOR 34
|
||||||
|
|
||||||
#define QM_IRQ_AONPT_0 (3)
|
#define QM_IRQ_AONPT_0 3
|
||||||
#define QM_IRQ_AONPT_0_MASK_OFFSET (32)
|
#define QM_IRQ_AONPT_0_MASK_OFFSET 32
|
||||||
#define QM_IRQ_AONPT_0_VECTOR 35
|
#define QM_IRQ_AONPT_0_VECTOR 35
|
||||||
|
|
||||||
#define QM_IRQ_SPI_MASTER_0 (7)
|
#define QM_IRQ_PWM_0 11
|
||||||
#define QM_IRQ_SPI_MASTER_0_MASK_OFFSET (3)
|
#define QM_IRQ_PWM_0_MASK_OFFSET 10
|
||||||
#define QM_IRQ_SPI_MASTER_0_VECTOR 39
|
|
||||||
|
|
||||||
#define QM_IRQ_PWM_0 (11)
|
|
||||||
#define QM_IRQ_PWM_0_MASK_OFFSET (10)
|
|
||||||
#define QM_IRQ_PWM_0_VECTOR 43
|
#define QM_IRQ_PWM_0_VECTOR 43
|
||||||
|
|
||||||
#define QM_IRQ_AC (14)
|
#define QM_IRQ_SPI_MASTER_0 7
|
||||||
#define QM_IRQ_AC_MASK_OFFSET (26)
|
#define QM_IRQ_SPI_MASTER_0_MASK_OFFSET 3
|
||||||
#define QM_IRQ_AC_VECTOR 46
|
#define QM_IRQ_SPI_MASTER_0_VECTOR 39
|
||||||
|
|
||||||
#define QM_IRQ_ADC_0 (9)
|
#define QM_IRQ_ADC_0 9
|
||||||
#define QM_IRQ_ADC_0_MASK_OFFSET (34)
|
#define QM_IRQ_ADC_0_MASK_OFFSET 34
|
||||||
#define QM_IRQ_ADC_0_VECTOR 41
|
#define QM_IRQ_ADC_0_VECTOR 41
|
||||||
|
|
||||||
#define QM_IRQ_ADC_PWR_0 (19)
|
#define QM_IRQ_ADC_PWR_0 19
|
||||||
#define QM_IRQ_ADC_PWR_0_MASK_OFFSET (33)
|
#define QM_IRQ_ADC_PWR_0_MASK_OFFSET 33
|
||||||
#define QM_IRQ_ADC_PWR_0_VECTOR 51
|
#define QM_IRQ_ADC_PWR_0_VECTOR 51
|
||||||
|
|
||||||
#define QM_IRQ_WDT_0 (16)
|
#define QM_IRQ_WDT_0 16
|
||||||
#define QM_IRQ_WDT_0_MASK_OFFSET (13)
|
#define QM_IRQ_WDT_0_MASK_OFFSET 13
|
||||||
#define QM_IRQ_WDT_0_VECTOR 48
|
#define QM_IRQ_WDT_0_VECTOR 48
|
||||||
|
|
||||||
#define QM_IRQ_GPIO_0 (15)
|
#define QM_IRQ_GPIO_0 15
|
||||||
#define QM_IRQ_GPIO_0_MASK_OFFSET (9)
|
#define QM_IRQ_GPIO_0_MASK_OFFSET 9
|
||||||
#define QM_IRQ_GPIO_0_VECTOR 47
|
#define QM_IRQ_GPIO_0_VECTOR 47
|
||||||
|
|
||||||
#define QM_IRQ_I2C_0 (4)
|
#define QM_IRQ_I2C_0 4
|
||||||
#define QM_IRQ_I2C_0_MASK_OFFSET (0)
|
#define QM_IRQ_I2C_0_MASK_OFFSET 0
|
||||||
#define QM_IRQ_I2C_0_VECTOR 36
|
#define QM_IRQ_I2C_0_VECTOR 36
|
||||||
|
|
||||||
#define QM_IRQ_PIC_TIMER (10)
|
#define QM_IRQ_PIC_TIMER 10
|
||||||
/* No SCSS mask register for PIC timer: point to an unused register */
|
/* No SCSS mask register for PIC timer: point to an unused register */
|
||||||
#define QM_IRQ_PIC_TIMER_MASK_OFFSET (1)
|
#define QM_IRQ_PIC_TIMER_MASK_OFFSET 1
|
||||||
#define QM_IRQ_PIC_TIMER_VECTOR 42
|
#define QM_IRQ_PIC_TIMER_VECTOR 42
|
||||||
|
|
||||||
#define QM_IRQ_SRAM (17)
|
#define QM_IRQ_AC 14
|
||||||
#define QM_IRQ_SRAM_MASK_OFFSET (29)
|
#define QM_IRQ_AC_MASK_OFFSET 26
|
||||||
|
#define QM_IRQ_AC_VECTOR 46
|
||||||
|
|
||||||
|
#define QM_IRQ_SRAM 17
|
||||||
|
#define QM_IRQ_SRAM_MASK_OFFSET 29
|
||||||
#define QM_IRQ_SRAM_VECTOR 49
|
#define QM_IRQ_SRAM_VECTOR 49
|
||||||
|
|
||||||
#define QM_IRQ_FLASH_0 (18)
|
#define QM_IRQ_FLASH_0 18
|
||||||
#define QM_IRQ_FLASH_0_MASK_OFFSET (30)
|
#define QM_IRQ_FLASH_0_MASK_OFFSET 30
|
||||||
#define QM_IRQ_FLASH_0_VECTOR 50
|
#define QM_IRQ_FLASH_0_VECTOR 50
|
||||||
|
|
||||||
#define QM_IRQ_UART_0 (8)
|
#define QM_IRQ_UART_0 8
|
||||||
#define QM_IRQ_UART_0_MASK_OFFSET (6)
|
#define QM_IRQ_UART_0_MASK_OFFSET 6
|
||||||
#define QM_IRQ_UART_0_VECTOR 40
|
#define QM_IRQ_UART_0_VECTOR 40
|
||||||
|
|
||||||
#define QM_IRQ_UART_1 (6)
|
#define QM_IRQ_UART_1 6
|
||||||
#define QM_IRQ_UART_1_MASK_OFFSET (7)
|
#define QM_IRQ_UART_1_MASK_OFFSET 7
|
||||||
#define QM_IRQ_UART_1_VECTOR 38
|
#define QM_IRQ_UART_1_VECTOR 38
|
||||||
|
|
||||||
#define QM_IRQ_DMA_0 (13)
|
#define QM_IRQ_DMA_0 13
|
||||||
#define QM_IRQ_DMA_0_MASK_OFFSET (14)
|
#define QM_IRQ_DMA_0_MASK_OFFSET 14
|
||||||
#define QM_IRQ_DMA_0_VECTOR 45
|
#define QM_IRQ_DMA_0_VECTOR 45
|
||||||
|
|
||||||
#define QM_IRQ_DMA_1 (12)
|
#define QM_IRQ_DMA_1 12
|
||||||
#define QM_IRQ_DMA_1_MASK_OFFSET (15)
|
#define QM_IRQ_DMA_1_MASK_OFFSET 15
|
||||||
#define QM_IRQ_DMA_1_VECTOR 44
|
#define QM_IRQ_DMA_1_VECTOR 44
|
||||||
|
|
||||||
#define QM_IRQ_DMA_ERR (0)
|
#define QM_IRQ_DMA_ERR 0
|
||||||
#define QM_IRQ_DMA_ERR_MASK_OFFSET (28)
|
#define QM_IRQ_DMA_ERR_MASK_OFFSET 28
|
||||||
#define QM_IRQ_DMA_ERR_VECTOR 32
|
#define QM_IRQ_DMA_ERR_VECTOR 32
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of PWM/Timer controllers.
|
* @name PWM / Timer
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Number of PWM / Timer controllers. */
|
||||||
typedef enum { QM_PWM_0 = 0, QM_PWM_NUM } qm_pwm_t;
|
typedef enum { QM_PWM_0 = 0, QM_PWM_NUM } qm_pwm_t;
|
||||||
|
|
||||||
/**
|
/** PWM ID type. */
|
||||||
* PWM id type.
|
|
||||||
*/
|
|
||||||
typedef enum { QM_PWM_ID_0 = 0, QM_PWM_ID_1, QM_PWM_ID_NUM } qm_pwm_id_t;
|
typedef enum { QM_PWM_ID_0 = 0, QM_PWM_ID_1, QM_PWM_ID_NUM } qm_pwm_id_t;
|
||||||
|
|
||||||
/**
|
/** PWM / Timer channel register map. */
|
||||||
* PWM / Timer register map.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t loadcount; /**< Load Count */
|
QM_RW uint32_t loadcount; /**< Load Count */
|
||||||
QM_RW uint32_t currentvalue; /**< Current Value */
|
QM_RW uint32_t currentvalue; /**< Current Value */
|
||||||
|
@ -478,6 +546,7 @@ typedef struct {
|
||||||
QM_RW uint32_t intstatus; /**< Interrupt Status */
|
QM_RW uint32_t intstatus; /**< Interrupt Status */
|
||||||
} qm_pwm_channel_t;
|
} qm_pwm_channel_t;
|
||||||
|
|
||||||
|
/** PWM / Timer register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
qm_pwm_channel_t timer[QM_PWM_ID_NUM]; /**< 4 Timers */
|
qm_pwm_channel_t timer[QM_PWM_ID_NUM]; /**< 4 Timers */
|
||||||
QM_RW uint32_t reserved[30];
|
QM_RW uint32_t reserved[30];
|
||||||
|
@ -501,14 +570,17 @@ qm_pwm_reg_t test_pwm_t;
|
||||||
|
|
||||||
#define QM_PWM_INTERRUPT_MASK_OFFSET (2)
|
#define QM_PWM_INTERRUPT_MASK_OFFSET (2)
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
* Number of WDT controllers.
|
|
||||||
*/
|
|
||||||
typedef enum { QM_WDT_0 = 0, QM_WDT_NUM } qm_wdt_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Watchdog timer register block type.
|
* @name WDT
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Number of WDT controllers. */
|
||||||
|
typedef enum { QM_WDT_0 = 0, QM_WDT_NUM } qm_wdt_t;
|
||||||
|
|
||||||
|
/** Watchdog timer register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t wdt_cr; /**< Control Register */
|
QM_RW uint32_t wdt_cr; /**< Control Register */
|
||||||
QM_RW uint32_t wdt_torr; /**< Timeout Range Register */
|
QM_RW uint32_t wdt_torr; /**< Timeout Range Register */
|
||||||
|
@ -538,15 +610,17 @@ qm_wdt_reg_t test_wdt;
|
||||||
#define QM_WDT ((qm_wdt_reg_t *)QM_WDT_BASE)
|
#define QM_WDT ((qm_wdt_reg_t *)QM_WDT_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of UART controllers.
|
* @name UART
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Number of UART controllers. */
|
||||||
typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t;
|
typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t;
|
||||||
|
|
||||||
/**
|
/** UART register map. */
|
||||||
* UART register block type.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t rbr_thr_dll; /**< Rx Buffer/ Tx Holding/ Div Latch Low */
|
QM_RW uint32_t rbr_thr_dll; /**< Rx Buffer/ Tx Holding/ Div Latch Low */
|
||||||
QM_RW uint32_t ier_dlh; /**< Interrupt Enable / Divisor Latch High */
|
QM_RW uint32_t ier_dlh; /**< Interrupt Enable / Divisor Latch High */
|
||||||
|
@ -587,14 +661,17 @@ extern qm_uart_reg_t *qm_uart[QM_UART_NUM];
|
||||||
#define QM_UART qm_uart
|
#define QM_UART qm_uart
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
* Number of SPI controllers.
|
|
||||||
*/
|
|
||||||
typedef enum { QM_SPI_MST_0 = 0, QM_SPI_SLV_0 = 1, QM_SPI_NUM } qm_spi_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SPI register block type
|
* @name SPI
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Number of SPI controllers. */
|
||||||
|
typedef enum { QM_SPI_MST_0 = 0, QM_SPI_SLV_0 = 1, QM_SPI_NUM } qm_spi_t;
|
||||||
|
|
||||||
|
/** SPI register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t ctrlr0; /**< Control Register 0 */
|
QM_RW uint32_t ctrlr0; /**< Control Register 0 */
|
||||||
QM_RW uint32_t ctrlr1; /**< Control Register 1 */
|
QM_RW uint32_t ctrlr1; /**< Control Register 1 */
|
||||||
|
@ -658,6 +735,8 @@ extern qm_spi_reg_t *qm_spi_controllers[QM_SPI_NUM];
|
||||||
#define QM_SPI_SR_BUSY BIT(0)
|
#define QM_SPI_SR_BUSY BIT(0)
|
||||||
#define QM_SPI_SR_TFNF BIT(1)
|
#define QM_SPI_SR_TFNF BIT(1)
|
||||||
#define QM_SPI_SR_TFE BIT(2)
|
#define QM_SPI_SR_TFE BIT(2)
|
||||||
|
#define QM_SPI_SR_RFNE BIT(3)
|
||||||
|
#define QM_SPI_SR_RFF BIT(4)
|
||||||
|
|
||||||
/* SPI Interrupt Mask register */
|
/* SPI Interrupt Mask register */
|
||||||
#define QM_SPI_IMR_MASK_ALL (0x00)
|
#define QM_SPI_IMR_MASK_ALL (0x00)
|
||||||
|
@ -685,14 +764,17 @@ extern qm_spi_reg_t *qm_spi_controllers[QM_SPI_NUM];
|
||||||
#define QM_SPI_DMACR_RDMAE BIT(0)
|
#define QM_SPI_DMACR_RDMAE BIT(0)
|
||||||
#define QM_SPI_DMACR_TDMAE BIT(1)
|
#define QM_SPI_DMACR_TDMAE BIT(1)
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
* Number of RTC controllers.
|
|
||||||
*/
|
|
||||||
typedef enum { QM_RTC_0 = 0, QM_RTC_NUM } qm_rtc_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* QM RTC Register block type.
|
* @name RTC
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Number of RTC controllers. */
|
||||||
|
typedef enum { QM_RTC_0 = 0, QM_RTC_NUM } qm_rtc_t;
|
||||||
|
|
||||||
|
/** RTC register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t rtc_ccvr; /**< Current Counter Value Register */
|
QM_RW uint32_t rtc_ccvr; /**< Current Counter Value Register */
|
||||||
QM_RW uint32_t rtc_cmr; /**< Current Match Register */
|
QM_RW uint32_t rtc_cmr; /**< Current Match Register */
|
||||||
|
@ -709,18 +791,24 @@ qm_rtc_reg_t test_rtc;
|
||||||
#define QM_RTC ((qm_rtc_reg_t *)(&test_rtc))
|
#define QM_RTC ((qm_rtc_reg_t *)(&test_rtc))
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/** RTC register base address */
|
/** RTC register base address. */
|
||||||
#define QM_RTC_BASE (0xB0000400)
|
#define QM_RTC_BASE (0xB0000400)
|
||||||
|
|
||||||
/** RTC register block */
|
/** RTC register block. */
|
||||||
#define QM_RTC ((qm_rtc_reg_t *)QM_RTC_BASE)
|
#define QM_RTC ((qm_rtc_reg_t *)QM_RTC_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of I2C controllers.
|
* @name I2C
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Number of I2C controllers. */
|
||||||
typedef enum { QM_I2C_0 = 0, QM_I2C_NUM } qm_i2c_t;
|
typedef enum { QM_I2C_0 = 0, QM_I2C_NUM } qm_i2c_t;
|
||||||
|
|
||||||
|
/** I2C register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t ic_con; /**< Control Register */
|
QM_RW uint32_t ic_con; /**< Control Register */
|
||||||
QM_RW uint32_t ic_tar; /**< Master Target Address */
|
QM_RW uint32_t ic_tar; /**< Master Target Address */
|
||||||
|
@ -785,10 +873,10 @@ qm_i2c_reg_t *test_i2c[QM_I2C_NUM];
|
||||||
#define QM_I2C test_i2c
|
#define QM_I2C test_i2c
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/** I2C Master register base address */
|
/** I2C Master register base address. */
|
||||||
#define QM_I2C_0_BASE (0xB0002800)
|
#define QM_I2C_0_BASE (0xB0002800)
|
||||||
|
|
||||||
/** I2C register block */
|
/** I2C register block. */
|
||||||
extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM];
|
extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM];
|
||||||
#define QM_I2C qm_i2c
|
#define QM_I2C qm_i2c
|
||||||
#endif
|
#endif
|
||||||
|
@ -810,6 +898,7 @@ extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM];
|
||||||
#define QM_I2C_IC_DATA_CMD_READ BIT(8)
|
#define QM_I2C_IC_DATA_CMD_READ BIT(8)
|
||||||
#define QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL BIT(9)
|
#define QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL BIT(9)
|
||||||
#define QM_I2C_IC_DATA_CMD_LSB_MASK (0x000000FF)
|
#define QM_I2C_IC_DATA_CMD_LSB_MASK (0x000000FF)
|
||||||
|
#define QM_I2C_IC_RAW_INTR_STAT_RX_FULL BIT(2)
|
||||||
#define QM_I2C_IC_RAW_INTR_STAT_TX_ABRT BIT(6)
|
#define QM_I2C_IC_RAW_INTR_STAT_TX_ABRT BIT(6)
|
||||||
#define QM_I2C_IC_TX_ABRT_SOURCE_NAK_MASK (0x1F)
|
#define QM_I2C_IC_TX_ABRT_SOURCE_NAK_MASK (0x1F)
|
||||||
#define QM_I2C_IC_TX_ABRT_SOURCE_ARB_LOST BIT(12)
|
#define QM_I2C_IC_TX_ABRT_SOURCE_ARB_LOST BIT(12)
|
||||||
|
@ -845,14 +934,17 @@ extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM];
|
||||||
#define QM_I2C_IC_DMA_CR_RX_ENABLE BIT(0)
|
#define QM_I2C_IC_DMA_CR_RX_ENABLE BIT(0)
|
||||||
#define QM_I2C_IC_DMA_CR_TX_ENABLE BIT(1)
|
#define QM_I2C_IC_DMA_CR_TX_ENABLE BIT(1)
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
* Number of GPIO controllers.
|
|
||||||
*/
|
|
||||||
typedef enum { QM_GPIO_0 = 0, QM_GPIO_NUM } qm_gpio_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GPIO register block type.
|
* @name GPIO
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Number of GPIO controllers. */
|
||||||
|
typedef enum { QM_GPIO_0 = 0, QM_GPIO_NUM } qm_gpio_t;
|
||||||
|
|
||||||
|
/** GPIO register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t gpio_swporta_dr; /**< Port A Data */
|
QM_RW uint32_t gpio_swporta_dr; /**< Port A Data */
|
||||||
QM_RW uint32_t gpio_swporta_ddr; /**< Port A Data Direction */
|
QM_RW uint32_t gpio_swporta_ddr; /**< Port A Data Direction */
|
||||||
|
@ -883,6 +975,7 @@ qm_gpio_reg_t *test_gpio[QM_GPIO_NUM];
|
||||||
|
|
||||||
#define QM_GPIO test_gpio
|
#define QM_GPIO test_gpio
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/** GPIO register base address */
|
/** GPIO register base address */
|
||||||
#define QM_GPIO_BASE (0xB0000C00)
|
#define QM_GPIO_BASE (0xB0000C00)
|
||||||
|
|
||||||
|
@ -891,14 +984,17 @@ extern qm_gpio_reg_t *qm_gpio[QM_GPIO_NUM];
|
||||||
#define QM_GPIO qm_gpio
|
#define QM_GPIO qm_gpio
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
* Number of ADC controllers.
|
|
||||||
*/
|
|
||||||
typedef enum { QM_ADC_0 = 0, QM_ADC_NUM } qm_adc_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ADC register block type.
|
* @name ADC
|
||||||
*/
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Number of ADC controllers. */
|
||||||
|
typedef enum { QM_ADC_0 = 0, QM_ADC_NUM } qm_adc_t;
|
||||||
|
|
||||||
|
/** ADC register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t adc_seq0; /**< ADC Channel Sequence Table Entry 0 */
|
QM_RW uint32_t adc_seq0; /**< ADC Channel Sequence Table Entry 0 */
|
||||||
QM_RW uint32_t adc_seq1; /**< ADC Channel Sequence Table Entry 1 */
|
QM_RW uint32_t adc_seq1; /**< ADC Channel Sequence Table Entry 1 */
|
||||||
|
@ -960,14 +1056,17 @@ qm_adc_reg_t test_adc;
|
||||||
#define QM_ADC_OP_MODE_DELAY_MASK (0xFFF8)
|
#define QM_ADC_OP_MODE_DELAY_MASK (0xFFF8)
|
||||||
#define QM_ADC_OP_MODE_OM_MASK (0x7)
|
#define QM_ADC_OP_MODE_OM_MASK (0x7)
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
* Number of Flash controllers.
|
|
||||||
*/
|
|
||||||
typedef enum { QM_FLASH_0 = 0, QM_FLASH_NUM } qm_flash_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flash register block type.
|
* @name Flash
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Number of Flash controllers. */
|
||||||
|
typedef enum { QM_FLASH_0 = 0, QM_FLASH_NUM } qm_flash_t;
|
||||||
|
|
||||||
|
/** Flash register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t tmg_ctrl; /**< TMG_CTRL */
|
QM_RW uint32_t tmg_ctrl; /**< TMG_CTRL */
|
||||||
QM_RW uint32_t rom_wr_ctrl; /**< ROM_WR_CTRL */
|
QM_RW uint32_t rom_wr_ctrl; /**< ROM_WR_CTRL */
|
||||||
|
@ -1001,7 +1100,7 @@ uint8_t test_flash_page[0x800];
|
||||||
#define QM_FLASH_MAX_ADDR (0xFFFFFFFF)
|
#define QM_FLASH_MAX_ADDR (0xFFFFFFFF)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/** Flash physical address mappings */
|
/* Flash physical address mappings */
|
||||||
#define QM_FLASH_REGION_DATA_0_BASE (0x00200000)
|
#define QM_FLASH_REGION_DATA_0_BASE (0x00200000)
|
||||||
#define QM_FLASH_REGION_SYS_0_BASE (0x00180000)
|
#define QM_FLASH_REGION_SYS_0_BASE (0x00180000)
|
||||||
#define QM_FLASH_REGION_OTP_0_BASE (0x00000000)
|
#define QM_FLASH_REGION_OTP_0_BASE (0x00000000)
|
||||||
|
@ -1009,12 +1108,13 @@ uint8_t test_flash_page[0x800];
|
||||||
#define QM_FLASH_PAGE_MASK (0xF800)
|
#define QM_FLASH_PAGE_MASK (0xF800)
|
||||||
#define QM_FLASH_MAX_ADDR (0x8000)
|
#define QM_FLASH_MAX_ADDR (0x8000)
|
||||||
|
|
||||||
/** Flash controller register base address */
|
/** Flash controller register base address. */
|
||||||
#define QM_FLASH_BASE_0 (0xB0100000)
|
#define QM_FLASH_BASE_0 (0xB0100000)
|
||||||
|
|
||||||
/** Flash controller register block */
|
/** Flash controller register block. */
|
||||||
extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM];
|
extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM];
|
||||||
#define QM_FLASH qm_flash
|
#define QM_FLASH qm_flash
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define QM_FLASH_REGION_DATA_BASE_OFFSET (0x04)
|
#define QM_FLASH_REGION_DATA_BASE_OFFSET (0x04)
|
||||||
|
@ -1024,9 +1124,14 @@ extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM];
|
||||||
(QM_FLASH_MAX_ADDR / (4 * QM_FLASH_PAGE_SIZE_DWORDS))
|
(QM_FLASH_MAX_ADDR / (4 * QM_FLASH_PAGE_SIZE_DWORDS))
|
||||||
#define QM_FLASH_LVE_MODE BIT(5)
|
#define QM_FLASH_LVE_MODE BIT(5)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Memory Protection Region register block type.
|
* @name Memory Protection Region
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Memory Protection Region register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t mpr_cfg[4]; /**< MPR CFG */
|
QM_RW uint32_t mpr_cfg[4]; /**< MPR CFG */
|
||||||
QM_RW uint32_t mpr_vdata; /**< MPR_VDATA */
|
QM_RW uint32_t mpr_vdata; /**< MPR_VDATA */
|
||||||
|
@ -1054,14 +1159,20 @@ qm_mpr_reg_t test_mpr;
|
||||||
#define QM_MPR_UP_BOUND_OFFSET (10)
|
#define QM_MPR_UP_BOUND_OFFSET (10)
|
||||||
#define QM_MPR_VSTS_VALID BIT(31)
|
#define QM_MPR_VSTS_VALID BIT(31)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name PIC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** PIC timer register structure. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t reg;
|
QM_RW uint32_t reg;
|
||||||
QM_RW uint32_t pad[3];
|
QM_RW uint32_t pad[3];
|
||||||
} pic_timer_reg_pad_t;
|
} pic_timer_reg_pad_t;
|
||||||
|
|
||||||
/**
|
/** PIC timer register map. */
|
||||||
* PIC timer register block type.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW pic_timer_reg_pad_t lvttimer; /**< Local Vector Table Timer */
|
QM_RW pic_timer_reg_pad_t lvttimer; /**< Local Vector Table Timer */
|
||||||
QM_RW pic_timer_reg_pad_t reserved[5];
|
QM_RW pic_timer_reg_pad_t reserved[5];
|
||||||
|
@ -1074,19 +1185,66 @@ qm_pic_timer_reg_t test_pic_timer;
|
||||||
#define QM_PIC_TIMER ((qm_pic_timer_reg_t *)(&test_pic_timer))
|
#define QM_PIC_TIMER ((qm_pic_timer_reg_t *)(&test_pic_timer))
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/** PIC timer */
|
/** PIC timer base address. */
|
||||||
#define QM_PIC_TIMER_BASE (0xFEE00320)
|
#define QM_PIC_TIMER_BASE (0xFEE00320)
|
||||||
#define QM_PIC_TIMER ((qm_pic_timer_reg_t *)QM_PIC_TIMER_BASE)
|
#define QM_PIC_TIMER ((qm_pic_timer_reg_t *)QM_PIC_TIMER_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MVIC register block type.
|
* @name Peripheral Clock
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** Peripheral clock register map. */
|
||||||
|
typedef enum {
|
||||||
|
CLK_PERIPH_REGISTER = BIT(0), /**< Peripheral Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_CLK = BIT(1), /**< Peripheral Clock Enable. */
|
||||||
|
CLK_PERIPH_I2C_M0 = BIT(2), /**< I2C Master 0 Clock Enable. */
|
||||||
|
CLK_PERIPH_SPI_S = BIT(4), /**< SPI Slave Clock Enable. */
|
||||||
|
CLK_PERIPH_SPI_M0 = BIT(5), /**< SPI Master 0 Clock Enable. */
|
||||||
|
CLK_PERIPH_GPIO_INTERRUPT = BIT(7), /**< GPIO Interrupt Clock Enable. */
|
||||||
|
CLK_PERIPH_GPIO_DB = BIT(8), /**< GPIO Debounce Clock Enable. */
|
||||||
|
CLK_PERIPH_WDT_REGISTER = BIT(10), /**< Watchdog Clock Enable. */
|
||||||
|
CLK_PERIPH_RTC_REGISTER = BIT(11), /**< RTC Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_PWM_REGISTER = BIT(12), /**< PWM Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_GPIO_REGISTER = BIT(13), /**< GPIO Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_SPI_M0_REGISTER =
|
||||||
|
BIT(14), /**< SPI Master 0 Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_SPI_S_REGISTER =
|
||||||
|
BIT(16), /**< SPI Slave Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_UARTA_REGISTER = BIT(17), /**< UARTA Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_UARTB_REGISTER = BIT(18), /**< UARTB Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_I2C_M0_REGISTER =
|
||||||
|
BIT(19), /**< I2C Master 0 Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_ADC = BIT(22), /**< ADC Clock Enable. */
|
||||||
|
CLK_PERIPH_ADC_REGISTER = BIT(23), /**< ADC Clock Gate Enable. */
|
||||||
|
CLK_PERIPH_ALL = 0xCFFFFF /**< Quark D2000 peripherals Enable. */
|
||||||
|
} clk_periph_t;
|
||||||
|
|
||||||
|
/* Default mask values */
|
||||||
|
#define CLK_EXTERN_DIV_DEF_MASK (0xFFFFFFE3)
|
||||||
|
#define CLK_SYS_CLK_DIV_DEF_MASK (0xFFFFF87F)
|
||||||
|
#define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83)
|
||||||
|
#define CLK_GPIO_DB_DIV_DEF_MASK (0xFFFFFFE1)
|
||||||
|
#define CLK_ADC_DIV_DEF_MASK (0xFC00FFFF)
|
||||||
|
#define CLK_PERIPH_DIV_DEF_MASK (0xFFFFFFF9)
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name MVIC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** MVIC register structure. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t reg;
|
QM_RW uint32_t reg;
|
||||||
QM_RW uint32_t pad[3];
|
QM_RW uint32_t pad[3];
|
||||||
} mvic_reg_pad_t;
|
} mvic_reg_pad_t;
|
||||||
|
|
||||||
|
/** MVIC register map. */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW mvic_reg_pad_t tpr; /**< Task priority*/
|
QM_RW mvic_reg_pad_t tpr; /**< Task priority*/
|
||||||
QM_RW mvic_reg_pad_t reserved;
|
QM_RW mvic_reg_pad_t reserved;
|
||||||
|
@ -1113,7 +1271,7 @@ qm_mvic_reg_t test_mvic;
|
||||||
#define QM_MVIC ((qm_mvic_reg_t *)(&test_mvic))
|
#define QM_MVIC ((qm_mvic_reg_t *)(&test_mvic))
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/** Quark Microcontroller D2000 Interrupt Controller */
|
/** Interrupt Controller base address. */
|
||||||
#define QM_MVIC_BASE (0xFEE00080)
|
#define QM_MVIC_BASE (0xFEE00080)
|
||||||
#define QM_MVIC ((qm_mvic_reg_t *)QM_MVIC_BASE)
|
#define QM_MVIC ((qm_mvic_reg_t *)QM_MVIC_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
@ -1142,28 +1300,27 @@ qm_ioapic_reg_t test_ioapic;
|
||||||
#define QM_IOAPIC ((qm_ioapic_reg_t *)QM_IOAPIC_BASE)
|
#define QM_IOAPIC ((qm_ioapic_reg_t *)QM_IOAPIC_BASE)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** DMA */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DMA instances
|
* @name DMA
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** DMA instances. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_DMA_0, /**< DMA controller id. */
|
QM_DMA_0, /**< DMA controller id. */
|
||||||
QM_DMA_NUM /**< Number of DMA controllers. */
|
QM_DMA_NUM /**< Number of DMA controllers. */
|
||||||
} qm_dma_t;
|
} qm_dma_t;
|
||||||
|
|
||||||
/**
|
/** DMA channel IDs. */
|
||||||
* DMA channel IDs
|
|
||||||
*/
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_DMA_CHANNEL_0 = 0, /**< DMA channel id for channel 0 */
|
QM_DMA_CHANNEL_0 = 0, /**< DMA channel id for channel 0 */
|
||||||
QM_DMA_CHANNEL_1, /**< DMA channel id for channel 1 */
|
QM_DMA_CHANNEL_1, /**< DMA channel id for channel 1 */
|
||||||
QM_DMA_CHANNEL_NUM /**< Number of DMA channels */
|
QM_DMA_CHANNEL_NUM /**< Number of DMA channels */
|
||||||
} qm_dma_channel_id_t;
|
} qm_dma_channel_id_t;
|
||||||
|
|
||||||
/**
|
/** DMA hardware handshake interfaces. */
|
||||||
* DMA hardware handshake interfaces
|
|
||||||
*/
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DMA_HW_IF_UART_A_TX = 0x0, /**< UART_A_TX */
|
DMA_HW_IF_UART_A_TX = 0x0, /**< UART_A_TX */
|
||||||
DMA_HW_IF_UART_A_RX = 0x1, /**< UART_A_RX */
|
DMA_HW_IF_UART_A_RX = 0x1, /**< UART_A_RX */
|
||||||
|
@ -1177,9 +1334,7 @@ typedef enum {
|
||||||
DMA_HW_IF_I2C_MASTER_0_RX = 0xd, /**< I2C_Master_0_RX */
|
DMA_HW_IF_I2C_MASTER_0_RX = 0xd, /**< I2C_Master_0_RX */
|
||||||
} qm_dma_handshake_interface_t;
|
} qm_dma_handshake_interface_t;
|
||||||
|
|
||||||
/**
|
/** DMA channel register map. */
|
||||||
* DMA channel register block type
|
|
||||||
*/
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t sar_low; /**< SAR */
|
QM_RW uint32_t sar_low; /**< SAR */
|
||||||
QM_RW uint32_t sar_high; /**< SAR */
|
QM_RW uint32_t sar_high; /**< SAR */
|
||||||
|
@ -1205,7 +1360,7 @@ typedef struct {
|
||||||
QM_RW uint32_t dst_sg_high; /**< DSR */
|
QM_RW uint32_t dst_sg_high; /**< DSR */
|
||||||
} qm_dma_chan_reg_t;
|
} qm_dma_chan_reg_t;
|
||||||
|
|
||||||
/** DMA channel control register offsets and masks */
|
/* DMA channel control register offsets and masks. */
|
||||||
#define QM_DMA_CTL_L_INT_EN_MASK BIT(0)
|
#define QM_DMA_CTL_L_INT_EN_MASK BIT(0)
|
||||||
#define QM_DMA_CTL_L_DST_TR_WIDTH_OFFSET (1)
|
#define QM_DMA_CTL_L_DST_TR_WIDTH_OFFSET (1)
|
||||||
#define QM_DMA_CTL_L_DST_TR_WIDTH_MASK (0x7 << QM_DMA_CTL_L_DST_TR_WIDTH_OFFSET)
|
#define QM_DMA_CTL_L_DST_TR_WIDTH_MASK (0x7 << QM_DMA_CTL_L_DST_TR_WIDTH_OFFSET)
|
||||||
|
@ -1228,7 +1383,7 @@ typedef struct {
|
||||||
#define QM_DMA_CTL_H_BLOCK_TS_MAX 4095
|
#define QM_DMA_CTL_H_BLOCK_TS_MAX 4095
|
||||||
#define QM_DMA_CTL_H_BLOCK_TS_MIN 1
|
#define QM_DMA_CTL_H_BLOCK_TS_MIN 1
|
||||||
|
|
||||||
/** DMA channel config register offsets and masks */
|
/* DMA channel config register offsets and masks. */
|
||||||
#define QM_DMA_CFG_L_CH_SUSP_MASK BIT(8)
|
#define QM_DMA_CFG_L_CH_SUSP_MASK BIT(8)
|
||||||
#define QM_DMA_CFG_L_FIFO_EMPTY_MASK BIT(9)
|
#define QM_DMA_CFG_L_FIFO_EMPTY_MASK BIT(9)
|
||||||
#define QM_DMA_CFG_L_HS_SEL_DST_OFFSET 10
|
#define QM_DMA_CFG_L_HS_SEL_DST_OFFSET 10
|
||||||
|
@ -1246,9 +1401,7 @@ typedef struct {
|
||||||
#define QM_DMA_CFG_H_DEST_PER_OFFSET (11)
|
#define QM_DMA_CFG_H_DEST_PER_OFFSET (11)
|
||||||
#define QM_DMA_CFG_H_DEST_PER_MASK (0xf << QM_DMA_CFG_H_DEST_PER_OFFSET)
|
#define QM_DMA_CFG_H_DEST_PER_MASK (0xf << QM_DMA_CFG_H_DEST_PER_OFFSET)
|
||||||
|
|
||||||
/**
|
/** DMA interrupt register map. */
|
||||||
* DMA interrupt register block type
|
|
||||||
*/
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t raw_tfr_low; /**< RawTfr */
|
QM_RW uint32_t raw_tfr_low; /**< RawTfr */
|
||||||
QM_RW uint32_t raw_tfr_high; /**< RawTfr */
|
QM_RW uint32_t raw_tfr_high; /**< RawTfr */
|
||||||
|
@ -1294,13 +1447,11 @@ typedef struct {
|
||||||
QM_RW uint32_t status_int_high; /**< StatusInt */
|
QM_RW uint32_t status_int_high; /**< StatusInt */
|
||||||
} qm_dma_int_reg_t;
|
} qm_dma_int_reg_t;
|
||||||
|
|
||||||
/** DMA interrupt status register bits */
|
/* DMA interrupt status register bits. */
|
||||||
#define QM_DMA_INT_STATUS_TFR BIT(0)
|
#define QM_DMA_INT_STATUS_TFR BIT(0)
|
||||||
#define QM_DMA_INT_STATUS_ERR BIT(4)
|
#define QM_DMA_INT_STATUS_ERR BIT(4)
|
||||||
|
|
||||||
/**
|
/** DMA miscellaneous register map. */
|
||||||
* DMA miscellaneous register block type
|
|
||||||
*/
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
QM_RW uint32_t cfg_low; /**< DmaCfgReg */
|
QM_RW uint32_t cfg_low; /**< DmaCfgReg */
|
||||||
QM_RW uint32_t cfg_high; /**< DmaCfgReg */
|
QM_RW uint32_t cfg_high; /**< DmaCfgReg */
|
||||||
|
@ -1313,10 +1464,10 @@ typedef struct {
|
||||||
QM_RW uint32_t reserved[4]; /**< Reserved */
|
QM_RW uint32_t reserved[4]; /**< Reserved */
|
||||||
} qm_dma_misc_reg_t;
|
} qm_dma_misc_reg_t;
|
||||||
|
|
||||||
/** Channel write enable in the misc channel enable register */
|
/** Channel write enable in the misc channel enable register. */
|
||||||
#define QM_DMA_MISC_CHAN_EN_WE_OFFSET (8)
|
#define QM_DMA_MISC_CHAN_EN_WE_OFFSET (8)
|
||||||
|
|
||||||
/** Controller enable bit in the misc config register */
|
/** Controller enable bit in the misc config register. */
|
||||||
#define QM_DMA_MISC_CFG_DMA_EN BIT(0)
|
#define QM_DMA_MISC_CFG_DMA_EN BIT(0)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -1336,45 +1487,13 @@ extern qm_dma_reg_t *qm_dma[QM_DMA_NUM];
|
||||||
#define QM_DMA qm_dma
|
#define QM_DMA qm_dma
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
* Peripheral clock type.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
CLK_PERIPH_REGISTER = BIT(0), /**< Peripheral Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_CLK = BIT(1), /**< Peripheral Clock Enable. */
|
|
||||||
CLK_PERIPH_I2C_M0 = BIT(2), /**< I2C Master 0 Clock Enable. */
|
|
||||||
CLK_PERIPH_SPI_S = BIT(4), /**< SPI Slave Clock Enable. */
|
|
||||||
CLK_PERIPH_SPI_M0 = BIT(5), /**< SPI Master 0 Clock Enable. */
|
|
||||||
CLK_PERIPH_GPIO_INTERRUPT = BIT(7), /**< GPIO Interrupt Clock Enable. */
|
|
||||||
CLK_PERIPH_GPIO_DB = BIT(8), /**< GPIO Debounce Clock Enable. */
|
|
||||||
CLK_PERIPH_WDT_REGISTER = BIT(10), /**< Watchdog Clock Enable. */
|
|
||||||
CLK_PERIPH_RTC_REGISTER = BIT(11), /**< RTC Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_PWM_REGISTER = BIT(12), /**< PWM Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_GPIO_REGISTER = BIT(13), /**< GPIO Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_SPI_M0_REGISTER =
|
|
||||||
BIT(14), /**< SPI Master 0 Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_SPI_S_REGISTER =
|
|
||||||
BIT(16), /**< SPI Slave Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_UARTA_REGISTER = BIT(17), /**< UARTA Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_UARTB_REGISTER = BIT(18), /**< UARTB Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_I2C_M0_REGISTER =
|
|
||||||
BIT(19), /**< I2C Master 0 Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_ADC = BIT(22), /**< ADC Clock Enable. */
|
|
||||||
CLK_PERIPH_ADC_REGISTER = BIT(23), /**< ADC Clock Gate Enable. */
|
|
||||||
CLK_PERIPH_ALL = 0xCFFFFF /**< Quark D2000 peripherals Enable. */
|
|
||||||
} clk_periph_t;
|
|
||||||
|
|
||||||
/* Default mask values */
|
|
||||||
#define CLK_EXTERN_DIV_DEF_MASK (0xFFFFFFE3)
|
|
||||||
#define CLK_SYS_CLK_DIV_DEF_MASK (0xFFFFF87F)
|
|
||||||
#define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83)
|
|
||||||
#define CLK_GPIO_DB_DIV_DEF_MASK (0xFFFFFFE1)
|
|
||||||
#define CLK_ADC_DIV_DEF_MASK (0xFC00FFFF)
|
|
||||||
#define CLK_PERIPH_DIV_DEF_MASK (0xFFFFFFF9)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version variables.
|
* @name Versioning
|
||||||
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if (UNIT_TEST)
|
#if (UNIT_TEST)
|
||||||
uint32_t test_rom_version;
|
uint32_t test_rom_version;
|
||||||
#define ROM_VERSION_ADDRESS &test_rom_version;
|
#define ROM_VERSION_ADDRESS &test_rom_version;
|
||||||
|
@ -1382,7 +1501,8 @@ uint32_t test_rom_version;
|
||||||
#define ROM_VERSION_ADDRESS (0x1FFC);
|
#define ROM_VERSION_ADDRESS (0x1FFC);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/** @} */
|
||||||
@}
|
|
||||||
*/
|
/** @} */
|
||||||
|
|
||||||
#endif /* __REGISTERS_H__ */
|
#endif /* __REGISTERS_H__ */
|
||||||
|
|
|
@ -33,32 +33,64 @@
|
||||||
#if (QM_SENSOR)
|
#if (QM_SENSOR)
|
||||||
#include "qm_sensor_regs.h"
|
#include "qm_sensor_regs.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "soc_watch.h"
|
||||||
|
|
||||||
void power_soc_lpss_enable()
|
void power_soc_lpss_enable()
|
||||||
{
|
{
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl |= QM_SCSS_CCU_SS_LPS_EN;
|
QM_SCSS_CCU->ccu_lp_clk_ctl |= QM_SCSS_CCU_SS_LPS_EN;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void power_soc_lpss_disable()
|
void power_soc_lpss_disable()
|
||||||
{
|
{
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_SCSS_CCU_SS_LPS_EN;
|
QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_SCSS_CCU_SS_LPS_EN;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void power_soc_sleep()
|
void power_soc_sleep()
|
||||||
{
|
{
|
||||||
|
#if (QM_SENSOR)
|
||||||
|
/* The sensor cannot be woken up with an edge triggered
|
||||||
|
* interrupt from the RTC.
|
||||||
|
* Switch to Level triggered interrupts.
|
||||||
|
* When waking up, the ROM will configure the RTC back to
|
||||||
|
* its initial settings.
|
||||||
|
*/
|
||||||
|
__builtin_arc_sr(QM_IRQ_RTC_0_VECTOR, QM_SS_AUX_IRQ_SELECT);
|
||||||
|
__builtin_arc_sr(QM_SS_IRQ_LEVEL_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Go to sleep */
|
/* Go to sleep */
|
||||||
QM_SCSS_PMU->slp_cfg &= ~QM_SCSS_SLP_CFG_LPMODE_EN;
|
QM_SCSS_PMU->slp_cfg &= ~QM_SCSS_SLP_CFG_LPMODE_EN;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_SLP_CFG);
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_SLEEP, 0);
|
||||||
QM_SCSS_PMU->pm1c |= QM_SCSS_PM1C_SLPEN;
|
QM_SCSS_PMU->pm1c |= QM_SCSS_PM1C_SLPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void power_soc_deep_sleep()
|
void power_soc_deep_sleep()
|
||||||
{
|
{
|
||||||
/* Switch to linear regulators */
|
#if (QM_SENSOR)
|
||||||
|
/* The sensor cannot be woken up with an edge triggered
|
||||||
|
* interrupt from the RTC.
|
||||||
|
* Switch to Level triggered interrupts.
|
||||||
|
* When waking up, the ROM will configure the RTC back to
|
||||||
|
* its initial settings.
|
||||||
|
*/
|
||||||
|
__builtin_arc_sr(QM_IRQ_RTC_0_VECTOR, QM_SS_AUX_IRQ_SELECT);
|
||||||
|
__builtin_arc_sr(QM_SS_IRQ_LEVEL_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Switch to linear regulators.
|
||||||
|
* For low power deep sleep mode, it is a requirement that the platform
|
||||||
|
* voltage regulators are not in switching mode.
|
||||||
|
*/
|
||||||
vreg_plat1p8_set_mode(VREG_MODE_LINEAR);
|
vreg_plat1p8_set_mode(VREG_MODE_LINEAR);
|
||||||
vreg_plat3p3_set_mode(VREG_MODE_LINEAR);
|
vreg_plat3p3_set_mode(VREG_MODE_LINEAR);
|
||||||
|
|
||||||
/* Enable low power sleep mode */
|
/* Enable low power sleep mode */
|
||||||
QM_SCSS_PMU->slp_cfg |= QM_SCSS_SLP_CFG_LPMODE_EN;
|
QM_SCSS_PMU->slp_cfg |= QM_SCSS_SLP_CFG_LPMODE_EN;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_SLP_CFG);
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_SLEEP, 0);
|
||||||
QM_SCSS_PMU->pm1c |= QM_SCSS_PM1C_SLPEN;
|
QM_SCSS_PMU->pm1c |= QM_SCSS_PM1C_SLPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,14 +103,20 @@ void power_cpu_c1()
|
||||||
void power_cpu_c2()
|
void power_cpu_c2()
|
||||||
{
|
{
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_SCSS_CCU_C2_LP_EN;
|
QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_SCSS_CCU_C2_LP_EN;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);
|
||||||
|
|
||||||
/* Read P_LVL2 to trigger a C2 request */
|
/* Read P_LVL2 to trigger a C2 request */
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_SLEEP, 0);
|
||||||
QM_SCSS_PMU->p_lvl2;
|
QM_SCSS_PMU->p_lvl2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void power_cpu_c2lp()
|
void power_cpu_c2lp()
|
||||||
{
|
{
|
||||||
QM_SCSS_CCU->ccu_lp_clk_ctl |= QM_SCSS_CCU_C2_LP_EN;
|
QM_SCSS_CCU->ccu_lp_clk_ctl |= QM_SCSS_CCU_C2_LP_EN;
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);
|
||||||
|
|
||||||
/* Read P_LVL2 to trigger a C2 request */
|
/* Read P_LVL2 to trigger a C2 request */
|
||||||
|
SOC_WATCH_LOG_EVENT(SOCW_EVENT_SLEEP, 0);
|
||||||
QM_SCSS_PMU->p_lvl2;
|
QM_SCSS_PMU->p_lvl2;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -69,7 +69,7 @@ typedef union {
|
||||||
QM_RW uint16_t osc_trim_4mhz; /**< 4MHz Oscillator trim code. */
|
QM_RW uint16_t osc_trim_4mhz; /**< 4MHz Oscillator trim code. */
|
||||||
} fields;
|
} fields;
|
||||||
QM_RW uint32_t osc_trim_u32[2]; /**< Oscillator trim code array.*/
|
QM_RW uint32_t osc_trim_u32[2]; /**< Oscillator trim code array.*/
|
||||||
QM_RW uint16_t osc_trim_u16[2]; /**< Oscillator trim code array.*/
|
QM_RW uint16_t osc_trim_u16[4]; /**< Oscillator trim code array.*/
|
||||||
} qm_flash_data_trim_t;
|
} qm_flash_data_trim_t;
|
||||||
|
|
||||||
#if (UNIT_TEST)
|
#if (UNIT_TEST)
|
||||||
|
@ -87,6 +87,117 @@ typedef union {
|
||||||
#define QM_FLASH_TRIM_PRESENT_MASK (0xFC00)
|
#define QM_FLASH_TRIM_PRESENT_MASK (0xFC00)
|
||||||
#define QM_FLASH_TRIM_PRESENT (0x0000)
|
#define QM_FLASH_TRIM_PRESENT (0x0000)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bootloader data
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** The flash controller where BL-Data is stored. */
|
||||||
|
#define BL_DATA_FLASH_CONTROLLER QM_FLASH_0
|
||||||
|
/** The flash region where BL-Data is stored. */
|
||||||
|
#define BL_DATA_FLASH_REGION QM_FLASH_REGION_SYS
|
||||||
|
/** The flash address where the BL-Data Section starts. */
|
||||||
|
#define BL_DATA_FLASH_REGION_BASE QM_FLASH_REGION_SYS_0_BASE
|
||||||
|
/** The flash page where the BL-Data Section starts. */
|
||||||
|
#define BL_DATA_SECTION_BASE_PAGE (94)
|
||||||
|
|
||||||
|
/** The size (in pages) of the System_0 flash region of Quark SE. */
|
||||||
|
#define QM_FLASH_REGION_SYS_0_PAGES (96)
|
||||||
|
/** The size (in pages) of the System_1 flash region of Quark SE. */
|
||||||
|
#define QM_FLASH_REGION_SYS_1_PAGES (96)
|
||||||
|
|
||||||
|
/** The size (in pages) of the Bootloader Data section. */
|
||||||
|
#define BL_DATA_SECTION_PAGES (2)
|
||||||
|
|
||||||
|
#if (BL_CONFIG_DUAL_BANK)
|
||||||
|
/* ARC Partition size, in pages */
|
||||||
|
#define BL_PARTITION_SIZE_ARC \
|
||||||
|
((QM_FLASH_REGION_SYS_0_PAGES - BL_DATA_SECTION_PAGES) / 2)
|
||||||
|
#define BL_PARTITION_SIZE_LMT (QM_FLASH_REGION_SYS_1_PAGES / 2)
|
||||||
|
#else /* !BL_CONFIG_DUAL_BANK */
|
||||||
|
#define BL_PARTITION_SIZE_ARC \
|
||||||
|
((QM_FLASH_REGION_SYS_0_PAGES - BL_DATA_SECTION_PAGES))
|
||||||
|
#define BL_PARTITION_SIZE_LMT (QM_FLASH_REGION_SYS_1_PAGES)
|
||||||
|
#endif /* BL_CONFIG_DUAL_BANK */
|
||||||
|
|
||||||
|
/** Number of boot targets. */
|
||||||
|
#define BL_BOOT_TARGETS_NUM (2)
|
||||||
|
|
||||||
|
#define BL_TARGET_IDX_LMT (0)
|
||||||
|
#define BL_TARGET_IDX_ARC (1)
|
||||||
|
|
||||||
|
#define BL_PARTITION_IDX_LMT0 (0)
|
||||||
|
#define BL_PARTITION_IDX_ARC0 (1)
|
||||||
|
#define BL_PARTITION_IDX_LMT1 (2)
|
||||||
|
#define BL_PARTITION_IDX_ARC1 (3)
|
||||||
|
|
||||||
|
#define BL_TARGET_0_LMT \
|
||||||
|
{ \
|
||||||
|
.active_partition_idx = BL_PARTITION_IDX_LMT0, .svn = 0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BL_TARGET_1_ARC \
|
||||||
|
{ \
|
||||||
|
.active_partition_idx = BL_PARTITION_IDX_ARC0, .svn = 0 \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macro for defining an application flash partition.
|
||||||
|
*
|
||||||
|
* @param[in] target The index of the target associated with the partition.
|
||||||
|
* @param[in] ctrl The flash controller on which the partition is located.
|
||||||
|
* @param[in] region_addr The base address of the region where the partition is
|
||||||
|
* located.
|
||||||
|
* @param[in] size The size in pages of the partition.
|
||||||
|
* @param[in] idx The index of the partition within the flash region (0 for
|
||||||
|
* the first partition in the region, 1 for the second one).
|
||||||
|
*/
|
||||||
|
#define DEFINE_PARTITION(target, ctrl, region_addr, size, idx) \
|
||||||
|
{ \
|
||||||
|
.target_idx = target, .controller = ctrl, \
|
||||||
|
.first_page = (idx * size), .num_pages = size, \
|
||||||
|
.start_addr = ((uint32_t *)region_addr) + \
|
||||||
|
(idx * size * QM_FLASH_PAGE_SIZE_DWORDS), \
|
||||||
|
.is_consistent = true \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* PARTITION 0: LMT-0 */
|
||||||
|
#define BL_PARTITION_0 \
|
||||||
|
DEFINE_PARTITION(BL_TARGET_IDX_LMT, QM_FLASH_1, \
|
||||||
|
QM_FLASH_REGION_SYS_1_BASE, BL_PARTITION_SIZE_LMT, 0)
|
||||||
|
|
||||||
|
/* PARTITION 1: ARC-0 */
|
||||||
|
#define BL_PARTITION_1 \
|
||||||
|
DEFINE_PARTITION(BL_TARGET_IDX_ARC, QM_FLASH_0, \
|
||||||
|
QM_FLASH_REGION_SYS_0_BASE, BL_PARTITION_SIZE_ARC, 0)
|
||||||
|
|
||||||
|
/* PARTITION 2: LMT-1 */
|
||||||
|
#define BL_PARTITION_2 \
|
||||||
|
DEFINE_PARTITION(BL_TARGET_IDX_LMT, QM_FLASH_1, \
|
||||||
|
QM_FLASH_REGION_SYS_1_BASE, BL_PARTITION_SIZE_LMT, 1)
|
||||||
|
|
||||||
|
/* PARTITION 3: ARC-1 */
|
||||||
|
#define BL_PARTITION_3 \
|
||||||
|
DEFINE_PARTITION(BL_TARGET_IDX_ARC, QM_FLASH_0, \
|
||||||
|
QM_FLASH_REGION_SYS_0_BASE, BL_PARTITION_SIZE_ARC, 1)
|
||||||
|
|
||||||
|
#define BL_TARGET_LIST \
|
||||||
|
{ \
|
||||||
|
BL_TARGET_0_LMT, BL_TARGET_1_ARC \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BL_CONFIG_DUAL_BANK
|
||||||
|
#define BL_PARTITION_LIST \
|
||||||
|
{ \
|
||||||
|
BL_PARTITION_0, BL_PARTITION_1, BL_PARTITION_2, BL_PARTITION_3 \
|
||||||
|
}
|
||||||
|
#else /* !BL_CONFIG_DUAL_BANK */
|
||||||
|
#define BL_PARTITION_LIST \
|
||||||
|
{ \
|
||||||
|
BL_PARTITION_0, BL_PARTITION_1 \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BL_CONFIG_DUAL_BANK */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -234,6 +234,7 @@ typedef enum {
|
||||||
#define QM_SS_I2C_TL_RX_TL_MASK (0xFF)
|
#define QM_SS_I2C_TL_RX_TL_MASK (0xFF)
|
||||||
#define QM_SS_I2C_TL_TX_TL_MASK (0xFF0000)
|
#define QM_SS_I2C_TL_TX_TL_MASK (0xFF0000)
|
||||||
|
|
||||||
|
#define QM_SS_I2C_INTR_CLR_ALL (0xFF)
|
||||||
#define QM_SS_I2C_INTR_CLR_TX_ABRT BIT(6)
|
#define QM_SS_I2C_INTR_CLR_TX_ABRT BIT(6)
|
||||||
|
|
||||||
#define QM_SS_I2C_TX_ABRT_SOURCE_NAK_MASK (0x09)
|
#define QM_SS_I2C_TX_ABRT_SOURCE_NAK_MASK (0x09)
|
||||||
|
@ -358,7 +359,7 @@ typedef enum {
|
||||||
#define QM_SS_ADC_CAL_VAL_GET_OFFSET (5)
|
#define QM_SS_ADC_CAL_VAL_GET_OFFSET (5)
|
||||||
#define QM_SS_ADC_CAL_VAL_GET_MASK (0xFE0)
|
#define QM_SS_ADC_CAL_VAL_GET_MASK (0xFE0)
|
||||||
#define QM_SS_ADC_CAL_ACK BIT(4)
|
#define QM_SS_ADC_CAL_ACK BIT(4)
|
||||||
#define QM_SS_ADC_PWR_MODE_STS BIT(3) /*FIXME doesnt match doc */
|
#define QM_SS_ADC_PWR_MODE_STS BIT(3)
|
||||||
|
|
||||||
#define SS_CLK_PERIPH_ALL_IN_CREG \
|
#define SS_CLK_PERIPH_ALL_IN_CREG \
|
||||||
(SS_CLK_PERIPH_ADC | SS_CLK_PERIPH_I2C_1 | SS_CLK_PERIPH_I2C_0 | \
|
(SS_CLK_PERIPH_ADC | SS_CLK_PERIPH_I2C_1 | SS_CLK_PERIPH_I2C_0 | \
|
||||||
|
@ -391,62 +392,62 @@ typedef enum {
|
||||||
* #define QM_SS_xxx - irq number
|
* #define QM_SS_xxx - irq number
|
||||||
* #define QM_SS_xxx_VECTOR - vector number
|
* #define QM_SS_xxx_VECTOR - vector number
|
||||||
*/
|
*/
|
||||||
#define QM_SS_INT_TIMER_0 (16)
|
#define QM_SS_INT_TIMER_0 16
|
||||||
#define QM_SS_INT_TIMER_1 (17)
|
#define QM_SS_INT_TIMER_1 17
|
||||||
|
|
||||||
#define QM_SS_IRQ_ADC_ERR (0)
|
#define QM_SS_IRQ_ADC_ERR 0
|
||||||
#define QM_SS_IRQ_ADC_ERR_VECTOR (18)
|
#define QM_SS_IRQ_ADC_ERR_VECTOR 18
|
||||||
|
|
||||||
#define QM_SS_IRQ_ADC_IRQ (1)
|
#define QM_SS_IRQ_ADC_IRQ 1
|
||||||
#define QM_SS_IRQ_ADC_IRQ_VECTOR (19)
|
#define QM_SS_IRQ_ADC_IRQ_VECTOR 19
|
||||||
|
|
||||||
#define QM_SS_IRQ_GPIO_INTR_0 (2)
|
#define QM_SS_IRQ_GPIO_INTR_0 2
|
||||||
#define QM_SS_IRQ_GPIO_INTR_0_VECTOR (20)
|
#define QM_SS_IRQ_GPIO_INTR_0_VECTOR 20
|
||||||
|
|
||||||
#define QM_SS_IRQ_GPIO_INTR_1 (3)
|
#define QM_SS_IRQ_GPIO_INTR_1 3
|
||||||
#define QM_SS_IRQ_GPIO_INTR_1_VECTOR (21)
|
#define QM_SS_IRQ_GPIO_INTR_1_VECTOR 21
|
||||||
|
|
||||||
#define QM_SS_IRQ_I2C_0_ERR (4)
|
#define QM_SS_IRQ_I2C_0_ERR 4
|
||||||
#define QM_SS_IRQ_I2C_0_ERR_VECTOR (22)
|
#define QM_SS_IRQ_I2C_0_ERR_VECTOR 22
|
||||||
|
|
||||||
#define QM_SS_IRQ_I2C_0_RX_AVAIL (5)
|
#define QM_SS_IRQ_I2C_0_RX_AVAIL 5
|
||||||
#define QM_SS_IRQ_I2C_0_RX_AVAIL_VECTOR (23)
|
#define QM_SS_IRQ_I2C_0_RX_AVAIL_VECTOR 23
|
||||||
|
|
||||||
#define QM_SS_IRQ_I2C_0_TX_REQ (6)
|
#define QM_SS_IRQ_I2C_0_TX_REQ 6
|
||||||
#define QM_SS_IRQ_I2C_0_TX_REQ_VECTOR (24)
|
#define QM_SS_IRQ_I2C_0_TX_REQ_VECTOR 24
|
||||||
|
|
||||||
#define QM_SS_IRQ_I2C_0_STOP_DET (7)
|
#define QM_SS_IRQ_I2C_0_STOP_DET 7
|
||||||
#define QM_SS_IRQ_I2C_0_STOP_DET_VECTOR (25)
|
#define QM_SS_IRQ_I2C_0_STOP_DET_VECTOR 25
|
||||||
|
|
||||||
#define QM_SS_IRQ_I2C_1_ERR (8)
|
#define QM_SS_IRQ_I2C_1_ERR 8
|
||||||
#define QM_SS_IRQ_I2C_1_ERR_VECTOR (26)
|
#define QM_SS_IRQ_I2C_1_ERR_VECTOR 26
|
||||||
|
|
||||||
#define QM_SS_IRQ_I2C_1_RX_AVAIL (9)
|
#define QM_SS_IRQ_I2C_1_RX_AVAIL 9
|
||||||
#define QM_SS_IRQ_I2C_1_RX_AVAIL_VECTOR (27)
|
#define QM_SS_IRQ_I2C_1_RX_AVAIL_VECTOR 27
|
||||||
|
|
||||||
#define QM_SS_IRQ_I2C_1_TX_REQ (10)
|
#define QM_SS_IRQ_I2C_1_TX_REQ 10
|
||||||
#define QM_SS_IRQ_I2C_1_TX_REQ_VECTOR (28)
|
#define QM_SS_IRQ_I2C_1_TX_REQ_VECTOR 28
|
||||||
|
|
||||||
#define QM_SS_IRQ_I2C_1_STOP_DET (11)
|
#define QM_SS_IRQ_I2C_1_STOP_DET 11
|
||||||
#define QM_SS_IRQ_I2C_1_STOP_DET_VECTOR (29)
|
#define QM_SS_IRQ_I2C_1_STOP_DET_VECTOR 29
|
||||||
|
|
||||||
#define QM_SS_IRQ_SPI_0_ERR_INT (12)
|
#define QM_SS_IRQ_SPI_0_ERR_INT 12
|
||||||
#define QM_SS_IRQ_SPI_0_ERR_INT_VECTOR (30)
|
#define QM_SS_IRQ_SPI_0_ERR_INT_VECTOR 30
|
||||||
|
|
||||||
#define QM_SS_IRQ_SPI_0_RX_AVAIL (13)
|
#define QM_SS_IRQ_SPI_0_RX_AVAIL 13
|
||||||
#define QM_SS_IRQ_SPI_0_RX_AVAIL_VECTOR (31)
|
#define QM_SS_IRQ_SPI_0_RX_AVAIL_VECTOR 31
|
||||||
|
|
||||||
#define QM_SS_IRQ_SPI_0_TX_REQ (14)
|
#define QM_SS_IRQ_SPI_0_TX_REQ 14
|
||||||
#define QM_SS_IRQ_SPI_0_TX_REQ_VECTOR (32)
|
#define QM_SS_IRQ_SPI_0_TX_REQ_VECTOR 32
|
||||||
|
|
||||||
#define QM_SS_IRQ_SPI_1_ERR_INT (15)
|
#define QM_SS_IRQ_SPI_1_ERR_INT 15
|
||||||
#define QM_SS_IRQ_SPI_1_ERR_INT_VECTOR (33)
|
#define QM_SS_IRQ_SPI_1_ERR_INT_VECTOR 33
|
||||||
|
|
||||||
#define QM_SS_IRQ_SPI_1_RX_AVAIL (16)
|
#define QM_SS_IRQ_SPI_1_RX_AVAIL 16
|
||||||
#define QM_SS_IRQ_SPI_1_RX_AVAIL_VECTOR (34)
|
#define QM_SS_IRQ_SPI_1_RX_AVAIL_VECTOR 34
|
||||||
|
|
||||||
#define QM_SS_IRQ_SPI_1_TX_REQ (17)
|
#define QM_SS_IRQ_SPI_1_TX_REQ 17
|
||||||
#define QM_SS_IRQ_SPI_1_TX_REQ_VECTOR (35)
|
#define QM_SS_IRQ_SPI_1_TX_REQ_VECTOR 35
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QM_SS_INT_PRIORITY_0 = 0,
|
QM_SS_INT_PRIORITY_0 = 0,
|
||||||
|
@ -468,7 +469,7 @@ typedef enum {
|
||||||
#define QM_SS_AUX_IRQ_STATUS (0x406)
|
#define QM_SS_AUX_IRQ_STATUS (0x406)
|
||||||
#define QM_SS_AUX_IRQ_SELECT (0x40B)
|
#define QM_SS_AUX_IRQ_SELECT (0x40B)
|
||||||
#define QM_SS_AUX_IRQ_ENABLE (0x40C)
|
#define QM_SS_AUX_IRQ_ENABLE (0x40C)
|
||||||
#define QM_SS_AUX_IRQ_TRIGER (0x40D)
|
#define QM_SS_AUX_IRQ_TRIGGER (0x40D)
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue