diff options
author | Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com> | 2016-06-30 17:25:00 -0300 |
---|---|---|
committer | Kuo-Lang Tseng <kuo-lang.tseng@intel.com> | 2016-07-01 13:43:02 -0700 |
commit | abd7496225ea4caf6b26e6fe7db998bcf5e539e4 (patch) | |
tree | f5abc4e575d32752d48c60d02c27f91bd1f04f51 /ext | |
parent | 19fa82ab910071382ca5df08f5c771450b7861f1 (diff) |
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
6b88a6b945e8 "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>
Diffstat (limited to 'ext')
50 files changed, 2625 insertions, 1161 deletions
diff --git a/ext/hal/qmsi/README b/ext/hal/qmsi/README index f403146cd..2d692e27e 100644 --- a/ext/hal/qmsi/README +++ b/ext/hal/qmsi/README @@ -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. diff --git a/ext/hal/qmsi/drivers/clk.c b/ext/hal/qmsi/drivers/clk.c index 7af11f0ec..fa93ba763 100644 --- a/ext/hal/qmsi/drivers/clk.c +++ b/ext/hal/qmsi/drivers/clk.c @@ -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; } diff --git a/ext/hal/qmsi/drivers/dma.h b/ext/hal/qmsi/drivers/dma.h index 3a4acb1a3..bcc7dd8f7 100644 --- a/ext/hal/qmsi/drivers/dma.h +++ b/ext/hal/qmsi/drivers/dma.h @@ -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); diff --git a/ext/hal/qmsi/drivers/include/qm_adc.h b/ext/hal/qmsi/drivers/include/qm_adc.h index c7011be63..3fb00d4ab 100644 --- a/ext/hal/qmsi/drivers/include/qm_adc.h +++ b/ext/hal/qmsi/drivers/include/qm_adc.h @@ -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. diff --git a/ext/hal/qmsi/drivers/include/qm_flash.h b/ext/hal/qmsi/drivers/include/qm_flash.h index 255ec2b58..051449f2d 100644 --- a/ext/hal/qmsi/drivers/include/qm_flash.h +++ b/ext/hal/qmsi/drivers/include/qm_flash.h @@ -32,7 +32,7 @@ #include "qm_common.h" #include "qm_soc_regs.h" - +#include "qm_interrupt.h" /** * Flash controller. * diff --git a/ext/hal/qmsi/drivers/include/qm_i2c.h b/ext/hal/qmsi/drivers/include/qm_i2c.h index 623dafe5c..32549ee1a 100644 --- a/ext/hal/qmsi/drivers/include/qm_i2c.h +++ b/ext/hal/qmsi/drivers/include/qm_i2c.h @@ -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. diff --git a/ext/hal/qmsi/drivers/include/qm_interrupt.h b/ext/hal/qmsi/drivers/include/qm_interrupt.h index ae83be8fa..5e9c3814e 100644 --- a/ext/hal/qmsi/drivers/include/qm_interrupt.h +++ b/ext/hal/qmsi/drivers/include/qm_interrupt.h @@ -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__) /* diff --git a/ext/hal/qmsi/drivers/include/qm_isr.h b/ext/hal/qmsi/drivers/include/qm_isr.h index d85dbb9f2..2f319861d 100644 --- a/ext/hal/qmsi/drivers/include/qm_isr.h +++ b/ext/hal/qmsi/drivers/include/qm_isr.h @@ -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. * diff --git a/ext/hal/qmsi/drivers/include/qm_mailbox.h b/ext/hal/qmsi/drivers/include/qm_mailbox.h index 766187f12..98815e0d6 100644 --- a/ext/hal/qmsi/drivers/include/qm_mailbox.h +++ b/ext/hal/qmsi/drivers/include/qm_mailbox.h @@ -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. diff --git a/ext/hal/qmsi/drivers/include/qm_pic_timer.h b/ext/hal/qmsi/drivers/include/qm_pic_timer.h index 0bae6f2d2..a5b2baaa6 100644 --- a/ext/hal/qmsi/drivers/include/qm_pic_timer.h +++ b/ext/hal/qmsi/drivers/include/qm_pic_timer.h @@ -54,6 +54,7 @@ typedef enum { typedef struct { qm_pic_timer_mode_t mode; /**< Operation mode. */ bool int_en; /**< Interrupt enable. */ + /** * User callback. * diff --git a/ext/hal/qmsi/drivers/include/qm_rtc.h b/ext/hal/qmsi/drivers/include/qm_rtc.h index 2a1cb07e7..bdd8eeca8 100644 --- a/ext/hal/qmsi/drivers/include/qm_rtc.h +++ b/ext/hal/qmsi/drivers/include/qm_rtc.h @@ -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. * diff --git a/ext/hal/qmsi/drivers/include/qm_spi.h b/ext/hal/qmsi/drivers/include/qm_spi.h index 1f7baaa85..9bf09d245 100644 --- a/ext/hal/qmsi/drivers/include/qm_spi.h +++ b/ext/hal/qmsi/drivers/include/qm_spi.h @@ -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; diff --git a/ext/hal/qmsi/drivers/include/qm_uart.h b/ext/hal/qmsi/drivers/include/qm_uart.h index 6655f9c28..fe62c2775 100644 --- a/ext/hal/qmsi/drivers/include/qm_uart.h +++ b/ext/hal/qmsi/drivers/include/qm_uart.h @@ -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. diff --git a/ext/hal/qmsi/drivers/include/soc_watch.h b/ext/hal/qmsi/drivers/include/soc_watch.h new file mode 100644 index 000000000..d24559e48 --- /dev/null +++ b/ext/hal/qmsi/drivers/include/soc_watch.h @@ -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__ */ diff --git a/ext/hal/qmsi/drivers/qm_adc.c b/ext/hal/qmsi/drivers/qm_adc.c index c65c4da2a..88195b300 100644 --- a/ext/hal/qmsi/drivers/qm_adc.c +++ b/ext/hal/qmsi/drivers/qm_adc.c @@ -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 | diff --git a/ext/hal/qmsi/drivers/qm_aon_counters.c b/ext/hal/qmsi/drivers/qm_aon_counters.c index 37f7ce75b..6a8fa2cdf 100644 --- a/ext/hal/qmsi/drivers/qm_aon_counters.c +++ b/ext/hal/qmsi/drivers/qm_aon_counters.c @@ -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); diff --git a/ext/hal/qmsi/drivers/qm_dma.c b/ext/hal/qmsi/drivers/qm_dma.c index d6d37db8c..65129c810 100644 --- a/ext/hal/qmsi/drivers/qm_dma.c +++ b/ext/hal/qmsi/drivers/qm_dma.c @@ -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]; diff --git a/ext/hal/qmsi/drivers/qm_fpr.c b/ext/hal/qmsi/drivers/qm_fpr.c index bef9c1ccf..1af8c9442 100644 --- a/ext/hal/qmsi/drivers/qm_fpr.c +++ b/ext/hal/qmsi/drivers/qm_fpr.c @@ -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 */ diff --git a/ext/hal/qmsi/drivers/qm_gpio.c b/ext/hal/qmsi/drivers/qm_gpio.c index 667299f82..edb41ebb2 100644 --- a/ext/hal/qmsi/drivers/qm_gpio.c +++ b/ext/hal/qmsi/drivers/qm_gpio.c @@ -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); } diff --git a/ext/hal/qmsi/drivers/qm_i2c.c b/ext/hal/qmsi/drivers/qm_i2c.c index 423bcdc7a..9c51210de 100644 --- a/ext/hal/qmsi/drivers/qm_i2c.c +++ b/ext/hal/qmsi/drivers/qm_i2c.c @@ -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 = diff --git a/ext/hal/qmsi/drivers/qm_interrupt.c b/ext/hal/qmsi/drivers/qm_interrupt.c index 56061c7c0..b35ef7c8c 100644 --- a/ext/hal/qmsi/drivers/qm_interrupt.c +++ b/ext/hal/qmsi/drivers/qm_interrupt.c @@ -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 diff --git a/ext/hal/qmsi/drivers/qm_mailbox.c b/ext/hal/qmsi/drivers/qm_mailbox.c index daf278190..323076870 100644 --- a/ext/hal/qmsi/drivers/qm_mailbox.c +++ b/ext/hal/qmsi/drivers/qm_mailbox.c @@ -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; } diff --git a/ext/hal/qmsi/drivers/qm_mpr.c b/ext/hal/qmsi/drivers/qm_mpr.c index 2cfe868af..15a3c7a46 100644 --- a/ext/hal/qmsi/drivers/qm_mpr.c +++ b/ext/hal/qmsi/drivers/qm_mpr.c @@ -58,14 +58,13 @@ 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) @@ -77,27 +76,67 @@ int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode, callback_data = callback_data; /* unmask interrupt */ - qm_irq_unmask(QM_IRQ_SRAM); -#if defined(QM_SENSOR) + 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; -#else /* QM_SENSOR */ + + 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) +{ + 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_irq_unmask(QM_IRQ_SRAM); + 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 */
\ No newline at end of file diff --git a/ext/hal/qmsi/drivers/qm_rtc.c b/ext/hal/qmsi/drivers/qm_rtc.c index b69e12432..6a8d9d533 100644 --- a/ext/hal/qmsi/drivers/qm_rtc.c +++ b/ext/hal/qmsi/drivers/qm_rtc.c @@ -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]); } diff --git a/ext/hal/qmsi/drivers/qm_spi.c b/ext/hal/qmsi/drivers/qm_spi.c index b648a05c5..1d97e7781 100644 --- a/ext/hal/qmsi/drivers/qm_spi.c +++ b/ext/hal/qmsi/drivers/qm_spi.c @@ -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; + 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 - default: - /* Slave SPI is not supported. */ - return -EINVAL; - } - /* 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, diff --git a/ext/hal/qmsi/drivers/qm_uart.c b/ext/hal/qmsi/drivers/qm_uart.c index eb6d94272..dea6e262e 100644 --- a/ext/hal/qmsi/drivers/qm_uart.c +++ b/ext/hal/qmsi/drivers/qm_uart.c @@ -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 diff --git a/ext/hal/qmsi/drivers/qm_version.c b/ext/hal/qmsi/drivers/qm_version.c index 3d580567c..f2599ea7a 100644 --- a/ext/hal/qmsi/drivers/qm_version.c +++ b/ext/hal/qmsi/drivers/qm_version.c @@ -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; } diff --git a/ext/hal/qmsi/drivers/qm_wdt.c b/ext/hal/qmsi/drivers/qm_wdt.c index 783c60331..57a4ebedd 100644 --- a/ext/hal/qmsi/drivers/qm_wdt.c +++ b/ext/hal/qmsi/drivers/qm_wdt.c @@ -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); diff --git a/ext/hal/qmsi/drivers/sensor/include/qm_ss_adc.h b/ext/hal/qmsi/drivers/sensor/include/qm_ss_adc.h index 0f1702377..12a66fc91 100644 --- a/ext/hal/qmsi/drivers/sensor/include/qm_ss_adc.h +++ b/ext/hal/qmsi/drivers/sensor/include/qm_ss_adc.h @@ -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. diff --git a/ext/hal/qmsi/drivers/sensor/include/qm_ss_gpio.h b/ext/hal/qmsi/drivers/sensor/include/qm_ss_gpio.h index 965e31029..66e2bd6f6 100644 --- a/ext/hal/qmsi/drivers/sensor/include/qm_ss_gpio.h +++ b/ext/hal/qmsi/drivers/sensor/include/qm_ss_gpio.h @@ -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. diff --git a/ext/hal/qmsi/drivers/sensor/include/qm_ss_i2c.h b/ext/hal/qmsi/drivers/sensor/include/qm_ss_i2c.h index 1cdb8c09a..76de61fb8 100644 --- a/ext/hal/qmsi/drivers/sensor/include/qm_ss_i2c.h +++ b/ext/hal/qmsi/drivers/sensor/include/qm_ss_i2c.h @@ -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. diff --git a/ext/hal/qmsi/drivers/sensor/include/qm_ss_spi.h b/ext/hal/qmsi/drivers/sensor/include/qm_ss_spi.h index c1f5c9321..9e0179f01 100644 --- a/ext/hal/qmsi/drivers/sensor/include/qm_ss_spi.h +++ b/ext/hal/qmsi/drivers/sensor/include/qm_ss_spi.h @@ -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; /** diff --git a/ext/hal/qmsi/drivers/sensor/include/qm_ss_timer.h b/ext/hal/qmsi/drivers/sensor/include/qm_ss_timer.h index a828a4b5b..189b53d2d 100644 --- a/ext/hal/qmsi/drivers/sensor/include/qm_ss_timer.h +++ b/ext/hal/qmsi/drivers/sensor/include/qm_ss_timer.h @@ -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. * diff --git a/ext/hal/qmsi/drivers/sensor/qm_ss_adc.c b/ext/hal/qmsi/drivers/sensor/qm_ss_adc.c index 417e8958d..b022094f7 100644 --- a/ext/hal/qmsi/drivers/sensor/qm_ss_adc.c +++ b/ext/hal/qmsi/drivers/sensor/qm_ss_adc.c @@ -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; diff --git a/ext/hal/qmsi/drivers/sensor/qm_ss_gpio.c b/ext/hal/qmsi/drivers/sensor/qm_ss_gpio.c index e0b693ffd..38b75858e 100644 --- a/ext/hal/qmsi/drivers/sensor/qm_ss_gpio.c +++ b/ext/hal/qmsi/drivers/sensor/qm_ss_gpio.c @@ -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); diff --git a/ext/hal/qmsi/drivers/sensor/qm_ss_i2c.c b/ext/hal/qmsi/drivers/sensor/qm_ss_i2c.c index ddc260edb..5615eb72b 100644 --- a/ext/hal/qmsi/drivers/sensor/qm_ss_i2c.c +++ b/ext/hal/qmsi/drivers/sensor/qm_ss_i2c.c @@ -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); - - /* wait until controller is disabled */ - while ((__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) & - QM_SS_I2C_ENABLE_STATUS_IC_EN)) - ; + int poll_count = I2C_POLL_COUNT; + + /* 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) diff --git a/ext/hal/qmsi/drivers/sensor/qm_ss_spi.c b/ext/hal/qmsi/drivers/sensor/qm_ss_spi.c index 8fb116b32..9beba4303 100644 --- a/ext/hal/qmsi/drivers/sensor/qm_ss_spi.c +++ b/ext/hal/qmsi/drivers/sensor/qm_ss_spi.c @@ -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); + const qm_ss_spi_async_transfer_t *const transfer = + spi_async_transfer[spi]; + spi_disable(spi); - QM_ASSERT((intr_stat & - (QM_SS_SPI_INTR_STAT_TXOI | QM_SS_SPI_INTR_STAT_RXFI)) == 0); + 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[spi]->callback) { - transfer[spi]->callback(transfer[spi]->data, -EIO, - QM_SS_SPI_RX_OVERFLOW, - transfer[spi]->rx_len - rx_c[spi]); + if ((intr_stat & QM_SS_SPI_INTR_RXOI) && transfer->callback) { + transfer->callback(transfer->callback_data, -EIO, + QM_SS_SPI_RX_OVERFLOW, + transfer->rx_len - rx_c[spi]); } } @@ -314,14 +326,24 @@ static void handle_spi_tx_interrupt(const qm_ss_spi_t spi) uint8_t bytes = BYTES_PER_FRAME(ctrl); uint8_t 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); } } } diff --git a/ext/hal/qmsi/drivers/sensor/sensor.mk b/ext/hal/qmsi/drivers/sensor/sensor.mk new file mode 100644 index 000000000..eaec3bc81 --- /dev/null +++ b/ext/hal/qmsi/drivers/sensor/sensor.mk @@ -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 $@ $< diff --git a/ext/hal/qmsi/drivers/sensor/ss_power_states.c b/ext/hal/qmsi/drivers/sensor/ss_power_states.c index 063ea5a08..2075ec284 100644 --- a/ext/hal/qmsi/drivers/sensor/ss_power_states.c +++ b/ext/hal/qmsi/drivers/sensor/ss_power_states.c @@ -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); } diff --git a/ext/hal/qmsi/drivers/soc_watch.c b/ext/hal/qmsi/drivers/soc_watch.c new file mode 100644 index 000000000..595194eec --- /dev/null +++ b/ext/hal/qmsi/drivers/soc_watch.c @@ -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)) */ diff --git a/ext/hal/qmsi/include/qm_common.h b/ext/hal/qmsi/include/qm_common.h index 8de124cc2..3b9e06bbe 100644 --- a/ext/hal/qmsi/include/qm_common.h +++ b/ext/hal/qmsi/include/qm_common.h @@ -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__ */ diff --git a/ext/hal/qmsi/include/spinlock.h b/ext/hal/qmsi/include/spinlock.h deleted file mode 100644 index 0819f2d85..000000000 --- a/ext/hal/qmsi/include/spinlock.h +++ /dev/null @@ -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__ */ diff --git a/ext/hal/qmsi/soc/quark_d2000/drivers/power_states.c b/ext/hal/qmsi/soc/quark_d2000/drivers/power_states.c index 2f5bd47f0..4f1b34713 100644 --- a/ext/hal/qmsi/soc/quark_d2000/drivers/power_states.c +++ b/ext/hal/qmsi/soc/quark_d2000/drivers/power_states.c @@ -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; } diff --git a/ext/hal/qmsi/soc/quark_d2000/include/flash_layout.h b/ext/hal/qmsi/soc/quark_d2000/include/flash_layout.h index b4dd64b5f..2dce50a4a 100644 --- a/ext/hal/qmsi/soc/quark_d2000/include/flash_layout.h +++ b/ext/hal/qmsi/soc/quark_d2000/include/flash_layout.h @@ -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 */ + /** * @} */ diff --git a/ext/hal/qmsi/soc/quark_d2000/include/power_states.h b/ext/hal/qmsi/soc/quark_d2000/include/power_states.h index b18990a1e..f3102cc16 100644 --- a/ext/hal/qmsi/soc/quark_d2000/include/power_states.h +++ b/ext/hal/qmsi/soc/quark_d2000/include/power_states.h @@ -41,11 +41,19 @@ */ /** +* 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); /** * @} diff --git a/ext/hal/qmsi/soc/quark_d2000/include/qm_soc_regs.h b/ext/hal/qmsi/soc/quark_d2000/include/qm_soc_regs.h index f46157061..8e07c00d0 100644 --- a/ext/hal/qmsi/soc/quark_d2000/include/qm_soc_regs.h +++ b/ext/hal/qmsi/soc/quark_d2000/include/qm_soc_regs.h @@ -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. + * @name WDT + * @{ */ + +/** Number of WDT controllers. */ typedef enum { QM_WDT_0 = 0, QM_WDT_NUM } qm_wdt_t; -/** - * Watchdog timer register block type. - */ +/** 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. - */ -typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t; +/** @} */ /** - * UART register block type. + * @name UART + * @{ */ +/** Number of UART controllers. */ +typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t; + +/** 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. + * @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 block type - */ +/** 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. + * @name RTC + * @{ */ + +/** Number of RTC controllers. */ typedef enum { QM_RTC_0 = 0, QM_RTC_NUM } qm_rtc_t; -/** - * QM RTC Register block type. - */ +/** 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. + * @name GPIO + * @{ */ + +/** Number of GPIO controllers. */ typedef enum { QM_GPIO_0 = 0, QM_GPIO_NUM } qm_gpio_t; -/** - * GPIO register block type. - */ +/** 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. + * @name ADC + * @{ */ + +/** Number of ADC controllers. */ typedef enum { QM_ADC_0 = 0, QM_ADC_NUM } qm_adc_t; -/** -* ADC register block type. -*/ +/** 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. + * @name Flash + * @{ */ + +/** Number of Flash controllers. */ typedef enum { QM_FLASH_0 = 0, QM_FLASH_NUM } qm_flash_t; -/** - * Flash register block type. - */ +/** 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__ */ diff --git a/ext/hal/qmsi/soc/quark_se/drivers/power_states.c b/ext/hal/qmsi/soc/quark_se/drivers/power_states.c index 935ededd1..382e30d6d 100644 --- a/ext/hal/qmsi/soc/quark_se/drivers/power_states.c +++ b/ext/hal/qmsi/soc/quark_se/drivers/power_states.c @@ -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 diff --git a/ext/hal/qmsi/soc/quark_se/include/flash_layout.h b/ext/hal/qmsi/soc/quark_se/include/flash_layout.h index 499d00ec4..2363de910 100644 --- a/ext/hal/qmsi/soc/quark_se/include/flash_layout.h +++ b/ext/hal/qmsi/soc/quark_se/include/flash_layout.h @@ -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 */ + /** * @} */ diff --git a/ext/hal/qmsi/soc/quark_se/include/qm_sensor_regs.h b/ext/hal/qmsi/soc/quark_se/include/qm_sensor_regs.h index 5d202f49c..75ac92004 100644 --- a/ext/hal/qmsi/soc/quark_se/include/qm_sensor_regs.h +++ b/ext/hal/qmsi/soc/quark_se/include/qm_sensor_regs.h @@ -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) /** @} */ diff --git a/ext/hal/qmsi/soc/quark_se/include/qm_soc_regs.h b/ext/hal/qmsi/soc/quark_se/include/qm_soc_regs.h index 1202237d1..e0d37577a 100644 --- a/ext/hal/qmsi/soc/quark_se/include/qm_soc_regs.h +++ b/ext/hal/qmsi/soc/quark_se/include/qm_soc_regs.h @@ -33,10 +33,10 @@ #include "qm_common.h" /** - * Quark SE SOC Register file. - * - * @brief Quark SE SOC Registers. + * Quark SE SoC Registers. * + * @defgroup groupQUARKSESEREG SoC Registers (SE) + * @{ */ #define QUARK_SE (1) @@ -49,12 +49,11 @@ #endif /** - * @defgroup groupSEREG Quark SE Registers - @{ + * @name System Core + * @{ */ -/* Core system registers */ - +/** 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 */ @@ -65,14 +64,13 @@ typedef struct { QM_RW uint32_t ccu_periph_clk_gate_ctl; /**< Peripheral Clock Gate Control */ QM_RW uint32_t - ccu_periph_clk_div_ctl0; /**< Peripheral Clock Divider Control 0 */ + ccu_periph_clk_div_ctl0; /**< Peripheral Clock Divider Control 0 */ QM_RW uint32_t ccu_gpio_db_clk_ctl; /**< Peripheral Clock Divider Control 1 */ QM_RW uint32_t ccu_ext_clock_ctl; /**< External Clock Control Register */ - QM_RW uint32_t ccu_ss_periph_clk_gate_ctl; /**< Sensor Subsystem - peripheral clock gate - control */ + /** Sensor Subsystem peripheral clock gate control */ + QM_RW uint32_t ccu_ss_periph_clk_gate_ctl; QM_RW uint32_t ccu_lp_clk_ctl; /**< System Low Power Clock Control */ QM_RW uint32_t reserved; QM_RW uint32_t ccu_mlayer_ahb_ctl; /**< AHB Control Register */ @@ -80,7 +78,6 @@ typedef struct { QM_RW uint32_t osc_lock_0; /**< Clocks Lock Register */ } qm_scss_ccu_reg_t; -/** system control subsystem clock control unit register block */ #if (UNIT_TEST) qm_scss_ccu_reg_t test_scss_ccu; #define QM_SCSS_CCU ((qm_scss_ccu_reg_t *)(&test_scss_ccu)) @@ -90,19 +87,66 @@ qm_scss_ccu_reg_t test_scss_ccu; #define QM_SCSS_CCU ((qm_scss_ccu_reg_t *)QM_SCSS_CCU_BASE) #endif +/* Hybrid oscillator output select select (0=Silicon, 1=Crystal) */ +#define QM_OSC0_MODE_SEL BIT(3) +#define QM_OSC0_PD BIT(2) +#define QM_OSC1_PD BIT(1) + +/* Enable Crystal oscillator. */ +#define QM_OSC0_EN_CRYSTAL BIT(0) + +/* 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. */ +#define OSC0_CFG1_FTRIMOTP_MASK (0x3FF00000) +#define OSC0_CFG1_FTRIMOTP_OFFS (20) +#define OSC0_CFG1_SI_FREQ_SEL_MASK (0x00000300) +#define OSC0_CFG1_SI_FREQ_SEL_OFFS (8) + #define QM_OSC0_MODE_SEL BIT(3) #define QM_OSC0_LOCK_SI BIT(0) #define QM_OSC0_LOCK_XTAL BIT(1) #define QM_OSC0_EN_SI_OSC BIT(1) -#define QM_OSC0_PD BIT(2) -#define QM_OSC1_PD 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) + +/* Clock enable / disable register. */ +#define QM_CCU_MLAYER_AHB_CTL (REG_VAL(0xB0800034)) + +/* System clock control */ +#define QM_CCU_SYS_CLK_SEL BIT(0) #define QM_SCSS_CCU_SYS_CLK_SEL BIT(0) #define QM_SCSS_CCU_C2_LP_EN (1) #define QM_SCSS_CCU_SS_LPS_EN (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 (0x00000300) #define QM_OSC0_SI_FREQ_SEL_DEF_MASK (0xFFFFFCFF) +#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_DMA_CLK_EN BIT(6) + +/** @} */ +/** + * @name General Purpose + * @{ + */ + +/** General Purpose register map. */ typedef struct { QM_RW uint32_t gps0; /**< General Purpose Sticky Register 0 */ QM_RW uint32_t gps1; /**< General Purpose Sticky Register 1 */ @@ -121,17 +165,23 @@ typedef struct { wo_st; /**< Write-One-to-Set Sticky Scratchpad Register */ } qm_scss_gp_reg_t; -/** system control subsystem general purpose register block */ #if (UNIT_TEST) qm_scss_gp_reg_t test_scss_gp; #define QM_SCSS_GP ((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 +/** @} */ + +/** + * @name Memory Control + * @{ + */ + +/** Memory Control register map. */ typedef struct { QM_RW uint32_t mem_ctrl; /**< Memory control */ } qm_scss_mem_reg_t; @@ -141,19 +191,26 @@ qm_scss_mem_reg_t test_scss_mem; #define QM_SCSS_MEM ((qm_scss_mem_reg_t *)(&test_scss_mem)) #else -/** system control subsystem memory control register block */ #define QM_SCSS_MEM_BASE (0xB0800200) #define QM_SCSS_MEM ((qm_scss_mem_reg_t *)QM_SCSS_MEM_BASE) #endif +/** @} */ + +/** + * @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) @@ -161,18 +218,25 @@ qm_scss_cmp_reg_t test_scss_cmp; #define QM_SCSS_CMP ((qm_scss_cmp_reg_t *)(&test_scss_cmp)) #else -/** system control subsystem comparators register block */ #define QM_SCSS_CMP_BASE (0xB0800300) #define QM_SCSS_CMP ((qm_scss_cmp_reg_t *)QM_SCSS_CMP_BASE) #endif #define QM_AC_HP_COMPARATORS_MASK (0x7FFC0) +/** @} */ + +/** + * @name APIC + * @{ + */ + typedef struct { QM_RW uint32_t reg; QM_RW uint32_t pad[3]; } apic_reg_pad_t; +/** APIC register block type. */ typedef struct { QM_RW apic_reg_pad_t reserved0[2]; QM_RW apic_reg_pad_t id; /**< LAPIC ID */ @@ -247,11 +311,19 @@ qm_ioapic_reg_t test_ioapic; #define QM_IOAPIC ((qm_ioapic_reg_t *)(&test_ioapic)) #else -/** IO/APIC */ +/** IO / APIC base address. */ #define QM_IOAPIC_BASE (0xFEC00000) #define QM_IOAPIC ((qm_ioapic_reg_t *)QM_IOAPIC_BASE) #endif +/** @} */ + +/** + * @name Interrupt + * @{ + */ + +/** SS I2C Interrupt register map. */ typedef struct { QM_RW uint32_t err_mask; QM_RW uint32_t rx_avail_mask; @@ -259,12 +331,14 @@ typedef struct { QM_RW uint32_t stop_det_mask; } int_ss_i2c_reg_t; +/** SS SPI Interrupt register map. */ typedef struct { QM_RW uint32_t err_int_mask; QM_RW uint32_t rx_avail_mask; QM_RW uint32_t tx_req_mask; } int_ss_spi_reg_t; +/** Interrupt register map. */ typedef struct { QM_RW uint32_t int_ss_adc_err_mask; QM_RW uint32_t int_ss_adc_irq_mask; @@ -303,14 +377,17 @@ typedef struct { QM_RW uint32_t int_comparators_host_mask; QM_RW uint32_t int_host_bus_err_mask; QM_RW uint32_t int_dma_error_mask; - QM_RW uint32_t int_sram_controller_mask; - QM_RW uint32_t int_flash_controller_0_mask; - QM_RW uint32_t int_flash_controller_1_mask; - QM_RW uint32_t int_aon_timer_mask; - QM_RW uint32_t int_adc_pwr_mask; - QM_RW uint32_t int_adc_calib_mask; + QM_RW uint32_t + int_sram_controller_mask; /**< Interrupt Routing Mask 28 */ + QM_RW uint32_t + int_flash_controller_0_mask; /**< Interrupt Routing Mask 29 */ + QM_RW uint32_t + int_flash_controller_1_mask; /**< Interrupt Routing Mask 30 */ + QM_RW uint32_t int_aon_timer_mask; /**< Interrupt Routing Mask 31 */ + QM_RW uint32_t int_adc_pwr_mask; /**< Interrupt Routing Mask 32 */ + QM_RW uint32_t int_adc_calib_mask; /**< Interrupt Routing Mask 33 */ QM_RW uint32_t int_aon_gpio_mask; - QM_RW uint32_t lock_int_mask_reg; + QM_RW uint32_t lock_int_mask_reg; /**< Interrupt Mask Lock Register */ } qm_scss_int_reg_t; /** Number of SCSS interrupt mask registers (excluding mask lock register) */ @@ -325,7 +402,7 @@ qm_scss_int_reg_t test_scss_int; #define QM_SCSS_INT ((qm_scss_int_reg_t *)(&test_scss_int)) #else -/** system control subsystem Interrupt masking register block */ +/* System control subsystem interrupt masking register block. */ #define QM_SCSS_INT_BASE (0xB0800400) #define QM_SCSS_INT ((qm_scss_int_reg_t *)QM_SCSS_INT_BASE) #endif @@ -338,7 +415,17 @@ qm_scss_int_reg_t test_scss_int; #define QM_INT_FLASH_CONTROLLER_HOST_MASK BIT(0) #define QM_INT_FLASH_CONTROLLER_SS_HALT_MASK BIT(24) #define QM_INT_FLASH_CONTROLLER_SS_MASK BIT(8) +#define QM_INT_ADC_PWR_MASK BIT(8) +#define QM_INT_ADC_CALIB_MASK BIT(8) + +/** @} */ + +/** + * @name Power Management + * @{ + */ +/** Power Management register map. */ typedef struct { QM_RW uint32_t p_lvl2; /**< Processor level 2 */ QM_RW uint32_t reserved[4]; @@ -349,19 +436,17 @@ typedef struct { QM_RW uint32_t plat1p8_vr; /**< Platform 1p8 voltage regulator */ QM_RW uint32_t host_vr; /**< Host Voltage Regulator */ QM_RW uint32_t slp_cfg; /**< Sleeping Configuration */ - QM_RW uint32_t - pmnetcs; /**< Power Management Network (PMNet) Control and -Status */ + /** Power Management Network (PMNet) Control and Status */ + QM_RW uint32_t pmnetcs; QM_RW uint32_t pm_wait; /**< Power Management Wait */ QM_RW uint32_t reserved2; QM_RW uint32_t p_sts; /**< Processor Status */ QM_RW uint32_t reserved3[3]; - QM_RW uint32_t rstc; /**< Reset control */ - QM_RW uint32_t rsts; /**< Reset status */ + QM_RW uint32_t rstc; /**< Reset Control */ + QM_RW uint32_t rsts; /**< Reset Status */ QM_RW uint32_t reserved4[6]; QM_RW uint32_t vr_lock; /**< Voltage regulator lock */ - QM_RW uint32_t pm_lock; /**< Power management lock */ - + QM_RW uint32_t pm_lock; /**< Power Management Lock */ } qm_scss_pmu_reg_t; #if (UNIT_TEST) @@ -369,7 +454,6 @@ qm_scss_pmu_reg_t test_scss_pmu; #define QM_SCSS_PMU ((qm_scss_pmu_reg_t *)(&test_scss_pmu)) #else -/** system control subsystem power management register block */ #define QM_SCSS_PMU_BASE (0xB0800504) #define QM_SCSS_PMU ((qm_scss_pmu_reg_t *)QM_SCSS_PMU_BASE) #endif @@ -378,6 +462,13 @@ qm_scss_pmu_reg_t test_scss_pmu; #define QM_P_STS_HALT_INTERRUPT_REDIRECTION BIT(26) #define QM_P_STS_ARC_HALT BIT(14) +/** @} */ + +/** + * @name Sensor Subsystem + * @{ + */ + #define QM_SCSS_SLP_CFG_LPMODE_EN BIT(8) #define QM_SCSS_SLP_CFG_RTC_DIS BIT(7) #define QM_SCSS_PM1C_SLPEN BIT(13) @@ -391,13 +482,7 @@ qm_scss_pmu_reg_t test_scss_pmu; #define QM_SCSS_VR_EN BIT(7) #define QM_SCSS_VR_VREG_SEL BIT(6) -#define QM_AON_VR_VSEL_MASK (0xFFE0) -#define QM_AON_VR_VSEL_1V2 (0x8) -#define QM_AON_VR_VSEL_1V35 (0xB) -#define QM_AON_VR_VSEL_1V8 (0x10) -#define QM_AON_VR_EN BIT(7) -#define QM_AON_VR_VSTRB BIT(5) - +/** Sensor Subsystem register map. */ typedef struct { QM_RW uint32_t ss_cfg; /**< Sensor Subsystem Configuration */ QM_RW uint32_t ss_sts; /**< Sensor Subsystem status */ @@ -408,25 +493,39 @@ qm_scss_ss_reg_t test_scss_ss; #define QM_SCSS_SS ((qm_scss_ss_reg_t *)(&test_scss_ss)) #else -/** system control subsystem sensor subsystem register block */ #define QM_SCSS_SS_BASE (0xB0800600) #define QM_SCSS_SS ((qm_scss_ss_reg_t *)QM_SCSS_SS_BASE) #endif +#define QM_SS_STS_HALT_INTERRUPT_REDIRECTION BIT(26) + +/** @} */ + /** - * Number of SCSS Always on controllers. + * @name Always-on controllers. + * @{ */ + +#define QM_AON_VR_VSEL_MASK (0xFFE0) +#define QM_AON_VR_VSEL_1V2 (0x8) +#define QM_AON_VR_VSEL_1V35 (0xB) +#define QM_AON_VR_VSEL_1V8 (0x10) +#define QM_AON_VR_EN BIT(7) +#define QM_AON_VR_VSTRB BIT(5) + +/** 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) @@ -434,11 +533,18 @@ qm_scss_aon_reg_t test_scss_aon; #define QM_SCSS_AON ((qm_scss_aon_reg_t *)(&test_scss_aon)) #else -/** system control subsystem always on register block */ #define QM_SCSS_AON_BASE (0xB0800700) #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 usb_phy_cfg0; /**< USB Configuration */ QM_RW uint32_t periph_cfg0; /**< Peripheral Configuration */ @@ -451,11 +557,18 @@ qm_scss_peripheral_reg_t test_scss_peripheral; #define QM_SCSS_PERIPHERAL ((qm_scss_peripheral_reg_t *)(&test_scss_peripheral)) #else -/** system control subsystem peripheral register block */ #define QM_SCSS_PERIPHERAL_BASE (0xB0800800) #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[4]; /**< Pin Mux Pullup */ QM_RW uint32_t pmux_slew[4]; /**< Pin Mux Slew Rate */ @@ -473,22 +586,55 @@ qm_scss_pmux_reg_t test_scss_pmux; #define QM_SCSS_PMUX ((qm_scss_pmux_reg_t *)(&test_scss_pmux)) #else -/** system control subsystem pin muxing register block */ #define QM_SCSS_PMUX_BASE (0xB0800900) #define QM_SCSS_PMUX ((qm_scss_pmux_reg_t *)QM_SCSS_PMUX_BASE) #endif +/* Pin MUX slew rate registers and settings */ +#define QM_PMUX_SLEW_4MA_DRIVER (0xFFFFFFFF) +#define QM_PMUX_SLEW0 (REG_VAL(0xB0800910)) +#define QM_PMUX_SLEW1 (REG_VAL(0xB0800914)) +#define QM_PMUX_SLEW2 (REG_VAL(0xB0800918)) +#define QM_PMUX_SLEW3 (REG_VAL(0xB080091C)) + +/** @} */ + /** - * Mailbox + * @name ID + * @{ */ + +/** Information register map. */ +typedef struct { + QM_RW uint32_t id; +} qm_scss_info_reg_t; + +#if (UNIT_TEST) +qm_scss_info_reg_t test_scss_info; +#define QM_SCSS_INFO ((qm_scss_info_reg_t *)(&test_scss_info)) + +#else +#define QM_SCSS_INFO_BASE (0xB0801000) +#define QM_SCSS_INFO ((qm_scss_info_reg_t *)QM_SCSS_INFO_BASE) +#endif + +/** @} */ + +/** + * @name Mailbox + * @{ + */ + #define QM_MBOX_TRIGGER_CH_INT BIT(31) +/** Mailbox register structure. */ typedef struct { QM_RW uint32_t ch_ctrl; /**< Channel Control Word */ QM_RW uint32_t ch_data[4]; /**< Channel Payload Data Word 0 */ QM_RW uint32_t ch_sts; /**< Channel status */ } qm_mailbox_t; +/** Mailbox register map. */ typedef struct { qm_mailbox_t mbox[8]; /**< 8 Mailboxes */ QM_RW uint32_t mbox_chall_sts; /**< All channel status */ @@ -499,35 +645,154 @@ qm_scss_mailbox_reg_t test_scss_mailbox; #define QM_SCSS_MAILBOX ((qm_scss_mailbox_reg_t *)(&test_scss_mailbox)) #else -/** system control subsystem mailbox register block */ #define QM_SCSS_MAILBOX_BASE (0xB0800A00) #define QM_SCSS_MAILBOX ((qm_scss_mailbox_reg_t *)QM_SCSS_MAILBOX_BASE) #endif -typedef struct { - QM_RW uint32_t id; -} qm_scss_info_reg_t; +/** @} */ -#if (UNIT_TEST) -qm_scss_info_reg_t test_scss_info; -#define QM_SCSS_INFO ((qm_scss_info_reg_t *)(&test_scss_info)) +/** + * @name IRQs and Interrupts + * @{ + */ -#else -/** system control subsystem information register block */ -#define QM_SCSS_INFO_BASE (0xB0801000) -#define QM_SCSS_INFO ((qm_scss_info_reg_t *)QM_SCSS_INFO_BASE) -#endif +/* IRQs and interrupt vectors. + * + * Any IRQ > 1 actually has a SCSS mask register offset of +1. + * The vector numbers must be defined without arithmetic expressions nor + * parentheses because they are expanded as token concatenation. + */ + +#define QM_INT_VECTOR_DOUBLE_FAULT 8 +#define QM_INT_VECTOR_PIC_TIMER 32 + +#define QM_IRQ_RTC_0 11 +#define QM_IRQ_RTC_0_MASK_OFFSET 12 +#define QM_IRQ_RTC_0_VECTOR 47 -/* Peripheral registers */ +#define QM_IRQ_PWM_0 9 +#define QM_IRQ_PWM_0_MASK_OFFSET 10 +#define QM_IRQ_PWM_0_VECTOR 45 + +#define QM_IRQ_USB_0 (10) +#define QM_IRQ_USB_0_MASK_OFFSET (11) +#define QM_IRQ_USB_0_VECTOR 46 + +#define QM_IRQ_SPI_MASTER_0 2 +#define QM_IRQ_SPI_MASTER_0_MASK_OFFSET 3 +#define QM_IRQ_SPI_MASTER_0_VECTOR 38 + +#define QM_IRQ_SPI_MASTER_1 3 +#define QM_IRQ_SPI_MASTER_1_MASK_OFFSET 4 +#define QM_IRQ_SPI_MASTER_1_VECTOR 39 + +#define QM_IRQ_WDT_0 12 +#define QM_IRQ_WDT_0_MASK_OFFSET 13 +#define QM_IRQ_WDT_0_VECTOR 48 + +#define QM_IRQ_GPIO_0 8 +#define QM_IRQ_GPIO_0_MASK_OFFSET 9 +#define QM_IRQ_GPIO_0_VECTOR 44 + +#define QM_IRQ_I2C_0 0 +#define QM_IRQ_I2C_0_MASK_OFFSET 0 +#define QM_IRQ_I2C_0_VECTOR 36 + +#define QM_IRQ_I2C_1 1 +#define QM_IRQ_I2C_1_MASK_OFFSET 1 +#define QM_IRQ_I2C_1_VECTOR 37 + +#define QM_IRQ_MBOX 21 +#define QM_IRQ_MBOX_MASK_OFFSET 22 +#define QM_IRQ_MBOX_VECTOR 57 + +#define QM_IRQ_AC 22 +#define QM_IRQ_AC_MASK_OFFSET 26 +#define QM_IRQ_AC_VECTOR 58 + +#define QM_IRQ_SRAM 25 +#define QM_IRQ_SRAM_MASK_OFFSET 29 +#define QM_IRQ_SRAM_VECTOR 61 + +#define QM_IRQ_FLASH_0 26 +#define QM_IRQ_FLASH_0_MASK_OFFSET 30 +#define QM_IRQ_FLASH_0_VECTOR 62 + +#define QM_IRQ_FLASH_1 27 +#define QM_IRQ_FLASH_1_MASK_OFFSET 31 +#define QM_IRQ_FLASH_1_VECTOR 63 + +#define QM_IRQ_AONPT_0 28 +#define QM_IRQ_AONPT_0_MASK_OFFSET 32 +#define QM_IRQ_AONPT_0_VECTOR 64 + +#define QM_IRQ_AONGPIO_0 31 +#define QM_IRQ_AONGPIO_0_MASK_OFFSET 35 +#define QM_IRQ_AONGPIO_0_VECTOR 67 + +#define QM_IRQ_UART_0 5 +#define QM_IRQ_UART_0_MASK_OFFSET 6 +#define QM_IRQ_UART_0_VECTOR 41 + +#define QM_IRQ_UART_1 6 +#define QM_IRQ_UART_1_MASK_OFFSET 7 +#define QM_IRQ_UART_1_VECTOR 42 + +#define QM_IRQ_DMA_0 13 +#define QM_IRQ_DMA_0_MASK_OFFSET 14 +#define QM_IRQ_DMA_0_VECTOR 49 + +#define QM_IRQ_DMA_1 14 +#define QM_IRQ_DMA_1_MASK_OFFSET 15 +#define QM_IRQ_DMA_1_VECTOR 50 + +#define QM_IRQ_DMA_2 15 +#define QM_IRQ_DMA_2_MASK_OFFSET 16 +#define QM_IRQ_DMA_2_VECTOR 51 + +#define QM_IRQ_DMA_3 16 +#define QM_IRQ_DMA_3_MASK_OFFSET 17 +#define QM_IRQ_DMA_3_VECTOR 52 + +#define QM_IRQ_DMA_4 17 +#define QM_IRQ_DMA_4_MASK_OFFSET 18 +#define QM_IRQ_DMA_4_VECTOR 53 + +#define QM_IRQ_DMA_5 18 +#define QM_IRQ_DMA_5_MASK_OFFSET 19 +#define QM_IRQ_DMA_5_VECTOR 54 + +#define QM_IRQ_DMA_6 19 +#define QM_IRQ_DMA_6_MASK_OFFSET 20 +#define QM_IRQ_DMA_6_VECTOR 55 + +#define QM_IRQ_DMA_7 20 +#define QM_IRQ_DMA_7_MASK_OFFSET 21 +#define QM_IRQ_DMA_7_VECTOR 56 + +#define QM_IRQ_DMA_ERR 24 +#define QM_IRQ_DMA_ERR_MASK_OFFSET 28 +#define QM_IRQ_DMA_ERR_VECTOR 60 + +#define QM_SS_IRQ_ADC_PWR 29 +#define QM_SS_IRQ_ADC_PWR_MASK_OFFSET 33 +#define QM_SS_IRQ_ADC_PWR_VECTOR 65 + +#define QM_SS_IRQ_ADC_CAL 30 +#define QM_SS_IRQ_ADC_CAL_MASK_OFFSET 34 +#define QM_SS_IRQ_ADC_CAL_VECTOR 66 + +/** @} */ /** - * 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, @@ -536,10 +801,7 @@ typedef enum { 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 */ @@ -548,6 +810,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[20]; @@ -571,14 +834,17 @@ qm_pwm_reg_t test_pwm_t; #define QM_PWM_INTERRUPT_MASK_OFFSET (2) +/** @} */ + /** - * Number of WDT controllers. + * @name WDT + * @{ */ + +/** Number of WDT controllers. */ typedef enum { QM_WDT_0 = 0, QM_WDT_NUM } qm_wdt_t; -/** - * Watchdog timer register block type. - */ +/** Watchdog timer register map. */ typedef struct { QM_RW uint32_t wdt_cr; /**< Control Register */ QM_RW uint32_t wdt_torr; /**< Timeout Range Register */ @@ -603,19 +869,22 @@ qm_wdt_reg_t test_wdt; #else /** WDT register base address */ #define QM_WDT_BASE (0xB0000000) + /** WDT register block */ #define QM_WDT ((qm_wdt_reg_t *)QM_WDT_BASE) #endif -/** - * Number of UART controllers. - */ -typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t; +/** @} */ /** - * UART register block type. + * @name UART + * @{ */ +/** Number of UART controllers. */ +typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t; + +/** 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 */ @@ -649,39 +918,14 @@ extern qm_uart_reg_t *qm_uart[QM_UART_NUM]; #define QM_UART qm_uart #endif -/** - * Number of RTC controllers. - */ -typedef enum { QM_RTC_0 = 0, QM_RTC_NUM } qm_rtc_t; +/** @} */ /** - * QM RTC Register block type. + * @name SPI + * @{ */ -typedef struct { - QM_RW uint32_t rtc_ccvr; /**< Current Counter Value Register */ - QM_RW uint32_t rtc_cmr; /**< Current Match Register */ - QM_RW uint32_t rtc_clr; /**< Counter Load Register */ - QM_RW uint32_t rtc_ccr; /**< Counter Control Register */ - QM_RW uint32_t rtc_stat; /**< Interrupt Status Register */ - QM_RW uint32_t rtc_rstat; /**< Interrupt Raw Status Register */ - QM_RW uint32_t rtc_eoi; /**< End of Interrupt Register */ - QM_RW uint32_t rtc_comp_version; /**< End of Interrupt Register */ -} qm_rtc_reg_t; - -#if (UNIT_TEST) -qm_rtc_reg_t test_rtc; -#define QM_RTC ((qm_rtc_reg_t *)(&test_rtc)) -#else -/** RTC register base address */ -#define QM_RTC_BASE (0xB0000400) -/** RTC register block */ -#define QM_RTC ((qm_rtc_reg_t *)QM_RTC_BASE) -#endif - -/** - * Number of SPI controllers. - */ +/** Number of SPI controllers. */ typedef enum { QM_SPI_MST_0 = 0, QM_SPI_MST_1, @@ -689,9 +933,7 @@ typedef enum { QM_SPI_NUM } qm_spi_t; -/** - * SPI register entries - */ +/** SPI register map. */ typedef struct { QM_RW uint32_t ctrlr0; /**< Control Register 0 */ QM_RW uint32_t ctrlr1; /**< Control Register 1 */ @@ -756,6 +998,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) @@ -783,14 +1027,51 @@ 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 I2C controllers. + * @name RTC + * @{ */ -typedef enum { QM_I2C_0 = 0, QM_I2C_1, QM_I2C_NUM } qm_i2c_t; + +/** 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 */ + QM_RW uint32_t rtc_clr; /**< Counter Load Register */ + QM_RW uint32_t rtc_ccr; /**< Counter Control Register */ + QM_RW uint32_t rtc_stat; /**< Interrupt Status Register */ + QM_RW uint32_t rtc_rstat; /**< Interrupt Raw Status Register */ + QM_RW uint32_t rtc_eoi; /**< End of Interrupt Register */ + QM_RW uint32_t rtc_comp_version; /**< End of Interrupt Register */ +} qm_rtc_reg_t; + +#if (UNIT_TEST) +qm_rtc_reg_t test_rtc; +#define QM_RTC ((qm_rtc_reg_t *)(&test_rtc)) + +#else +/** RTC register base address. */ +#define QM_RTC_BASE (0xB0000400) + +/** RTC register block. */ +#define QM_RTC ((qm_rtc_reg_t *)QM_RTC_BASE) +#endif + +/** @} */ /** - * I2C Register block type. + * @name I2C + * @{ */ + +/** Number of I2C controllers. */ +typedef enum { QM_I2C_0 = 0, QM_I2C_1, 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 */ @@ -854,11 +1135,11 @@ 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) #define QM_I2C_1_BASE (0xB0002C00) -/** I2C register block */ +/** I2C register block. */ extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM]; #define QM_I2C qm_i2c #endif @@ -916,14 +1197,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. + * @name GPIO + * @{ */ + +/** Number of GPIO controllers. */ typedef enum { QM_GPIO_0 = 0, QM_AON_GPIO_0 = 1, QM_GPIO_NUM } qm_gpio_t; -/** - * GPIO register block type. - */ +/** 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 */ @@ -966,14 +1250,17 @@ extern qm_gpio_reg_t *qm_gpio[QM_GPIO_NUM]; #define QM_GPIO qm_gpio #endif +/** @} */ + /** - * Number of Flash controllers. + * @name Flash + * @{ */ + +/** Number of Flash controllers. */ typedef enum { QM_FLASH_0 = 0, QM_FLASH_1, QM_FLASH_NUM } qm_flash_t; -/** - * Flash register block type. - */ +/** Flash register map. */ typedef struct { QM_RW uint32_t tmg_ctrl; /**< TMG_CTRL */ QM_RW uint32_t rom_wr_ctrl; /**< ROM_WR_CTRL */ @@ -986,7 +1273,7 @@ typedef struct { QM_RW uint32_t mpr_wr_cfg; /**< Flash Write Protection Control Register */ QM_RW uint32_t mpr_vsts; /**< Protection Status Register */ - QM_RW uint32_t mpr_vdata; /** MPR_VDATA */ + QM_RW uint32_t mpr_vdata; /**< MPR Violation Data Value Register */ QM_RW uint32_t padding[0x3FFF2]; /* (0x100000 - 0x38) / 4 */ } qm_flash_reg_t; @@ -1005,19 +1292,23 @@ uint8_t test_flash_page[0x800]; #define QM_FLASH_MAX_ADDR (0xFFFFFFFF) #else -/** Flash controller 0 register block */ -#define QM_FLASH_BASE_0 (0xB0100000) -#define QM_FLASH_BASE_1 (0xB0200000) -extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM]; -#define QM_FLASH qm_flash +/* Flash physical address mappings */ -/** Flash physical address mappings */ #define QM_FLASH_REGION_SYS_1_BASE (0x40030000) #define QM_FLASH_REGION_SYS_0_BASE (0x40000000) #define QM_FLASH_REGION_OTP_0_BASE (0xFFFFE000) + #define QM_FLASH_PAGE_MASK (0x3F800) #define QM_FLASH_MAX_ADDR (0x30000) +/** Flash controller register base address. */ +#define QM_FLASH_BASE_0 (0xB0100000) +#define QM_FLASH_BASE_1 (0xB0200000) + +/** 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 (0x00) @@ -1027,9 +1318,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 */ @@ -1064,31 +1360,14 @@ qm_mpr_reg_t test_mpr; #define QM_CCU_EXT_CLK_DIV_EN BIT(2) /** End of External clock control @}*/ -/** GPIO Debounce Clock Control @{*/ -#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) -/** End of GPIO Debounce Clock Control @}*/ - -/** Peripheral clock divider control 0 @{*/ -#define QM_CCU_PERIPH_PCLK_DIV_OFFSET (1) -#define QM_CCU_PERIPH_PCLK_DIV_EN BIT(0) -/** End of Peripheral clock divider control 0 @}*/ - -/** System clock control @{*/ -#define QM_CCU_SYS_CLK_SEL 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 (0x00000300) -#define QM_CCU_DMA_CLK_EN BIT(6) - -#define QM_CCU_RTC_CLK_DIV_OFFSET (3) -#define QM_CCU_SYS_CLK_DIV_OFFSET (8) +/** @} */ /** - * Peripheral clock type. + * @name Peripheral Clock + * @{ */ + +/** Peripheral clock type. */ typedef enum { CLK_PERIPH_REGISTER = BIT(0), /**< Peripheral Clock Gate Enable. */ CLK_PERIPH_CLK = BIT(1), /**< Peripheral Clock Enable. */ @@ -1122,29 +1401,25 @@ typedef enum { /* Default mask values */ #define CLK_EXTERN_DIV_DEF_MASK (0xFFFFFFE3) -#define CLK_SYS_CLK_DIV_DEF_MASK (0xFFFFF87F) +#define CLK_SYS_CLK_DIV_DEF_MASK (0xFFFFFC7F) #define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83) #define CLK_GPIO_DB_DIV_DEF_MASK (0xFFFFFFE1) #define CLK_PERIPH_DIV_DEF_MASK (0xFFFFFFF9) -#define SYS_CLK_HYB_OSC_32MHZ_SETTINGS *((volatile uint32_t *)0x00000004) -#define SYS_CLK_HYB_OSC_4MHZ_SETTINGS *((volatile uint32_t *)0x00000008) - -/** End of System clock control 0 @}*/ - -/** 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 */ @@ -1157,9 +1432,7 @@ typedef enum { 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 */ @@ -1179,9 +1452,7 @@ typedef enum { DMA_HW_IF_I2C_MASTER_1_RX = 0xf, /**< I2C_Master_1_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 */ @@ -1207,7 +1478,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) @@ -1230,7 +1501,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 @@ -1248,9 +1519,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 */ @@ -1296,13 +1565,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 */ @@ -1315,10 +1582,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 { @@ -1338,148 +1605,12 @@ extern qm_dma_reg_t *qm_dma[QM_DMA_NUM]; #define QM_DMA qm_dma #endif -/** IRQs and interrupt vectors. - * - * Any IRQ > 1 actually has a SCSS mask register offset of +1. - * The vector numbers must be defined without arithmetic expressions nor - * parentheses because they are expanded as token concatenation. - */ - -#define QM_INT_VECTOR_DOUBLE_FAULT 8 -#define QM_INT_VECTOR_PIC_TIMER 32 - -#define QM_IRQ_GPIO_0 (8) -#define QM_IRQ_GPIO_0_MASK_OFFSET (9) -#define QM_IRQ_GPIO_0_VECTOR 44 - -#define QM_IRQ_PWM_0 (9) -#define QM_IRQ_PWM_0_MASK_OFFSET (10) -#define QM_IRQ_PWM_0_VECTOR 45 - -#define QM_IRQ_USB_0 (10) -#define QM_IRQ_USB_0_MASK_OFFSET (11) -#define QM_IRQ_USB_0_VECTOR 46 - -#define QM_IRQ_SPI_MASTER_0 (2) -#define QM_IRQ_SPI_MASTER_0_MASK_OFFSET (3) -#define QM_IRQ_SPI_MASTER_0_VECTOR 38 - -#define QM_IRQ_SPI_MASTER_1 (3) -#define QM_IRQ_SPI_MASTER_1_MASK_OFFSET (4) -#define QM_IRQ_SPI_MASTER_1_VECTOR 39 - -#define QM_IRQ_RTC_0 (11) -#define QM_IRQ_RTC_0_MASK_OFFSET (12) -#define QM_IRQ_RTC_0_VECTOR 47 - -#define QM_IRQ_WDT_0 (12) -#define QM_IRQ_WDT_0_MASK_OFFSET (13) -#define QM_IRQ_WDT_0_VECTOR 48 - -#define QM_IRQ_I2C_0 (0) -#define QM_IRQ_I2C_0_MASK_OFFSET (0) -#define QM_IRQ_I2C_0_VECTOR 36 - -#define QM_IRQ_I2C_1 (1) -#define QM_IRQ_I2C_1_MASK_OFFSET (1) -#define QM_IRQ_I2C_1_VECTOR 37 - -#define QM_IRQ_MBOX (21) -#define QM_IRQ_MBOX_MASK_OFFSET (22) -#define QM_IRQ_MBOX_VECTOR 57 - -#define QM_IRQ_AC (22) -#define QM_IRQ_AC_MASK_OFFSET (26) -#define QM_IRQ_AC_VECTOR 58 - -#define QM_IRQ_SRAM (25) -#define QM_IRQ_SRAM_MASK_OFFSET (29) -#define QM_IRQ_SRAM_VECTOR 61 - -#define QM_IRQ_FLASH_0 (26) -#define QM_IRQ_FLASH_0_MASK_OFFSET (30) -#define QM_IRQ_FLASH_0_VECTOR 62 - -#define QM_IRQ_FLASH_1 (27) -#define QM_IRQ_FLASH_1_MASK_OFFSET (31) -#define QM_IRQ_FLASH_1_VECTOR 63 - -#define QM_IRQ_AONPT_0 (28) -#define QM_IRQ_AONPT_0_MASK_OFFSET (32) -#define QM_IRQ_AONPT_0_VECTOR 64 +/** @} */ -#define QM_IRQ_AONGPIO_0 (31) -#define QM_IRQ_AONGPIO_0_MASK_OFFSET (35) -#define QM_IRQ_AONGPIO_0_VECTOR 67 - -#define QM_IRQ_UART_0 (5) -#define QM_IRQ_UART_0_MASK_OFFSET (6) -#define QM_IRQ_UART_0_VECTOR 41 - -#define QM_IRQ_UART_1 (6) -#define QM_IRQ_UART_1_MASK_OFFSET (7) -#define QM_IRQ_UART_1_VECTOR 42 - -#define QM_IRQ_DMA_0 (13) -#define QM_IRQ_DMA_0_MASK_OFFSET (14) -#define QM_IRQ_DMA_0_VECTOR 49 - -#define QM_IRQ_DMA_1 (14) -#define QM_IRQ_DMA_1_MASK_OFFSET (15) -#define QM_IRQ_DMA_1_VECTOR 50 - -#define QM_IRQ_DMA_2 (15) -#define QM_IRQ_DMA_2_MASK_OFFSET (16) -#define QM_IRQ_DMA_2_VECTOR 51 - -#define QM_IRQ_DMA_3 (16) -#define QM_IRQ_DMA_3_MASK_OFFSET (17) -#define QM_IRQ_DMA_3_VECTOR 52 - -#define QM_IRQ_DMA_4 (17) -#define QM_IRQ_DMA_4_MASK_OFFSET (18) -#define QM_IRQ_DMA_4_VECTOR 53 - -#define QM_IRQ_DMA_5 (18) -#define QM_IRQ_DMA_5_MASK_OFFSET (19) -#define QM_IRQ_DMA_5_VECTOR 54 - -#define QM_IRQ_DMA_6 (19) -#define QM_IRQ_DMA_6_MASK_OFFSET (20) -#define QM_IRQ_DMA_6_VECTOR 55 - -#define QM_IRQ_DMA_7 (20) -#define QM_IRQ_DMA_7_MASK_OFFSET (21) -#define QM_IRQ_DMA_7_VECTOR 56 - -#define QM_IRQ_DMA_ERR (24) -#define QM_IRQ_DMA_ERR_MASK_OFFSET (28) -#define QM_IRQ_DMA_ERR_VECTOR 60 - -#define QM_SS_IRQ_ADC_PWR (29) -#define QM_SS_IRQ_ADC_PWR_MASK_OFFSET (33) -#define QM_SS_IRQ_ADC_PWR_VECTOR (65) - -#define QM_SS_IRQ_ADC_CAL (30) -#define QM_SS_IRQ_ADC_CAL_MASK_OFFSET (34) -#define QM_SS_IRQ_ADC_CAL_VECTOR (66) - -/* Hybrid oscillator output select select (0=Silicon, 1=Crystal)*/ -#define QM_OSC0_MODE_SEL BIT(3) -/* Enable Crystal oscillator*/ -#define QM_OSC0_EN_CRYSTAL BIT(0) - -/* 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 */ -#define OSC0_CFG1_FTRIMOTP_MASK (0x3FF00000) -#define OSC0_CFG1_FTRIMOTP_OFFS (20) -#define OSC0_CFG1_SI_FREQ_SEL_MASK (0x00000300) -#define OSC0_CFG1_SI_FREQ_SEL_OFFS (8) +/** + * @name USB + * @{ + */ /** USB register base address */ #define QM_USB_BASE (0xB0500000) @@ -1495,24 +1626,14 @@ extern qm_dma_reg_t *qm_dma[QM_DMA_NUM]; /* USB clock enable bit*/ #define QM_CCU_USB_CLK_EN BIT(1) -/* Clock enable/disable register*/ -#define QM_CCU_MLAYER_AHB_CTL (REG_VAL(0xB0800034)) - -/* Ensure CLK divide by one is set*/ -#define QM_CCU_SYS_CLK_DIV_BY_ONE (0xFFFFFCFF) -/* SYS CLK register*/ -#define QM_CCU_SYS_CLK_CTL (REG_VAL(0xB0800038)) -/* Pin MUX slew rate registers and settings */ -#define QM_PMUX_SLEW_4MA_DRIVER (0xFFFFFFFF) -#define QM_PMUX_SLEW0 (REG_VAL(0xB0800910)) -#define QM_PMUX_SLEW1 (REG_VAL(0xB0800914)) -#define QM_PMUX_SLEW2 (REG_VAL(0xB0800918)) -#define QM_PMUX_SLEW3 (REG_VAL(0xB080091C)) +/** @} */ /** - * Version variables. + * @name Versioning + * @{ */ + #if (UNIT_TEST) uint32_t test_rom_version; #define ROM_VERSION_ADDRESS &test_rom_version; @@ -1520,4 +1641,8 @@ uint32_t test_rom_version; #define ROM_VERSION_ADDRESS (0xFFFFFFEC); #endif +/** @} */ + +/** @} */ + #endif /* __REGISTERS_H__ */ |