ext qmsi: Update to QMSI 1.1-Beta

QMSI 1.1 Beta is available on Github:
https://github.com/01org/qmsi/releases/tag/v1.1.0-beta

Update the QMSI drop we maintain in Zephyr and
keep the modification to qm_soc_regs.h introduced on commit
6b88a6b945 "ext qmsi: Add USB base and interrupt defines" since
that patch hasn't made into the QMSI 1.1-Beta release in time.

Also, fix the build where needed:
- add hard dependency from qm_i2c to qm_dma
- fix spi_qmsi_ss.c due to new parameter naming
- fix adc_qmsi.c and adc_qmsi_ss.c due to a new parameter

Change-Id: I01388c787f5ee6ee97fece2e42b24a717522207f
Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
Signed-off-by: Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
This commit is contained in:
Jesus Sanchez-Palencia 2016-06-30 17:25:00 -03:00 committed by Kuo-Lang Tseng
parent 19fa82ab91
commit abd7496225
54 changed files with 2647 additions and 1180 deletions

View file

@ -110,6 +110,7 @@ static int adc_qmsi_read(struct device *dev, struct adc_seq_table *seq_tbl)
{
int i, ret = 0;
qm_adc_xfer_t xfer;
qm_adc_status_t status;
struct adc_info *info = dev->driver_data;
@ -148,7 +149,7 @@ static int adc_qmsi_read(struct device *dev, struct adc_seq_table *seq_tbl)
* register to check if the number of samples required has been
* captured
*/
if (qm_adc_convert(QM_ADC_0, &xfer) != 0) {
if (qm_adc_convert(QM_ADC_0, &xfer, &status) != 0) {
ret = -EIO;
adc_unlock(info);
break;

View file

@ -116,6 +116,7 @@ static int adc_qmsi_ss_read(struct device *dev, struct adc_seq_table *seq_tbl)
{
int i, ret = 0;
qm_ss_adc_xfer_t xfer;
qm_ss_adc_status_t status;
struct adc_info *info = dev->driver_data;
@ -154,7 +155,7 @@ static int adc_qmsi_ss_read(struct device *dev, struct adc_seq_table *seq_tbl)
* register to check if the number of samples required has been
* captured
*/
if (qm_ss_adc_convert(QM_SS_ADC_0, &xfer) != 0) {
if (qm_ss_adc_convert(QM_SS_ADC_0, &xfer, &status) != 0) {
ret = -EIO;
adc_unlock(info);
break;

View file

@ -56,6 +56,7 @@ config I2C_QMSI_SS
config I2C_QMSI
bool "QMSI I2C driver"
depends on I2C && QMSI
select DMA_QMSI
default n
help
This option enable the QMSI I2C driver.

View file

@ -169,7 +169,7 @@ static int ss_spi_qmsi_transceive(struct device *dev,
xfer->rx_len = rx_buf_len / dfs;
xfer->tx = (uint8_t *)tx_buf;
xfer->tx_len = tx_buf_len / dfs;
xfer->data = dev;
xfer->callback_data = dev;
xfer->callback = spi_qmsi_callback;
if (tx_buf_len == 0) {

View file

@ -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.

View file

@ -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;
}

View file

@ -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);

View file

@ -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.

View file

@ -32,7 +32,7 @@
#include "qm_common.h"
#include "qm_soc_regs.h"
#include "qm_interrupt.h"
/**
* Flash controller.
*

View file

@ -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.

View file

@ -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__)
/*

View file

@ -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.
*

View file

@ -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.

View file

@ -54,6 +54,7 @@ typedef enum {
typedef struct {
qm_pic_timer_mode_t mode; /**< Operation mode. */
bool int_en; /**< Interrupt enable. */
/**
* User callback.
*

View file

@ -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.
*

View file

@ -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;

View file

@ -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.

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2016, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SOC_WATCH_H__
#define __SOC_WATCH_H__
/* This file relies on the SOC being defined, which comes from qm_soc_regs.h */
#include "qm_soc_regs.h"
/**
* SoC Watch (Energy Analyzer).
*
* @defgroup group SOC_WATCH
* @{
*/
#include "qm_common.h"
/*
* To activate the functionality in this file, compile with
* SOC_WATCH_ENABLE=1 on the make command line.
*
* Accurate timestamping through sleep modes also requires:
* + board design: provide an RTC crystal
* + application : don't reset or disable the RTC.
*/
/**
* Power profiling events enumeration.
*
* In order to maintain binary compatibility, only SOCW_EVENT_MAX should
* ever be altered: new events should be inserted before SOCW_EVENT_MAX,
* and SOCW_EVENT_MAX incremented. Add events, do not replace them.
*/
typedef enum {
SOCW_EVENT_HALT = 0, /**< CPU Halt. */
SOCW_EVENT_INTERRUPT = 1, /**< CPU interrupt generated. */
SOCW_EVENT_SLEEP = 2, /**< Sleep mode entered. */
SOCW_EVENT_REGISTER = 3, /**< SOC register altered. */
SOCW_EVENT_APP = 4, /**< Application-defined event. */
SOCW_EVENT_MAX = 5 /**< End of events sentinel. */
} soc_watch_event_t;
/**
* Register ID enumeration.
*
* The Register Event stores a register ID enumeration instead of a
* register address in order to save space. Registers can be added,
* but they should not be deleted, in order to preserve compatibility
* with different versions of the post-processor.
*
* Note that most of these names mirror the names used elsewhere in
* the QMSI code, although these are upper case, while the register
* pointer names are in lower case. That's one clue for identifying
* where logging calls should to be added: wherever you see one of the
* named registers below being written, you should consider that write
* may need a corresponding SoC Watch logging call.
*/
#if (QUARK_D2000)
typedef enum {
/* Clock rate registers */
SOCW_REG_OSC0_CFG1 = 0, /**< 0x000 OSC0_CFG1 register. */
SOCW_REG_CCU_LP_CLK_CTL = 1, /**< 0x02C Clock Control register.*/
SOCW_REG_CCU_SYS_CLK_CTL = 2, /**< 0x038 System Clock Control. */
/* Clock gating registers. */
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL = 3, /**< 0x018 Perip Clock Gate Ctl.*/
SOCW_REG_CCU_EXT_CLK_CTL = 4, /**< 0x024 CCU Ext Clock Gate Ctl.*/
/* Registers affecting power consumption */
SOCW_REG_CMP_PWR = 5, /**< 0x30C Comprtr Power Enable. */
SOCW_REG_PMUX_PULLUP = 6, /**< 0x900 Pin Mux Pullup. */
SOCW_REG_PMUX_SLEW = 7, /**< 0x910 Pin Mux Slew. */
SOCW_REG_PMUX_IN_EN = 8, /**< 0x920 Pin Mux In Enable. */
SOCW_REG_MAX, /**< Register enum sentinel. */
} soc_watch_reg_t;
#elif(QUARK_SE)
typedef enum {
/* Clock rate registers */
SOCW_REG_OSC0_CFG1 = 0, /**< 0x000 OSC0_CFG1 register. */
SOCW_REG_CCU_LP_CLK_CTL = 1, /**< 0x02C Clock Control register. */
SOCW_REG_CCU_SYS_CLK_CTL = 2, /**< 0x038 System Clock Control. */
/* Clock gating registers. */
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL = 3, /**< 0x018 Perip Clock Gate Ctl.*/
SOCW_REG_CCU_SS_PERIPH_CLK_GATE_CTL = 4, /**< 0x0028 SS PCL Gate Ctl.*/
SOCW_REG_CCU_EXT_CLK_CTL = 5, /**< 0x024 CCU Ext Clock Gate Ctl.*/
/* Registers affecting power consumption */
SOCW_REG_CMP_PWR = 6, /**< 0x30C Comparator Power Enable. */
SOCW_REG_SLP_CFG = 7, /**< 0x550 Sleep Configuration. */
SOCW_REG_PMUX_PULLUP0 = 8, /**< 0x900 Pin Mux Pullup. */
SOCW_REG_PMUX_PULLUP1 = 9, /**< 0x904 Pin Mux Pullup. */
SOCW_REG_PMUX_PULLUP2 = 10, /**< 0x908 Pin Mux Pullup. */
SOCW_REG_PMUX_PULLUP3 = 11, /**< 0x90c Pin Mux Pullup. */
SOCW_REG_PMUX_SLEW0 = 12, /**< 0x910 Pin Mux Slew. */
SOCW_REG_PMUX_SLEW1 = 13, /**< 0x914 Pin Mux Slew. */
SOCW_REG_PMUX_SLEW2 = 14, /**< 0x918 Pin Mux Slew. */
SOCW_REG_PMUX_SLEW3 = 15, /**< 0x91c Pin Mux Slew. */
SOCW_REG_PMUX_IN_EN0 = 16, /**< 0x920 Pin Mux In Enable. */
SOCW_REG_PMUX_IN_EN1 = 17, /**< 0x924 Pin Mux In Enable. */
SOCW_REG_PMUX_IN_EN2 = 18, /**< 0x928 Pin Mux In Enable. */
SOCW_REG_PMUX_IN_EN3 = 19, /**< 0x92c Pin Mux In Enable. */
SOCW_REG_MAX, /**< Register enum sentinel. */
} soc_watch_reg_t;
#endif /* QUARK_SE */
/**
* Log a power profile event.
*
* Log an event related to power management. This should be things like
* halts, or register reads which cause us to go to low power states, or
* register reads that affect the clock rate, or other clock gating.
*
* @param[in] event_id The Event ID of the profile event.
* @param[in] ev_data A parameter to the event ID (if the event needs one).
*/
void soc_watch_log_event(soc_watch_event_t event_id, uintptr_t ev_data);
/**
* Log an application event via the power profile logger.
*
* This allows applications layered on top of QMSI to log their own
* events. The subtype identifies the type of data for the user, and
* 'data' is the actual information being logged.
*
* @param[in] event_id The Event ID of the profile event.
* @param[in] ev_subtype A 1-byte user-defined event_id.
* @param[in] ev_data A parameter to the event ID (if the event needs one).
*
* @returns Nothing.
*/
void soc_watch_log_app_event(soc_watch_event_t event_id, uint8_t ev_subtype,
uintptr_t ev_data);
/**
* @}
*/
#endif /* __SOC_WATCH_H__ */

View file

@ -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 |

View file

@ -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);

View file

@ -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];

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 =

View file

@ -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

View file

@ -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;
}

View file

@ -58,14 +58,61 @@ int qm_mpr_set_config(const qm_mpr_id_t id, const qm_mpr_config_t *const cfg)
/* MPR Upper bound 16:10 */
((cfg->up_bound & ADDRESS_MASK_7_BIT) << QM_MPR_UP_BOUND_OFFSET)
/* MPR Lower bound 6:0 */
|
cfg->low_bound;
| cfg->low_bound;
/* enable/lock */
QM_MPR->mpr_cfg[id] |= (cfg->en_lock_mask << QM_MPR_EN_LOCK_OFFSET);
return 0;
}
#if (QM_SENSOR)
int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
qm_mpr_callback_t callback_fn,
void *callback_data)
{
QM_CHECK(mode <= MPR_VIOL_MODE_PROBE, -EINVAL);
/* interrupt mode */
if (MPR_VIOL_MODE_INTERRUPT == mode) {
callback = callback_fn;
callback_data = callback_data;
/* unmask interrupt */
QM_SCSS_INT->int_sram_controller_mask &=
~QM_INT_SRAM_CONTROLLER_SS_MASK;
QM_SCSS_INT->int_sram_controller_mask |=
QM_INT_SRAM_CONTROLLER_SS_HALT_MASK;
QM_SCSS_SS->ss_cfg &= ~QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
}
/* probe or reset mode */
else {
/* mask interrupt */
QM_SCSS_INT->int_sram_controller_mask |=
QM_INT_SRAM_CONTROLLER_SS_MASK;
QM_SCSS_INT->int_sram_controller_mask &=
~QM_INT_SRAM_CONTROLLER_SS_HALT_MASK;
if (MPR_VIOL_MODE_PROBE == mode) {
/* When an enabled host halt interrupt occurs, this bit
* determines if the interrupt event triggers a warm
* reset
* or an entry into Probe Mode.
* 0b : Warm Reset
* 1b : Probe Mode Entry
*/
QM_SCSS_SS->ss_cfg |=
QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
} else {
QM_SCSS_SS->ss_cfg &=
~QM_SS_STS_HALT_INTERRUPT_REDIRECTION;
}
}
return 0;
}
#else
int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
qm_mpr_callback_t callback_fn,
void *callback_data)
@ -78,26 +125,18 @@ int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
/* unmask interrupt */
qm_irq_unmask(QM_IRQ_SRAM);
#if defined(QM_SENSOR)
QM_SCSS_INT->int_sram_controller_mask |=
QM_INT_SRAM_CONTROLLER_SS_HALT_MASK;
#else /* QM_SENSOR */
QM_SCSS_INT->int_sram_controller_mask |=
QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK;
#endif /* QM_SENSOR */
}
/* probe or reset mode */
else {
/* mask interrupt */
qm_irq_mask(QM_IRQ_SRAM);
#if defined(QM_SENSOR)
QM_SCSS_INT->int_sram_controller_mask &=
~QM_INT_SRAM_CONTROLLER_SS_HALT_MASK;
#else /* QM_SENSOR */
QM_SCSS_INT->int_sram_controller_mask &=
~QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK;
#endif /* QM_SENSOR */
if (MPR_VIOL_MODE_PROBE == mode) {
@ -110,12 +149,11 @@ int qm_mpr_set_violation_policy(const qm_mpr_viol_mode_t mode,
*/
QM_SCSS_PMU->p_sts |=
QM_P_STS_HALT_INTERRUPT_REDIRECTION;
}
else {
} else {
QM_SCSS_PMU->p_sts &=
~QM_P_STS_HALT_INTERRUPT_REDIRECTION;
}
}
return 0;
}
#endif /* QM_SENSOR */

View file

