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
|
@ -110,6 +110,7 @@ static int adc_qmsi_read(struct device *dev, struct adc_seq_table *seq_tbl)
|
|||
{
|
||||
int i, ret = 0;
|
||||
qm_adc_xfer_t xfer;
|
||||
qm_adc_status_t status;
|
||||
|
||||
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
|
||||
* captured
|
||||
*/
|
||||
if (qm_adc_convert(QM_ADC_0, &xfer) != 0) {
|
||||
if (qm_adc_convert(QM_ADC_0, &xfer, &status) != 0) {
|
||||
ret = -EIO;
|
||||
adc_unlock(info);
|
||||
break;
|
||||
|
|
|
@ -116,6 +116,7 @@ static int adc_qmsi_ss_read(struct device *dev, struct adc_seq_table *seq_tbl)
|
|||
{
|
||||
int i, ret = 0;
|
||||
qm_ss_adc_xfer_t xfer;
|
||||
qm_ss_adc_status_t status;
|
||||
|
||||
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
|
||||
* 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;
|
||||
adc_unlock(info);
|
||||
break;
|
||||
|
|
|
@ -56,6 +56,7 @@ config I2C_QMSI_SS
|
|||
config I2C_QMSI
|
||||
bool "QMSI I2C driver"
|
||||
depends on I2C && QMSI
|
||||
select DMA_QMSI
|
||||
default n
|
||||
help
|
||||
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->tx = (uint8_t *)tx_buf;
|
||||
xfer->tx_len = tx_buf_len / dfs;
|
||||
xfer->data = dev;
|
||||
xfer->callback_data = dev;
|
||||
xfer->callback = spi_qmsi_callback;
|
||||
|
||||
if (tx_buf_len == 0) {
|
||||
|
|
|
@ -8,8 +8,8 @@ Microcontroller products. It currently support the following SoCs:
|
|||
- Intel® Quark™ D2000 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.
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#include "soc_watch.h"
|
||||
|
||||
#if (QM_SENSOR) && (!UNIT_TEST)
|
||||
/* Timestamp counter for Sensor Subsystem is 32bit. */
|
||||
#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)
|
||||
{
|
||||
QM_CHECK(div <= CLK_SYS_DIV_NUM, -EINVAL);
|
||||
QM_CHECK(div < CLK_SYS_DIV_NUM, -EINVAL);
|
||||
QM_CHECK(mode <= CLK_SYS_CRYSTAL_OSC, -EINVAL);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -173,11 +178,26 @@ int clk_trim_read(uint32_t *const value)
|
|||
|
||||
int clk_trim_apply(const uint32_t value)
|
||||
{
|
||||
/* Enable trim mode */
|
||||
QM_SCSS_CCU->osc0_cfg0 |= BIT(1);
|
||||
|
||||
/* Apply trim code */
|
||||
QM_SCSS_CCU->osc0_cfg1 &= ~OSC0_CFG1_FTRIMOTP_MASK;
|
||||
QM_SCSS_CCU->osc0_cfg1 |=
|
||||
(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;
|
||||
}
|
||||
|
||||
|
@ -270,6 +290,9 @@ int clk_periph_enable(const clk_periph_t 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;
|
||||
}
|
||||
|
||||
|
@ -279,6 +302,9 @@ int clk_periph_disable(const clk_periph_t 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,10 +159,6 @@ static int dma_channel_disable(const qm_dma_t dma,
|
|||
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. */
|
||||
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,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.
|
||||
* @retval 0 on success.
|
||||
* @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.
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include "qm_common.h"
|
||||
#include "qm_soc_regs.h"
|
||||
|
||||
#include "qm_interrupt.h"
|
||||
/**
|
||||
* Flash controller.
|
||||
*
|
||||
|
|
|
@ -58,9 +58,9 @@
|
|||
/**
|
||||
* QM I2C addressing type.
|
||||
*/
|
||||
typedef enum{
|
||||
typedef enum {
|
||||
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;
|
||||
|
||||
/**
|
||||
|
@ -68,7 +68,7 @@ typedef enum{
|
|||
*/
|
||||
typedef enum {
|
||||
QM_I2C_MASTER, /**< Master mode. */
|
||||
QM_I2C_SLAVE /**< Slave mode. */
|
||||
QM_I2C_SLAVE /**< Slave mode. */
|
||||
} qm_i2c_mode_t;
|
||||
|
||||
/**
|
||||
|
@ -84,27 +84,27 @@ typedef enum {
|
|||
* I2C status type.
|
||||
*/
|
||||
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_10ADDR1_NOACK = BIT(1), /**< 10-bit address noack. */
|
||||
QM_I2C_TX_ABRT_10ADDR2_NOACK = BIT(2), /**< 10-bit second address
|
||||
byte address 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_READ = BIT(5), /**< Read after general call. */
|
||||
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_HS_NORSTRT = BIT(8), /**< High Speed with restart
|
||||
disabled. */
|
||||
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_READ = BIT(5), /**< Read after general call. */
|
||||
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_HS_NORSTRT = BIT(8), /**< High Speed with restart
|
||||
disabled. */
|
||||
QM_I2C_TX_ABRT_10B_RD_NORSTRT = BIT(10), /**< 10-bit address read and
|
||||
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_ABRT_SLVFLUSH_TXFIFO = BIT(13), /**< Slave flush tx FIFO. */
|
||||
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_USER_ABRT = BIT(16), /**< User abort. */
|
||||
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
||||
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_USER_ABRT = BIT(16), /**< User abort. */
|
||||
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
||||
} qm_i2c_status_t;
|
||||
|
||||
/**
|
||||
|
@ -135,7 +135,7 @@ typedef struct {
|
|||
bool stop; /**< Generate master STOP. */
|
||||
void (*callback)(void *data, int rc, qm_i2c_status_t status,
|
||||
uint32_t len); /**< Callback. */
|
||||
void *callback_data; /**< Callback identifier. */
|
||||
void *callback_data; /**< Callback identifier. */
|
||||
} 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.
|
||||
*/
|
||||
int qm_i2c_master_read(const qm_i2c_t i2c, const uint16_t slave_addr,
|
||||
uint8_t *const data, uint32_t len,
|
||||
const bool stop, qm_i2c_status_t *const status);
|
||||
uint8_t *const data, uint32_t len, const bool stop,
|
||||
qm_i2c_status_t *const status);
|
||||
|
||||
/**
|
||||
* 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] xfer Transfer structure includes write / read buffers, length,
|
||||
* user callback function and the callback context. This must
|
||||
* not be NULL.
|
||||
* user callback function and the callback context.
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
#if (UNIT_TEST)
|
||||
#define qm_int_vector_request(vector, isr)
|
||||
void qm_int_vector_request(uint32_t vector, qm_isr_t isr);
|
||||
#else
|
||||
#if (__iamcu__)
|
||||
/*
|
||||
|
|
|
@ -69,6 +69,7 @@ QM_ISR_DECLARE(qm_adc_pwr_0_isr);
|
|||
* @endcode if IRQ based calibration is used.
|
||||
*/
|
||||
QM_ISR_DECLARE(qm_ss_adc_0_cal_isr);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#endif /* QUARK_SE */
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
|
@ -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.
|
||||
*/
|
||||
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.
|
||||
|
@ -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.
|
||||
*/
|
||||
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.
|
||||
|
|
|
@ -54,6 +54,7 @@ typedef enum {
|
|||
typedef struct {
|
||||
qm_pic_timer_mode_t mode; /**< Operation mode. */
|
||||
bool int_en; /**< Interrupt enable. */
|
||||
|
||||
/**
|
||||
* User callback.
|
||||
*
|
||||
|
|
|
@ -59,6 +59,7 @@ typedef struct {
|
|||
uint32_t init_val; /**< Initial value in RTC clocks. */
|
||||
bool alarm_en; /**< Alarm enable. */
|
||||
uint32_t alarm_val; /**< Alarm value in RTC clocks. */
|
||||
|
||||
/**
|
||||
* User callback.
|
||||
*
|
||||
|
@ -75,6 +76,13 @@ typedef struct {
|
|||
* an alarm is required. If the alarm is enabled, register an ISR with the user
|
||||
* 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] 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
|
||||
* 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] alarm_val Value to set alarm to.
|
||||
*
|
||||
|
|
|
@ -99,7 +99,9 @@ typedef enum {
|
|||
/**
|
||||
* 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 {
|
||||
QM_SPI_SS_DISABLED = 0, /**< Slave select disable. */
|
||||
|
@ -139,8 +141,8 @@ typedef struct {
|
|||
*/
|
||||
typedef struct {
|
||||
uint8_t *tx; /**< Write data. */
|
||||
uint16_t tx_len; /**< Write data Length. */
|
||||
uint8_t *rx; /**< Read data. */
|
||||
uint16_t tx_len; /**< Write data Length. */
|
||||
uint16_t rx_len; /**< Read buffer length. */
|
||||
|
||||
/**
|
||||
|
@ -152,8 +154,8 @@ typedef struct {
|
|||
* @param[in] data The callback user data.
|
||||
* @param[in] error 0 on success.
|
||||
* Negative @ref errno for possible error codes.
|
||||
* @param[in] status SPI driver status.
|
||||
* @param[in] len Length of the SPI transfer if successful, 0
|
||||
* @param[in] status SPI driver status.
|
||||
* @param[in] len Length of the SPI transfer if successful, 0
|
||||
* otherwise.
|
||||
*/
|
||||
void (*callback)(void *data, int error, qm_spi_status_t status,
|
||||
|
@ -166,8 +168,8 @@ typedef struct {
|
|||
*/
|
||||
typedef struct {
|
||||
uint8_t *tx; /**< Write Data. */
|
||||
uint16_t tx_len; /**< Write Data Length. */
|
||||
uint8_t *rx; /**< Read Data. */
|
||||
uint16_t tx_len; /**< Write Data Length. */
|
||||
uint16_t rx_len; /**< Receive Data Length. */
|
||||
} 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] xfer Structure containing pre-allocated
|
||||
* 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.
|
||||
* @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] xfer Structure containing pre-allocated read
|
||||
* 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.
|
||||
* @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_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] xfer Structure containing a pre-allocated write buffer
|
||||
* 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 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 bool dummy_conversion = false;
|
||||
|
||||
|
@ -79,10 +79,10 @@ static void qm_adc_isr_handler(const qm_adc_t adc)
|
|||
/* Disable all interrupts. */
|
||||
QM_ADC[adc].adc_intr_enable = 0;
|
||||
/* Call the user callback. */
|
||||
if (irq_xfer[adc].callback) {
|
||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data,
|
||||
-EIO, QM_ADC_OVERFLOW,
|
||||
QM_ADC_TRANSFER);
|
||||
if (irq_xfer[adc]->callback) {
|
||||
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
|
||||
-EIO, QM_ADC_OVERFLOW,
|
||||
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. */
|
||||
samples_to_read = QM_ADC[adc].adc_fifo_count;
|
||||
if (samples_to_read >
|
||||
(irq_xfer[adc].samples_len - count[adc])) {
|
||||
(irq_xfer[adc]->samples_len - count[adc])) {
|
||||
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
|
||||
* 2, 4 or 6 bits for 10, 8 and 6 bit resolution respectively
|
||||
* to get the correct value. */
|
||||
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 >>
|
||||
(2 * (3 - resolution[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
|
||||
* 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. */
|
||||
QM_ADC[adc].adc_cmd = QM_ADC_CMD_STOP_CONT;
|
||||
/* Disable all interrupts. */
|
||||
QM_ADC[adc].adc_intr_enable = 0;
|
||||
/* Call the user callback. */
|
||||
if (irq_xfer[adc].callback) {
|
||||
irq_xfer[adc].callback(
|
||||
irq_xfer[adc].callback_data, 0,
|
||||
if (irq_xfer[adc]->callback) {
|
||||
irq_xfer[adc]->callback(
|
||||
irq_xfer[adc]->callback_data, 0,
|
||||
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. */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ static void qm_adc_isr_handler(const qm_adc_t adc)
|
|||
|
||||
/* Call the user callback if it is set. */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ static void qm_adc_pwr_0_isr_handler(const qm_adc_t adc)
|
|||
} else {
|
||||
/* Call the user callback function */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ int qm_adc_irq_calibrate(const qm_adc_t adc,
|
|||
cal_callback[adc] = callback;
|
||||
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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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)
|
||||
;
|
||||
|
||||
if (status) {
|
||||
*status = QM_ADC_COMPLETE;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* 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);
|
||||
|
||||
/* 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. */
|
||||
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;
|
||||
}
|
||||
|
||||
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(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
|
||||
* 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);
|
||||
if (!return_code) {
|
||||
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;
|
||||
}
|
||||
|
||||
#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,
|
||||
const qm_flash_t flash,
|
||||
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);
|
||||
#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] |=
|
||||
QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK;
|
||||
#endif /* QM_SENSOR */
|
||||
|
||||
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);
|
||||
#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] &=
|
||||
~QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK;
|
||||
#endif /* QM_SENSOR */
|
||||
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
|
||||
#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]) {
|
||||
(*callback[gpio])(callback_data[gpio], int_status);
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
#define SPK_LEN_FS_FSP (2)
|
||||
|
||||
/* number of retries before giving up on disabling the controller */
|
||||
#define MAX_T_POLL_COUNT (100)
|
||||
#define TI2C_POLL_MICROSECOND (10000)
|
||||
#define I2C_POLL_COUNT (1000000)
|
||||
#define I2C_POLL_MICROSECOND (1)
|
||||
|
||||
#ifndef UNIT_TEST
|
||||
#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
|
||||
|
||||
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],
|
||||
i2c_read_buffer_remaining[QM_I2C_NUM];
|
||||
i2c_read_cmd_send[QM_I2C_NUM];
|
||||
|
||||
/**
|
||||
* I2C DMA controller configuration descriptor.
|
||||
|
@ -61,12 +61,13 @@ typedef struct {
|
|||
qm_dma_t dma_controller_id;
|
||||
qm_dma_channel_id_t dma_tx_channel_id; /* TX channel ID */
|
||||
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_transfer_t dma_rx_transfer_config; /* Configuration for RX */
|
||||
/* Configuration for writing READ commands during an RX operation */
|
||||
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*/
|
||||
int multimaster_abort_status;
|
||||
} i2c_dma_context_t;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
const qm_i2c_transfer_t *const transfer = i2c_transfer[i2c];
|
||||
uint32_t ic_data_cmd = 0, count_tx = (QM_I2C_FIFO_SIZE - TX_TL);
|
||||
qm_i2c_status_t status = 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];
|
||||
|
||||
|
@ -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;
|
||||
|
||||
rc = (status & QM_I2C_TX_ABRT_USER_ABRT) ? -ECANCELED : -EIO;
|
||||
if (i2c_transfer[i2c].callback) {
|
||||
/* NOTE: currently 0 is returned for length but we
|
||||
* may revisit that soon
|
||||
|
||||
if ((i2c_dma_context[i2c].ongoing_dma_rx_operation == true) ||
|
||||
(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(
|
||||
i2c_transfer[i2c].callback_data, rc, status, 0);
|
||||
qm_i2c_dma_transfer_terminate(i2c);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
@ -133,39 +149,38 @@ static void qm_i2c_isr_handler(const qm_i2c_t i2c)
|
|||
/* RX read from buffer */
|
||||
if (controller->ic_intr_stat & QM_I2C_IC_INTR_STAT_RX_FULL) {
|
||||
|
||||
while (i2c_read_buffer_remaining[i2c] && controller->ic_rxflr) {
|
||||
i2c_transfer[i2c].rx[i2c_read_pos[i2c]] =
|
||||
while (read_buffer_remaining && controller->ic_rxflr) {
|
||||
transfer->rx[i2c_read_pos[i2c]] =
|
||||
controller->ic_data_cmd;
|
||||
i2c_read_buffer_remaining[i2c]--;
|
||||
read_buffer_remaining--;
|
||||
i2c_read_pos[i2c]++;
|
||||
|
||||
if (i2c_read_buffer_remaining[i2c] == 0) {
|
||||
if (read_buffer_remaining == 0) {
|
||||
/* mask rx full interrupt if transfer
|
||||
* complete
|
||||
*/
|
||||
controller->ic_intr_mask &=
|
||||
~QM_I2C_IC_INTR_MASK_RX_FULL;
|
||||
|
||||
if (i2c_transfer[i2c].stop) {
|
||||
if (transfer->stop) {
|
||||
controller_disable(i2c);
|
||||
}
|
||||
|
||||
if (i2c_transfer[i2c].callback) {
|
||||
i2c_transfer[i2c].callback(
|
||||
i2c_transfer[i2c].callback_data, 0,
|
||||
if (transfer->callback) {
|
||||
transfer->callback(
|
||||
transfer->callback_data, 0,
|
||||
QM_I2C_IDLE, i2c_read_pos[i2c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i2c_read_buffer_remaining[i2c] > 0 &&
|
||||
i2c_read_buffer_remaining[i2c] < (RX_TL + 1)) {
|
||||
if (read_buffer_remaining > 0 &&
|
||||
read_buffer_remaining < (RX_TL + 1)) {
|
||||
/* Adjust the RX threshold so the next 'RX_FULL'
|
||||
* interrupt is generated when all the remaining
|
||||
* data are received.
|
||||
*/
|
||||
controller->ic_rx_tl =
|
||||
i2c_read_buffer_remaining[i2c] - 1;
|
||||
controller->ic_rx_tl = read_buffer_remaining - 1;
|
||||
}
|
||||
|
||||
/* 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_status & QM_I2C_IC_STATUS_TFE) &&
|
||||
(i2c_transfer[i2c].tx != NULL) &&
|
||||
(i2c_transfer[i2c].tx_len == 0) &&
|
||||
(i2c_transfer[i2c].rx_len == 0)) {
|
||||
(transfer->tx != NULL) && (write_buffer_remaining == 0) &&
|
||||
(read_buffer_remaining == 0)) {
|
||||
|
||||
controller->ic_intr_mask &=
|
||||
~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
|
||||
* transaction, disable the controller now
|
||||
*/
|
||||
if ((i2c_read_buffer_remaining[i2c] == 0) &&
|
||||
i2c_transfer[i2c].stop) {
|
||||
if (transfer->stop) {
|
||||
controller_disable(i2c);
|
||||
|
||||
/* callback */
|
||||
if (i2c_transfer[i2c].callback) {
|
||||
i2c_transfer[i2c].callback(
|
||||
i2c_transfer[i2c].callback_data, 0,
|
||||
if (transfer->callback) {
|
||||
transfer->callback(
|
||||
transfer->callback_data, 0,
|
||||
QM_I2C_IDLE, i2c_write_pos[i2c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ((count_tx) && i2c_transfer[i2c].tx_len) {
|
||||
while ((count_tx) && write_buffer_remaining) {
|
||||
count_tx--;
|
||||
write_buffer_remaining--;
|
||||
|
||||
/* write command -IC_DATA_CMD[8] = 0 */
|
||||
/* fill IC_DATA_CMD[7:0] with the data */
|
||||
ic_data_cmd = i2c_transfer[i2c].tx[i2c_write_pos[i2c]];
|
||||
i2c_transfer[i2c].tx_len--;
|
||||
ic_data_cmd = transfer->tx[i2c_write_pos[i2c]];
|
||||
|
||||
/* if transfer is a combined transfer, only
|
||||
* send stop at
|
||||
* end of the transfer sequence */
|
||||
if (i2c_transfer[i2c].stop &&
|
||||
(i2c_transfer[i2c].tx_len == 0) &&
|
||||
(i2c_transfer[i2c].rx_len == 0)) {
|
||||
if (transfer->stop && (write_buffer_remaining == 0) &&
|
||||
(read_buffer_remaining == 0)) {
|
||||
|
||||
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 -
|
||||
(controller->ic_txflr + controller->ic_rxflr + 1);
|
||||
|
||||
while (i2c_transfer[i2c].rx_len &&
|
||||
(i2c_transfer[i2c].tx_len == 0) && count_tx) {
|
||||
while (i2c_read_cmd_send[i2c] &&
|
||||
(write_buffer_remaining == 0) && count_tx) {
|
||||
count_tx--;
|
||||
i2c_transfer[i2c].rx_len--;
|
||||
i2c_read_cmd_send[i2c]--;
|
||||
|
||||
/* if transfer is a combined transfer, only
|
||||
* send stop at
|
||||
* end of
|
||||
* the transfer sequence */
|
||||
if (i2c_transfer[i2c].stop &&
|
||||
(i2c_transfer[i2c].rx_len == 0) &&
|
||||
(i2c_transfer[i2c].tx_len == 0)) {
|
||||
/* If transfer is a combined transfer, only send stop at
|
||||
* end of the transfer sequence
|
||||
*/
|
||||
if (transfer->stop && (i2c_read_cmd_send[i2c] == 0)) {
|
||||
controller->ic_data_cmd =
|
||||
QM_I2C_IC_DATA_CMD_READ |
|
||||
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 */
|
||||
if ((i2c_transfer[i2c].tx_len == 0) &&
|
||||
(i2c_transfer[i2c].rx_len == 0)) {
|
||||
if ((write_buffer_remaining == 0) &&
|
||||
(read_buffer_remaining == 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 */
|
||||
if (controller_disable(i2c)) {
|
||||
return -EAGAIN;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
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;
|
||||
controller->ic_ss_scl_lcnt = lo_cnt;
|
||||
controller->ic_ss_scl_hcnt = hi_cnt;
|
||||
controller->ic_fs_spklen = SPK_LEN_SS;
|
||||
break;
|
||||
|
||||
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;
|
||||
controller->ic_fs_scl_lcnt = lo_cnt;
|
||||
controller->ic_fs_scl_hcnt = hi_cnt;
|
||||
controller->ic_fs_spklen = SPK_LEN_FS_FSP;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -517,7 +528,7 @@ int qm_i2c_master_write(const qm_i2c_t i2c, const uint16_t slave_addr,
|
|||
/* disable controller */
|
||||
if (true == stop) {
|
||||
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 */
|
||||
if (true == stop) {
|
||||
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_read_pos[i2c] = 0;
|
||||
i2c_read_buffer_remaining[i2c] = xfer->rx_len;
|
||||
memcpy(&i2c_transfer[i2c], xfer, sizeof(i2c_transfer[i2c]));
|
||||
i2c_read_cmd_send[i2c] = xfer->rx_len;
|
||||
i2c_transfer[i2c] = xfer;
|
||||
|
||||
/* set threshold */
|
||||
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))
|
||||
;
|
||||
}
|
||||
|
||||
/* be sure that all interrupts flag are cleared */
|
||||
controller->ic_clr_intr;
|
||||
}
|
||||
|
||||
static int controller_disable(const qm_i2c_t 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 */
|
||||
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 */
|
||||
while ((controller->ic_enable_status & QM_I2C_IC_ENABLE_STATUS_IC_EN) &&
|
||||
poll_count--) {
|
||||
clk_sys_udelay(TI2C_POLL_MICROSECOND);
|
||||
clk_sys_udelay(I2C_POLL_MICROSECOND);
|
||||
}
|
||||
|
||||
/* 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(
|
||||
i2c_dma_context[i2c].dma_controller_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) {
|
||||
/* First terminate the DMA transfer */
|
||||
rc = qm_dma_transfer_terminate(
|
||||
i2c_dma_context[i2c].dma_controller_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;
|
||||
}
|
||||
if (i2c_dma_context[i2c].ongoing_dma_rx_operation) {
|
||||
/* First terminate the DMA transfer */
|
||||
rc |= qm_dma_transfer_terminate(
|
||||
i2c_dma_context[i2c].dma_controller_id,
|
||||
i2c_dma_context[i2c].dma_rx_channel_id);
|
||||
}
|
||||
|
||||
/* And terminate the I2C transfer */
|
||||
if (rc == 0) {
|
||||
QM_I2C[i2c]->ic_enable |= QM_I2C_IC_ENABLE_CONTROLLER_ABORT;
|
||||
/* Check if any of the calls failed */
|
||||
if (rc != 0) {
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
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,
|
||||
uint32_t len)
|
||||
{
|
||||
const qm_i2c_transfer_t *const transfer = i2c_transfer[i2c];
|
||||
qm_i2c_status_t status;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 (i2c_transfer[i2c].callback != NULL) {
|
||||
if (transfer->callback != NULL) {
|
||||
qm_i2c_get_status(i2c, &status);
|
||||
i2c_transfer[i2c].callback(
|
||||
i2c_transfer[i2c].callback_data, error_code, status,
|
||||
len);
|
||||
transfer->callback(transfer->callback_data, error_code,
|
||||
status, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -785,8 +796,10 @@ static void i2c_dma_transmit_callback(void *callback_context, uint32_t len,
|
|||
qm_i2c_status_t status;
|
||||
|
||||
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 */
|
||||
QM_I2C[i2c]->ic_dma_cr &= ~QM_I2C_IC_DMA_CR_TX_ENABLE;
|
||||
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
|
||||
a combined transaction */
|
||||
if ((i2c_transfer[i2c].stop == true) &&
|
||||
(i2c_transfer[i2c].rx_len == 0)) {
|
||||
if ((transfer->stop == true) &&
|
||||
(transfer->rx_len == 0)) {
|
||||
data_command |=
|
||||
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
|
||||
this is a combined transaction */
|
||||
if (i2c_transfer[i2c].rx_len > 0) {
|
||||
if (transfer->rx_len > 0) {
|
||||
i2c_start_dma_read(i2c);
|
||||
} else {
|
||||
/* Let's disable the I2C controller if we are
|
||||
done */
|
||||
if (i2c_transfer[i2c].stop == true) {
|
||||
if (transfer->stop == true) {
|
||||
/* This callback is called when DMA is
|
||||
done, but I2C can still be
|
||||
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
|
||||
only if this is a TX only operation, not in a
|
||||
combined transaction */
|
||||
if (i2c_transfer[i2c].callback != NULL) {
|
||||
if (transfer->callback != NULL) {
|
||||
qm_i2c_get_status(i2c, &status);
|
||||
i2c_transfer[i2c].callback(
|
||||
i2c_transfer[i2c].callback_data,
|
||||
error_code, status, len);
|
||||
transfer->callback(
|
||||
transfer->callback_data, error_code,
|
||||
status, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
@ -856,26 +875,31 @@ static void i2c_dma_receive_callback(void *callback_context, uint32_t len,
|
|||
qm_i2c_status_t status;
|
||||
|
||||
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 */
|
||||
QM_I2C[i2c]->ic_dma_cr &= ~QM_I2C_IC_DMA_CR_RX_ENABLE;
|
||||
i2c_dma_context[i2c].ongoing_dma_rx_operation = false;
|
||||
|
||||
/* Let's disable the I2C controller if we are done */
|
||||
if (i2c_transfer[i2c].stop == true) {
|
||||
if (transfer->stop == true) {
|
||||
controller_disable(i2c);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
i2c_transfer[i2c].callback(
|
||||
i2c_transfer[i2c].callback_data, error_code, status,
|
||||
len);
|
||||
transfer->callback(transfer->callback_data, error_code,
|
||||
status, len);
|
||||
}
|
||||
} 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);
|
||||
|
||||
/* 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 */
|
||||
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 */
|
||||
/* NOTE: This can be optimized for performance */
|
||||
QM_I2C[i2c]->ic_dma_rdlr = 0;
|
||||
QM_I2C[i2c]->ic_dma_tdlr = 0;
|
||||
|
||||
i2c_dma_context[i2c].multimaster_abort_status = 0;
|
||||
|
||||
/* Setup RX if something to receive */
|
||||
if (xfer->rx_len > 0) {
|
||||
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)
|
||||
{
|
||||
#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;
|
||||
#else
|
||||
idt_set_intr_gate_desc(vector, (uint32_t)isr);
|
||||
|
@ -180,7 +190,7 @@ static void ss_register_irq(unsigned int vector)
|
|||
/* Edge sensitive. */
|
||||
__builtin_arc_sr(vector, QM_SS_AUX_IRQ_SELECT);
|
||||
__builtin_arc_sr(QM_SS_IRQ_EDGE_SENSITIVE,
|
||||
QM_SS_AUX_IRQ_TRIGER);
|
||||
QM_SS_AUX_IRQ_TRIGGER);
|
||||
}
|
||||
}
|
||||
#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,
|
||||
const 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;
|
||||
|
||||
/* Check if the previous message has been consumed. */
|
||||
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)
|
||||
{
|
||||
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
|
||||
* 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_CHECK(mbox_ch < QM_MBOX_CH_NUM, -EINVAL);
|
||||
qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_SCSS_MAILBOX +
|
||||
mbox_ch;
|
||||
*status = mbox_reg->ch_sts &QM_MBOX_CH_STATUS_MASK;
|
||||
qm_mailbox_t *const mbox_reg =
|
||||
(qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch;
|
||||
*status = mbox_reg->ch_sts & QM_MBOX_CH_STATUS_MASK;
|
||||
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 */
|
||||
((cfg->up_bound & ADDRESS_MASK_7_BIT) << QM_MPR_UP_BOUND_OFFSET)
|
||||
/* MPR Lower bound 6:0 */
|
||||
|
|
||||
cfg->low_bound;
|
||||
| cfg->low_bound;
|
||||
|
||||
/* enable/lock */
|
||||
QM_MPR->mpr_cfg[id] |= (cfg->en_lock_mask << QM_MPR_EN_LOCK_OFFSET);
|
||||
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,
|
||||
qm_mpr_callback_t callback_fn,
|
||||
void *callback_data)
|
||||
|
@ -78,26 +125,18 @@ int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
|
|||
|
||||
/* unmask interrupt */
|
||||
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_INT_SRAM_CONTROLLER_HOST_HALT_MASK;
|
||||
#endif /* QM_SENSOR */
|
||||
}
|
||||
|
||||
/* probe or reset mode */
|
||||
else {
|
||||
/* mask interrupt */
|
||||
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_INT_SRAM_CONTROLLER_HOST_HALT_MASK;
|
||||
#endif /* QM_SENSOR */
|
||||
|
||||
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_P_STS_HALT_INTERRUPT_REDIRECTION;
|
||||
}
|
||||
|
||||
else {
|
||||
} else {
|
||||
QM_SCSS_PMU->p_sts &=
|
||||
~QM_P_STS_HALT_INTERRUPT_REDIRECTION;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* QM_SENSOR */
|
|
@ -37,6 +37,33 @@ QM_ISR_DECLARE(qm_rtc_isr_0)
|
|||
/* Disable RTC interrupt */
|
||||
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]) {
|
||||
(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
|
||||
* 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
|
||||
* FIFO, i.e. the burst length cannot be bigger than (16 - watermark level). */
|
||||
#define SPI_DMATDLR_DMATDL (0x03)
|
||||
* generated. The destination burst length has to fit in the remaining space
|
||||
* of the transmit FIFO, thus it must be <= (SPI_FIFOS_DEPTH - TDLR).
|
||||
* 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
|
||||
|
||||
/* SPI DMA receive watermark level. When the number of valid data entries in the
|
||||
|
@ -50,13 +58,21 @@
|
|||
* 0 1
|
||||
* 3 4
|
||||
* 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_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
|
||||
* driver. */
|
||||
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 volatile uint16_t tx_counter[QM_SPI_NUM], rx_counter[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];
|
||||
/* DMA (memory to SPI controller) callback information. */
|
||||
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 (transfer->callback) {
|
||||
transfer->callback(transfer->callback_data, -EIO,
|
||||
QM_SPI_RX_OVERFLOW,
|
||||
rx_counter[spi]);
|
||||
QM_SPI_RX_OVERFLOW, rx_counter[spi]);
|
||||
}
|
||||
|
||||
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;
|
||||
const uint8_t *tx_buffer = xfer->tx;
|
||||
|
||||
int frames;
|
||||
|
||||
/* RX Only transfers need a dummy byte to be sent for starting.
|
||||
* 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;
|
||||
}
|
||||
|
||||
while (i_rx && controller->rxflr) {
|
||||
if (i_rx && (controller->sr & QM_SPI_SR_RFNE)) {
|
||||
read_frame(spi, rx_buffer);
|
||||
rx_buffer += dfs[spi];
|
||||
i_rx--;
|
||||
}
|
||||
|
||||
frames =
|
||||
SPI_FIFOS_DEPTH - controller->txflr - controller->rxflr - 1;
|
||||
while (i_tx && frames) {
|
||||
if (i_tx && (controller->sr & QM_SPI_SR_TFNF)) {
|
||||
write_frame(spi, tx_buffer);
|
||||
tx_buffer += dfs[spi];
|
||||
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;
|
||||
}
|
||||
|
@ -548,12 +549,10 @@ static void spi_dma_callback(void *callback_context, uint32_t len,
|
|||
/* TX transfer. */
|
||||
frames_expected = transfer->tx_len;
|
||||
cb_pending_alternate_p = &dma_context_rx[spi].cb_pending;
|
||||
} else if (dma_context_p == &dma_context_rx[spi]) {
|
||||
/* RX tranfer. */
|
||||
} else {
|
||||
/* RX transfer. */
|
||||
frames_expected = transfer->rx_len;
|
||||
cb_pending_alternate_p = &dma_context_tx[spi].cb_pending;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
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_channel_id < QM_DMA_CHANNEL_NUM, -EINVAL);
|
||||
|
||||
int ret = -EINVAL;
|
||||
dma_context_t *dma_context_p = NULL;
|
||||
qm_dma_channel_config_t dma_chan_cfg = {0};
|
||||
dma_chan_cfg.handshake_polarity = QM_DMA_HANDSHAKE_POLARITY_HIGH;
|
||||
|
@ -630,21 +628,14 @@ int qm_spi_dma_channel_config(
|
|||
|
||||
switch (dma_channel_direction) {
|
||||
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)
|
||||
case QM_SPI_MST_1:
|
||||
dma_chan_cfg.handshake_interface =
|
||||
DMA_HW_IF_SPI_MASTER_1_TX;
|
||||
break;
|
||||
dma_chan_cfg.handshake_interface =
|
||||
(QM_SPI_MST_0 == spi) ? DMA_HW_IF_SPI_MASTER_0_TX
|
||||
: DMA_HW_IF_SPI_MASTER_1_TX;
|
||||
#else
|
||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_SPI_MASTER_0_TX;
|
||||
#endif
|
||||
default:
|
||||
/* Slave SPI is not supported. */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The DMA burst length has to fit in the space remaining in the
|
||||
* TX FIFO after the watermark level, DMATDLR. */
|
||||
|
@ -656,22 +647,14 @@ int qm_spi_dma_channel_config(
|
|||
break;
|
||||
|
||||
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
|
||||
* watermark level, DMARDLR + 1. */
|
||||
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);
|
||||
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. */
|
||||
dma_context_p->spi_id = spi;
|
||||
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. */
|
||||
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,
|
||||
|
|
|
@ -47,17 +47,20 @@ typedef struct {
|
|||
const qm_uart_transfer_t *xfer; /**< User transfer structure. */
|
||||
} dma_context_t;
|
||||
|
||||
/* UART Callback pointers. */
|
||||
static uart_client_callback_t write_callback[QM_UART_NUM];
|
||||
static uart_client_callback_t read_callback[QM_UART_NUM];
|
||||
|
||||
/* User callback data. */
|
||||
static void *write_data[QM_UART_NUM], *read_data[QM_UART_NUM];
|
||||
/**
|
||||
* Parameters returned by DMA driver on DMA transfer complete callback.
|
||||
*/
|
||||
typedef volatile struct {
|
||||
void *context; /**< Pointer to dma_context_t struct. */
|
||||
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 */
|
||||
static uint8_t *write_buffer[QM_UART_NUM], *read_buffer[QM_UART_NUM];
|
||||
static uint32_t write_pos[QM_UART_NUM], write_len[QM_UART_NUM];
|
||||
static uint32_t read_pos[QM_UART_NUM], read_len[QM_UART_NUM];
|
||||
static uint32_t write_pos[QM_UART_NUM];
|
||||
static uint32_t read_pos[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. */
|
||||
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];
|
||||
/* DMA core being used by each UART. */
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||
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):
|
||||
|
@ -89,6 +105,22 @@ static void qm_uart_isr_handler(const qm_uart_t uart)
|
|||
*/
|
||||
switch (interrupt_id) {
|
||||
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)) {
|
||||
regs->ier_dlh &= ~QM_UART_IER_ETBEI;
|
||||
/*
|
||||
|
@ -99,10 +131,10 @@ static void qm_uart_isr_handler(const qm_uart_t uart)
|
|||
* complete.
|
||||
*/
|
||||
regs->scr |= BIT(0);
|
||||
if (write_callback[uart]) {
|
||||
write_callback[uart](write_data[uart], 0,
|
||||
QM_UART_IDLE,
|
||||
write_pos[uart]);
|
||||
if (write_transfer->callback) {
|
||||
write_transfer->callback(
|
||||
write_transfer->callback_data, 0,
|
||||
QM_UART_IDLE, write_pos[uart]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -116,7 +148,7 @@ static void qm_uart_isr_handler(const qm_uart_t uart)
|
|||
: QM_UART_FIFO_HALF_DEPTH;
|
||||
while (count-- && !is_write_xfer_complete(uart)) {
|
||||
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.
|
||||
*/
|
||||
if (lsr & QM_UART_LSR_ERROR_BITS) {
|
||||
if (read_callback[uart]) {
|
||||
read_callback[uart](
|
||||
read_data[uart], -EIO,
|
||||
if (read_transfer->callback) {
|
||||
read_transfer->callback(
|
||||
read_transfer->callback_data, -EIO,
|
||||
lsr & QM_UART_LSR_ERROR_BITS, 0);
|
||||
}
|
||||
}
|
||||
if (lsr & QM_UART_LSR_DR) {
|
||||
read_buffer[uart][read_pos[uart]++] =
|
||||
read_transfer->data[read_pos[uart]++] =
|
||||
regs->rbr_thr_dll;
|
||||
} else {
|
||||
/* 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 &=
|
||||
~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
|
||||
if (read_callback[uart]) {
|
||||
read_callback[uart](read_data[uart], 0,
|
||||
QM_UART_IDLE,
|
||||
read_pos[uart]);
|
||||
if (read_transfer->callback) {
|
||||
read_transfer->callback(
|
||||
read_transfer->callback_data, 0,
|
||||
QM_UART_IDLE, read_pos[uart]);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
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
|
||||
* in the future.
|
||||
*/
|
||||
read_callback[uart](read_data[uart], -EIO,
|
||||
regs->lsr & QM_UART_LSR_ERROR_BITS,
|
||||
0);
|
||||
read_transfer->callback(
|
||||
read_transfer->callback_data, -EIO,
|
||||
regs->lsr & QM_UART_LSR_ERROR_BITS, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -363,10 +395,7 @@ int qm_uart_irq_write(const qm_uart_t uart,
|
|||
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||
|
||||
write_pos[uart] = 0;
|
||||
write_len[uart] = xfer->data_len;
|
||||
write_buffer[uart] = xfer->data;
|
||||
write_callback[uart] = xfer->callback;
|
||||
write_data[uart] = xfer->callback_data;
|
||||
uart_write_transfer[uart] = xfer;
|
||||
|
||||
/* Set threshold */
|
||||
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];
|
||||
|
||||
read_pos[uart] = 0;
|
||||
read_len[uart] = xfer->data_len;
|
||||
read_buffer[uart] = xfer->data;
|
||||
read_callback[uart] = xfer->callback;
|
||||
read_data[uart] = xfer->callback_data;
|
||||
uart_read_transfer[uart] = xfer;
|
||||
|
||||
/* Set threshold */
|
||||
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_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. */
|
||||
regs->ier_dlh &= ~QM_UART_IER_ETBEI;
|
||||
if (write_callback[uart]) {
|
||||
write_callback[uart](write_data[uart], -ECANCELED, QM_UART_IDLE,
|
||||
write_pos[uart]);
|
||||
if (transfer->callback) {
|
||||
transfer->callback(transfer->callback_data, -ECANCELED,
|
||||
QM_UART_IDLE, write_pos[uart]);
|
||||
}
|
||||
write_len[uart] = 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_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'
|
||||
* interrupts.
|
||||
*/
|
||||
regs->ier_dlh &= ~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
|
||||
if (read_callback[uart]) {
|
||||
read_callback[uart](read_data[uart], -ECANCELED, QM_UART_IDLE,
|
||||
read_pos[uart]);
|
||||
if (transfer->callback) {
|
||||
transfer->callback(transfer->callback_data, -ECANCELED,
|
||||
QM_UART_IDLE, read_pos[uart]);
|
||||
}
|
||||
read_len[uart] = 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,
|
||||
int error_code)
|
||||
{
|
||||
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);
|
||||
const uart_client_callback_t client_callback = xfer->callback;
|
||||
void *const client_data = xfer->callback_data;
|
||||
|
@ -457,19 +526,19 @@ static void uart_dma_callback(void *callback_context, uint32_t len,
|
|||
return;
|
||||
}
|
||||
|
||||
if (error_code) {
|
||||
if (error) {
|
||||
/*
|
||||
* Transfer failed, pass to client the error code returned by
|
||||
* 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) {
|
||||
/* Transfer completed successfully. */
|
||||
client_callback(client_data, 0, QM_UART_IDLE, len);
|
||||
client_callback(client_data, 0, status, len);
|
||||
} else {
|
||||
QM_ASSERT(len < client_expected_len);
|
||||
/* 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) {
|
||||
case QM_DMA_MEMORY_TO_PERIPHERAL:
|
||||
switch (uart) {
|
||||
case QM_UART_0:
|
||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_UART_A_TX;
|
||||
break;
|
||||
case QM_UART_1:
|
||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_UART_B_TX;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
dma_chan_cfg.handshake_interface = (QM_UART_0 == uart)
|
||||
? DMA_HW_IF_UART_A_TX
|
||||
: DMA_HW_IF_UART_B_TX;
|
||||
|
||||
/*
|
||||
* The DMA driver needs a pointer to the DMA context structure
|
||||
|
@ -516,16 +578,9 @@ int qm_uart_dma_channel_config(
|
|||
break;
|
||||
|
||||
case QM_DMA_PERIPHERAL_TO_MEMORY:
|
||||
switch (uart) {
|
||||
case QM_UART_0:
|
||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_UART_A_RX;
|
||||
break;
|
||||
case QM_UART_1:
|
||||
dma_chan_cfg.handshake_interface = DMA_HW_IF_UART_B_RX;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
dma_chan_cfg.handshake_interface = (QM_UART_0 == uart)
|
||||
? DMA_HW_IF_UART_A_RX
|
||||
: DMA_HW_IF_UART_B_RX;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
ver_pointer = (uint32_t*)ROM_VERSION_ADDRESS;
|
||||
ver_pointer = (uint32_t *)ROM_VERSION_ADDRESS;
|
||||
|
||||
return *ver_pointer;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
*/
|
||||
|
||||
#include "qm_wdt.h"
|
||||
#include "soc_watch.h"
|
||||
|
||||
#define QM_WDT_RELOAD_VALUE (0x76)
|
||||
|
||||
|
@ -37,7 +38,7 @@ static void *callback_data[QM_WDT_NUM];
|
|||
QM_ISR_DECLARE(qm_wdt_isr_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);
|
||||
}
|
||||
|
@ -58,6 +59,8 @@ int qm_wdt_start(const qm_wdt_t wdt)
|
|||
#else
|
||||
#error("Unsupported / unspecified processor detected.");
|
||||
#endif
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||
|
||||
QM_SCSS_PERIPHERAL->periph_cfg0 |= BIT(1);
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#define __QM_SS_ADC_H__
|
||||
|
||||
#include "qm_common.h"
|
||||
#include "qm_soc_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.
|
||||
*
|
||||
* 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] 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,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.
|
||||
* @retval 0 on success.
|
||||
* @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.
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
* GPIO SS pin states.
|
||||
*/
|
||||
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_STATE_NUM
|
||||
} qm_ss_gpio_state_t;
|
||||
|
@ -60,6 +60,7 @@ typedef struct {
|
|||
uint32_t int_type; /**< Interrupt type, 0b: level; 1b: edge. */
|
||||
uint32_t int_polarity; /**< Interrupt polarity, 0b: low, 1b: high. */
|
||||
uint32_t int_debounce; /**< Debounce on/off. */
|
||||
|
||||
/**
|
||||
* 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] 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.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
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.
|
||||
|
|
|
@ -71,32 +71,32 @@
|
|||
*/
|
||||
typedef enum {
|
||||
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 Speed Type.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SS_I2C_SPEED_STD = 1, /**< Standard mode (100 Kbps). */
|
||||
QM_SS_I2C_SPEED_FAST = 2 /**< Fast mode (400 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_t;
|
||||
|
||||
/**
|
||||
* QM SS I2C status type.
|
||||
*/
|
||||
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_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
||||
QM_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
||||
QM_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
||||
QM_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
||||
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_MASTER_DIS = BIT(11), /**< Master disabled. */
|
||||
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_SLV_ARBLOST = BIT(14), /**< Slave lost bus. */
|
||||
QM_I2C_TX_ABRT_SLVRD_INTX = BIT(15), /**< Slave read completion. */
|
||||
QM_I2C_TX_ABRT_USER_ABRT = BIT(16), /**< User abort. */
|
||||
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
||||
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_USER_ABRT = BIT(16), /**< User abort. */
|
||||
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
||||
} qm_ss_i2c_status_t;
|
||||
|
||||
/**
|
||||
|
@ -120,6 +120,7 @@ typedef struct {
|
|||
uint8_t *rx; /**< Read data. */
|
||||
uint32_t rx_len; /**< Read buffer length. */
|
||||
bool stop; /**< Generate master STOP. */
|
||||
|
||||
/**
|
||||
* 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] xfer Transfer structure includes write / read data and length,
|
||||
* user callback function and the callback context.
|
||||
* This must not be NULL.
|
||||
* user callback function and the callback context.
|
||||
* 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.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
|
|
|
@ -110,14 +110,16 @@ typedef enum {
|
|||
/**
|
||||
* 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 {
|
||||
QM_SS_SPI_SS_NONE = 0, /**< No slave select. */
|
||||
QM_SS_SPI_SS_0 = BIT(0), /**< Slave select 0. */
|
||||
QM_SS_SPI_SS_1 = BIT(1), /**< Slave select 1. */
|
||||
QM_SS_SPI_SS_2 = BIT(2), /**< Slave select 2. */
|
||||
QM_SS_SPI_SS_3 = BIT(3), /**< Slave select 3. */
|
||||
QM_SS_SPI_SS_DISABLED = 0, /**< Slave select disable. */
|
||||
QM_SS_SPI_SS_0 = BIT(0), /**< Slave select 0. */
|
||||
QM_SS_SPI_SS_1 = BIT(1), /**< Slave select 1. */
|
||||
QM_SS_SPI_SS_2 = BIT(2), /**< Slave select 2. */
|
||||
QM_SS_SPI_SS_3 = BIT(3), /**< Slave select 3. */
|
||||
} qm_ss_spi_slave_select_t;
|
||||
|
||||
/**
|
||||
|
@ -169,7 +171,7 @@ typedef struct {
|
|||
*/
|
||||
void (*callback)(void *data, int error, qm_ss_spi_status_t status,
|
||||
uint16_t len);
|
||||
void *data; /**< Callback user data. */
|
||||
void *callback_data; /**< Callback user data. */
|
||||
} qm_ss_spi_async_transfer_t;
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
* Sensor Subsystem Timer Configuration Type.
|
||||
*/
|
||||
typedef struct {
|
||||
bool watchdog_mode; /**< Watchdog mode. */
|
||||
bool watchdog_mode; /**< Watchdog mode. */
|
||||
|
||||
/**
|
||||
* Increments in run state only.
|
||||
|
@ -55,8 +55,9 @@ typedef struct {
|
|||
* running state.
|
||||
*/
|
||||
bool inc_run_only;
|
||||
bool int_en; /**< Interrupt enable. */
|
||||
uint32_t count; /**< Final count value. */
|
||||
bool int_en; /**< Interrupt enable. */
|
||||
uint32_t count; /**< Final count value. */
|
||||
|
||||
/**
|
||||
* User callback.
|
||||
*
|
||||
|
|
|
@ -43,11 +43,11 @@
|
|||
#define QM_SS_ADC_CMD_START_CAL (3)
|
||||
#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)
|
||||
|
||||
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 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 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 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. */
|
||||
samples_to_read = FIFO_INTERRUPT_THRESHOLD;
|
||||
if (samples_to_read > (irq_xfer[adc].samples_len - count[adc])) {
|
||||
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];
|
||||
}
|
||||
|
||||
/* 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_ADC_SET_POP_RX);
|
||||
/* 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) >>
|
||||
(ADC_SAMPLE_SHIFT - resolution[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_ADC_CTRL_CLR_DATA_A);
|
||||
|
||||
if (count[adc] == irq_xfer[adc].samples_len) {
|
||||
if (count[adc] == irq_xfer[adc]->samples_len) {
|
||||
/* Stop the sequencer. */
|
||||
QM_SS_REG_AUX_NAND(controller + QM_SS_ADC_CTRL,
|
||||
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);
|
||||
|
||||
/* Call the user callback. */
|
||||
if (irq_xfer[adc].callback) {
|
||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data, 0,
|
||||
QM_SS_ADC_COMPLETE,
|
||||
QM_SS_ADC_TRANSFER);
|
||||
if (irq_xfer[adc]->callback) {
|
||||
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data, 0,
|
||||
QM_SS_ADC_COMPLETE,
|
||||
QM_SS_ADC_TRANSFER);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
if (intstat & QM_SS_ADC_INTSTAT_OVERFLOW) {
|
||||
if (irq_xfer[adc].callback) {
|
||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data,
|
||||
-EIO, QM_SS_ADC_OVERFLOW,
|
||||
QM_SS_ADC_TRANSFER);
|
||||
if (irq_xfer[adc]->callback) {
|
||||
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
|
||||
-EIO, QM_SS_ADC_OVERFLOW,
|
||||
QM_SS_ADC_TRANSFER);
|
||||
}
|
||||
}
|
||||
if (intstat & QM_SS_ADC_INTSTAT_UNDERFLOW) {
|
||||
if (irq_xfer[adc].callback) {
|
||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data,
|
||||
-EIO, QM_SS_ADC_UNDERFLOW,
|
||||
QM_SS_ADC_TRANSFER);
|
||||
if (irq_xfer[adc]->callback) {
|
||||
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
|
||||
-EIO, QM_SS_ADC_UNDERFLOW,
|
||||
QM_SS_ADC_TRANSFER);
|
||||
}
|
||||
}
|
||||
if (intstat & QM_SS_ADC_INTSTAT_SEQERROR) {
|
||||
if (irq_xfer[adc].callback) {
|
||||
irq_xfer[adc].callback(irq_xfer[adc].callback_data,
|
||||
-EIO, QM_SS_ADC_SEQERROR,
|
||||
QM_SS_ADC_TRANSFER);
|
||||
if (irq_xfer[adc]->callback) {
|
||||
irq_xfer[adc]->callback(irq_xfer[adc]->callback_data,
|
||||
-EIO, QM_SS_ADC_SEQERROR,
|
||||
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
|
||||
* as it is enabled so it is necessary to ignore it the first time the
|
||||
* ISR runs. */
|
||||
if (!first_mode_callback_ignored[adc]) {
|
||||
first_mode_callback_ignored[adc] = true;
|
||||
if (ignore_spurious_interrupt[adc]) {
|
||||
ignore_spurious_interrupt[adc] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -215,7 +218,7 @@ static void qm_ss_adc_isr_cal_handler(const qm_ss_adc_t 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_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)
|
||||
{
|
||||
uint32_t creg, delay;
|
||||
uint32_t creg, delay, intstat;
|
||||
uint32_t controller = adc_base[adc];
|
||||
|
||||
QM_CHECK(adc < QM_SS_ADC_NUM, -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. */
|
||||
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)) {
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
if ((mode >= QM_SS_ADC_MODE_NORM_CAL)) {
|
||||
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)))
|
||||
{
|
||||
uint32_t creg;
|
||||
uint32_t creg, intstat;
|
||||
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_adc();
|
||||
|
||||
|
@ -458,13 +477,21 @@ int qm_ss_adc_calibrate(const qm_ss_adc_t adc __attribute__((unused)))
|
|||
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_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_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;
|
||||
}
|
||||
|
||||
|
@ -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)),
|
||||
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(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. */
|
||||
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 |
|
||||
|
@ -515,9 +547,17 @@ int qm_ss_adc_set_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
|||
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_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;
|
||||
}
|
||||
|
@ -535,7 +575,8 @@ int qm_ss_adc_get_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
|||
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 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). */
|
||||
if (res > 1) {
|
||||
if (status) {
|
||||
*status = res;
|
||||
}
|
||||
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);
|
||||
|
||||
/* 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. */
|
||||
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,
|
||||
const qm_ss_gpio_state_t state)
|
||||
const qm_ss_gpio_state_t state)
|
||||
{
|
||||
uint32_t val;
|
||||
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
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "qm_ss_i2c.h"
|
||||
#include "clk.h"
|
||||
|
||||
#define SPK_LEN_SS (1)
|
||||
#define SPK_LEN_FS (2)
|
||||
#define TX_TL (2)
|
||||
#define RX_TL (5)
|
||||
|
||||
#include <string.h>
|
||||
#include "qm_ss_i2c.h"
|
||||
#include "clk.h"
|
||||
/* number of retries before giving up on disabling the controller */
|
||||
#define I2C_POLL_COUNT (1000000)
|
||||
#define I2C_POLL_MICROSECOND (1)
|
||||
|
||||
/*
|
||||
* 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 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],
|
||||
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_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)
|
||||
{
|
||||
const qm_ss_i2c_transfer_t *const transfer = i2c_transfer[i2c];
|
||||
uint32_t controller = i2c_base[i2c], data_cmd = 0,
|
||||
count_tx = (QM_SS_I2C_FIFO_SIZE - TX_TL);
|
||||
qm_ss_i2c_status_t status = 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 */
|
||||
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;
|
||||
|
||||
if (i2c_transfer[i2c].callback) {
|
||||
i2c_transfer[i2c].callback(
|
||||
i2c_transfer[i2c].callback_data, rc, status, 0);
|
||||
if (i2c_transfer[i2c]->callback) {
|
||||
i2c_transfer[i2c]->callback(
|
||||
i2c_transfer[i2c]->callback_data, rc, status, 0);
|
||||
}
|
||||
|
||||
controller_disable(i2c);
|
||||
}
|
||||
|
||||
/* RX read from buffer */
|
||||
if ((__builtin_arc_lr(controller + QM_SS_I2C_INTR_STAT) &
|
||||
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_sr(QM_SS_I2C_DATA_CMD_POP,
|
||||
controller + QM_SS_I2C_DATA_CMD);
|
||||
/* 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);
|
||||
i2c_read_buffer_remaining[i2c]--;
|
||||
read_buffer_remaining--;
|
||||
i2c_read_pos[i2c]++;
|
||||
|
||||
if (i2c_read_buffer_remaining[i2c] == 0) {
|
||||
if (read_buffer_remaining == 0) {
|
||||
/* mask rx full interrupt if transfer
|
||||
* complete
|
||||
*/
|
||||
|
@ -129,19 +139,19 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
|||
(controller + QM_SS_I2C_INTR_MASK),
|
||||
QM_SS_I2C_INTR_MASK_RX_FULL);
|
||||
|
||||
if (i2c_transfer[i2c].stop) {
|
||||
if (i2c_transfer[i2c]->stop) {
|
||||
controller_disable(i2c);
|
||||
}
|
||||
|
||||
if (i2c_transfer[i2c].callback) {
|
||||
i2c_transfer[i2c].callback(
|
||||
i2c_transfer[i2c].callback_data, 0,
|
||||
if (i2c_transfer[i2c]->callback) {
|
||||
i2c_transfer[i2c]->callback(
|
||||
i2c_transfer[i2c]->callback_data, 0,
|
||||
QM_I2C_IDLE, i2c_read_pos[i2c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i2c_read_buffer_remaining[i2c] > 0 &&
|
||||
i2c_read_buffer_remaining[i2c] < (RX_TL + 1)) {
|
||||
if (read_buffer_remaining > 0 &&
|
||||
read_buffer_remaining < (RX_TL + 1)) {
|
||||
/* Adjust the RX threshold so the next 'RX_FULL'
|
||||
* interrupt is generated when all the remaining
|
||||
* 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_I2C_TL_RX_TL_MASK);
|
||||
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
|
||||
|
@ -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) &
|
||||
QM_SS_I2C_STATUS_TFE) &&
|
||||
(i2c_transfer[i2c].tx != NULL) &&
|
||||
(i2c_transfer[i2c].tx_len == 0) &&
|
||||
(i2c_transfer[i2c].rx_len == 0)) {
|
||||
(i2c_transfer[i2c]->tx != NULL) &&
|
||||
(write_buffer_remaining == 0) &&
|
||||
(read_buffer_remaining == 0)) {
|
||||
|
||||
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_INTR_MASK),
|
||||
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
|
||||
* transaction, disable the controller now
|
||||
*/
|
||||
if ((i2c_read_buffer_remaining[i2c] == 0) &&
|
||||
i2c_transfer[i2c].stop) {
|
||||
if (i2c_transfer[i2c]->stop) {
|
||||
controller_disable(i2c);
|
||||
|
||||
/* callback */
|
||||
if (i2c_transfer[i2c].callback) {
|
||||
i2c_transfer[i2c].callback(
|
||||
i2c_transfer[i2c].callback_data, 0,
|
||||
QM_I2C_IDLE, i2c_write_pos[i2c]);
|
||||
if (i2c_transfer[i2c]->callback) {
|
||||
i2c_transfer[i2c]->callback(
|
||||
i2c_transfer[i2c]->callback_data, 0,
|
||||
QM_I2C_IDLE, i2c_write_pos[i2c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ((count_tx) && i2c_transfer[i2c].tx_len) {
|
||||
while ((count_tx) && write_buffer_remaining) {
|
||||
count_tx--;
|
||||
write_buffer_remaining--;
|
||||
|
||||
/* write command -IC_DATA_CMD[8] = 0 */
|
||||
/* fill IC_DATA_CMD[7:0] with the data */
|
||||
data_cmd = QM_SS_I2C_DATA_CMD_PUSH |
|
||||
i2c_transfer[i2c].tx[i2c_write_pos[i2c]];
|
||||
i2c_transfer[i2c].tx_len--;
|
||||
i2c_transfer[i2c]->tx[i2c_write_pos[i2c]];
|
||||
|
||||
/* if transfer is a combined transfer, only
|
||||
* send stop at
|
||||
* end of the transfer sequence */
|
||||
if (i2c_transfer[i2c].stop &&
|
||||
(i2c_transfer[i2c].tx_len == 0) &&
|
||||
(i2c_transfer[i2c].rx_len == 0)) {
|
||||
if (i2c_transfer[i2c]->stop &&
|
||||
(read_buffer_remaining == 0) &&
|
||||
(write_buffer_remaining == 0)) {
|
||||
|
||||
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_RXFLR) + 1));
|
||||
|
||||
while (i2c_transfer[i2c].rx_len &&
|
||||
(i2c_transfer[i2c].tx_len == 0) && count_tx) {
|
||||
while (i2c_read_cmd_send[i2c] &&
|
||||
(write_buffer_remaining == 0) && count_tx) {
|
||||
count_tx--;
|
||||
i2c_transfer[i2c].rx_len--;
|
||||
i2c_read_cmd_send[i2c]--;
|
||||
|
||||
/* if transfer is a combined transfer, only
|
||||
* send stop at
|
||||
* end of
|
||||
* the transfer sequence */
|
||||
if (i2c_transfer[i2c].stop &&
|
||||
(i2c_transfer[i2c].rx_len == 0) &&
|
||||
(i2c_transfer[i2c].tx_len == 0)) {
|
||||
if (i2c_transfer[i2c]->stop &&
|
||||
(i2c_read_cmd_send[i2c] == 0)) {
|
||||
|
||||
__builtin_arc_sr((QM_SS_I2C_DATA_CMD_CMD |
|
||||
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
|
||||
* empty */
|
||||
if ((i2c_transfer[i2c].tx_len == 0) &&
|
||||
(i2c_transfer[i2c].rx_len == 0)) {
|
||||
if ((write_buffer_remaining == 0) &&
|
||||
(read_buffer_remaining == 0)) {
|
||||
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_TL),
|
||||
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);
|
||||
|
||||
/* disable controller */
|
||||
controller_disable(i2c);
|
||||
if (controller_disable(i2c)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* set mode */
|
||||
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,
|
||||
-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) |
|
||||
(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) {
|
||||
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);
|
||||
break;
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@ -480,7 +492,9 @@ int qm_ss_i2c_master_write(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
|
|||
|
||||
/* disable controller */
|
||||
if (true == stop) {
|
||||
controller_disable(i2c);
|
||||
if (controller_disable(i2c)) {
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
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*/
|
||||
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 */
|
||||
*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 */
|
||||
if (true == stop) {
|
||||
controller_disable(i2c);
|
||||
if (controller_disable(i2c)) {
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
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_read_pos[i2c] = 0;
|
||||
i2c_read_buffer_remaining[i2c] = xfer->rx_len;
|
||||
memcpy(&i2c_transfer[i2c], xfer, sizeof(i2c_transfer[i2c]));
|
||||
i2c_read_cmd_send[i2c] = xfer->rx_len;
|
||||
i2c_transfer[i2c] = xfer;
|
||||
|
||||
/* set threshold */
|
||||
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))
|
||||
;
|
||||
}
|
||||
|
||||
/* 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];
|
||||
if (__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
|
||||
QM_SS_I2C_ENABLE_STATUS_IC_EN) {
|
||||
/* disable controller */
|
||||
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_CON),
|
||||
QM_SS_I2C_CON_ENABLE);
|
||||
int poll_count = I2C_POLL_COUNT;
|
||||
|
||||
/* wait until controller is disabled */
|
||||
while ((__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
|
||||
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 */
|
||||
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)
|
||||
|
|
|
@ -38,13 +38,11 @@
|
|||
|
||||
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 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 */
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uint32_t dr;
|
||||
|
@ -211,7 +209,7 @@ int qm_ss_spi_transfer(const qm_ss_spi_t spi,
|
|||
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)
|
||||
;
|
||||
|
||||
|
@ -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);
|
||||
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
||||
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)
|
||||
: 1,
|
||||
-EINVAL);
|
||||
|
||||
transfer[spi] = xfer;
|
||||
spi_async_transfer[spi] = xfer;
|
||||
tx_c[spi] = xfer->tx_len;
|
||||
rx_c[spi] = xfer->rx_len;
|
||||
tx_p[spi] = xfer->tx;
|
||||
rx_p[spi] = xfer->rx;
|
||||
/* RX only transfers need a dummy frame byte to be sent. */
|
||||
if (tmode == QM_SS_SPI_TMOD_RX) {
|
||||
tx_p[spi] = (uint8_t *)&dummy_frame;
|
||||
tx_c[spi] = 1;
|
||||
|
||||
/* Set NDF (Number of Data Frames) in RX or EEPROM Read mode. (-1) */
|
||||
if (tmode == QM_SS_SPI_TMOD_RX || tmode == QM_SS_SPI_TMOD_EEPROM_READ) {
|
||||
ctrl &= ~QM_SS_SPI_CTRL_NDF_MASK;
|
||||
ctrl |= ((xfer->rx_len - 1) << QM_SS_SPI_CTRL_NDF_OFFS) &
|
||||
QM_SS_SPI_CTRL_NDF_MASK;
|
||||
__builtin_arc_sr(ctrl, base[spi] + QM_SS_SPI_CTRL);
|
||||
}
|
||||
|
||||
uint32_t ftlr =
|
||||
|
@ -256,35 +256,44 @@ int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi,
|
|||
|
||||
/* Unmask all interrupts */
|
||||
__builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_INTR_MASK);
|
||||
|
||||
/* Enable SPI device */
|
||||
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;
|
||||
}
|
||||
|
||||
int qm_ss_spi_transfer_terminate(const qm_ss_spi_t spi)
|
||||
{
|
||||
QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL);
|
||||
const qm_ss_spi_async_transfer_t *const transfer =
|
||||
spi_async_transfer[spi];
|
||||
|
||||
spi_disable(spi);
|
||||
|
||||
if (transfer[spi]->callback) {
|
||||
if (transfer->callback) {
|
||||
uint32_t len = 0;
|
||||
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
|
||||
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
||||
QM_SS_SPI_CTRL_TMOD_OFFS);
|
||||
if (tmode == QM_SS_SPI_TMOD_TX ||
|
||||
tmode == QM_SS_SPI_TMOD_TX_RX) {
|
||||
len = transfer[spi]->tx_len - tx_c[spi];
|
||||
len = transfer->tx_len - tx_c[spi];
|
||||
} else {
|
||||
len = transfer[spi]->rx_len - rx_c[spi];
|
||||
len = transfer->rx_len - rx_c[spi];
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: change this to return controller-specific code
|
||||
* 'user aborted'.
|
||||
*/
|
||||
transfer[spi]->callback(transfer[spi]->data, -ECANCELED,
|
||||
QM_SS_SPI_IDLE, (uint16_t)len);
|
||||
transfer->callback(transfer->callback_data, -ECANCELED,
|
||||
QM_SS_SPI_IDLE, (uint16_t)len);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uint32_t intr_stat = __builtin_arc_lr(base[spi] + QM_SS_SPI_INTR_STAT);
|
||||
spi_disable(spi);
|
||||
QM_ASSERT((intr_stat &
|
||||
(QM_SS_SPI_INTR_STAT_TXOI | QM_SS_SPI_INTR_STAT_RXFI)) == 0);
|
||||
const qm_ss_spi_async_transfer_t *const transfer =
|
||||
spi_async_transfer[spi];
|
||||
|
||||
if ((intr_stat & QM_SS_SPI_INTR_RXOI) && transfer[spi]->callback) {
|
||||
transfer[spi]->callback(transfer[spi]->data, -EIO,
|
||||
QM_SS_SPI_RX_OVERFLOW,
|
||||
transfer[spi]->rx_len - rx_c[spi]);
|
||||
spi_disable(spi);
|
||||
QM_ASSERT((intr_stat & QM_SS_SPI_INTR_STAT_TXOI) == 0);
|
||||
QM_ASSERT((intr_stat & QM_SS_SPI_INTR_STAT_RXUI) == 0);
|
||||
|
||||
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 tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
|
||||
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 &&
|
||||
!(__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY)) {
|
||||
if (tmode == QM_SS_SPI_TMOD_TX) {
|
||||
spi_disable(spi);
|
||||
if (transfer[spi]->callback) {
|
||||
transfer[spi]->callback(transfer[spi]->data, 0,
|
||||
QM_SS_SPI_IDLE,
|
||||
transfer[spi]->tx_len);
|
||||
if (transfer->callback) {
|
||||
transfer->callback(transfer->callback_data, 0,
|
||||
QM_SS_SPI_IDLE,
|
||||
transfer->tx_len);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
int32_t cnt = FIFO_SIZE - rxflr - txflr - 1;
|
||||
while (tx_c[spi] && cnt > 0) {
|
||||
fifo_write(spi, tx_p[spi], bytes);
|
||||
tx_p[spi] += bytes;
|
||||
fifo_write(spi, tx_buffer, bytes);
|
||||
tx_buffer += bytes;
|
||||
tx_c[spi]--;
|
||||
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);
|
||||
/* Calculate number of bytes per frame (1 or 2)*/
|
||||
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 &&
|
||||
rx_c[spi]) {
|
||||
fifo_read(spi, rx_p[spi], bytes);
|
||||
rx_p[spi] += bytes;
|
||||
fifo_read(spi, rx_buffer, bytes);
|
||||
rx_buffer += bytes;
|
||||
rx_c[spi]--;
|
||||
}
|
||||
/* 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);
|
||||
} else {
|
||||
spi_disable(spi);
|
||||
if (transfer[spi]->callback) {
|
||||
transfer[spi]->callback(transfer[spi]->data, 0,
|
||||
QM_SS_SPI_IDLE,
|
||||
transfer[spi]->rx_len);
|
||||
if (transfer->callback) {
|
||||
transfer->callback(transfer->callback_data, 0,
|
||||
QM_SS_SPI_IDLE, transfer->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 "qm_isr.h"
|
||||
#include "qm_sensor_regs.h"
|
||||
|
||||
/* Sensor Subsystem sleep operand definition.
|
||||
* 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)
|
||||
{
|
||||
/* 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 */
|
||||
switch (mode) {
|
||||
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));
|
||||
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 :
|
||||
|
@ -81,8 +95,20 @@ void ss_power_cpu_ss1(const ss_power_cpu_ss1_mode_t mode)
|
|||
*/
|
||||
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 */
|
||||
__asm__ __volatile__("sleep %0"
|
||||
:
|
||||
: "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))
|
||||
|
||||
/* QM_ASSERT is not currently available for Zephyr. */
|
||||
#define ASSERT_EXCLUDE (ZEPHYR_OS)
|
||||
|
||||
/**
|
||||
* In our reference implementation, by default DEBUG enables QM_PUTS and
|
||||
* QM_ASSERT but not QM_PRINTF.
|
||||
* User can modify this block to customise the default DEBUG configuration.
|
||||
*/
|
||||
|
||||
#if (DEBUG)
|
||||
#if !ASSERT_EXCLUDE
|
||||
#ifndef ASSERT_ENABLE
|
||||
#define ASSERT_ENABLE (1)
|
||||
#endif
|
||||
#endif /* ASSERT_EXCLUDE */
|
||||
#ifndef PUTS_ENABLE
|
||||
#define PUTS_ENABLE (1)
|
||||
#endif
|
||||
|
@ -112,7 +118,8 @@ void stdout_uart_setup(uint32_t baud_divisors);
|
|||
#endif /* PRINTF_ENABLE || PUTS_ENABLE || ASSERT_ENABLE */
|
||||
|
||||
#if (PRINTF_ENABLE)
|
||||
#define QM_PRINTF(...) printf(__VA_ARGS__)
|
||||
int pico_printf(const char *format, ...);
|
||||
#define QM_PRINTF(...) pico_printf(__VA_ARGS__)
|
||||
#else
|
||||
#define QM_PRINTF(...)
|
||||
#endif /* PRINTF_ENABLE */
|
||||
|
@ -146,7 +153,7 @@ void stdout_uart_setup(uint32_t baud_divisors);
|
|||
#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
|
||||
* running on the other core).
|
||||
*/
|
||||
|
@ -266,4 +273,39 @@ void stdout_uart_setup(uint32_t baud_divisors);
|
|||
#define QM_VER_STRINGIFY(major, minor, 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__ */
|
||||
|
|
|
@ -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 "clk.h"
|
||||
#include "qm_comparator.h"
|
||||
|
||||
#include "qm_isr.h"
|
||||
#include "qm_adc.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");
|
||||
}
|
||||
|
||||
|
@ -55,7 +57,7 @@ static void clear_all_pending_interrupts(void)
|
|||
QM_GPIO[QM_GPIO_0]->gpio_porta_eoi = -1;
|
||||
}
|
||||
|
||||
void soc_sleep(void)
|
||||
void power_soc_sleep(void)
|
||||
{
|
||||
/* Variables to save register values. */
|
||||
uint32_t ac_power_save;
|
||||
|
@ -79,6 +81,8 @@ void soc_sleep(void)
|
|||
* Mask registers.
|
||||
*/
|
||||
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
|
||||
|
@ -93,10 +97,9 @@ void soc_sleep(void)
|
|||
* frequency than RTC clock.
|
||||
*/
|
||||
/* CCU_LP_CLK_CTL.CCU_EXIT_TO_HYBOSC */
|
||||
QM_SCSS_CCU->ccu_lp_clk_ctl |= QM_CCU_EXIT_TO_HYBOSC;
|
||||
|
||||
/* Power down hybrid oscillator after HALT instruction is executed. */
|
||||
QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_PD;
|
||||
QM_SCSS_CCU->ccu_lp_clk_ctl |=
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* Enter SoC sleep mode. */
|
||||
cpu_halt();
|
||||
power_cpu_halt();
|
||||
|
||||
/* From here on, restore the SoC to an active state. */
|
||||
/* Set the RAR to normal mode. */
|
||||
|
@ -137,6 +140,8 @@ void soc_sleep(void)
|
|||
QM_SCSS_CCU->ccu_sys_clk_ctl |=
|
||||
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. */
|
||||
while (!(QM_SCSS_CCU->osc0_stat1 &
|
||||
(QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {
|
||||
|
@ -145,12 +150,14 @@ void soc_sleep(void)
|
|||
/* Restore original clocking, ADC, analog comparator states. */
|
||||
QM_SCSS_CCU->osc0_cfg1 = osc0_cfg_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_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. */
|
||||
uint32_t ac_power_save;
|
||||
|
@ -170,9 +177,23 @@ void soc_deep_sleep(void)
|
|||
/* Clear any pending interrupts. */
|
||||
clear_all_pending_interrupts();
|
||||
|
||||
/* Only clear the comparator wake mask bit. */
|
||||
QM_SCSS_CCU->wake_mask =
|
||||
SET_ALL_BITS & ~QM_CCU_WAKE_MASK_COMPARATOR_BIT;
|
||||
/*
|
||||
* Clear the wake mask bits. Default behaviour is to wake from GPIO /
|
||||
* 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_adc_set_mode(QM_ADC_0, QM_ADC_MODE_DEEP_PWR_DOWN);
|
||||
|
@ -186,15 +207,20 @@ void soc_deep_sleep(void)
|
|||
|
||||
/* Disable external clocks. */
|
||||
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. */
|
||||
QM_SCSS_PMUX->pmux_slew[0] = 0;
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_PMUX_SLEW);
|
||||
|
||||
/* Disable RTC. */
|
||||
QM_SCSS_CCU->osc1_cfg0 &= ~QM_OSC1_PD;
|
||||
if (wake_event != POWER_WAKE_FROM_RTC) {
|
||||
/* Disable RTC. */
|
||||
QM_SCSS_CCU->osc1_cfg0 &= ~QM_OSC1_PD;
|
||||
|
||||
/* Set system clock source to hyb osc, 4 MHz, scaled down to 32 kHz. */
|
||||
clk_sys_set_mode(CLK_SYS_HYB_OSC_4MHZ, CLK_SYS_DIV_128);
|
||||
/* Set system clock source to
|
||||
* 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. */
|
||||
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_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. */
|
||||
QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_PD;
|
||||
|
@ -244,8 +271,16 @@ void soc_deep_sleep(void)
|
|||
/* Set the RAR to retention mode. */
|
||||
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. */
|
||||
cpu_halt();
|
||||
power_cpu_halt();
|
||||
|
||||
/* We are now exiting from deep sleep mode. */
|
||||
/* Set the RAR to normal mode. */
|
||||
|
@ -297,6 +332,7 @@ void soc_deep_sleep(void)
|
|||
while (!(QM_SCSS_CCU->osc0_stat1 &
|
||||
(QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {
|
||||
};
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_SYS_CLK_CTL);
|
||||
|
||||
/* Re-enable clocks. */
|
||||
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->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_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_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_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 (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.
|
||||
*
|
||||
* Halts the CPU until next interrupt or reset.
|
||||
*/
|
||||
void cpu_halt(void);
|
||||
void power_cpu_halt(void);
|
||||
|
||||
/**
|
||||
* Put SoC to sleep.
|
||||
|
@ -68,15 +76,19 @@ void cpu_halt(void);
|
|||
* - RTC
|
||||
* - Low power comparators
|
||||
*/
|
||||
void soc_sleep();
|
||||
void power_soc_sleep();
|
||||
|
||||
/**
|
||||
* Put SoC to deep sleep.
|
||||
*
|
||||
* Enter into deep sleep mode. All clocks are gated. The only way to return
|
||||
* from this is to have an interrupt trigger on the low power comparators.
|
||||
* Enter into deep sleep mode. All clocks are gated. The Wake source for this
|
||||
* 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"
|
||||
|
||||
/**
|
||||
* Quark Microcontroller D2000 Register file.
|
||||
*
|
||||
* @brief Quark Microcontroller D2000 Registers.
|
||||
* Quark D2000 SoC Registers.
|
||||
*
|
||||
* @defgroup groupQUARKD2000SEREG SoC Registers (D2000)
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define QUARK_D2000 (1)
|
||||
|
@ -44,10 +44,11 @@
|
|||
#define HAS_MVIC (1)
|
||||
|
||||
/**
|
||||
* @defgroup groupD2000REG Quark D2000 Registers
|
||||
@{
|
||||
* @name System Core
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** System Core register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t osc0_cfg0; /**< Hybrid Oscillator Configuration 0 */
|
||||
QM_RW uint32_t osc0_stat1; /**< Hybrid Oscillator status 1 */
|
||||
|
@ -79,7 +80,6 @@ qm_scss_ccu_reg_t test_scss_ccu;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
|
@ -88,16 +88,16 @@ qm_scss_ccu_reg_t test_scss_ccu;
|
|||
#define QM_OSC0_PD BIT(2)
|
||||
#define QM_OSC1_PD BIT(1)
|
||||
|
||||
/* Enable Crystal oscillator*/
|
||||
/* Enable Crystal oscillator. */
|
||||
#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_OFFS (16)
|
||||
#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_MASK (0x00600000)
|
||||
#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_OFFS (20)
|
||||
#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_XTAL BIT(1)
|
||||
#define QM_OSC0_EN_SI_OSC BIT(1)
|
||||
|
||||
#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_PERIPH_CLK_EN BIT(1)
|
||||
#define QM_CCU_ADC_CLK_DIV_OFFSET (16)
|
||||
#define QM_CCU_ADC_CLK_DIV_DEF_MASK (0xFC00FFFF)
|
||||
#define QM_CCU_PERIPH_PCLK_DIV_DEF_MASK (0xFFFFFFF8)
|
||||
#define QM_CCU_PERIPH_PCLK_DIV_OFFSET (1)
|
||||
#define QM_CCU_PERIPH_PCLK_DIV_EN BIT(0)
|
||||
#define QM_CCU_RTC_CLK_EN BIT(1)
|
||||
#define QM_CCU_RTC_CLK_DIV_EN BIT(2)
|
||||
#define QM_CCU_SYS_CLK_DIV_EN BIT(7)
|
||||
#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_CCU_SYS_CLK_DIV_DEF_MASK (0xFFFFF47F)
|
||||
#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_EXT_CLK_DIV_EN BIT(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_EN BIT(0)
|
||||
#define QM_CCU_RTC_CLK_DIV_OFFSET (3)
|
||||
#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_EXT_CLK_DIV_DEF_MASK (0xFFFFFFE3)
|
||||
#define QM_CCU_RTC_CLK_DIV_DEF_MASK (0xFFFFFF83)
|
||||
#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_GPIO_BIT BIT(15)
|
||||
|
||||
#define QM_CCU_GPIO_DB_CLK_EN BIT(0)
|
||||
#define QM_HYB_OSC_PD_LATCH_EN BIT(14)
|
||||
#define QM_RTC_OSC_PD_LATCH_EN BIT(15)
|
||||
#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)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name General Purpose
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** General Purpose register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t gps0; /**< General Purpose Sticky Registers */
|
||||
QM_RW uint32_t gps1; /**< General Purpose Sticky Registers */
|
||||
QM_RW uint32_t gps2; /**< General Purpose Sticky Registers */
|
||||
QM_RW uint32_t gps3; /**< General Purpose Sticky Registers */
|
||||
QM_RW uint32_t gps0; /**< General Purpose Sticky Register 0 */
|
||||
QM_RW uint32_t gps1; /**< General Purpose Sticky Register 1 */
|
||||
QM_RW uint32_t gps2; /**< General Purpose Sticky Register 2 */
|
||||
QM_RW uint32_t gps3; /**< General Purpose Sticky Register 3 */
|
||||
QM_RW uint32_t reserved;
|
||||
QM_RW uint32_t gp0; /**< General Purpose Scratchpad Registers */
|
||||
QM_RW uint32_t gp1; /**< General Purpose Scratchpad Registers */
|
||||
QM_RW uint32_t gp2; /**< General Purpose Scratchpad Registers */
|
||||
QM_RW uint32_t gp3; /**< General Purpose Scratchpad Registers */
|
||||
QM_RW uint32_t gp0; /**< General Purpose Scratchpad Register 0 */
|
||||
QM_RW uint32_t gp1; /**< General Purpose Scratchpad Register 1 */
|
||||
QM_RW uint32_t gp2; /**< General Purpose Scratchpad Register 2 */
|
||||
QM_RW uint32_t gp3; /**< General Purpose Scratchpad Register 3 */
|
||||
QM_RW uint32_t reserved1[3];
|
||||
QM_RW uint32_t wo_sp; /**< Write-One-to-Set Scratchpad Register */
|
||||
QM_RW uint32_t
|
||||
|
@ -166,21 +182,28 @@ qm_scss_gp_reg_t test_scss_gp;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
#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)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Comparator
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Comparator register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t cmp_en; /**< Comparator enable */
|
||||
QM_RW uint32_t cmp_ref_sel; /**< Comparator reference select */
|
||||
QM_RW uint32_t cmp_en; /**< Comparator enable. */
|
||||
QM_RW uint32_t cmp_ref_sel; /**< Comparator reference select. */
|
||||
QM_RW uint32_t
|
||||
cmp_ref_pol; /**< Comparator reference polarity select register */
|
||||
QM_RW uint32_t cmp_pwr; /**< Comparator power enable register */
|
||||
cmp_ref_pol; /**< Comparator reference polarity select register. */
|
||||
QM_RW uint32_t cmp_pwr; /**< Comparator power enable register. */
|
||||
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;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
|
@ -189,12 +212,19 @@ qm_scss_cmp_reg_t test_scss_cmp;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
#define QM_AC_HP_COMPARATORS_MASK (0x7FFC0)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Interrupt
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Interrupt register map. */
|
||||
typedef struct {
|
||||
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. */
|
||||
|
@ -244,17 +274,23 @@ qm_scss_int_reg_t test_scss_int;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
#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_MASK BIT(0)
|
||||
#define QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK BIT(16)
|
||||
#define QM_INT_FLASH_CONTROLLER_HOST_MASK BIT(0)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Power Management
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Power Management register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t aon_vr; /**< AON Voltage Regulator */
|
||||
QM_RW uint32_t reserved[5];
|
||||
|
@ -274,12 +310,18 @@ qm_scss_pmu_reg_t test_scss_pmu;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
#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_VREG_SEL BIT(8)
|
||||
#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_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;
|
||||
|
||||
/** Always-on Controller register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t aonc_cnt; /**< Always on counter register */
|
||||
QM_RW uint32_t aonc_cfg; /**< Always on counter enable */
|
||||
QM_RW uint32_t aonpt_cnt; /**< Always on periodic timer */
|
||||
QM_RW uint32_t aonc_cnt; /**< Always-on counter register. */
|
||||
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_stat; /**< Always on periodic timer status register */
|
||||
QM_RW uint32_t aonpt_ctrl; /**< Always on periodic timer control */
|
||||
aonpt_stat; /**< Always-on periodic timer status register. */
|
||||
QM_RW uint32_t aonpt_ctrl; /**< Always-on periodic timer control. */
|
||||
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;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
|
@ -310,10 +351,17 @@ qm_scss_aon_reg_t test_scss_aon;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Peripheral Registers
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Peripheral Registers register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t periph_cfg0; /**< Peripheral Configuration */
|
||||
QM_RW uint32_t reserved[2];
|
||||
|
@ -326,10 +374,17 @@ qm_scss_peripheral_reg_t test_scss_peripheral;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Pin MUX
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Pin MUX register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t pmux_pullup[1]; /**< Pin Mux Pullup */
|
||||
QM_RW uint32_t reserved[3];
|
||||
|
@ -352,10 +407,17 @@ qm_scss_pmux_reg_t test_scss_pmux;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name ID
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Information register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t id; /**< Identification Register */
|
||||
QM_RW uint32_t rev; /**< Revision Register */
|
||||
|
@ -371,11 +433,17 @@ qm_scss_info_reg_t test_scss_info;
|
|||
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
/** IRQs and interrupt vectors.
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name IRQs and Interrupts
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* IRQs and interrupt vectors.
|
||||
*
|
||||
* The vector numbers must be defined without arithmetic expressions nor
|
||||
* 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_IRQ_RTC_0 (2)
|
||||
#define QM_IRQ_RTC_0_MASK_OFFSET (12)
|
||||
#define QM_IRQ_RTC_0 2
|
||||
#define QM_IRQ_RTC_0_MASK_OFFSET 12
|
||||
#define QM_IRQ_RTC_0_VECTOR 34
|
||||
|
||||
#define QM_IRQ_AONPT_0 (3)
|
||||
#define QM_IRQ_AONPT_0_MASK_OFFSET (32)
|
||||
#define QM_IRQ_AONPT_0 3
|
||||
#define QM_IRQ_AONPT_0_MASK_OFFSET 32
|
||||
#define QM_IRQ_AONPT_0_VECTOR 35
|
||||
|
||||
#define QM_IRQ_SPI_MASTER_0 (7)
|
||||
#define QM_IRQ_SPI_MASTER_0_MASK_OFFSET (3)
|
||||
#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 11
|
||||
#define QM_IRQ_PWM_0_MASK_OFFSET 10
|
||||
#define QM_IRQ_PWM_0_VECTOR 43
|
||||
|
||||
#define QM_IRQ_AC (14)
|
||||
#define QM_IRQ_AC_MASK_OFFSET (26)
|
||||
#define QM_IRQ_AC_VECTOR 46
|
||||
#define QM_IRQ_SPI_MASTER_0 7
|
||||
#define QM_IRQ_SPI_MASTER_0_MASK_OFFSET 3
|
||||
#define QM_IRQ_SPI_MASTER_0_VECTOR 39
|
||||
|
||||
#define QM_IRQ_ADC_0 (9)
|
||||
#define QM_IRQ_ADC_0_MASK_OFFSET (34)
|
||||
#define QM_IRQ_ADC_0 9
|
||||
#define QM_IRQ_ADC_0_MASK_OFFSET 34
|
||||
#define QM_IRQ_ADC_0_VECTOR 41
|
||||
|
||||
#define QM_IRQ_ADC_PWR_0 (19)
|
||||
#define QM_IRQ_ADC_PWR_0_MASK_OFFSET (33)
|
||||
#define QM_IRQ_ADC_PWR_0 19
|
||||
#define QM_IRQ_ADC_PWR_0_MASK_OFFSET 33
|
||||
#define QM_IRQ_ADC_PWR_0_VECTOR 51
|
||||
|
||||
#define QM_IRQ_WDT_0 (16)
|
||||
#define QM_IRQ_WDT_0_MASK_OFFSET (13)
|
||||
#define QM_IRQ_WDT_0 16
|
||||
#define QM_IRQ_WDT_0_MASK_OFFSET 13
|
||||
#define QM_IRQ_WDT_0_VECTOR 48
|
||||
|
||||
#define QM_IRQ_GPIO_0 (15)
|
||||
#define QM_IRQ_GPIO_0_MASK_OFFSET (9)
|
||||
#define QM_IRQ_GPIO_0 15
|
||||
#define QM_IRQ_GPIO_0_MASK_OFFSET 9
|
||||
#define QM_IRQ_GPIO_0_VECTOR 47
|
||||
|
||||
#define QM_IRQ_I2C_0 (4)
|
||||
#define QM_IRQ_I2C_0_MASK_OFFSET (0)
|
||||
#define QM_IRQ_I2C_0 4
|
||||
#define QM_IRQ_I2C_0_MASK_OFFSET 0
|
||||
#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 */
|
||||
#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_SRAM (17)
|
||||
#define QM_IRQ_SRAM_MASK_OFFSET (29)
|
||||
#define QM_IRQ_AC 14
|
||||
#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_FLASH_0 (18)
|
||||
#define QM_IRQ_FLASH_0_MASK_OFFSET (30)
|
||||
#define QM_IRQ_FLASH_0 18
|
||||
#define QM_IRQ_FLASH_0_MASK_OFFSET 30
|
||||
#define QM_IRQ_FLASH_0_VECTOR 50
|
||||
|
||||
#define QM_IRQ_UART_0 (8)
|
||||
#define QM_IRQ_UART_0_MASK_OFFSET (6)
|
||||
#define QM_IRQ_UART_0 8
|
||||
#define QM_IRQ_UART_0_MASK_OFFSET 6
|
||||
#define QM_IRQ_UART_0_VECTOR 40
|
||||
|
||||
#define QM_IRQ_UART_1 (6)
|
||||
#define QM_IRQ_UART_1_MASK_OFFSET (7)
|
||||
#define QM_IRQ_UART_1 6
|
||||
#define QM_IRQ_UART_1_MASK_OFFSET 7
|
||||
#define QM_IRQ_UART_1_VECTOR 38
|
||||
|
||||
#define QM_IRQ_DMA_0 (13)
|
||||
#define QM_IRQ_DMA_0_MASK_OFFSET (14)
|
||||
#define QM_IRQ_DMA_0 13
|
||||
#define QM_IRQ_DMA_0_MASK_OFFSET 14
|
||||
#define QM_IRQ_DMA_0_VECTOR 45
|
||||
|
||||
#define QM_IRQ_DMA_1 (12)
|
||||
#define QM_IRQ_DMA_1_MASK_OFFSET (15)
|
||||
#define QM_IRQ_DMA_1 12
|
||||
#define QM_IRQ_DMA_1_MASK_OFFSET 15
|
||||
#define QM_IRQ_DMA_1_VECTOR 44
|
||||
|
||||
#define QM_IRQ_DMA_ERR (0)
|
||||
#define QM_IRQ_DMA_ERR_MASK_OFFSET (28)
|
||||
#define QM_IRQ_DMA_ERR 0
|
||||
#define QM_IRQ_DMA_ERR_MASK_OFFSET 28
|
||||
#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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* PWM / Timer register map.
|
||||
*/
|
||||
|
||||
/** PWM / Timer channel register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t loadcount; /**< Load Count */
|
||||
QM_RW uint32_t currentvalue; /**< Current Value */
|
||||
|
@ -478,6 +546,7 @@ typedef struct {
|
|||
QM_RW uint32_t intstatus; /**< Interrupt Status */
|
||||
} qm_pwm_channel_t;
|
||||
|
||||
/** PWM / Timer register map. */
|
||||
typedef struct {
|
||||
qm_pwm_channel_t timer[QM_PWM_ID_NUM]; /**< 4 Timers */
|
||||
QM_RW uint32_t reserved[30];
|
||||
|
@ -501,14 +570,17 @@ qm_pwm_reg_t test_pwm_t;
|
|||
|
||||
#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 {
|
||||
QM_RW uint32_t wdt_cr; /**< Control 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)
|
||||
#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;
|
||||
|
||||
/**
|
||||
* UART register block type.
|
||||
*/
|
||||
|
||||
/** UART register map. */
|
||||
typedef struct {
|
||||
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 */
|
||||
|
@ -587,14 +661,17 @@ extern qm_uart_reg_t *qm_uart[QM_UART_NUM];
|
|||
#define QM_UART qm_uart
|
||||
#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 {
|
||||
QM_RW uint32_t ctrlr0; /**< Control Register 0 */
|
||||
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_TFNF BIT(1)
|
||||
#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 */
|
||||
#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_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 {
|
||||
QM_RW uint32_t rtc_ccvr; /**< Current Counter Value 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))
|
||||
|
||||
#else
|
||||
/** RTC register base address */
|
||||
/** RTC register base address. */
|
||||
#define QM_RTC_BASE (0xB0000400)
|
||||
|
||||
/** RTC register block */
|
||||
/** RTC register block. */
|
||||
#define QM_RTC ((qm_rtc_reg_t *)QM_RTC_BASE)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Number of I2C controllers.
|
||||
* @name I2C
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Number of I2C controllers. */
|
||||
typedef enum { QM_I2C_0 = 0, QM_I2C_NUM } qm_i2c_t;
|
||||
|
||||
/** I2C register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t ic_con; /**< Control Register */
|
||||
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
|
||||
|
||||
#else
|
||||
/** I2C Master register base address */
|
||||
/** I2C Master register base address. */
|
||||
#define QM_I2C_0_BASE (0xB0002800)
|
||||
|
||||
/** I2C register block */
|
||||
/** I2C register block. */
|
||||
extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM];
|
||||
#define QM_I2C qm_i2c
|
||||
#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_STOP_BIT_CTRL BIT(9)
|
||||
#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_TX_ABRT_SOURCE_NAK_MASK (0x1F)
|
||||
#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_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 {
|
||||
QM_RW uint32_t gpio_swporta_dr; /**< Port A Data */
|
||||
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
|
||||
#else
|
||||
|
||||
/** GPIO register base address */
|
||||
#define QM_GPIO_BASE (0xB0000C00)
|
||||
|
||||
|
@ -891,14 +984,17 @@ extern qm_gpio_reg_t *qm_gpio[QM_GPIO_NUM];
|
|||
#define QM_GPIO qm_gpio
|
||||
#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 {
|
||||
QM_RW uint32_t adc_seq0; /**< ADC Channel Sequence Table Entry 0 */
|
||||
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_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 {
|
||||
QM_RW uint32_t tmg_ctrl; /**< TMG_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)
|
||||
#else
|
||||
|
||||
/** Flash physical address mappings */
|
||||
/* Flash physical address mappings */
|
||||
#define QM_FLASH_REGION_DATA_0_BASE (0x00200000)
|
||||
#define QM_FLASH_REGION_SYS_0_BASE (0x00180000)
|
||||
#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_MAX_ADDR (0x8000)
|
||||
|
||||
/** Flash controller register base address */
|
||||
/** Flash controller register base address. */
|
||||
#define QM_FLASH_BASE_0 (0xB0100000)
|
||||
|
||||
/** Flash controller register block */
|
||||
/** Flash controller register block. */
|
||||
extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM];
|
||||
#define QM_FLASH qm_flash
|
||||
|
||||
#endif
|
||||
|
||||
#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))
|
||||
#define QM_FLASH_LVE_MODE BIT(5)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Memory Protection Region register block type.
|
||||
* @name Memory Protection Region
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Memory Protection Region register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t mpr_cfg[4]; /**< MPR CFG */
|
||||
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_VSTS_VALID BIT(31)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name PIC
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** PIC timer register structure. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t reg;
|
||||
QM_RW uint32_t pad[3];
|
||||
} pic_timer_reg_pad_t;
|
||||
|
||||
/**
|
||||
* PIC timer register block type.
|
||||
*/
|
||||
/** PIC timer register map. */
|
||||
typedef struct {
|
||||
QM_RW pic_timer_reg_pad_t lvttimer; /**< Local Vector Table Timer */
|
||||
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))
|
||||
|
||||
#else
|
||||
/** PIC timer */
|
||||
/** PIC timer base address. */
|
||||
#define QM_PIC_TIMER_BASE (0xFEE00320)
|
||||
#define QM_PIC_TIMER ((qm_pic_timer_reg_t *)QM_PIC_TIMER_BASE)
|
||||
#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 {
|
||||
QM_RW uint32_t reg;
|
||||
QM_RW uint32_t pad[3];
|
||||
} mvic_reg_pad_t;
|
||||
|
||||
/** MVIC register map. */
|
||||
typedef struct {
|
||||
QM_RW mvic_reg_pad_t tpr; /**< Task priority*/
|
||||
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))
|
||||
|
||||
#else
|
||||
/** Quark Microcontroller D2000 Interrupt Controller */
|
||||
/** Interrupt Controller base address. */
|
||||
#define QM_MVIC_BASE (0xFEE00080)
|
||||
#define QM_MVIC ((qm_mvic_reg_t *)QM_MVIC_BASE)
|
||||
#endif
|
||||
|
@ -1142,28 +1300,27 @@ qm_ioapic_reg_t test_ioapic;
|
|||
#define QM_IOAPIC ((qm_ioapic_reg_t *)QM_IOAPIC_BASE)
|
||||
#endif
|
||||
|
||||
/** DMA */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* DMA instances
|
||||
* @name DMA
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** DMA instances. */
|
||||
typedef enum {
|
||||
QM_DMA_0, /**< DMA controller id. */
|
||||
QM_DMA_NUM /**< Number of DMA controllers. */
|
||||
} qm_dma_t;
|
||||
|
||||
/**
|
||||
* DMA channel IDs
|
||||
*/
|
||||
/** DMA channel IDs. */
|
||||
typedef enum {
|
||||
QM_DMA_CHANNEL_0 = 0, /**< DMA channel id for channel 0 */
|
||||
QM_DMA_CHANNEL_1, /**< DMA channel id for channel 1 */
|
||||
QM_DMA_CHANNEL_NUM /**< Number of DMA channels */
|
||||
} qm_dma_channel_id_t;
|
||||
|
||||
/**
|
||||
* DMA hardware handshake interfaces
|
||||
*/
|
||||
/** DMA hardware handshake interfaces. */
|
||||
typedef enum {
|
||||
DMA_HW_IF_UART_A_TX = 0x0, /**< UART_A_TX */
|
||||
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 */
|
||||
} qm_dma_handshake_interface_t;
|
||||
|
||||
/**
|
||||
* DMA channel register block type
|
||||
*/
|
||||
/** DMA channel register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t sar_low; /**< SAR */
|
||||
QM_RW uint32_t sar_high; /**< SAR */
|
||||
|
@ -1205,7 +1360,7 @@ typedef struct {
|
|||
QM_RW uint32_t dst_sg_high; /**< DSR */
|
||||
} 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_DST_TR_WIDTH_OFFSET (1)
|
||||
#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_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_FIFO_EMPTY_MASK BIT(9)
|
||||
#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_MASK (0xf << QM_DMA_CFG_H_DEST_PER_OFFSET)
|
||||
|
||||
/**
|
||||
* DMA interrupt register block type
|
||||
*/
|
||||
/** DMA interrupt register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t raw_tfr_low; /**< RawTfr */
|
||||
QM_RW uint32_t raw_tfr_high; /**< RawTfr */
|
||||
|
@ -1294,13 +1447,11 @@ typedef struct {
|
|||
QM_RW uint32_t status_int_high; /**< StatusInt */
|
||||
} 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_ERR BIT(4)
|
||||
|
||||
/**
|
||||
* DMA miscellaneous register block type
|
||||
*/
|
||||
/** DMA miscellaneous register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t cfg_low; /**< DmaCfgReg */
|
||||
QM_RW uint32_t cfg_high; /**< DmaCfgReg */
|
||||
|
@ -1313,10 +1464,10 @@ typedef struct {
|
|||
QM_RW uint32_t reserved[4]; /**< Reserved */
|
||||
} 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)
|
||||
|
||||
/** 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)
|
||||
|
||||
typedef struct {
|
||||
|
@ -1336,45 +1487,13 @@ extern qm_dma_reg_t *qm_dma[QM_DMA_NUM];
|
|||
#define QM_DMA qm_dma
|
||||
#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)
|
||||
uint32_t test_rom_version;
|
||||
#define ROM_VERSION_ADDRESS &test_rom_version;
|
||||
|
@ -1382,7 +1501,8 @@ uint32_t test_rom_version;
|
|||
#define ROM_VERSION_ADDRESS (0x1FFC);
|
||||
#endif
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* __REGISTERS_H__ */
|
||||
|
|
|
@ -33,32 +33,64 @@
|
|||
#if (QM_SENSOR)
|
||||
#include "qm_sensor_regs.h"
|
||||
#endif
|
||||
#include "soc_watch.h"
|
||||
|
||||
void power_soc_lpss_enable()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
#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 */
|
||||
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;
|
||||
}
|
||||
|
||||
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_plat3p3_set_mode(VREG_MODE_LINEAR);
|
||||
|
||||
/* Enable low power sleep mode */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -71,14 +103,20 @@ void power_cpu_c1()
|
|||
void power_cpu_c2()
|
||||
{
|
||||
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 */
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_SLEEP, 0);
|
||||
QM_SCSS_PMU->p_lvl2;
|
||||
}
|
||||
|
||||
void power_cpu_c2lp()
|
||||
{
|
||||
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 */
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_SLEEP, 0);
|
||||
QM_SCSS_PMU->p_lvl2;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -69,7 +69,7 @@ typedef union {
|
|||
QM_RW uint16_t osc_trim_4mhz; /**< 4MHz Oscillator trim code. */
|
||||
} fields;
|
||||
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;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
|
@ -87,6 +87,117 @@ typedef union {
|
|||
#define QM_FLASH_TRIM_PRESENT_MASK (0xFC00)
|
||||
#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_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_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_MASK (0xFE0)
|
||||
#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 \
|
||||
(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_VECTOR - vector number
|
||||
*/
|
||||
#define QM_SS_INT_TIMER_0 (16)
|
||||
#define QM_SS_INT_TIMER_1 (17)
|
||||
#define QM_SS_INT_TIMER_0 16
|
||||
#define QM_SS_INT_TIMER_1 17
|
||||
|
||||
#define QM_SS_IRQ_ADC_ERR (0)
|
||||
#define QM_SS_IRQ_ADC_ERR_VECTOR (18)
|
||||
#define QM_SS_IRQ_ADC_ERR 0
|
||||
#define QM_SS_IRQ_ADC_ERR_VECTOR 18
|
||||
|
||||
#define QM_SS_IRQ_ADC_IRQ (1)
|
||||
#define QM_SS_IRQ_ADC_IRQ_VECTOR (19)
|
||||
#define QM_SS_IRQ_ADC_IRQ 1
|
||||
#define QM_SS_IRQ_ADC_IRQ_VECTOR 19
|
||||
|
||||
#define QM_SS_IRQ_GPIO_INTR_0 (2)
|
||||
#define QM_SS_IRQ_GPIO_INTR_0_VECTOR (20)
|
||||
#define QM_SS_IRQ_GPIO_INTR_0 2
|
||||
#define QM_SS_IRQ_GPIO_INTR_0_VECTOR 20
|
||||
|
||||
#define QM_SS_IRQ_GPIO_INTR_1 (3)
|
||||
#define QM_SS_IRQ_GPIO_INTR_1_VECTOR (21)
|
||||
#define QM_SS_IRQ_GPIO_INTR_1 3
|
||||
#define QM_SS_IRQ_GPIO_INTR_1_VECTOR 21
|
||||
|
||||
#define QM_SS_IRQ_I2C_0_ERR (4)
|
||||
#define QM_SS_IRQ_I2C_0_ERR_VECTOR (22)
|
||||
#define QM_SS_IRQ_I2C_0_ERR 4
|
||||
#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_VECTOR (23)
|
||||
#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_TX_REQ (6)
|
||||
#define QM_SS_IRQ_I2C_0_TX_REQ_VECTOR (24)
|
||||
#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_STOP_DET (7)
|
||||
#define QM_SS_IRQ_I2C_0_STOP_DET_VECTOR (25)
|
||||
#define QM_SS_IRQ_I2C_0_STOP_DET 7
|
||||
#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_VECTOR (26)
|
||||
#define QM_SS_IRQ_I2C_1_ERR 8
|
||||
#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_VECTOR (27)
|
||||
#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_TX_REQ (10)
|
||||
#define QM_SS_IRQ_I2C_1_TX_REQ_VECTOR (28)
|
||||
#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_STOP_DET (11)
|
||||
#define QM_SS_IRQ_I2C_1_STOP_DET_VECTOR (29)
|
||||
#define QM_SS_IRQ_I2C_1_STOP_DET 11
|
||||
#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_VECTOR (30)
|
||||
#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_RX_AVAIL (13)
|
||||
#define QM_SS_IRQ_SPI_0_RX_AVAIL_VECTOR (31)
|
||||
#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_TX_REQ (14)
|
||||
#define QM_SS_IRQ_SPI_0_TX_REQ_VECTOR (32)
|
||||
#define QM_SS_IRQ_SPI_0_TX_REQ 14
|
||||
#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_VECTOR (33)
|
||||
#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_RX_AVAIL (16)
|
||||
#define QM_SS_IRQ_SPI_1_RX_AVAIL_VECTOR (34)
|
||||
#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_TX_REQ (17)
|
||||
#define QM_SS_IRQ_SPI_1_TX_REQ_VECTOR (35)
|
||||
#define QM_SS_IRQ_SPI_1_TX_REQ 17
|
||||
#define QM_SS_IRQ_SPI_1_TX_REQ_VECTOR 35
|
||||
|
||||
typedef enum {
|
||||
QM_SS_INT_PRIORITY_0 = 0,
|
||||
|
@ -468,7 +469,7 @@ typedef enum {
|
|||
#define QM_SS_AUX_IRQ_STATUS (0x406)
|
||||
#define QM_SS_AUX_IRQ_SELECT (0x40B)
|
||||
#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…
Reference in a new issue