258 lines
6.0 KiB
C
258 lines
6.0 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <device.h>
|
|
#include <xtensa_api.h>
|
|
#include <xtensa/xtruntime.h>
|
|
#include <board.h>
|
|
#include <irq_nextlevel.h>
|
|
#include <xtensa/hal.h>
|
|
#include <init.h>
|
|
|
|
#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL
|
|
#include <logging/log.h>
|
|
LOG_MODULE_REGISTER(soc);
|
|
|
|
static u32_t ref_clk_freq;
|
|
|
|
void _soc_irq_enable(u32_t irq)
|
|
{
|
|
struct device *dev_cavs, *dev_ictl;
|
|
|
|
switch (XTENSA_IRQ_NUMBER(irq)) {
|
|
case CAVS_ICTL_0_IRQ:
|
|
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_0_NAME);
|
|
break;
|
|
case CAVS_ICTL_1_IRQ:
|
|
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_1_NAME);
|
|
break;
|
|
case CAVS_ICTL_2_IRQ:
|
|
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_2_NAME);
|
|
break;
|
|
case CAVS_ICTL_3_IRQ:
|
|
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_3_NAME);
|
|
break;
|
|
default:
|
|
/* regular interrupt */
|
|
_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
|
|
return;
|
|
}
|
|
|
|
if (!dev_cavs) {
|
|
LOG_DBG("board: CAVS device binding failed");
|
|
return;
|
|
}
|
|
|
|
/* If the control comes here it means the specified interrupt
|
|
* is in either CAVS interrupt logic or DW interrupt controller
|
|
*/
|
|
_xtensa_irq_enable(XTENSA_IRQ_NUMBER(irq));
|
|
|
|
switch (CAVS_IRQ_NUMBER(irq)) {
|
|
case DW_ICTL_IRQ_CAVS_OFFSET:
|
|
dev_ictl = device_get_binding(CONFIG_DW_ICTL_NAME);
|
|
break;
|
|
default:
|
|
/* The source of the interrupt is in CAVS interrupt logic */
|
|
irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
|
|
return;
|
|
}
|
|
|
|
if (!dev_ictl) {
|
|
LOG_DBG("board: DW intr_control device binding failed");
|
|
return;
|
|
}
|
|
|
|
/* If the control comes here it means the specified interrupt
|
|
* is in DW interrupt controller
|
|
*/
|
|
irq_enable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
|
|
|
|
/* Manipulate the relevant bit in the interrupt controller
|
|
* register as needed
|
|
*/
|
|
irq_enable_next_level(dev_ictl, INTR_CNTL_IRQ_NUM(irq));
|
|
}
|
|
|
|
void _soc_irq_disable(u32_t irq)
|
|
{
|
|
struct device *dev_cavs, *dev_ictl;
|
|
|
|
switch (XTENSA_IRQ_NUMBER(irq)) {
|
|
case CAVS_ICTL_0_IRQ:
|
|
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_0_NAME);
|
|
break;
|
|
case CAVS_ICTL_1_IRQ:
|
|
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_1_NAME);
|
|
break;
|
|
case CAVS_ICTL_2_IRQ:
|
|
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_2_NAME);
|
|
break;
|
|
case CAVS_ICTL_3_IRQ:
|
|
dev_cavs = device_get_binding(CONFIG_CAVS_ICTL_3_NAME);
|
|
break;
|
|
default:
|
|
/* regular interrupt */
|
|
_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
|
|
return;
|
|
}
|
|
|
|
if (!dev_cavs) {
|
|
LOG_DBG("board: CAVS device binding failed");
|
|
return;
|
|
}
|
|
|
|
/* If the control comes here it means the specified interrupt
|
|
* is in either CAVS interrupt logic or DW interrupt controller
|
|
*/
|
|
|
|
switch (CAVS_IRQ_NUMBER(irq)) {
|
|
case DW_ICTL_IRQ_CAVS_OFFSET:
|
|
dev_ictl = device_get_binding(CONFIG_DW_ICTL_NAME);
|
|
break;
|
|
default:
|
|
/* The source of the interrupt is in CAVS interrupt logic */
|
|
irq_disable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
|
|
|
|
/* Disable the parent IRQ if all children are disabled */
|
|
if (!irq_is_enabled_next_level(dev_cavs)) {
|
|
_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!dev_ictl) {
|
|
LOG_DBG("board: DW intr_control device binding failed");
|
|
return;
|
|
}
|
|
|
|
/* If the control comes here it means the specified interrupt
|
|
* is in DW interrupt controller.
|
|
* Manipulate the relevant bit in the interrupt controller
|
|
* register as needed
|
|
*/
|
|
irq_disable_next_level(dev_ictl, INTR_CNTL_IRQ_NUM(irq));
|
|
|
|
/* Disable the parent IRQ if all children are disabled */
|
|
if (!irq_is_enabled_next_level(dev_ictl)) {
|
|
irq_disable_next_level(dev_cavs, CAVS_IRQ_NUMBER(irq));
|
|
|
|
if (!irq_is_enabled_next_level(dev_cavs)) {
|
|
_xtensa_irq_disable(XTENSA_IRQ_NUMBER(irq));
|
|
}
|
|
}
|
|
}
|
|
|
|
void soc_config_iomux_ctsrts(void)
|
|
{
|
|
volatile struct soc_io_mux_regs *regs =
|
|
(volatile struct soc_io_mux_regs *)IOMUX_BASE;
|
|
|
|
/* Configure the MUX to select GPIO functionality for GPIO 23 and 24 */
|
|
regs->io_mux_ctl0 |= SOC_UART_RTS_CTS_MS;
|
|
}
|
|
|
|
void soc_config_iomux_i2c(void)
|
|
{
|
|
volatile struct soc_io_mux_regs *regs =
|
|
(volatile struct soc_io_mux_regs *)IOMUX_BASE;
|
|
|
|
/* Configure the MUX to select the correct I2C port (I2C1) */
|
|
regs->io_mux_ctl2 |= SOC_I2C_I0_I1_MS;
|
|
}
|
|
|
|
static inline void soc_set_resource_ownership(void)
|
|
{
|
|
volatile struct soc_resource_alloc_regs *regs =
|
|
(volatile struct soc_resource_alloc_regs *)
|
|
SOC_RESOURCE_ALLOC_REG_BASE;
|
|
int index;
|
|
|
|
|
|
/* set ownership of DMA controllers and channels */
|
|
for (index = 0; index < SOC_NUM_LPGPDMAC; index++) {
|
|
regs->lpgpdmacxo[index] = SOC_LPGPDMAC_OWNER_DSP;
|
|
}
|
|
|
|
/* set ownership of I2S and DMIC controllers */
|
|
regs->dspiopo = SOC_DSPIOP_I2S_OWNSEL_DSP |
|
|
SOC_DSPIOP_DMIC_OWNSEL_DSP;
|
|
|
|
/* set ownership of timestamp and M/N dividers */
|
|
regs->geno = SOC_GENO_TIMESTAMP_OWNER_DSP |
|
|
SOC_GENO_MNDIV_OWNER_DSP;
|
|
}
|
|
|
|
void dcache_writeback_region(void *addr, size_t size)
|
|
{
|
|
xthal_dcache_region_writeback(addr, size);
|
|
}
|
|
|
|
void dcache_invalidate_region(void *addr, size_t size)
|
|
{
|
|
xthal_dcache_region_invalidate(addr, size);
|
|
}
|
|
|
|
u32_t soc_get_ref_clk_freq(void)
|
|
{
|
|
return ref_clk_freq;
|
|
}
|
|
|
|
static void soc_set_power_and_clock(void)
|
|
{
|
|
volatile struct soc_dsp_shim_regs *regs =
|
|
(volatile struct soc_dsp_shim_regs *)
|
|
SOC_DSP_SHIM_REG_BASE;
|
|
|
|
regs->clkctl |= SOC_CLKCTL_REQ_FAST_CLK | SOC_CLKCTL_OCS_FAST_CLK;
|
|
regs->pwrctl |= SOC_PWRCTL_DISABLE_PWR_GATING_DSP1 |
|
|
SOC_PWRCTL_DISABLE_PWR_GATING_DSP0;
|
|
}
|
|
|
|
static void soc_read_bootstraps(void)
|
|
{
|
|
u32_t bootstrap;
|
|
|
|
bootstrap = *((volatile u32_t *)SOC_S1000_GLB_CTRL_STRAPS);
|
|
|
|
bootstrap &= SOC_S1000_STRAP_REF_CLK;
|
|
|
|
switch (bootstrap) {
|
|
case SOC_S1000_STRAP_REF_CLK_19P2:
|
|
ref_clk_freq = 19200000;
|
|
break;
|
|
case SOC_S1000_STRAP_REF_CLK_24P576:
|
|
ref_clk_freq = 24576000;
|
|
break;
|
|
case SOC_S1000_STRAP_REF_CLK_38P4:
|
|
default:
|
|
ref_clk_freq = 38400000;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int soc_init(struct device *dev)
|
|
{
|
|
soc_read_bootstraps();
|
|
|
|
LOG_INF("Reference clock frequency: %u Hz", ref_clk_freq);
|
|
|
|
soc_set_resource_ownership();
|
|
soc_set_power_and_clock();
|
|
|
|
#ifdef CONFIG_I2C
|
|
soc_config_iomux_i2c();
|
|
#endif
|
|
|
|
#ifdef CONFIG_GPIO
|
|
soc_config_iomux_ctsrts();
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
SYS_INIT(soc_init, PRE_KERNEL_1, 99);
|