@ -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]);
}

View file

@ -36,9 +36,17 @@
/* SPI DMA transmit watermark level. When the number of valid data entries in
* the transmit FIFO is equal to or below this field value, dma_tx_req is
* generated. The burst length has to fit in the remaining space of the transmit
* FIFO, i.e. the burst length cannot be bigger than (16 - watermark level). */
#define SPI_DMATDLR_DMATDL (0x03)
* generated. The destination burst length has to fit in the remaining space
* of the transmit FIFO, thus it must be <= (SPI_FIFOS_DEPTH - TDLR).
* For optimal results it must be set to that delta so we can ensure the number
* of DMA transactions (bursts) needed are minimal, leading to a better bus
* utilization.
*
* With that in mind, here we choose 4 frames as a watermark level (TDLR) so we
* can end up with a valid value for SPI_DMA_WRITE_BURST_LENGTH of 4 frames,
* still adhering to the above (FIFOS_DEPTH - TDLR = 4).
*/
#define SPI_DMATDLR_DMATDL (0x4)
#define SPI_DMA_WRITE_BURST_LENGTH QM_DMA_BURST_TRANS_LENGTH_4
/* SPI DMA receive watermark level. When the number of valid data entries in the
@ -50,13 +58,21 @@
* 0 1
* 3 4
* 7 (highest) 8
*
* By keeping SPI_DMA_READ_BURST_LENGTH = RDLR + 1, we have optimal results
* since it reduces the number of DMA transactions, leading to a better bus
* utilization.
*
* Note that, unlike we do for IRQ transfers, there is no need to adjust the
* watermark level (RDLR for DMA transfers, RXFTLR for IRQ ones) during or at
* the start of the DMA transaction, if rx_len < RDLR. This is done
* automatically
* by the SPI DMA interface when it decides between burst or single transactions
* through means of the BLOCK_TS and SRC_MSIZE ratio.
*/
#define SPI_DMARDLR_DMARDL (0x03)
#define SPI_DMA_READ_BURST_LENGTH QM_DMA_BURST_TRANS_LENGTH_4
/* Arbitrary byte sent in RX-only mode. */
#define SPI_RX_ONLY_DUMMY_BYTE (0xf0)
/* DMA transfer information, relevant on callback invocations from the DMA
* driver. */
typedef struct {
@ -81,7 +97,7 @@ qm_spi_reg_t *qm_spi_controllers[QM_SPI_NUM] = {
static const qm_spi_async_transfer_t *spi_async_transfer[QM_SPI_NUM];
static volatile uint16_t tx_counter[QM_SPI_NUM], rx_counter[QM_SPI_NUM];
static uint8_t dfs[QM_SPI_NUM];
static const uint32_t tx_dummy_frame = SPI_RX_ONLY_DUMMY_BYTE;
static const uint32_t tx_dummy_frame = 0;
static qm_spi_tmode_t tmode[QM_SPI_NUM];
/* DMA (memory to SPI controller) callback information. */
static dma_context_t dma_context_tx[QM_SPI_NUM];
@ -220,8 +236,7 @@ static void handle_spi_interrupt(const qm_spi_t spi)
if (int_status & QM_SPI_ISR_RXOIS) {
if (transfer->callback) {
transfer->callback(transfer->callback_data, -EIO,
QM_SPI_RX_OVERFLOW,
rx_counter[spi]);
QM_SPI_RX_OVERFLOW, rx_counter[spi]);
}
controller->rxoicr;
@ -361,8 +376,6 @@ int qm_spi_transfer(const qm_spi_t spi, const qm_spi_transfer_t *const xfer,
uint8_t *rx_buffer = xfer->rx;
const uint8_t *tx_buffer = xfer->tx;
int frames;
/* RX Only transfers need a dummy byte to be sent for starting.
* This is covered by the databook on page 42.
*/
@ -381,33 +394,21 @@ int qm_spi_transfer(const qm_spi_t spi, const qm_spi_transfer_t *const xfer,
break;
}
while (i_rx && controller->rxflr) {
if (i_rx && (controller->sr & QM_SPI_SR_RFNE)) {
read_frame(spi, rx_buffer);
rx_buffer += dfs[spi];
i_rx--;
}
frames =
SPI_FIFOS_DEPTH - controller->txflr - controller->rxflr - 1;
while (i_tx && frames) {
if (i_tx && (controller->sr & QM_SPI_SR_TFNF)) {
write_frame(spi, tx_buffer);
tx_buffer += dfs[spi];
i_tx--;
frames--;
}
/* Databook page 43 says we always need to busy-wait until the
* controller is ready again after writing frames to the TX
* FIFO.
*
* That is only needed for TX or TX_RX transfer modes.
*/
if (tmode[spi] == QM_SPI_TMOD_TX_RX ||
tmode[spi] == QM_SPI_TMOD_TX) {
wait_for_controller(controller);
}
}
wait_for_controller(controller);
controller->ssienr = 0; /** Disable SPI Device */
controller->ssienr = 0; /* Disable SPI Device */
return rc;
}
@ -548,12 +549,10 @@ static void spi_dma_callback(void *callback_context, uint32_t len,
/* TX transfer. */
frames_expected = transfer->tx_len;
cb_pending_alternate_p = &dma_context_rx[spi].cb_pending;
} else if (dma_context_p == &dma_context_rx[spi]) {
/* RX tranfer. */
} else {
/* RX transfer. */
frames_expected = transfer->rx_len;
cb_pending_alternate_p = &dma_context_tx[spi].cb_pending;
} else {
return;
}
QM_ASSERT(cb_pending_alternate_p);
@ -598,7 +597,6 @@ int qm_spi_dma_channel_config(
QM_CHECK(dma_ctrl_id < QM_DMA_NUM, -EINVAL);
QM_CHECK(dma_channel_id < QM_DMA_CHANNEL_NUM, -EINVAL);
int ret = -EINVAL;
dma_context_t *dma_context_p = NULL;
qm_dma_channel_config_t dma_chan_cfg = {0};
dma_chan_cfg.handshake_polarity = QM_DMA_HANDSHAKE_POLARITY_HIGH;
@ -630,21 +628,14 @@ int qm_spi_dma_channel_config(
switch (dma_channel_direction) {
case QM_DMA_MEMORY_TO_PERIPHERAL:
switch (spi) {
case QM_SPI_MST_0:
dma_chan_cfg.handshake_interface =
DMA_HW_IF_SPI_MASTER_0_TX;
break;
#if (QUARK_SE)
case QM_SPI_MST_1:
dma_chan_cfg.handshake_interface =
DMA_HW_IF_SPI_MASTER_1_TX;
break;
dma_chan_cfg.handshake_interface =
(QM_SPI_MST_0 == spi) ? DMA_HW_IF_SPI_MASTER_0_TX
: DMA_HW_IF_SPI_MASTER_1_TX;
#else
dma_chan_cfg.handshake_interface = DMA_HW_IF_SPI_MASTER_0_TX;
#endif
default:
/* Slave SPI is not supported. */
return -EINVAL;
}
/* The DMA burst length has to fit in the space remaining in the
* TX FIFO after the watermark level, DMATDLR. */
@ -656,22 +647,14 @@ int qm_spi_dma_channel_config(
break;
case QM_DMA_PERIPHERAL_TO_MEMORY:
switch (spi) {
case QM_SPI_MST_0:
dma_chan_cfg.handshake_interface =
DMA_HW_IF_SPI_MASTER_0_RX;
break;
#if (QUARK_SE)
case QM_SPI_MST_1:
dma_chan_cfg.handshake_interface =
DMA_HW_IF_SPI_MASTER_1_RX;
break;
#endif
default:
/* Slave SPI is not supported. */
return -EINVAL;
}
#if (QUARK_SE)
dma_chan_cfg.handshake_interface =
(QM_SPI_MST_0 == spi) ? DMA_HW_IF_SPI_MASTER_0_RX
: DMA_HW_IF_SPI_MASTER_1_RX;
#else
dma_chan_cfg.handshake_interface = DMA_HW_IF_SPI_MASTER_0_RX;
#endif
/* The DMA burst length has to match the value of the receive
* watermark level, DMARDLR + 1. */
dma_chan_cfg.source_burst_length = SPI_DMA_READ_BURST_LENGTH;
@ -693,12 +676,6 @@ int qm_spi_dma_channel_config(
QM_ASSERT(dma_context_p);
dma_chan_cfg.callback_context = dma_context_p;
ret = qm_dma_channel_set_config(dma_ctrl_id, dma_channel_id,
&dma_chan_cfg);
if (ret) {
return ret;
}
/* To be used on received DMA callback. */
dma_context_p->spi_id = spi;
dma_context_p->dma_channel_id = dma_channel_id;
@ -706,7 +683,8 @@ int qm_spi_dma_channel_config(
/* To be used on transfer setup. */
dma_core[spi] = dma_ctrl_id;
return 0;
return qm_dma_channel_set_config(dma_ctrl_id, dma_channel_id,
&dma_chan_cfg);
}
int qm_spi_dma_transfer(const qm_spi_t spi,

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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;
/**

View file

@ -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.
*

View file

@ -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;

View file

@ -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);

View file

@ -26,14 +26,19 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include "qm_ss_i2c.h"
#include "clk.h"
#define SPK_LEN_SS (1)
#define SPK_LEN_FS (2)
#define TX_TL (2)
#define RX_TL (5)
#include <string.h>
#include "qm_ss_i2c.h"
#include "clk.h"
/* number of retries before giving up on disabling the controller */
#define I2C_POLL_COUNT (1000000)
#define I2C_POLL_MICROSECOND (1)
/*
* NOTE: There are a number of differences between this Sensor Subsystem I2C
@ -59,19 +64,22 @@
*/
static uint32_t i2c_base[QM_SS_I2C_NUM] = {QM_SS_I2C_0_BASE, QM_SS_I2C_1_BASE};
static qm_ss_i2c_transfer_t i2c_transfer[QM_SS_I2C_NUM];
static const qm_ss_i2c_transfer_t *i2c_transfer[QM_SS_I2C_NUM];
static uint32_t i2c_write_pos[QM_SS_I2C_NUM], i2c_read_pos[QM_SS_I2C_NUM],
i2c_read_buffer_remaining[QM_SS_I2C_NUM];
i2c_read_cmd_send[QM_SS_I2C_NUM];
static void controller_enable(const qm_ss_i2c_t i2c);
static void controller_disable(const qm_ss_i2c_t i2c);
static int controller_disable(const qm_ss_i2c_t i2c);
static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
{
const qm_ss_i2c_transfer_t *const transfer = i2c_transfer[i2c];
uint32_t controller = i2c_base[i2c], data_cmd = 0,
count_tx = (QM_SS_I2C_FIFO_SIZE - TX_TL);
qm_ss_i2c_status_t status = 0;
int rc = 0;
uint32_t read_buffer_remaining = transfer->rx_len - i2c_read_pos[i2c];
uint32_t write_buffer_remaining = transfer->tx_len - i2c_write_pos[i2c];
/* Check for errors */
QM_ASSERT(!(__builtin_arc_lr(controller + QM_SS_I2C_INTR_STAT) &
@ -101,27 +109,29 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
rc = (status & QM_I2C_TX_ABRT_USER_ABRT) ? -ECANCELED : -EIO;
if (i2c_transfer[i2c].callback) {
i2c_transfer[i2c].callback(
i2c_transfer[i2c].callback_data, rc, status, 0);
if (i2c_transfer[i2c]->callback) {
i2c_transfer[i2c]->callback(
i2c_transfer[i2c]->callback_data, rc, status, 0);
}
controller_disable(i2c);
}
/* RX read from buffer */
if ((__builtin_arc_lr(controller + QM_SS_I2C_INTR_STAT) &
QM_SS_I2C_INTR_STAT_RX_FULL)) {
while (i2c_read_buffer_remaining[i2c] &&
while (read_buffer_remaining &&
(__builtin_arc_lr(controller + QM_SS_I2C_RXFLR))) {
__builtin_arc_sr(QM_SS_I2C_DATA_CMD_POP,
controller + QM_SS_I2C_DATA_CMD);
/* IC_DATA_CMD[7:0] contains received data */
i2c_transfer[i2c].rx[i2c_read_pos[i2c]] =
i2c_transfer[i2c]->rx[i2c_read_pos[i2c]] =
__builtin_arc_lr(controller + QM_SS_I2C_DATA_CMD);
i2c_read_buffer_remaining[i2c]--;
read_buffer_remaining--;
i2c_read_pos[i2c]++;
if (i2c_read_buffer_remaining[i2c] == 0) {
if (read_buffer_remaining == 0) {
/* mask rx full interrupt if transfer
* complete
*/
@ -129,19 +139,19 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
(controller + QM_SS_I2C_INTR_MASK),
QM_SS_I2C_INTR_MASK_RX_FULL);
if (i2c_transfer[i2c].stop) {
if (i2c_transfer[i2c]->stop) {
controller_disable(i2c);
}
if (i2c_transfer[i2c].callback) {
i2c_transfer[i2c].callback(
i2c_transfer[i2c].callback_data, 0,
if (i2c_transfer[i2c]->callback) {
i2c_transfer[i2c]->callback(
i2c_transfer[i2c]->callback_data, 0,
QM_I2C_IDLE, i2c_read_pos[i2c]);
}
}
}
if (i2c_read_buffer_remaining[i2c] > 0 &&
i2c_read_buffer_remaining[i2c] < (RX_TL + 1)) {
if (read_buffer_remaining > 0 &&
read_buffer_remaining < (RX_TL + 1)) {
/* Adjust the RX threshold so the next 'RX_FULL'
* interrupt is generated when all the remaining
* data are received.
@ -149,7 +159,7 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_TL),
QM_SS_I2C_TL_RX_TL_MASK);
QM_SS_REG_AUX_OR((controller + QM_SS_I2C_TL),
(i2c_read_buffer_remaining[i2c] - 1));
(read_buffer_remaining - 1));
}
/* RX_FULL INTR is autocleared when the buffer
@ -162,9 +172,9 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
if ((__builtin_arc_lr(controller + QM_SS_I2C_STATUS) &
QM_SS_I2C_STATUS_TFE) &&
(i2c_transfer[i2c].tx != NULL) &&
(i2c_transfer[i2c].tx_len == 0) &&
(i2c_transfer[i2c].rx_len == 0)) {
(i2c_transfer[i2c]->tx != NULL) &&
(write_buffer_remaining == 0) &&
(read_buffer_remaining == 0)) {
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_INTR_MASK),
QM_SS_I2C_INTR_MASK_TX_EMPTY);
@ -172,34 +182,33 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
/* if this is not a combined
* transaction, disable the controller now
*/
if ((i2c_read_buffer_remaining[i2c] == 0) &&
i2c_transfer[i2c].stop) {
if (i2c_transfer[i2c]->stop) {
controller_disable(i2c);
/* callback */
if (i2c_transfer[i2c].callback) {
i2c_transfer[i2c].callback(
i2c_transfer[i2c].callback_data, 0,
QM_I2C_IDLE, i2c_write_pos[i2c]);
if (i2c_transfer[i2c]->callback) {
i2c_transfer[i2c]->callback(
i2c_transfer[i2c]->callback_data, 0,
QM_I2C_IDLE, i2c_write_pos[i2c]);
}
}
}
while ((count_tx) && i2c_transfer[i2c].tx_len) {
while ((count_tx) && write_buffer_remaining) {
count_tx--;
write_buffer_remaining--;
/* write command -IC_DATA_CMD[8] = 0 */
/* fill IC_DATA_CMD[7:0] with the data */
data_cmd = QM_SS_I2C_DATA_CMD_PUSH |
i2c_transfer[i2c].tx[i2c_write_pos[i2c]];
i2c_transfer[i2c].tx_len--;
i2c_transfer[i2c]->tx[i2c_write_pos[i2c]];
/* if transfer is a combined transfer, only
* send stop at
* end of the transfer sequence */
if (i2c_transfer[i2c].stop &&
(i2c_transfer[i2c].tx_len == 0) &&
(i2c_transfer[i2c].rx_len == 0)) {
if (i2c_transfer[i2c]->stop &&
(read_buffer_remaining == 0) &&
(write_buffer_remaining == 0)) {
data_cmd |= QM_SS_I2C_DATA_CMD_STOP;
}
@ -220,18 +229,17 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
(__builtin_arc_lr(controller + QM_SS_I2C_TXFLR) +
(__builtin_arc_lr(controller + QM_SS_I2C_RXFLR) + 1));
while (i2c_transfer[i2c].rx_len &&
(i2c_transfer[i2c].tx_len == 0) && count_tx) {
while (i2c_read_cmd_send[i2c] &&
(write_buffer_remaining == 0) && count_tx) {
count_tx--;
i2c_transfer[i2c].rx_len--;
i2c_read_cmd_send[i2c]--;
/* if transfer is a combined transfer, only
* send stop at
* end of
* the transfer sequence */
if (i2c_transfer[i2c].stop &&
(i2c_transfer[i2c].rx_len == 0) &&
(i2c_transfer[i2c].tx_len == 0)) {
if (i2c_transfer[i2c]->stop &&
(i2c_read_cmd_send[i2c] == 0)) {
__builtin_arc_sr((QM_SS_I2C_DATA_CMD_CMD |
QM_SS_I2C_DATA_CMD_PUSH |
@ -249,8 +257,8 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
/* generate a tx_empty interrupt when tx fifo is fully
* empty */
if ((i2c_transfer[i2c].tx_len == 0) &&
(i2c_transfer[i2c].rx_len == 0)) {
if ((write_buffer_remaining == 0) &&
(read_buffer_remaining == 0)) {
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_TL),
QM_SS_I2C_TL_TX_TL_MASK);
}
@ -297,7 +305,9 @@ int qm_ss_i2c_set_config(const qm_ss_i2c_t i2c,
controller + QM_SS_I2C_INTR_MASK);
/* disable controller */
controller_disable(i2c);
if (controller_disable(i2c)) {
return -EBUSY;
}
/* set mode */
con |= QM_SS_I2C_CON_RESTART_EN |
@ -379,7 +389,7 @@ int qm_ss_i2c_set_speed(const qm_ss_i2c_t i2c, const qm_ss_i2c_speed_t speed,
lo_cnt > QM_SS_I2C_IC_LCNT_MIN,
-EINVAL);
con &= ~QM_SS_I2C_CON_SPEED_MASK;
con &= ~(QM_SS_I2C_CON_SPEED_MASK | QM_SS_I2C_CON_SPKLEN_MASK);
full_cnt = (lo_cnt & QM_SS_I2C_SS_FS_SCL_CNT_16BIT_MASK) |
(hi_cnt & QM_SS_I2C_SS_FS_SCL_CNT_16BIT_MASK)
@ -387,12 +397,14 @@ int qm_ss_i2c_set_speed(const qm_ss_i2c_t i2c, const qm_ss_i2c_speed_t speed,
switch (speed) {
case QM_SS_I2C_SPEED_STD:
con |= QM_SS_I2C_CON_SPEED_SS;
con |= (QM_SS_I2C_CON_SPEED_SS |
(SPK_LEN_SS << QM_SS_I2C_CON_SPKLEN_OFFSET));
__builtin_arc_sr(full_cnt, controller + QM_SS_I2C_SS_SCL_CNT);
break;
case QM_SS_I2C_SPEED_FAST:
con |= QM_SS_I2C_CON_SPEED_FS;
con |= (QM_SS_I2C_CON_SPEED_FS |
(SPK_LEN_FS << QM_SS_I2C_CON_SPKLEN_OFFSET));
__builtin_arc_sr(full_cnt, controller + QM_SS_I2C_FS_SCL_CNT);
break;
}
@ -480,7 +492,9 @@ int qm_ss_i2c_master_write(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
/* disable controller */
if (true == stop) {
controller_disable(i2c);
if (controller_disable(i2c)) {
ret = -EBUSY;
}
}
if (status != NULL) {
@ -550,7 +564,8 @@ int qm_ss_i2c_master_read(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
/* wait until rx fifo is empty, indicating pop is complete*/
while ((__builtin_arc_lr(controller + QM_SS_I2C_STATUS) &
QM_SS_I2C_STATUS_RFNE));
QM_SS_I2C_STATUS_RFNE))
;
/* IC_DATA_CMD[7:0] contains received data */
*d = __builtin_arc_lr(controller + QM_SS_I2C_DATA_CMD);
@ -559,7 +574,9 @@ int qm_ss_i2c_master_read(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
/* disable controller */
if (true == stop) {
controller_disable(i2c);
if (controller_disable(i2c)) {
ret = -EBUSY;
}
}
if (status != NULL) {
@ -595,8 +612,8 @@ int qm_ss_i2c_master_irq_transfer(const qm_ss_i2c_t i2c,
i2c_write_pos[i2c] = 0;
i2c_read_pos[i2c] = 0;
i2c_read_buffer_remaining[i2c] = xfer->rx_len;
memcpy(&i2c_transfer[i2c], xfer, sizeof(i2c_transfer[i2c]));
i2c_read_cmd_send[i2c] = xfer->rx_len;
i2c_transfer[i2c] = xfer;
/* set threshold */
if (xfer->rx_len > 0 && xfer->rx_len < (RX_TL + 1)) {
@ -643,22 +660,30 @@ static void controller_enable(const qm_ss_i2c_t i2c)
QM_SS_I2C_ENABLE_STATUS_IC_EN))
;
}
/* Clear all interruption flags */
__builtin_arc_sr(QM_SS_I2C_INTR_CLR_ALL,
controller + QM_SS_I2C_INTR_CLR);
}
static void controller_disable(const qm_ss_i2c_t i2c)
static int controller_disable(const qm_ss_i2c_t i2c)
{
uint32_t controller = i2c_base[i2c];
if (__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
QM_SS_I2C_ENABLE_STATUS_IC_EN) {
/* disable controller */
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_CON),
QM_SS_I2C_CON_ENABLE);
int poll_count = I2C_POLL_COUNT;
/* wait until controller is disabled */
while ((__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
QM_SS_I2C_ENABLE_STATUS_IC_EN))
;
/* disable controller */
QM_SS_REG_AUX_NAND((controller + QM_SS_I2C_CON), QM_SS_I2C_CON_ENABLE);
/* wait until controller is disabled */
while ((__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
QM_SS_I2C_ENABLE_STATUS_IC_EN) &&
poll_count--) {
clk_sys_udelay(I2C_POLL_MICROSECOND);
}
/* returns 0 if ok, meaning controller is disabled */
return (__builtin_arc_lr(controller + QM_SS_I2C_ENABLE_STATUS) &
QM_SS_I2C_ENABLE_STATUS_IC_EN);
}
int qm_ss_i2c_irq_transfer_terminate(const qm_ss_i2c_t i2c)

View file

@ -38,13 +38,11 @@
static uint32_t base[QM_SS_SPI_NUM] = {QM_SS_SPI_0_BASE, QM_SS_SPI_1_BASE};
static const qm_ss_spi_async_transfer_t *transfer[QM_SS_SPI_NUM];
static const qm_ss_spi_async_transfer_t *spi_async_transfer[QM_SS_SPI_NUM];
static uint32_t rx_c[QM_SS_SPI_NUM];
static uint32_t tx_c[QM_SS_SPI_NUM];
static uint8_t *rx_p[QM_SS_SPI_NUM];
static uint8_t *tx_p[QM_SS_SPI_NUM];
static uint16_t dummy_frame;
static const uint16_t dummy_frame = 0;
/* Private Functions */
static void spi_disable(const qm_ss_spi_t spi)
@ -57,7 +55,7 @@ static void spi_disable(const qm_ss_spi_t spi)
__builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_CLR_INTR);
}
static __inline__ void fifo_write(const qm_ss_spi_t spi, void *data,
static __inline__ void fifo_write(const qm_ss_spi_t spi, const void *data,
uint8_t size)
{
uint32_t dr;
@ -211,7 +209,7 @@ int qm_ss_spi_transfer(const qm_ss_spi_t spi,
tx_cnt--;
}
}
/* Wait for last byte transfered */
/* Wait for last byte transferred */
while (__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY)
;
@ -231,20 +229,22 @@ int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi,
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
QM_SS_SPI_CTRL_TMOD_OFFS);
uint8_t bytes = BYTES_PER_FRAME(ctrl);
QM_CHECK(tmode == QM_SS_SPI_TMOD_TX_RX ? (xfer->tx_len == xfer->rx_len)
: 1,
-EINVAL);
transfer[spi] = xfer;
spi_async_transfer[spi] = xfer;
tx_c[spi] = xfer->tx_len;
rx_c[spi] = xfer->rx_len;
tx_p[spi] = xfer->tx;
rx_p[spi] = xfer->rx;
/* RX only transfers need a dummy frame byte to be sent. */
if (tmode == QM_SS_SPI_TMOD_RX) {
tx_p[spi] = (uint8_t *)&dummy_frame;
tx_c[spi] = 1;
/* Set NDF (Number of Data Frames) in RX or EEPROM Read mode. (-1) */
if (tmode == QM_SS_SPI_TMOD_RX || tmode == QM_SS_SPI_TMOD_EEPROM_READ) {
ctrl &= ~QM_SS_SPI_CTRL_NDF_MASK;
ctrl |= ((xfer->rx_len - 1) << QM_SS_SPI_CTRL_NDF_OFFS) &
QM_SS_SPI_CTRL_NDF_MASK;
__builtin_arc_sr(ctrl, base[spi] + QM_SS_SPI_CTRL);
}
uint32_t ftlr =
@ -256,35 +256,44 @@ int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi,
/* Unmask all interrupts */
__builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_INTR_MASK);
/* Enable SPI device */
QM_SS_REG_AUX_OR(base[spi] + QM_SS_SPI_SPIEN, QM_SS_SPI_SPIEN_EN);
/* RX only transfers need a dummy frame byte to be sent. */
if (tmode == QM_SS_SPI_TMOD_RX) {
fifo_write(spi, (uint8_t *)&dummy_frame, bytes);
}
return 0;
}
int qm_ss_spi_transfer_terminate(const qm_ss_spi_t spi)
{
QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL);
const qm_ss_spi_async_transfer_t *const transfer =
spi_async_transfer[spi];
spi_disable(spi);
if (transfer[spi]->callback) {
if (transfer->callback) {
uint32_t len = 0;
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
QM_SS_SPI_CTRL_TMOD_OFFS);
if (tmode == QM_SS_SPI_TMOD_TX ||
tmode == QM_SS_SPI_TMOD_TX_RX) {
len = transfer[spi]->tx_len - tx_c[spi];
len = transfer->tx_len - tx_c[spi];
} else {
len = transfer[spi]->rx_len - rx_c[spi];
len = transfer->rx_len - rx_c[spi];
}
/*
* NOTE: change this to return controller-specific code
* 'user aborted'.
*/
transfer[spi]->callback(transfer[spi]->data, -ECANCELED,
QM_SS_SPI_IDLE, (uint16_t)len);
transfer->callback(transfer->callback_data, -ECANCELED,
QM_SS_SPI_IDLE, (uint16_t)len);
}
return 0;
@ -293,14 +302,17 @@ int qm_ss_spi_transfer_terminate(const qm_ss_spi_t spi)
static void handle_spi_err_interrupt(const qm_ss_spi_t spi)
{
uint32_t intr_stat = __builtin_arc_lr(base[spi] + QM_SS_SPI_INTR_STAT);
spi_disable(spi);
QM_ASSERT((intr_stat &
(QM_SS_SPI_INTR_STAT_TXOI | QM_SS_SPI_INTR_STAT_RXFI)) == 0);
const qm_ss_spi_async_transfer_t *const transfer =
spi_async_transfer[spi];
if ((intr_stat & QM_SS_SPI_INTR_RXOI) && transfer[spi]->callback) {
transfer[spi]->callback(transfer[spi]->data, -EIO,
QM_SS_SPI_RX_OVERFLOW,
transfer[spi]->rx_len - rx_c[spi]);
spi_disable(spi);
QM_ASSERT((intr_stat & QM_SS_SPI_INTR_STAT_TXOI) == 0);
QM_ASSERT((intr_stat & QM_SS_SPI_INTR_STAT_RXUI) == 0);
if ((intr_stat & QM_SS_SPI_INTR_RXOI) && transfer->callback) {
transfer->callback(transfer->callback_data, -EIO,
QM_SS_SPI_RX_OVERFLOW,
transfer->rx_len - rx_c[spi]);
}
}
@ -314,14 +326,24 @@ static void handle_spi_tx_interrupt(const qm_ss_spi_t spi)
uint8_t bytes = BYTES_PER_FRAME(ctrl);
uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >>
QM_SS_SPI_CTRL_TMOD_OFFS);
const qm_ss_spi_async_transfer_t *const transfer =
spi_async_transfer[spi];
/* Jump to the right position of TX buffer.
* If no bytes were transmitted before, we start from the beginning,
* otherwise we jump to the next frame to be sent.
*/
const uint8_t *tx_buffer =
transfer->tx + ((transfer->tx_len - tx_c[spi]) * bytes);
if (tx_c[spi] == 0 &&
!(__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY)) {
if (tmode == QM_SS_SPI_TMOD_TX) {
spi_disable(spi);
if (transfer[spi]->callback) {
transfer[spi]->callback(transfer[spi]->data, 0,
QM_SS_SPI_IDLE,
transfer[spi]->tx_len);
if (transfer->callback) {
transfer->callback(transfer->callback_data, 0,
QM_SS_SPI_IDLE,
transfer->tx_len);
}
} else {
QM_SS_REG_AUX_NAND(base[spi] + QM_SS_SPI_INTR_MASK,
@ -334,8 +356,8 @@ static void handle_spi_tx_interrupt(const qm_ss_spi_t spi)
uint32_t txflr = __builtin_arc_lr(base[spi] + QM_SS_SPI_TXFLR);
int32_t cnt = FIFO_SIZE - rxflr - txflr - 1;
while (tx_c[spi] && cnt > 0) {
fifo_write(spi, tx_p[spi], bytes);
tx_p[spi] += bytes;
fifo_write(spi, tx_buffer, bytes);
tx_buffer += bytes;
tx_c[spi]--;
cnt--;
}
@ -349,10 +371,21 @@ static void handle_spi_rx_interrupt(const qm_ss_spi_t spi)
uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL);
/* Calculate number of bytes per frame (1 or 2)*/
uint8_t bytes = BYTES_PER_FRAME(ctrl);
const qm_ss_spi_async_transfer_t *const transfer =
spi_async_transfer[spi];
/*
* Jump to the right position of RX buffer.
* If no bytes were received before, we start from the beginning,
* otherwise we jump to the next available frame position.
*/
uint8_t *rx_buffer =
transfer->rx + ((transfer->rx_len - rx_c[spi]) * bytes);
while (__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_RFNE &&
rx_c[spi]) {
fifo_read(spi, rx_p[spi], bytes);
rx_p[spi] += bytes;
fifo_read(spi, rx_buffer, bytes);
rx_buffer += bytes;
rx_c[spi]--;
}
/* Set new FIFO threshold or complete transfer */
@ -366,10 +399,9 @@ static void handle_spi_rx_interrupt(const qm_ss_spi_t spi)
__builtin_arc_sr(ftlr, base[spi] + QM_SS_SPI_FTLR);
} else {
spi_disable(spi);
if (transfer[spi]->callback) {
transfer[spi]->callback(transfer[spi]->data, 0,
QM_SS_SPI_IDLE,
transfer[spi]->rx_len);
if (transfer->callback) {
transfer->callback(transfer->callback_data, 0,
QM_SS_SPI_IDLE, transfer->rx_len);
}
}
}

View file

@ -0,0 +1,44 @@
#
# Copyright (c) 2016, Intel Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. Neither the name of the Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
### Variables
SENSOR_DIR = $(BASE_DIR)/drivers/sensor
OBJ_DIRS += $(SENSOR_DIR)/$(BUILD)/$(SOC)/$(TARGET)
SENSOR_SOURCES = $(wildcard $(SENSOR_DIR)/*.c)
OBJECTS += $(addprefix $(DRV_DIR)/$(BUILD)/$(SOC)/$(TARGET)/$(OBJ)/,$(notdir $(SENSOR_SOURCES:.c=.o)))
### Flags
CFLAGS += -I$(SENSOR_DIR)
CFLAGS += -I$(SENSOR_DIR)/include
CFLAGS += -I$(BASE_DIR)/soc/$(SOC_ROOT_DIR)/include
### Build C files
$(DRV_DIR)/$(BUILD)/$(SOC)/$(TARGET)/$(OBJ)/%.o: $(SENSOR_DIR)/%.c
$(call mkdir, $(DRV_DIR)/$(BUILD)/$(SOC)/$(TARGET)/$(OBJ))
$(CC) $(CFLAGS) -c -o $@ $<

View file

@ -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);
}

View file

@ -0,0 +1,355 @@
/*
* Copyright (c) 2016, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* SoC Watch - QMSI power profiler
*/
#if (SOC_WATCH_ENABLE) && (!QM_SENSOR)
#include <x86intrin.h>
#include "qm_common.h"
#include "qm_soc_regs.h"
#include "qm_interrupt.h"
#include "soc_watch.h"
/*
* Define a macro for exposing some functions and other definitions
* only when unit testing. If we're not unit testing, then declare
* them as static, so that their declarations are hidden to normal
* code.
*/
#if (UNIT_TEST)
#define NONUTSTATIC
#else
#define NONUTSTATIC static
#endif
/**
* "Event strings" table, describing message structures.
* The first character is the event code to write to the data file.
* The 2nd and subsequent characters describe how to format the record's
* data. Note that the ordering here needs to agree with the
* enumeration list in qmsw_stub.h.
*
* Table characters:
* + First char = event code to write into the result file.
* + T = TSC Timestamp (Hi-res timestamp)
* + t = RTC Timestamp (lo-res timestamp)
* + 1 = interpret ev_data as a 1-byte value
* + 4 = interpret ev_data as a 4-byte value
* + R = Using ev_data as a register enumeration, read that register,
* + and put that 4-byte value into the data file.
* + L = Trigger an RTC timestamp Later
*/
NONUTSTATIC const char *ev_strs[] = {
"HT", /* Halt event */
"IT1", /* Interrupt event */
"STtL", /* Sleep event */
"RT1R", /* Register read event: Timestamp, reg enum, reg value*/
"UTs4", /* User event: timestamp, subtype, data value. */
};
/*
* This list of registers corresponds to the SoC Watch register ID
* enumeration in soc_watch.h, and MUST STAY IN AGREEMENT with that
* list, since that enumeration is used to index this list.
*
* To record a register value, the SoC Watch code indexes into this
* array, and reads the corresponding address found in that slot.
*/
#if (QUARK_D2000)
static const uint32_t *platform_regs[] = {
(uint32_t *)(&QM_SCSS_CCU->osc0_cfg1),
(uint32_t *)(&QM_SCSS_CCU->ccu_lp_clk_ctl),
(uint32_t *)(&QM_SCSS_CCU->ccu_sys_clk_ctl),
/* Clock Gating Registers */
(uint32_t *)(&QM_SCSS_CCU->ccu_periph_clk_gate_ctl),
(uint32_t *)(&QM_SCSS_CCU->ccu_ext_clock_ctl),
/* Power Consumption regs */
(uint32_t *)(&QM_SCSS_CMP->cmp_pwr),
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup),
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew),
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en)};
#elif(QUARK_SE)
static const uint32_t *platform_regs[] = {
(uint32_t *)(&QM_SCSS_CCU->osc0_cfg1),
(uint32_t *)(&QM_SCSS_CCU->ccu_lp_clk_ctl),
(uint32_t *)(&QM_SCSS_CCU->ccu_sys_clk_ctl),
/* Clock Gating Registers */
(uint32_t *)(&QM_SCSS_CCU->ccu_periph_clk_gate_ctl),
(uint32_t *)(&QM_SCSS_CCU->ccu_ss_periph_clk_gate_ctl),
(uint32_t *)(&QM_SCSS_CCU->ccu_ext_clock_ctl),
/* Power Consumption regs */
(uint32_t *)(&QM_SCSS_CMP->cmp_pwr), (uint32_t *)(&QM_SCSS_PMU->slp_cfg),
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup),
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup[1]),
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup[2]),
(uint32_t *)(&QM_SCSS_PMUX->pmux_pullup[3]),
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew),
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew[1]),
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew[2]),
(uint32_t *)(&QM_SCSS_PMUX->pmux_slew[3]),
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en),
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en[1]),
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en[2]),
(uint32_t *)(&QM_SCSS_PMUX->pmux_in_en[3])};
#endif /* QUARK_SE */
/* Define VERBOSE to turn on printf-based logging */
#ifdef VERBOSE
#define SOC_WATCH_TRACE QM_PRINTF
#else
#define SOC_WATCH_TRACE(...)
#endif
/*
* mlog routines -- low-level memory debug logging.
* Only enable if there's a need to debug this module.
*/
#ifdef MLOG_ENABLE
#define MLOG(e) mlog(e)
#define MLOG_BYTE(b) mlog_byte(b)
#define MLOG_SIZE 512 /* Must be a power of 2 */
static uint8_t mlog_events[MLOG_SIZE];
static uint16_t mlog_idx = 0;
void mlog(uint8_t event)
{
mlog_events[++mlog_idx % (MLOG_SIZE)] = event;
}
void mlog_byte(uint8_t byte)
{
const char c[] = {"0123456789ABCDEF"};
MLOG(c[byte >> 4]);
MLOG(c[byte & 4]);
}
#else /* !MLOG_ENABLE */
#define MLOG(event)
#define MLOG_BYTE(b)
#endif /* !MLOG_ENABLE */
/*
* CONFIGURABLE: Set this to control the number of bytes of RAM you
* want to dedicate to event buffering. The larger the buffer,
* the fewer (expensive) flushes we will have to do. The smaller,
* the lower the memory cost, but the more flushes you will do.
*/
#define SOC_WATCH_EVENT_BUFFER_SIZE (256) /* Measured in bytes */
/**
* Power profiling event data buffer. Symbol must be globally
* visible, so that it can be seen by external tools.
*/
struct sw_profiling_event_buffer {
uint8_t eb_idx; /* Index of next byte to be written */
uint8_t eb_size; /* Buffer size == SOC_WATCH_EVENT_BUFFER_SIZE */
uint8_t event_data[SOC_WATCH_EVENT_BUFFER_SIZE - 2]; /* Event data -
sizeof(idx + size) */
} soc_watch_event_buffer = {0, SOC_WATCH_EVENT_BUFFER_SIZE - 1, {0}};
/* High water mark, i.e. "start trying to flush" point. */
#define SW_EB_HIGH_WATER (((SOC_WATCH_EVENT_BUFFER_SIZE - 2) * 7) >> 3)
NONUTSTATIC int soc_watch_buffer_full(void)
{
return (soc_watch_event_buffer.eb_idx >= SW_EB_HIGH_WATER);
}
/**
* Flag used by the JTAG data extraction routine. During setup, a HW
* watchpoint is placed on this address. During the flush routine,
* software writes to it, causing the HW watchpoint to fire, and
* OpenOCD to extract the data. This symbol MUST be globally visible
* in order for JTAG data transfer to work.
*/
volatile uint8_t soc_watch_flush_flag = 0;
/*
* soc_watch_event_buffer_flush -- Trigger the data buffer flush.
*/
static void soc_watch_event_buffer_flush(void)
{
/* Figure out if we can successfully flush the data out.
* If we're sleeping, the JTAG query will fail.
*/
#if (QUARK_D2000)
/**
* If the "we're going to sleep" bit is set, parts of the
* SOC are already asleep, and transferring data over
* the JTAG port is not always reliable. So defer transferring
* the data until later.
* @TODO: Determine if there is also a sensitivity to the
* clock rate.
*/
MLOG('F');
if (QM_SCSS_PMU->aon_vr & QM_AON_VR_VREG_SEL) {
MLOG('-');
return; /* We would only send junk, so don't flush. */
}
#endif
soc_watch_flush_flag = 1; /* Trigger the data extract brkpt */
soc_watch_event_buffer.eb_idx = 0;
MLOG('+');
}
/* Store a byte in the event buffer. */
static void eb_write_char(uint8_t data)
{
SOC_WATCH_TRACE("c%d:0x%x [0]=%x\n", soc_watch_event_buffer.eb_idx,
data, soc_watch_event_buffer.event_data[0]);
soc_watch_event_buffer.event_data[soc_watch_event_buffer.eb_idx++] =
data;
}
/* Store a word in the event buffer. */
static void eb_write_uint32(uint32_t *data)
{
uint32_t *uip = (uint32_t *)&soc_watch_event_buffer
.event_data[soc_watch_event_buffer.eb_idx];
*uip = *data;
SOC_WATCH_TRACE("I%d:0x%x\n", soc_watch_event_buffer.eb_idx, *data);
soc_watch_event_buffer.eb_idx += sizeof(uint32_t);
}
/* Log an event with one parameter. */
void soc_watch_log_event(soc_watch_event_t event_id, uintptr_t ev_data)
{
soc_watch_log_app_event(event_id, 0, ev_data);
}
/*
* Log an event with two parameters, where the subtype comes from
* the user. Note that what actually makes this an 'application event' is
* the event_id, not the fact that it is coming in via this interface.
*/
void soc_watch_log_app_event(soc_watch_event_t event_id, uint8_t ev_subtype,
uintptr_t ev_data)
{
static uint8_t record_rtc = 0;
const uint32_t *rtc_ctr = (uint32_t *)&QM_RTC->rtc_ccr;
const char *cp;
uint64_t tsc = __builtin_ia32_rdtsc(); /* Grab hi-res timestamp */
uint32_t rtc_val = *rtc_ctr;
#define AVG_EVENT_SIZE 8 /* Size of a typical message in bytes. */
MLOG('[');
qm_irq_disable();
/* TODO: We know exactly how many bytes of storage we need,
* since we know the event code. So don't do an "AVG" size thing
* here--use the exact size!
*/
if ((soc_watch_event_buffer.eb_idx + AVG_EVENT_SIZE) <=
soc_watch_event_buffer.eb_size) {
/* Map a halt event to a sleep event where appropriate. */
#if (QUARK_D2000)
if (event_id == SOCW_EVENT_HALT) {
if (QM_SCSS_PMU->aon_vr & QM_AON_VR_VREG_SEL) {
event_id = SOCW_EVENT_SLEEP;
}
}
#endif
/* Record the RTC of the waking event, if it's rousing us from
* sleep. */
if (record_rtc) {
eb_write_char('t');
eb_write_uint32((uint32_t *)(&rtc_val)); /* Timestamp */
record_rtc = 0;
}
if (event_id >= SOCW_EVENT_MAX) {
SOC_WATCH_TRACE("Unknown event id: 0x%x\n", event_id);
MLOG('?');
qm_irq_enable();
return;
}
cp = ev_strs[event_id]; /* Look up event string */
SOC_WATCH_TRACE("%c", *cp);
MLOG(*cp);
eb_write_char(*cp); /* Write event code */
while (*++cp) {
switch (*cp) {
case 'T':
eb_write_uint32((uint32_t *)(&tsc)); /* Hi-res
Timestamp */
break;
case 't':
eb_write_uint32(
(uint32_t *)(&rtc_val)); /* Lo-res
Timestamp */
break;
case 'L':
record_rtc = 1;
break;
case 'R': /* Register data value */
eb_write_uint32(
(uint32_t *)platform_regs[ev_data]);
break;
case '4': /* 32-bit data value */
eb_write_uint32((uint32_t *)&ev_data);
break;
case '1':
/* Register ID */
eb_write_char(((uint32_t)ev_data) & 0xff);
break;
case 's':
/* Event subtype */
eb_write_char(((uint32_t)ev_subtype) & 0xff);
break;
default:
SOC_WATCH_TRACE(
"Unknown string char: 0x%x on string "
"0x%x\n",
*cp, event_id);
break;
}
}
}
/*
* If this is an interrupt which roused the CPU out of a sleep state,
* don't flush the buffer. (Due to a bug in OpenOCD, doing so will
* clear the HW watchpoint, ensuring no further flushes are seen by
* OpenOCD.)
*/
if ((soc_watch_buffer_full()) && (event_id != SOCW_EVENT_INTERRUPT)) {
SOC_WATCH_TRACE("\n --- FLUSH: idx= %d ---\n",
soc_watch_event_buffer.eb_idx);
soc_watch_event_buffer_flush();
}
MLOG(':');
MLOG_BYTE(soc_watch_event_buffer.eb_idx);
qm_irq_enable();
MLOG(']');
}
#endif /* !(defined(SOC_WATCH) && (!QM_SENSOR)) */

View file

@ -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__ */

View file

@ -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__ */

View file

@ -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;
}

View file

@ -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 */
/**
* @}
*/

View file

@ -40,12 +40,20 @@
* @{
*/
/**
* Wake source for deep sleep mode type.
*/
typedef enum {
POWER_WAKE_FROM_GPIO_COMP, /**< Use GPIO / Comparator as wake source. */
POWER_WAKE_FROM_RTC, /**< Use RTC as wake source. */
} power_wake_event_t;
/**
* Put CPU in halt state.
*
* Halts the CPU until next interrupt or reset.
*/
void cpu_halt(void);
void power_cpu_halt(void);
/**
* Put SoC to sleep.
@ -68,15 +76,19 @@ void cpu_halt(void);
* - RTC
* - Low power comparators
*/
void soc_sleep();
void power_soc_sleep();
/**
* Put SoC to deep sleep.
*
* Enter into deep sleep mode. All clocks are gated. The only way to return
* from this is to have an interrupt trigger on the low power comparators.
* Enter into deep sleep mode. All clocks are gated. The Wake source for this
* function depends on the input parameter, POWER_WAKE_FROM_GPIO_COMP will
* enable waking from GPIO or comparator pins and POWER_WAKE_FROM_RTC will
* enable waking from the RTC.
*
* @param[in] wake_source Select wake source for deep sleep mode.
*/
void soc_deep_sleep();
void power_soc_deep_sleep(const power_wake_event_t wake_event);
/**
* @}

View file

@ -33,10 +33,10 @@
#include "qm_common.h"
/**
* Quark Microcontroller D2000 Register file.
*
* @brief Quark Microcontroller D2000 Registers.
* Quark D2000 SoC Registers.
*
* @defgroup groupQUARKD2000SEREG SoC Registers (D2000)
* @{
*/
#define QUARK_D2000 (1)
@ -44,10 +44,11 @@
#define HAS_MVIC (1)
/**
* @defgroup groupD2000REG Quark D2000 Registers
@{
* @name System Core
* @{
*/
/** System Core register map. */
typedef struct {
QM_RW uint32_t osc0_cfg0; /**< Hybrid Oscillator Configuration 0 */
QM_RW uint32_t osc0_stat1; /**< Hybrid Oscillator status 1 */
@ -79,7 +80,6 @@ qm_scss_ccu_reg_t test_scss_ccu;
#else
#define QM_SCSS_CCU_BASE (0xB0800000)
/** system control subsystem clock control unit register block */
#define QM_SCSS_CCU ((qm_scss_ccu_reg_t *)QM_SCSS_CCU_BASE)
#endif
@ -88,16 +88,16 @@ qm_scss_ccu_reg_t test_scss_ccu;
#define QM_OSC0_PD BIT(2)
#define QM_OSC1_PD BIT(1)
/* Enable Crystal oscillator*/
/* Enable Crystal oscillator. */
#define QM_OSC0_EN_CRYSTAL BIT(0)
/* Crystal oscillator parameters */
/* Crystal oscillator parameters. */
#define OSC0_CFG1_OSC0_FADJ_XTAL_MASK (0x000F0000)
#define OSC0_CFG1_OSC0_FADJ_XTAL_OFFS (16)
#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_MASK (0x00600000)
#define OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_OFFS (21)
/* Silicon Oscillator parameters */
/* Silicon Oscillator parameters. */
#define OSC0_CFG1_FTRIMOTP_MASK (0x3FF00000)
#define OSC0_CFG1_FTRIMOTP_OFFS (20)
#define OSC0_CFG1_SI_FREQ_SEL_MASK (0x00000300)
@ -106,36 +106,44 @@ qm_scss_ccu_reg_t test_scss_ccu;
#define QM_OSC0_LOCK_SI BIT(0)
#define QM_OSC0_LOCK_XTAL BIT(1)
#define QM_OSC0_EN_SI_OSC BIT(1)
#define QM_SI_OSC_1V2_MODE BIT(0)
/** Peripheral clock divider control */
#define QM_CCU_PERIPH_PCLK_DIV_OFFSET (1)
#define QM_CCU_PERIPH_PCLK_DIV_EN BIT(0)
/* System clock control */
#define QM_CCU_SYS_CLK_SEL BIT(0)
#define QM_CCU_PERIPH_CLK_EN BIT(1)
#define QM_CCU_ADC_CLK_DIV_OFFSET (16)
#define QM_CCU_ADC_CLK_DIV_DEF_MASK (0xFC00FFFF)
#define QM_CCU_PERIPH_PCLK_DIV_DEF_MASK (0xFFFFFFF8)
#define QM_CCU_PERIPH_PCLK_DIV_OFFSET (1)
#define QM_CCU_PERIPH_PCLK_DIV_EN BIT(0)
#define QM_CCU_RTC_CLK_EN BIT(1)
#define QM_CCU_RTC_CLK_DIV_EN BIT(2)
#define QM_CCU_SYS_CLK_DIV_EN BIT(7)
#define QM_CCU_SYS_CLK_DIV_MASK (0x00000700)
#define QM_CCU_SYS_CLK_DIV_DEF_MASK (0xFFFFF47F)
#define QM_OSC0_SI_FREQ_SEL_DEF_MASK (0xFFFFFCFF)
#define QM_CCU_SYS_CLK_DIV_DEF_MASK (0xFFFFF47F)
#define QM_OSC0_SI_FREQ_SEL_4MHZ (3 >> 8)
#define QM_CCU_RTC_CLK_DIV_EN BIT(2)
#define QM_CCU_EXTERN_DIV_OFFSET (3)
#define QM_CCU_EXT_CLK_DIV_EN BIT(2)
#define QM_CCU_GPIO_DB_DIV_OFFSET (2)
#define QM_CCU_GPIO_DB_CLK_DIV_EN BIT(1)
#define QM_CCU_GPIO_DB_CLK_EN BIT(0)
#define QM_CCU_RTC_CLK_DIV_OFFSET (3)
#define QM_CCU_SYS_CLK_DIV_OFFSET (8)
#define QM_CCU_RTC_CLK_EN BIT(1)
#define QM_CCU_GPIO_DB_CLK_DIV_DEF_MASK (0xFFFFFFE1)
#define QM_CCU_EXT_CLK_DIV_DEF_MASK (0xFFFFFFE3)
#define QM_CCU_RTC_CLK_DIV_DEF_MASK (0xFFFFFF83)
#define QM_CCU_DMA_CLK_EN BIT(6)
#define QM_CCU_WAKE_MASK_RTC_BIT BIT(2)
#define QM_CCU_WAKE_MASK_GPIO_BIT BIT(15)
#define QM_CCU_WAKE_MASK_COMPARATOR_BIT BIT(14)
#define QM_CCU_WAKE_MASK_GPIO_BIT BIT(15)
#define QM_CCU_GPIO_DB_CLK_EN BIT(0)
#define QM_HYB_OSC_PD_LATCH_EN BIT(14)
#define QM_RTC_OSC_PD_LATCH_EN BIT(15)
#define QM_CCU_EXIT_TO_HYBOSC BIT(4)
@ -144,16 +152,24 @@ qm_scss_ccu_reg_t test_scss_ccu;
#define QM_WAKE_PROBE_MODE_MASK BIT(13)
/** @} */
/**
* @name General Purpose
* @{
*/
/** General Purpose register map. */
typedef struct {
QM_RW uint32_t gps0; /**< General Purpose Sticky Registers */
QM_RW uint32_t gps1; /**< General Purpose Sticky Registers */
QM_RW uint32_t gps2; /**< General Purpose Sticky Registers */
QM_RW uint32_t gps3; /**< General Purpose Sticky Registers */
QM_RW uint32_t gps0; /**< General Purpose Sticky Register 0 */
QM_RW uint32_t gps1; /**< General Purpose Sticky Register 1 */
QM_RW uint32_t gps2; /**< General Purpose Sticky Register 2 */
QM_RW uint32_t gps3; /**< General Purpose Sticky Register 3 */
QM_RW uint32_t reserved;
QM_RW uint32_t gp0; /**< General Purpose Scratchpad Registers */
QM_RW uint32_t gp1; /**< General Purpose Scratchpad Registers */
QM_RW uint32_t gp2; /**< General Purpose Scratchpad Registers */
QM_RW uint32_t gp3; /**< General Purpose Scratchpad Registers */
QM_RW uint32_t gp0; /**< General Purpose Scratchpad Register 0 */
QM_RW uint32_t gp1; /**< General Purpose Scratchpad Register 1 */
QM_RW uint32_t gp2; /**< General Purpose Scratchpad Register 2 */
QM_RW uint32_t gp3; /**< General Purpose Scratchpad Register 3 */
QM_RW uint32_t reserved1[3];
QM_RW uint32_t wo_sp; /**< Write-One-to-Set Scratchpad Register */
QM_RW uint32_t
@ -166,21 +182,28 @@ qm_scss_gp_reg_t test_scss_gp;
#else
#define QM_SCSS_GP_BASE (0xB0800100)
/** system control subsystem general purpose register block */
#define QM_SCSS_GP ((qm_scss_gp_reg_t *)QM_SCSS_GP_BASE)
#endif
#define QM_SCSS_GP_POWER_STATES_MASK (BIT(6) | BIT(7) | BIT(8) | BIT(9))
#define QM_SCSS_GP_POWER_STATE_DEEP_SLEEP BIT(6)
/** @} */
/**
* @name Comparator
* @{
*/
/** Comparator register map. */
typedef struct {
QM_RW uint32_t cmp_en; /**< Comparator enable */
QM_RW uint32_t cmp_ref_sel; /**< Comparator reference select */
QM_RW uint32_t cmp_en; /**< Comparator enable. */
QM_RW uint32_t cmp_ref_sel; /**< Comparator reference select. */
QM_RW uint32_t
cmp_ref_pol; /**< Comparator reference polarity select register */
QM_RW uint32_t cmp_pwr; /**< Comparator power enable register */
cmp_ref_pol; /**< Comparator reference polarity select register. */
QM_RW uint32_t cmp_pwr; /**< Comparator power enable register. */
QM_RW uint32_t reserved[6];
QM_RW uint32_t cmp_stat_clr; /**< Comparator clear register */
QM_RW uint32_t cmp_stat_clr; /**< Comparator clear register. */
} qm_scss_cmp_reg_t;
#if (UNIT_TEST)
@ -189,12 +212,19 @@ qm_scss_cmp_reg_t test_scss_cmp;
#else
#define QM_SCSS_CMP_BASE (0xB0800300)
/** system control subsystem comparators register block */
#define QM_SCSS_CMP ((qm_scss_cmp_reg_t *)QM_SCSS_CMP_BASE)
#endif
#define QM_AC_HP_COMPARATORS_MASK (0x7FFC0)
/** @} */
/**
* @name Interrupt
* @{
*/
/** Interrupt register map. */
typedef struct {
QM_RW uint32_t int_i2c_mst_0_mask; /**< Interrupt Routing Mask 0 */
QM_RW uint32_t reserved[2]; /* There is a hole in the address space. */
@ -244,17 +274,23 @@ qm_scss_int_reg_t test_scss_int;
#else
#define QM_SCSS_INT_BASE (0xB0800448)
/** system control subsystem Interrupt masking register block */
#define QM_SCSS_INT ((qm_scss_int_reg_t *)QM_SCSS_INT_BASE)
#endif
#define QM_INT_TIMER_HOST_HALT_MASK BIT(0)
#define QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK BIT(16)
#define QM_INT_SRAM_CONTROLLER_HOST_MASK BIT(0)
#define QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK BIT(16)
#define QM_INT_FLASH_CONTROLLER_HOST_MASK BIT(0)
/** @} */
/**
* @name Power Management
* @{
*/
/** Power Management register map. */
typedef struct {
QM_RW uint32_t aon_vr; /**< AON Voltage Regulator */
QM_RW uint32_t reserved[5];
@ -274,12 +310,18 @@ qm_scss_pmu_reg_t test_scss_pmu;
#else
#define QM_SCSS_PMU_BASE (0xB0800540)
/** system control subsystem power management register block */
#define QM_SCSS_PMU ((qm_scss_pmu_reg_t *)QM_SCSS_PMU_BASE)
#endif
#define QM_P_STS_HALT_INTERRUPT_REDIRECTION BIT(26)
/** @} */
/**
* @name Always-on controllers.
* @{
*/
#define QM_AON_VR_ROK_BUF_VREG_MASK BIT(9)
#define QM_AON_VR_VREG_SEL BIT(8)
#define QM_AON_VR_PASS_CODE (0x9DC4 << 16)
@ -288,20 +330,19 @@ qm_scss_pmu_reg_t test_scss_pmu;
#define QM_AON_VR_VSEL_1V8 (0x10)
#define QM_AON_VR_VSTRB BIT(5)
/**
* Number of SCSS Always on controllers.
*/
/** Number of SCSS Always-on controllers. */
typedef enum { QM_SCSS_AON_0 = 0, QM_SCSS_AON_NUM } qm_scss_aon_t;
/** Always-on Controller register map. */
typedef struct {
QM_RW uint32_t aonc_cnt; /**< Always on counter register */
QM_RW uint32_t aonc_cfg; /**< Always on counter enable */
QM_RW uint32_t aonpt_cnt; /**< Always on periodic timer */
QM_RW uint32_t aonc_cnt; /**< Always-on counter register. */
QM_RW uint32_t aonc_cfg; /**< Always-on counter enable. */
QM_RW uint32_t aonpt_cnt; /**< Always-on periodic timer. */
QM_RW uint32_t
aonpt_stat; /**< Always on periodic timer status register */
QM_RW uint32_t aonpt_ctrl; /**< Always on periodic timer control */
aonpt_stat; /**< Always-on periodic timer status register. */
QM_RW uint32_t aonpt_ctrl; /**< Always-on periodic timer control. */
QM_RW uint32_t
aonpt_cfg; /**< Always on periodic timer configuration register */
aonpt_cfg; /**< Always-on periodic timer configuration register. */
} qm_scss_aon_reg_t;
#if (UNIT_TEST)
@ -310,10 +351,17 @@ qm_scss_aon_reg_t test_scss_aon;
#else
#define QM_SCSS_AON_BASE (0xB0800700)
/** system control subsystem always on register block */
#define QM_SCSS_AON ((qm_scss_aon_reg_t *)QM_SCSS_AON_BASE)
#endif
/** @} */
/**
* @name Peripheral Registers
* @{
*/
/** Peripheral Registers register map. */
typedef struct {
QM_RW uint32_t periph_cfg0; /**< Peripheral Configuration */
QM_RW uint32_t reserved[2];
@ -326,10 +374,17 @@ qm_scss_peripheral_reg_t test_scss_peripheral;
#else
#define QM_SCSS_PERIPHERAL_BASE (0xB0800804)
/** system control subsystem peripheral register block */
#define QM_SCSS_PERIPHERAL ((qm_scss_peripheral_reg_t *)QM_SCSS_PERIPHERAL_BASE)
#endif
/** @} */
/**
* @name Pin MUX
* @{
*/
/** Pin MUX register map. */
typedef struct {
QM_RW uint32_t pmux_pullup[1]; /**< Pin Mux Pullup */
QM_RW uint32_t reserved[3];
@ -352,10 +407,17 @@ qm_scss_pmux_reg_t test_scss_pmux;
#else
#define QM_SCSS_PMUX_BASE (0xB0800900)
/** system control subsystem pin muxing register block */
#define QM_SCSS_PMUX ((qm_scss_pmux_reg_t *)QM_SCSS_PMUX_BASE)
#endif
/** @} */
/**
* @name ID
* @{
*/
/** Information register map. */
typedef struct {
QM_RW uint32_t id; /**< Identification Register */
QM_RW uint32_t rev; /**< Revision Register */
@ -371,11 +433,17 @@ qm_scss_info_reg_t test_scss_info;
#else
#define QM_SCSS_INFO_BASE (0xB0801000)
/** system control subsystem pin muxing register block */
#define QM_SCSS_INFO ((qm_scss_info_reg_t *)QM_SCSS_INFO_BASE)
#endif
/** IRQs and interrupt vectors.
/** @} */
/**
* @name IRQs and Interrupts
* @{
*/
/* IRQs and interrupt vectors.
*
* The vector numbers must be defined without arithmetic expressions nor
* parentheses because they are expanded as token concatenation.
@ -383,93 +451,93 @@ qm_scss_info_reg_t test_scss_info;
#define QM_INT_VECTOR_DOUBLE_FAULT 8
#define QM_IRQ_RTC_0 (2)
#define QM_IRQ_RTC_0_MASK_OFFSET (12)
#define QM_IRQ_RTC_0 2
#define QM_IRQ_RTC_0_MASK_OFFSET 12
#define QM_IRQ_RTC_0_VECTOR 34
#define QM_IRQ_AONPT_0 (3)
#define QM_IRQ_AONPT_0_MASK_OFFSET (32)
#define QM_IRQ_AONPT_0 3
#define QM_IRQ_AONPT_0_MASK_OFFSET 32
#define QM_IRQ_AONPT_0_VECTOR 35
#define QM_IRQ_SPI_MASTER_0 (7)
#define QM_IRQ_SPI_MASTER_0_MASK_OFFSET (3)
#define QM_IRQ_SPI_MASTER_0_VECTOR 39
#define QM_IRQ_PWM_0 (11)
#define QM_IRQ_PWM_0_MASK_OFFSET (10)
#define QM_IRQ_PWM_0 11
#define QM_IRQ_PWM_0_MASK_OFFSET 10
#define QM_IRQ_PWM_0_VECTOR 43
#define QM_IRQ_AC (14)
#define QM_IRQ_AC_MASK_OFFSET (26)
#define QM_IRQ_AC_VECTOR 46
#define QM_IRQ_SPI_MASTER_0 7
#define QM_IRQ_SPI_MASTER_0_MASK_OFFSET 3
#define QM_IRQ_SPI_MASTER_0_VECTOR 39
#define QM_IRQ_ADC_0 (9)
#define QM_IRQ_ADC_0_MASK_OFFSET (34)
#define QM_IRQ_ADC_0 9
#define QM_IRQ_ADC_0_MASK_OFFSET 34
#define QM_IRQ_ADC_0_VECTOR 41
#define QM_IRQ_ADC_PWR_0 (19)
#define QM_IRQ_ADC_PWR_0_MASK_OFFSET (33)
#define QM_IRQ_ADC_PWR_0 19
#define QM_IRQ_ADC_PWR_0_MASK_OFFSET 33
#define QM_IRQ_ADC_PWR_0_VECTOR 51
#define QM_IRQ_WDT_0 (16)
#define QM_IRQ_WDT_0_MASK_OFFSET (13)
#define QM_IRQ_WDT_0 16
#define QM_IRQ_WDT_0_MASK_OFFSET 13
#define QM_IRQ_WDT_0_VECTOR 48
#define QM_IRQ_GPIO_0 (15)
#define QM_IRQ_GPIO_0_MASK_OFFSET (9)
#define QM_IRQ_GPIO_0 15
#define QM_IRQ_GPIO_0_MASK_OFFSET 9
#define QM_IRQ_GPIO_0_VECTOR 47
#define QM_IRQ_I2C_0 (4)
#define QM_IRQ_I2C_0_MASK_OFFSET (0)
#define QM_IRQ_I2C_0 4
#define QM_IRQ_I2C_0_MASK_OFFSET 0
#define QM_IRQ_I2C_0_VECTOR 36
#define QM_IRQ_PIC_TIMER (10)
#define QM_IRQ_PIC_TIMER 10
/* No SCSS mask register for PIC timer: point to an unused register */
#define QM_IRQ_PIC_TIMER_MASK_OFFSET (1)
#define QM_IRQ_PIC_TIMER_MASK_OFFSET 1
#define QM_IRQ_PIC_TIMER_VECTOR 42
#define QM_IRQ_SRAM (17)
#define QM_IRQ_SRAM_MASK_OFFSET (29)
#define QM_IRQ_AC 14
#define QM_IRQ_AC_MASK_OFFSET 26
#define QM_IRQ_AC_VECTOR 46
#define QM_IRQ_SRAM 17
#define QM_IRQ_SRAM_MASK_OFFSET 29
#define QM_IRQ_SRAM_VECTOR 49
#define QM_IRQ_FLASH_0 (18)
#define QM_IRQ_FLASH_0_MASK_OFFSET (30)
#define QM_IRQ_FLASH_0 18
#define QM_IRQ_FLASH_0_MASK_OFFSET 30
#define QM_IRQ_FLASH_0_VECTOR 50
#define QM_IRQ_UART_0 (8)
#define QM_IRQ_UART_0_MASK_OFFSET (6)
#define QM_IRQ_UART_0 8
#define QM_IRQ_UART_0_MASK_OFFSET 6
#define QM_IRQ_UART_0_VECTOR 40
#define QM_IRQ_UART_1 (6)
#define QM_IRQ_UART_1_MASK_OFFSET (7)
#define QM_IRQ_UART_1 6
#define QM_IRQ_UART_1_MASK_OFFSET 7
#define QM_IRQ_UART_1_VECTOR 38
#define QM_IRQ_DMA_0 (13)
#define QM_IRQ_DMA_0_MASK_OFFSET (14)
#define QM_IRQ_DMA_0 13
#define QM_IRQ_DMA_0_MASK_OFFSET 14
#define QM_IRQ_DMA_0_VECTOR 45
#define QM_IRQ_DMA_1 (12)
#define QM_IRQ_DMA_1_MASK_OFFSET (15)
#define QM_IRQ_DMA_1 12
#define QM_IRQ_DMA_1_MASK_OFFSET 15
#define QM_IRQ_DMA_1_VECTOR 44
#define QM_IRQ_DMA_ERR (0)
#define QM_IRQ_DMA_ERR_MASK_OFFSET (28)
#define QM_IRQ_DMA_ERR 0
#define QM_IRQ_DMA_ERR_MASK_OFFSET 28
#define QM_IRQ_DMA_ERR_VECTOR 32
/** @} */
/**
* Number of PWM/Timer controllers.
* @name PWM / Timer
* @{
*/
/** Number of PWM / Timer controllers. */
typedef enum { QM_PWM_0 = 0, QM_PWM_NUM } qm_pwm_t;
/**
* PWM id type.
*/
/** PWM ID type. */
typedef enum { QM_PWM_ID_0 = 0, QM_PWM_ID_1, QM_PWM_ID_NUM } qm_pwm_id_t;
/**
* PWM / Timer register map.
*/
/** PWM / Timer channel register map. */
typedef struct {
QM_RW uint32_t loadcount; /**< Load Count */
QM_RW uint32_t currentvalue; /**< Current Value */
@ -478,6 +546,7 @@ typedef struct {
QM_RW uint32_t intstatus; /**< Interrupt Status */
} qm_pwm_channel_t;
/** PWM / Timer register map. */
typedef struct {
qm_pwm_channel_t timer[QM_PWM_ID_NUM]; /**< 4 Timers */
QM_RW uint32_t reserved[30];
@ -501,14 +570,17 @@ qm_pwm_reg_t test_pwm_t;
#define QM_PWM_INTERRUPT_MASK_OFFSET (2)
/**
* Number of WDT controllers.
*/
typedef enum { QM_WDT_0 = 0, QM_WDT_NUM } qm_wdt_t;
/** @} */
/**
* Watchdog timer register block type.
* @name WDT
* @{
*/
/** Number of WDT controllers. */
typedef enum { QM_WDT_0 = 0, QM_WDT_NUM } qm_wdt_t;
/** Watchdog timer register map. */
typedef struct {
QM_RW uint32_t wdt_cr; /**< Control Register */
QM_RW uint32_t wdt_torr; /**< Timeout Range Register */
@ -538,15 +610,17 @@ qm_wdt_reg_t test_wdt;
#define QM_WDT ((qm_wdt_reg_t *)QM_WDT_BASE)
#endif
/** @} */
/**
* Number of UART controllers.
* @name UART
* @{
*/
/** Number of UART controllers. */
typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t;
/**
* UART register block type.
*/
/** UART register map. */
typedef struct {
QM_RW uint32_t rbr_thr_dll; /**< Rx Buffer/ Tx Holding/ Div Latch Low */
QM_RW uint32_t ier_dlh; /**< Interrupt Enable / Divisor Latch High */
@ -587,14 +661,17 @@ extern qm_uart_reg_t *qm_uart[QM_UART_NUM];
#define QM_UART qm_uart
#endif
/**
* Number of SPI controllers.
*/
typedef enum { QM_SPI_MST_0 = 0, QM_SPI_SLV_0 = 1, QM_SPI_NUM } qm_spi_t;
/** @} */
/**
* SPI register block type
* @name SPI
* @{
*/
/** Number of SPI controllers. */
typedef enum { QM_SPI_MST_0 = 0, QM_SPI_SLV_0 = 1, QM_SPI_NUM } qm_spi_t;
/** SPI register map. */
typedef struct {
QM_RW uint32_t ctrlr0; /**< Control Register 0 */
QM_RW uint32_t ctrlr1; /**< Control Register 1 */
@ -658,6 +735,8 @@ extern qm_spi_reg_t *qm_spi_controllers[QM_SPI_NUM];
#define QM_SPI_SR_BUSY BIT(0)
#define QM_SPI_SR_TFNF BIT(1)
#define QM_SPI_SR_TFE BIT(2)
#define QM_SPI_SR_RFNE BIT(3)
#define QM_SPI_SR_RFF BIT(4)
/* SPI Interrupt Mask register */
#define QM_SPI_IMR_MASK_ALL (0x00)
@ -685,14 +764,17 @@ extern qm_spi_reg_t *qm_spi_controllers[QM_SPI_NUM];
#define QM_SPI_DMACR_RDMAE BIT(0)
#define QM_SPI_DMACR_TDMAE BIT(1)
/**
* Number of RTC controllers.
*/
typedef enum { QM_RTC_0 = 0, QM_RTC_NUM } qm_rtc_t;
/** @} */
/**
* QM RTC Register block type.
* @name RTC
* @{
*/
/** Number of RTC controllers. */
typedef enum { QM_RTC_0 = 0, QM_RTC_NUM } qm_rtc_t;
/** RTC register map. */
typedef struct {
QM_RW uint32_t rtc_ccvr; /**< Current Counter Value Register */
QM_RW uint32_t rtc_cmr; /**< Current Match Register */
@ -709,18 +791,24 @@ qm_rtc_reg_t test_rtc;
#define QM_RTC ((qm_rtc_reg_t *)(&test_rtc))
#else
/** RTC register base address */
/** RTC register base address. */
#define QM_RTC_BASE (0xB0000400)
/** RTC register block */
/** RTC register block. */
#define QM_RTC ((qm_rtc_reg_t *)QM_RTC_BASE)
#endif
/** @} */
/**
* Number of I2C controllers.
* @name I2C
* @{
*/
/** Number of I2C controllers. */
typedef enum { QM_I2C_0 = 0, QM_I2C_NUM } qm_i2c_t;
/** I2C register map. */
typedef struct {
QM_RW uint32_t ic_con; /**< Control Register */
QM_RW uint32_t ic_tar; /**< Master Target Address */
@ -785,10 +873,10 @@ qm_i2c_reg_t *test_i2c[QM_I2C_NUM];
#define QM_I2C test_i2c
#else
/** I2C Master register base address */
/** I2C Master register base address. */
#define QM_I2C_0_BASE (0xB0002800)
/** I2C register block */
/** I2C register block. */
extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM];
#define QM_I2C qm_i2c
#endif
@ -810,6 +898,7 @@ extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM];
#define QM_I2C_IC_DATA_CMD_READ BIT(8)
#define QM_I2C_IC_DATA_CMD_STOP_BIT_CTRL BIT(9)
#define QM_I2C_IC_DATA_CMD_LSB_MASK (0x000000FF)
#define QM_I2C_IC_RAW_INTR_STAT_RX_FULL BIT(2)
#define QM_I2C_IC_RAW_INTR_STAT_TX_ABRT BIT(6)
#define QM_I2C_IC_TX_ABRT_SOURCE_NAK_MASK (0x1F)
#define QM_I2C_IC_TX_ABRT_SOURCE_ARB_LOST BIT(12)
@ -845,14 +934,17 @@ extern qm_i2c_reg_t *qm_i2c[QM_I2C_NUM];
#define QM_I2C_IC_DMA_CR_RX_ENABLE BIT(0)
#define QM_I2C_IC_DMA_CR_TX_ENABLE BIT(1)
/**
* Number of GPIO controllers.
*/
typedef enum { QM_GPIO_0 = 0, QM_GPIO_NUM } qm_gpio_t;
/** @} */
/**
* GPIO register block type.
* @name GPIO
* @{
*/
/** Number of GPIO controllers. */
typedef enum { QM_GPIO_0 = 0, QM_GPIO_NUM } qm_gpio_t;
/** GPIO register map. */
typedef struct {
QM_RW uint32_t gpio_swporta_dr; /**< Port A Data */
QM_RW uint32_t gpio_swporta_ddr; /**< Port A Data Direction */
@ -883,6 +975,7 @@ qm_gpio_reg_t *test_gpio[QM_GPIO_NUM];
#define QM_GPIO test_gpio
#else
/** GPIO register base address */
#define QM_GPIO_BASE (0xB0000C00)
@ -891,14 +984,17 @@ extern qm_gpio_reg_t *qm_gpio[QM_GPIO_NUM];
#define QM_GPIO qm_gpio
#endif
/**
* Number of ADC controllers.
*/
typedef enum { QM_ADC_0 = 0, QM_ADC_NUM } qm_adc_t;
/** @} */
/**
* ADC register block type.
*/
* @name ADC
* @{
*/
/** Number of ADC controllers. */
typedef enum { QM_ADC_0 = 0, QM_ADC_NUM } qm_adc_t;
/** ADC register map. */
typedef struct {
QM_RW uint32_t adc_seq0; /**< ADC Channel Sequence Table Entry 0 */
QM_RW uint32_t adc_seq1; /**< ADC Channel Sequence Table Entry 1 */
@ -960,14 +1056,17 @@ qm_adc_reg_t test_adc;
#define QM_ADC_OP_MODE_DELAY_MASK (0xFFF8)
#define QM_ADC_OP_MODE_OM_MASK (0x7)
/**
* Number of Flash controllers.
*/
typedef enum { QM_FLASH_0 = 0, QM_FLASH_NUM } qm_flash_t;
/** @} */
/**
* Flash register block type.
* @name Flash
* @{
*/
/** Number of Flash controllers. */
typedef enum { QM_FLASH_0 = 0, QM_FLASH_NUM } qm_flash_t;
/** Flash register map. */
typedef struct {
QM_RW uint32_t tmg_ctrl; /**< TMG_CTRL */
QM_RW uint32_t rom_wr_ctrl; /**< ROM_WR_CTRL */
@ -1001,7 +1100,7 @@ uint8_t test_flash_page[0x800];
#define QM_FLASH_MAX_ADDR (0xFFFFFFFF)
#else
/** Flash physical address mappings */
/* Flash physical address mappings */
#define QM_FLASH_REGION_DATA_0_BASE (0x00200000)
#define QM_FLASH_REGION_SYS_0_BASE (0x00180000)
#define QM_FLASH_REGION_OTP_0_BASE (0x00000000)
@ -1009,12 +1108,13 @@ uint8_t test_flash_page[0x800];
#define QM_FLASH_PAGE_MASK (0xF800)
#define QM_FLASH_MAX_ADDR (0x8000)
/** Flash controller register base address */
/** Flash controller register base address. */
#define QM_FLASH_BASE_0 (0xB0100000)
/** Flash controller register block */
/** Flash controller register block. */
extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM];
#define QM_FLASH qm_flash
#endif
#define QM_FLASH_REGION_DATA_BASE_OFFSET (0x04)
@ -1024,9 +1124,14 @@ extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM];
(QM_FLASH_MAX_ADDR / (4 * QM_FLASH_PAGE_SIZE_DWORDS))
#define QM_FLASH_LVE_MODE BIT(5)
/** @} */
/**
* Memory Protection Region register block type.
* @name Memory Protection Region
* @{
*/
/** Memory Protection Region register map. */
typedef struct {
QM_RW uint32_t mpr_cfg[4]; /**< MPR CFG */
QM_RW uint32_t mpr_vdata; /**< MPR_VDATA */
@ -1054,14 +1159,20 @@ qm_mpr_reg_t test_mpr;
#define QM_MPR_UP_BOUND_OFFSET (10)
#define QM_MPR_VSTS_VALID BIT(31)
/** @} */
/**
* @name PIC
* @{
*/
/** PIC timer register structure. */
typedef struct {
QM_RW uint32_t reg;
QM_RW uint32_t pad[3];
} pic_timer_reg_pad_t;
/**
* PIC timer register block type.
*/
/** PIC timer register map. */
typedef struct {
QM_RW pic_timer_reg_pad_t lvttimer; /**< Local Vector Table Timer */
QM_RW pic_timer_reg_pad_t reserved[5];
@ -1074,19 +1185,66 @@ qm_pic_timer_reg_t test_pic_timer;
#define QM_PIC_TIMER ((qm_pic_timer_reg_t *)(&test_pic_timer))
#else
/** PIC timer */
/** PIC timer base address. */
#define QM_PIC_TIMER_BASE (0xFEE00320)
#define QM_PIC_TIMER ((qm_pic_timer_reg_t *)QM_PIC_TIMER_BASE)
#endif
/** @} */
/**
* MVIC register block type.
* @name Peripheral Clock
* @{
*/
/** Peripheral clock register map. */
typedef enum {
CLK_PERIPH_REGISTER = BIT(0), /**< Peripheral Clock Gate Enable. */
CLK_PERIPH_CLK = BIT(1), /**< Peripheral Clock Enable. */
CLK_PERIPH_I2C_M0 = BIT(2), /**< I2C Master 0 Clock Enable. */
CLK_PERIPH_SPI_S = BIT(4), /**< SPI Slave Clock Enable. */
CLK_PERIPH_SPI_M0 = BIT(5), /**< SPI Master 0 Clock Enable. */
CLK_PERIPH_GPIO_INTERRUPT = BIT(7), /**< GPIO Interrupt Clock Enable. */
CLK_PERIPH_GPIO_DB = BIT(8), /**< GPIO Debounce Clock Enable. */
CLK_PERIPH_WDT_REGISTER = BIT(10), /**< Watchdog Clock Enable. */
CLK_PERIPH_RTC_REGISTER = BIT(11), /**< RTC Clock Gate Enable. */
CLK_PERIPH_PWM_REGISTER = BIT(12), /**< PWM Clock Gate Enable. */
CLK_PERIPH_GPIO_REGISTER = BIT(13), /**< GPIO Clock Gate Enable. */
CLK_PERIPH_SPI_M0_REGISTER =
BIT(14), /**< SPI Master 0 Clock Gate Enable. */
CLK_PERIPH_SPI_S_REGISTER =
BIT(16), /**< SPI Slave Clock Gate Enable. */
CLK_PERIPH_UARTA_REGISTER = BIT(17), /**< UARTA Clock Gate Enable. */
CLK_PERIPH_UARTB_REGISTER = BIT(18), /**< UARTB Clock Gate Enable. */
CLK_PERIPH_I2C_M0_REGISTER =
BIT(19), /**< I2C Master 0 Clock Gate Enable. */
CLK_PERIPH_ADC = BIT(22), /**< ADC Clock Enable. */
CLK_PERIPH_ADC_REGISTER = BIT(23), /**< ADC Clock Gate Enable. */
CLK_PERIPH_ALL = 0xCFFFFF /**< Quark D2000 peripherals Enable. */
} clk_periph_t;
/* Default mask values */
#define CLK_EXTERN_DIV_DEF_MASK (0xFFFFFFE3)
#define CLK_SYS_CLK_DIV_DEF_MASK (0xFFFFF87F)
#define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83)
#define CLK_GPIO_DB_DIV_DEF_MASK (0xFFFFFFE1)
#define CLK_ADC_DIV_DEF_MASK (0xFC00FFFF)
#define CLK_PERIPH_DIV_DEF_MASK (0xFFFFFFF9)
/** @} */
/**
* @name MVIC
* @{
*/
/** MVIC register structure. */
typedef struct {
QM_RW uint32_t reg;
QM_RW uint32_t pad[3];
} mvic_reg_pad_t;
/** MVIC register map. */
typedef struct {
QM_RW mvic_reg_pad_t tpr; /**< Task priority*/
QM_RW mvic_reg_pad_t reserved;
@ -1113,7 +1271,7 @@ qm_mvic_reg_t test_mvic;
#define QM_MVIC ((qm_mvic_reg_t *)(&test_mvic))
#else
/** Quark Microcontroller D2000 Interrupt Controller */
/** Interrupt Controller base address. */
#define QM_MVIC_BASE (0xFEE00080)
#define QM_MVIC ((qm_mvic_reg_t *)QM_MVIC_BASE)
#endif
@ -1142,28 +1300,27 @@ qm_ioapic_reg_t test_ioapic;
#define QM_IOAPIC ((qm_ioapic_reg_t *)QM_IOAPIC_BASE)
#endif
/** DMA */
/** @} */
/**
* DMA instances
* @name DMA
* @{
*/
/** DMA instances. */
typedef enum {
QM_DMA_0, /**< DMA controller id. */
QM_DMA_NUM /**< Number of DMA controllers. */
} qm_dma_t;
/**
* DMA channel IDs
*/
/** DMA channel IDs. */
typedef enum {
QM_DMA_CHANNEL_0 = 0, /**< DMA channel id for channel 0 */
QM_DMA_CHANNEL_1, /**< DMA channel id for channel 1 */
QM_DMA_CHANNEL_NUM /**< Number of DMA channels */
} qm_dma_channel_id_t;
/**
* DMA hardware handshake interfaces
*/
/** DMA hardware handshake interfaces. */
typedef enum {
DMA_HW_IF_UART_A_TX = 0x0, /**< UART_A_TX */
DMA_HW_IF_UART_A_RX = 0x1, /**< UART_A_RX */
@ -1177,9 +1334,7 @@ typedef enum {
DMA_HW_IF_I2C_MASTER_0_RX = 0xd, /**< I2C_Master_0_RX */
} qm_dma_handshake_interface_t;
/**
* DMA channel register block type
*/
/** DMA channel register map. */
typedef struct {
QM_RW uint32_t sar_low; /**< SAR */
QM_RW uint32_t sar_high; /**< SAR */
@ -1205,7 +1360,7 @@ typedef struct {
QM_RW uint32_t dst_sg_high; /**< DSR */
} qm_dma_chan_reg_t;
/** DMA channel control register offsets and masks */
/* DMA channel control register offsets and masks. */
#define QM_DMA_CTL_L_INT_EN_MASK BIT(0)
#define QM_DMA_CTL_L_DST_TR_WIDTH_OFFSET (1)
#define QM_DMA_CTL_L_DST_TR_WIDTH_MASK (0x7 << QM_DMA_CTL_L_DST_TR_WIDTH_OFFSET)
@ -1228,7 +1383,7 @@ typedef struct {
#define QM_DMA_CTL_H_BLOCK_TS_MAX 4095
#define QM_DMA_CTL_H_BLOCK_TS_MIN 1
/** DMA channel config register offsets and masks */
/* DMA channel config register offsets and masks. */
#define QM_DMA_CFG_L_CH_SUSP_MASK BIT(8)
#define QM_DMA_CFG_L_FIFO_EMPTY_MASK BIT(9)
#define QM_DMA_CFG_L_HS_SEL_DST_OFFSET 10
@ -1246,9 +1401,7 @@ typedef struct {
#define QM_DMA_CFG_H_DEST_PER_OFFSET (11)
#define QM_DMA_CFG_H_DEST_PER_MASK (0xf << QM_DMA_CFG_H_DEST_PER_OFFSET)
/**
* DMA interrupt register block type
*/
/** DMA interrupt register map. */
typedef struct {
QM_RW uint32_t raw_tfr_low; /**< RawTfr */
QM_RW uint32_t raw_tfr_high; /**< RawTfr */
@ -1294,13 +1447,11 @@ typedef struct {
QM_RW uint32_t status_int_high; /**< StatusInt */
} qm_dma_int_reg_t;
/** DMA interrupt status register bits */
/* DMA interrupt status register bits. */
#define QM_DMA_INT_STATUS_TFR BIT(0)
#define QM_DMA_INT_STATUS_ERR BIT(4)
/**
* DMA miscellaneous register block type
*/
/** DMA miscellaneous register map. */
typedef struct {
QM_RW uint32_t cfg_low; /**< DmaCfgReg */
QM_RW uint32_t cfg_high; /**< DmaCfgReg */
@ -1313,10 +1464,10 @@ typedef struct {
QM_RW uint32_t reserved[4]; /**< Reserved */
} qm_dma_misc_reg_t;
/** Channel write enable in the misc channel enable register */
/** Channel write enable in the misc channel enable register. */
#define QM_DMA_MISC_CHAN_EN_WE_OFFSET (8)
/** Controller enable bit in the misc config register */
/** Controller enable bit in the misc config register. */
#define QM_DMA_MISC_CFG_DMA_EN BIT(0)
typedef struct {
@ -1336,45 +1487,13 @@ extern qm_dma_reg_t *qm_dma[QM_DMA_NUM];
#define QM_DMA qm_dma
#endif
/**
* Peripheral clock type.
*/
typedef enum {
CLK_PERIPH_REGISTER = BIT(0), /**< Peripheral Clock Gate Enable. */
CLK_PERIPH_CLK = BIT(1), /**< Peripheral Clock Enable. */
CLK_PERIPH_I2C_M0 = BIT(2), /**< I2C Master 0 Clock Enable. */
CLK_PERIPH_SPI_S = BIT(4), /**< SPI Slave Clock Enable. */
CLK_PERIPH_SPI_M0 = BIT(5), /**< SPI Master 0 Clock Enable. */
CLK_PERIPH_GPIO_INTERRUPT = BIT(7), /**< GPIO Interrupt Clock Enable. */
CLK_PERIPH_GPIO_DB = BIT(8), /**< GPIO Debounce Clock Enable. */
CLK_PERIPH_WDT_REGISTER = BIT(10), /**< Watchdog Clock Enable. */
CLK_PERIPH_RTC_REGISTER = BIT(11), /**< RTC Clock Gate Enable. */
CLK_PERIPH_PWM_REGISTER = BIT(12), /**< PWM Clock Gate Enable. */
CLK_PERIPH_GPIO_REGISTER = BIT(13), /**< GPIO Clock Gate Enable. */
CLK_PERIPH_SPI_M0_REGISTER =
BIT(14), /**< SPI Master 0 Clock Gate Enable. */
CLK_PERIPH_SPI_S_REGISTER =
BIT(16), /**< SPI Slave Clock Gate Enable. */
CLK_PERIPH_UARTA_REGISTER = BIT(17), /**< UARTA Clock Gate Enable. */
CLK_PERIPH_UARTB_REGISTER = BIT(18), /**< UARTB Clock Gate Enable. */
CLK_PERIPH_I2C_M0_REGISTER =
BIT(19), /**< I2C Master 0 Clock Gate Enable. */
CLK_PERIPH_ADC = BIT(22), /**< ADC Clock Enable. */
CLK_PERIPH_ADC_REGISTER = BIT(23), /**< ADC Clock Gate Enable. */
CLK_PERIPH_ALL = 0xCFFFFF /**< Quark D2000 peripherals Enable. */
} clk_periph_t;
/* Default mask values */
#define CLK_EXTERN_DIV_DEF_MASK (0xFFFFFFE3)
#define CLK_SYS_CLK_DIV_DEF_MASK (0xFFFFF87F)
#define CLK_RTC_DIV_DEF_MASK (0xFFFFFF83)
#define CLK_GPIO_DB_DIV_DEF_MASK (0xFFFFFFE1)
#define CLK_ADC_DIV_DEF_MASK (0xFC00FFFF)
#define CLK_PERIPH_DIV_DEF_MASK (0xFFFFFFF9)
/** @} */
/**
* Version variables.
* @name Versioning
* @{
*/
#if (UNIT_TEST)
uint32_t test_rom_version;
#define ROM_VERSION_ADDRESS &test_rom_version;
@ -1382,7 +1501,8 @@ uint32_t test_rom_version;
#define ROM_VERSION_ADDRESS (0x1FFC);
#endif
/**
@}
*/
/** @} */
/** @} */
#endif /* __REGISTERS_H__ */

View file

@ -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

View file

@ -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 */
/**
* @}
*/

View file

@ -234,6 +234,7 @@ typedef enum {
#define QM_SS_I2C_TL_RX_TL_MASK (0xFF)
#define QM_SS_I2C_TL_TX_TL_MASK (0xFF0000)
#define QM_SS_I2C_INTR_CLR_ALL (0xFF)
#define QM_SS_I2C_INTR_CLR_TX_ABRT BIT(6)
#define QM_SS_I2C_TX_ABRT_SOURCE_NAK_MASK (0x09)
@ -358,7 +359,7 @@ typedef enum {
#define QM_SS_ADC_CAL_VAL_GET_OFFSET (5)
#define QM_SS_ADC_CAL_VAL_GET_MASK (0xFE0)
#define QM_SS_ADC_CAL_ACK BIT(4)
#define QM_SS_ADC_PWR_MODE_STS BIT(3) /*FIXME doesnt match doc */
#define QM_SS_ADC_PWR_MODE_STS BIT(3)
#define SS_CLK_PERIPH_ALL_IN_CREG \
(SS_CLK_PERIPH_ADC | SS_CLK_PERIPH_I2C_1 | SS_CLK_PERIPH_I2C_0 | \
@ -391,62 +392,62 @@ typedef enum {
* #define QM_SS_xxx - irq number
* #define QM_SS_xxx_VECTOR - vector number
*/
#define QM_SS_INT_TIMER_0 (16)
#define QM_SS_INT_TIMER_1 (17)
#define QM_SS_INT_TIMER_0 16
#define QM_SS_INT_TIMER_1 17
#define QM_SS_IRQ_ADC_ERR (0)
#define QM_SS_IRQ_ADC_ERR_VECTOR (18)
#define QM_SS_IRQ_ADC_ERR 0
#define QM_SS_IRQ_ADC_ERR_VECTOR 18
#define QM_SS_IRQ_ADC_IRQ (1)
#define QM_SS_IRQ_ADC_IRQ_VECTOR (19)
#define QM_SS_IRQ_ADC_IRQ 1
#define QM_SS_IRQ_ADC_IRQ_VECTOR 19
#define QM_SS_IRQ_GPIO_INTR_0 (2)
#define QM_SS_IRQ_GPIO_INTR_0_VECTOR (20)
#define QM_SS_IRQ_GPIO_INTR_0 2
#define QM_SS_IRQ_GPIO_INTR_0_VECTOR 20
#define QM_SS_IRQ_GPIO_INTR_1 (3)
#define QM_SS_IRQ_GPIO_INTR_1_VECTOR (21)
#define QM_SS_IRQ_GPIO_INTR_1 3
#define QM_SS_IRQ_GPIO_INTR_1_VECTOR 21
#define QM_SS_IRQ_I2C_0_ERR (4)
#define QM_SS_IRQ_I2C_0_ERR_VECTOR (22)
#define QM_SS_IRQ_I2C_0_ERR 4
#define QM_SS_IRQ_I2C_0_ERR_VECTOR 22
#define QM_SS_IRQ_I2C_0_RX_AVAIL (5)
#define QM_SS_IRQ_I2C_0_RX_AVAIL_VECTOR (23)
#define QM_SS_IRQ_I2C_0_RX_AVAIL 5
#define QM_SS_IRQ_I2C_0_RX_AVAIL_VECTOR 23
#define QM_SS_IRQ_I2C_0_TX_REQ (6)
#define QM_SS_IRQ_I2C_0_TX_REQ_VECTOR (24)
#define QM_SS_IRQ_I2C_0_TX_REQ 6
#define QM_SS_IRQ_I2C_0_TX_REQ_VECTOR 24
#define QM_SS_IRQ_I2C_0_STOP_DET (7)
#define QM_SS_IRQ_I2C_0_STOP_DET_VECTOR (25)
#define QM_SS_IRQ_I2C_0_STOP_DET 7
#define QM_SS_IRQ_I2C_0_STOP_DET_VECTOR 25
#define QM_SS_IRQ_I2C_1_ERR (8)
#define QM_SS_IRQ_I2C_1_ERR_VECTOR (26)
#define QM_SS_IRQ_I2C_1_ERR 8
#define QM_SS_IRQ_I2C_1_ERR_VECTOR 26
#define QM_SS_IRQ_I2C_1_RX_AVAIL (9)
#define QM_SS_IRQ_I2C_1_RX_AVAIL_VECTOR (27)
#define QM_SS_IRQ_I2C_1_RX_AVAIL 9
#define QM_SS_IRQ_I2C_1_RX_AVAIL_VECTOR 27
#define QM_SS_IRQ_I2C_1_TX_REQ (10)
#define QM_SS_IRQ_I2C_1_TX_REQ_VECTOR (28)
#define QM_SS_IRQ_I2C_1_TX_REQ 10
#define QM_SS_IRQ_I2C_1_TX_REQ_VECTOR 28
#define QM_SS_IRQ_I2C_1_STOP_DET (11)
#define QM_SS_IRQ_I2C_1_STOP_DET_VECTOR (29)
#define QM_SS_IRQ_I2C_1_STOP_DET 11
#define QM_SS_IRQ_I2C_1_STOP_DET_VECTOR 29
#define QM_SS_IRQ_SPI_0_ERR_INT (12)
#define QM_SS_IRQ_SPI_0_ERR_INT_VECTOR (30)
#define QM_SS_IRQ_SPI_0_ERR_INT 12
#define QM_SS_IRQ_SPI_0_ERR_INT_VECTOR 30
#define QM_SS_IRQ_SPI_0_RX_AVAIL (13)
#define QM_SS_IRQ_SPI_0_RX_AVAIL_VECTOR (31)
#define QM_SS_IRQ_SPI_0_RX_AVAIL 13
#define QM_SS_IRQ_SPI_0_RX_AVAIL_VECTOR 31
#define QM_SS_IRQ_SPI_0_TX_REQ (14)
#define QM_SS_IRQ_SPI_0_TX_REQ_VECTOR (32)
#define QM_SS_IRQ_SPI_0_TX_REQ 14
#define QM_SS_IRQ_SPI_0_TX_REQ_VECTOR 32
#define QM_SS_IRQ_SPI_1_ERR_INT (15)
#define QM_SS_IRQ_SPI_1_ERR_INT_VECTOR (33)
#define QM_SS_IRQ_SPI_1_ERR_INT 15
#define QM_SS_IRQ_SPI_1_ERR_INT_VECTOR 33
#define QM_SS_IRQ_SPI_1_RX_AVAIL (16)
#define QM_SS_IRQ_SPI_1_RX_AVAIL_VECTOR (34)
#define QM_SS_IRQ_SPI_1_RX_AVAIL 16
#define QM_SS_IRQ_SPI_1_RX_AVAIL_VECTOR 34
#define QM_SS_IRQ_SPI_1_TX_REQ (17)
#define QM_SS_IRQ_SPI_1_TX_REQ_VECTOR (35)
#define QM_SS_IRQ_SPI_1_TX_REQ 17
#define QM_SS_IRQ_SPI_1_TX_REQ_VECTOR 35
typedef enum {
QM_SS_INT_PRIORITY_0 = 0,
@ -468,7 +469,7 @@ typedef enum {
#define QM_SS_AUX_IRQ_STATUS (0x406)
#define QM_SS_AUX_IRQ_SELECT (0x40B)
#define QM_SS_AUX_IRQ_ENABLE (0x40C)
#define QM_SS_AUX_IRQ_TRIGER (0x40D)
#define QM_SS_AUX_IRQ_TRIGGER (0x40D)
/** @} */

File diff suppressed because it is too large Load diff