soc/intel_s1000: Add new cAVS shim & IDC interfaces

This board, whose hardware is just a cAVS 1.8 device without an x86
host CPU, started life (as all the cAVS devices did) as a
cut-and-pasted copy of the same basic code.

Because of hardware and schedule limitations, it didn't get the same
unification treatment that all the other platforms did.  But it turns
out that in SMP configurations (which... it's not clear if we actually
test on hardware?) it wants to use the cavs_timer driver, which now
uses the new SOC API and not the old one.  Which s1000 doesn't expose.

So... I guess we have to continue to cut and paste until we can find
time to unify this.  Add a copy of the new shim/IDC headers to this
SOC and expose them via devivcetree.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2021-11-30 07:38:16 -08:00 committed by Anas Nashif
parent 33c97f6116
commit 1e1830de95
3 changed files with 297 additions and 0 deletions

View file

@ -49,6 +49,11 @@
#interrupt-cells = <3>;
};
shim: shim@71f00 {
compatible = "intel,cavs-shim";
reg = <0x71f00 0x100>;
};
cavs0: cavs@78800 {
compatible = "intel,cavs-intc";
reg = <0x78800 0x10>;

View file

@ -0,0 +1,148 @@
/*
* Copyright (c) 2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_SOC_INTEL_ADSP_CAVS_IDC_H_
#define ZEPHYR_SOC_INTEL_ADSP_CAVS_IDC_H_
/*
* (I)ntra (D)SP (C)ommunication is the facility for sending
* interrupts directly between DSP cores. The interface
* is... somewhat needlessly complicated.
*
* Each core has a set of registers its is supposed to use, but all
* registers seem to behave symmetrically regardless of which CPU does
* the access.
*
* Each core has a "ITC" register associated with each other core in
* the system (including itself). When the high bit becomes 1 in an
* ITC register, an IDC interrupt is latched for the target core.
* Data in other bits is stored but otherwise ignored, it's merely
* data to be transmitted along with the interrupt.
*
* On the target core, there is a "TFC" register for each core that
* reflects the same value written to ITC. In fact experimentally
* these seem to be the same register at different addresses. When
* the high bit of TFC is written with a 1, the value becomes ZERO,
* indicating an acknowledgment of the interrupt. This action can
* also latch an interrupt to send back to the originator if unmasked
* (see below).
*
* (There is also an IETC/TEFC register pair that stores 30 bits of
* data but otherwise has no hardware behavior. This is probably best
* ignored for new protocols, as experimentally it seems to provide no
* performance benefit vs. storing a message in RAM. The cAVS 1.5/1.8
* ROM boot protocol uses it to store an entry point address, though.)
*
* So you can send a synchronous message from core "src" (where src is
* the PRID of the CPU, equal to arch_curr_cpu()->id in Zephyr) to
* core "dst" with:
*
* IDC[src].core[dst].itc = BIT(31) | message;
* while (IDC[src].core[dst].itc & BIT(31)) {}
*
* And the other side (on cpu "dst", generally in the IDC interruupt
* handler) will read and acknowledge those same values via:
*
* uint32_t my_msg = IDC[dst].core[src].tfc & 0x7fffffff;
* IDC[dst].core[src].tfc = BIT(31); // clear high bit to signal completion
*
* And for clarity, at all times and for all cores and all pairs of src/dst:
*
* IDC[src].core[dst].itc == IDC[dst].core[src].tfc
*
* Finally note the two control registers at the end of each core's
* register block, which store a bitmask of cores that are allowed to
* send that core an interrupt via either ITC (set high "BUSY" bit) or
* TFC (clear high "DONE" bit). This masking is in ADDITION to the
* level 2 bit for IDC in the per-core INTCTRL DSP register AND the
* Xtensa architectural INTENABLE SR. You must enable IDC interrupts
* form core "src" to core "dst" with:
*
* IDC[dst].busy_int |= BIT(src) // Or disable with "&= ~BIT(src)" of course
*/
struct cavs_idc {
struct {
uint32_t tfc; /* (T)arget (F)rom (C)ore */
uint32_t tefc; /* ^^ + (E)xtension */
uint32_t itc; /* (I)nitiator (T)o (C)ore */
uint32_t ietc; /* ^^ + (E)xtension */
} core[4];
uint32_t unused0[4];
uint8_t busy_int; /* bitmask of cores that can IDC via ITC */
uint8_t done_int; /* bitmask of cores that can IDC via TFC */
uint8_t unused1;
uint8_t unused2;
uint32_t unused3[11];
};
#define IDC ((volatile struct cavs_idc *)DT_REG_ADDR(DT_NODELABEL(idc)))
extern void soc_idc_init(void);
/* cAVS interrupt mask bits. Each core has one of these structs
* indexed in the intctrl[] array. Each external interrupt source
* indexes one bit in one of the state substructs (one each for Xtensa
* level 2-5 interrupts). The "mask" field shows the current masking
* state, with a 1 representing "interrupt disabled". The "status"
* field indicates interrupts that are currently latched and awaiting
* delivery. Write bits to "set" to set the mask bit to 1 and disable
* interrupts. Write a 1 bit to "clear" to force the mask bit to 0
* and enable them. For example, for core "c":
*
* INTCTRL[c].l2.clear = 0x10; // unmask IDC interrupt
*
* INTCTRL[c].l3.set = 0xffffffff; // Mask all L3 interrupts
*
* Note that this interrupt controller is separate from the Xtensa
* architectural interrupt hardware controlled by the
* INTENABLE/INTERRUPT/INTSET/INTCLEAR special registers on each core
* which much also be configured for interrupts to arrive. Note also
* that some hardware (like IDC, see above) implements a third (!)
* layer of interrupt masking.
*/
struct cavs_intctrl {
struct {
uint32_t set, clear, mask, status;
} l2, l3, l4, l5;
};
/* Named interrupt bits in the above registers */
#define CAVS_L2_HPGPDMA BIT(24) /* HP General Purpose DMA */
#define CAVS_L2_DWCT1 BIT(23) /* DSP Wall Clock Timer 1 */
#define CAVS_L2_DWCT0 BIT(22) /* DSP Wall Clock Timer 0 */
#define CAVS_L2_L2ME BIT(21) /* L2 Memory Error */
#define CAVS_L2_DTS BIT(20) /* DSP Timestamping */
#define CAVS_L2_SHA BIT(16) /* SHA-256 */
#define CAVS_L2_DCLC BIT(15) /* Demand Cache Line Command */
#define CAVS_L2_IDC BIT(8) /* IDC */
#define CAVS_L2_HIPC BIT(7) /* Host IPC */
#define CAVS_L2_MIPC BIT(6) /* CSME IPC */
#define CAVS_L2_PIPC BIT(5) /* PMC IPC */
#define CAVS_L2_SIPC BIT(4) /* Sensor Hub IPC */
#define CAVS_L3_DSPGCL BIT(31) /* DSP Gateway Code Loader */
#define CAVS_L3_DSPGHOS(n) BIT(16 + n) /* DSP Gateway Host Output Stream */
#define CAVS_L3_HPGPDMA BIT(15) /* HP General Purpose DMA */
#define CAVS_L3_DSPGHIS(n) BIT(n) /* DSP Gateway Host Input Stream */
#define CAVS_L4_DSPGLOS(n) BIT(16 + n) /* DSP Gateway Link Output Stream */
#define CAVS_L4_LPGPGMA BIT(15) /* LP General Purpose DMA */
#define CAVS_L4_DSPGLIS(n) BIT(n) /* DSP Gateway Link Input Stream */
#define CAVS_L5_LPGPDMA BIT(16) /* LP General Purpose DMA */
#define CAVS_L5_DWCT1 BIT(15) /* DSP Wall CLock Timer 1 */
#define CAVS_L5_DWCT0 BIT(14) /* DSP Wall Clock Timer 0 */
#define CAVS_L5_DMIX BIT(13) /* Digital Mixer */
#define CAVS_L5_ANC BIT(12) /* Active Noise Cancellation */
#define CAVS_L5_SNDW BIT(11) /* SoundWire */
#define CAVS_L5_SLIM BIT(10) /* Slimbus */
#define CAVS_L5_DSPK BIT(9) /* Digital Speaker */
#define CAVS_L5_DMIC BIT(8) /* Digital Mic */
#define CAVS_L5_I2S(n) BIT(n) /* I2S */
#define CAVS_INTCTRL \
((volatile struct cavs_intctrl *)DT_REG_ADDR(DT_NODELABEL(cavs0)))
#endif /* ZEPHYR_SOC_INTEL_ADSP_CAVS_IDC_H_ */

View file

@ -0,0 +1,144 @@
/*
* Copyright (c) 2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_SOC_INTEL_ADSP_CAVS_SHIM_H_
#define ZEPHYR_SOC_INTEL_ADSP_CAVS_SHIM_H_
/* The "shim" block contains most of the general system control
* registers on cAVS platforms. While the base address changes, it
* has remained largely, but not perfectly, compatible between
* versions.
*/
#ifndef _ASMLANGUAGE
struct cavs_shim {
uint32_t skuid;
uint32_t _unused0[7];
uint32_t dspwc_lo;
uint32_t dspwc_hi;
uint32_t dspwctcs;
uint32_t _unused1[1];
uint32_t dspwct0c_lo;
uint32_t dspwct0c_hi;
uint32_t dspwct1c_lo;
uint32_t dspwct1c_hi;
uint32_t _unused2[14];
uint32_t clkctl;
uint32_t clksts;
uint32_t hspgctl; /* cAVS 1.5, see cavs_l2lm for 1.8+ */
uint32_t lspgctl; /* cAVS 1.5, see cavs_l2lm for 1.8+ */
uint32_t hsrmctl; /* cAVS 1.5, see cavs_l2lm for 1.8+ */
uint32_t lsrmctl; /* cAVS 1.5, see cavs_l2lm for 1.8+ */
uint16_t pwrctl;
uint16_t pwrsts;
uint32_t lpsctl;
uint32_t lpsdmas0;
uint32_t lpsdmas1;
uint32_t spsreq;
uint32_t ldoctl;
uint32_t _unused3[2];
union {
/* cAVS 1.5 */
struct {
uint32_t hspgists;
uint32_t lspgists;
uint32_t _unused4[2];
};
/* cAVS 1.8+ */
struct {
uint32_t lpsalhss0;
uint32_t lpsalhss1;
uint32_t lpsalhss2;
uint32_t lpsalhss3;
};
};
uint32_t _unused5[4];
uint32_t l2mecs;
uint32_t l2mpat;
uint32_t _unused6[2];
uint32_t ltrc;
uint32_t _unused8[3];
uint32_t dbgo;
uint32_t svcfg;
uint32_t _unused9[2];
};
/* L2 Local Memory control (cAVS 1.8+) */
struct cavs_l2lm {
uint32_t l2lmcap;
uint32_t l2lmpat;
uint32_t _unused0[2];
uint32_t hspgctl0;
uint32_t hsrmctl0;
uint32_t hspgists0;
uint32_t _unused1;
uint32_t hspgctl1;
uint32_t hsrmctl1;
uint32_t hspgists1;
uint32_t _unused2[9];
uint32_t lspgctl;
uint32_t lsrmctl;
uint32_t lspgists;
};
#define CAVS_L2LM (*((volatile struct cavs_l2lm *)DT_REG_ADDR(DT_NODELABEL(l2lm))))
/* Host memory window control. Not strictly part of the shim block. */
struct cavs_win {
uint32_t dmwba;
uint32_t dmwlo;
};
#define CAVS_WIN ((volatile struct cavs_win *)DT_REG_ADDR(DT_NODELABEL(win)))
#endif /* _ASMLANGUAGE */
#define CAVS_SHIM (*((volatile struct cavs_shim *)DT_REG_ADDR(DT_NODELABEL(shim))))
/* cAVS 1.8+ CLKCTL bits */
#define CAVS_CLKCTL_RHROSCC BIT(31) /* Request HP RING oscillator */
#define CAVS_CLKCTL_RXOSCC BIT(30) /* Request XTAL oscillator */
#define CAVS_CLKCTL_RLROSCC BIT(29) /* Request LP RING oscillator */
#define CAVS_CLKCTL_SLIMFDCGB BIT(25) /* Slimbus force dynamic clock gating*/
#define CAVS_CLKCTL_TCPLCG(x) BIT(16+x) /* Set bit: prevent clock gating on core x */
#define CAVS_CLKCTL_SLIMCSS BIT(6) /* Slimbus clock (0: XTAL, 1: Audio) */
#define CAVS_CLKCTL_OCS BIT(2) /* Oscillator clock (0: LP, 1: HP) */
#define CAVS_CLKCTL_LMCS BIT(1) /* LP mem divisor (0: div/2, 1: div/4) */
#define CAVS_CLKCTL_HMCS BIT(0) /* HP mem divisor (0: div/2, 1: div/4) */
/* cAVS 1.5 had a somewhat different CLKCTL (some fields were the same) */
#define CAVS15_CLKCTL_RAPLLC BIT(31)
#define CAVS15_CLKCTL_RFROSCC BIT(29)
#define CAVS15_CLKCTL_HPGPDMAFDCGB BIT(28)
#define CAVS15_CLKCTL_LPGPDMAFDCGB(x) BIT(26+x)
#define CAVS15_CLKCTL_SLIMFDCGB BIT(25)
#define CAVS15_CLKCTL_DMICFDCGB BIT(24)
#define CAVS15_CLKCTL_I2SFDCGB(x) BIT(20+x)
#define CAVS15_CLKCTL_I2SEFDCGB(x) BIT(18+x)
#define CAVS15_CLKCTL_DPCS(div) ((((div)-1) & 3) << 8) /* DSP PLL divisor (1/2/4) */
#define CAVS15_CLKCTL_TCPAPLLS BIT(7)
#define CAVS15_CLKCTL_LDCS BIT(5)
#define CAVS15_CLKCTL_HDCS BIT(4)
#define CAVS15_CLKCTL_LDOCS BIT(3)
#define CAVS15_CLKCTL_HDOCS BIT(2)
#define CAVS15_CLKCTL_LMPCS BIT(1)
#define CAVS15_CLKCTL_HMPCS BIT(0)
#define SHIM_PWRCTL_TCPDSPPG(x) BIT(x)
#ifdef SOC_SERIES_INTEL_CAVS_V25
# define SHIM_LDOCTL_HPSRAM_LDO_ON (3 << 0 | 3 << 16)
# define SHIM_LDOCTL_HPSRAM_LDO_BYPASS BIT(16)
#else
# define SHIM_LDOCTL_HPSRAM_LDO_ON (3 << 0)
# define SHIM_LDOCTL_HPSRAM_LDO_BYPASS BIT(0)
#endif
#define SHIM_LDOCTL_LPSRAM_LDO_ON (3 << 2)
#define SHIM_LDOCTL_LPSRAM_LDO_BYPASS BIT(2)
#define CAVS_DMWBA_ENABLE BIT(0)
#define CAVS_DMWBA_READONLY BIT(1)
#endif /* ZEPHYR_SOC_INTEL_ADSP_CAVS_SHIM_H_ */