1 /* 2 * Copyright (c) 2021 Intel Corporation 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 #ifndef ZEPHYR_SOC_INTEL_ADSP_CAVS_IDC_H_ 7 #define ZEPHYR_SOC_INTEL_ADSP_CAVS_IDC_H_ 8 9 #include <intel_adsp_ipc_devtree.h> 10 11 /* 12 * (I)ntra (D)SP (C)ommunication is the facility for sending 13 * interrupts directly between DSP cores. The interface 14 * is... somewhat needlessly complicated. 15 * 16 * Each core has a set of registers its is supposed to use, but all 17 * registers seem to behave symmetrically regardless of which CPU does 18 * the access. 19 * 20 * Each core has a "ITC" register associated with each other core in 21 * the system (including itself). When the high bit becomes 1 in an 22 * ITC register, an IDC interrupt is latched for the target core. 23 * Data in other bits is stored but otherwise ignored, it's merely 24 * data to be transmitted along with the interrupt. 25 * 26 * On the target core, there is a "TFC" register for each core that 27 * reflects the same value written to ITC. In fact experimentally 28 * these seem to be the same register at different addresses. When 29 * the high bit of TFC is written with a 1, the value becomes ZERO, 30 * indicating an acknowledgment of the interrupt. This action can 31 * also latch an interrupt to send back to the originator if unmasked 32 * (see below). 33 * 34 * (There is also an IETC/TEFC register pair that stores 30 bits of 35 * data but otherwise has no hardware behavior. This is probably best 36 * ignored for new protocols, as experimentally it seems to provide no 37 * performance benefit vs. storing a message in RAM. The cAVS 1.5/1.8 38 * ROM boot protocol uses it to store an entry point address, though.) 39 * 40 * So you can send a synchronous message from core "src" (where src is 41 * the PRID of the CPU, equal to arch_curr_cpu()->id in Zephyr) to 42 * core "dst" with: 43 * 44 * IDC[src].core[dst].itc = BIT(31) | message; 45 * while (IDC[src].core[dst].itc & BIT(31)) {} 46 * 47 * And the other side (on cpu "dst", generally in the IDC interrupt 48 * handler) will read and acknowledge those same values via: 49 * 50 * uint32_t my_msg = IDC[dst].core[src].tfc & 0x7fffffff; 51 * IDC[dst].core[src].tfc = BIT(31); // clear high bit to signal completion 52 * 53 * And for clarity, at all times and for all cores and all pairs of src/dst: 54 * 55 * IDC[src].core[dst].itc == IDC[dst].core[src].tfc 56 * 57 * Finally note the two control registers at the end of each core's 58 * register block, which store a bitmask of cores that it is allowed 59 * to signal with an interrupt via either ITC (set high "BUSY" bit) or 60 * TFC (clear high "DONE" bit). This masking is in ADDITION to the 61 * level 2 bit for IDC in the per-core INTCTRL DSP register AND the 62 * Xtensa architectural INTENABLE SR. You must enable IDC interrupts 63 * form core "src" to core "dst" with: 64 * 65 * IDC[src].busy_int |= BIT(dst) // Or disable with "&= ~BIT(dst)" of course 66 */ 67 struct cavs_idc { 68 struct { 69 uint32_t tfc; /* (T)arget (F)rom (C)ore */ 70 uint32_t tefc; /* ^^ + (E)xtension */ 71 uint32_t itc; /* (I)nitiator (T)o (C)ore */ 72 uint32_t ietc; /* ^^ + (E)xtension */ 73 } core[4]; 74 uint32_t unused0[4]; 75 uint8_t busy_int; /* bitmask of cores that can IDC via ITC */ 76 uint8_t done_int; /* bitmask of cores that can IDC via TFC */ 77 uint8_t unused1; 78 uint8_t unused2; 79 uint32_t unused3[11]; 80 }; 81 82 #define IDC ((volatile struct cavs_idc *)INTEL_ADSP_IDC_REG_ADDRESS) 83 84 extern void soc_idc_init(void); 85 86 /* cAVS interrupt mask bits. Each core has one of these structs 87 * indexed in the intctrl[] array. Each external interrupt source 88 * indexes one bit in one of the state substructs (one each for Xtensa 89 * level 2-5 interrupts). The "mask" field shows the current masking 90 * state, with a 1 representing "interrupt disabled". The "status" 91 * field indicates interrupts that are currently latched and awaiting 92 * delivery. Write bits to "set" to set the mask bit to 1 and disable 93 * interrupts. Write a 1 bit to "clear" to force the mask bit to 0 94 * and enable them. For example, for core "c": 95 * 96 * INTCTRL[c].l2.clear = 0x10; // unmask IDC interrupt 97 * 98 * INTCTRL[c].l3.set = 0xffffffff; // Mask all L3 interrupts 99 * 100 * Note that this interrupt controller is separate from the Xtensa 101 * architectural interrupt hardware controlled by the 102 * INTENABLE/INTERRUPT/INTSET/INTCLEAR special registers on each core 103 * which much also be configured for interrupts to arrive. Note also 104 * that some hardware (like IDC, see above) implements a third (!) 105 * layer of interrupt masking. 106 */ 107 struct cavs_intctrl { 108 struct { 109 uint32_t set, clear, mask, status; 110 } l2, l3, l4, l5; 111 }; 112 113 /* Named interrupt bits in the above registers */ 114 #define CAVS_L2_HPGPDMA BIT(24) /* HP General Purpose DMA */ 115 #define CAVS_L2_DWCT1 BIT(23) /* DSP Wall Clock Timer 1 */ 116 #define CAVS_L2_DWCT0 BIT(22) /* DSP Wall Clock Timer 0 */ 117 #define CAVS_L2_L2ME BIT(21) /* L2 Memory Error */ 118 #define CAVS_L2_DTS BIT(20) /* DSP Timestamping */ 119 #define CAVS_L2_SHA BIT(16) /* SHA-256 */ 120 #define CAVS_L2_DCLC BIT(15) /* Demand Cache Line Command */ 121 #define CAVS_L2_IDC BIT(8) /* IDC */ 122 #define CAVS_L2_HIPC BIT(7) /* Host IPC */ 123 #define CAVS_L2_MIPC BIT(6) /* CSME IPC */ 124 #define CAVS_L2_PIPC BIT(5) /* PMC IPC */ 125 #define CAVS_L2_SIPC BIT(4) /* Sensor Hub IPC */ 126 127 #define CAVS_L3_DSPGCL BIT(31) /* DSP Gateway Code Loader */ 128 #define CAVS_L3_DSPGHOS(n) BIT(16 + n) /* DSP Gateway Host Output Stream */ 129 #define CAVS_L3_HPGPDMA BIT(15) /* HP General Purpose DMA */ 130 #define CAVS_L3_DSPGHIS(n) BIT(n) /* DSP Gateway Host Input Stream */ 131 132 #define CAVS_L4_DSPGLOS(n) BIT(16 + n) /* DSP Gateway Link Output Stream */ 133 #define CAVS_L4_LPGPGMA BIT(15) /* LP General Purpose DMA */ 134 #define CAVS_L4_DSPGLIS(n) BIT(n) /* DSP Gateway Link Input Stream */ 135 136 #define CAVS_L5_LPGPDMA BIT(16) /* LP General Purpose DMA */ 137 #define CAVS_L5_DWCT1 BIT(15) /* DSP Wall CLock Timer 1 */ 138 #define CAVS_L5_DWCT0 BIT(14) /* DSP Wall Clock Timer 0 */ 139 #define CAVS_L5_DMIX BIT(13) /* Digital Mixer */ 140 #define CAVS_L5_ANC BIT(12) /* Active Noise Cancellation */ 141 #define CAVS_L5_SNDW BIT(11) /* SoundWire */ 142 #define CAVS_L5_SLIM BIT(10) /* Slimbus */ 143 #define CAVS_L5_DSPK BIT(9) /* Digital Speaker */ 144 #define CAVS_L5_DMIC BIT(8) /* Digital Mic */ 145 #define CAVS_L5_I2S(n) BIT(n) /* I2S */ 146 147 #define CAVS_INTCTRL \ 148 ((volatile struct cavs_intctrl *)DT_REG_ADDR(DT_NODELABEL(cavs_intc0))) 149 150 #endif /* ZEPHYR_SOC_INTEL_ADSP_CAVS_IDC_H_ */ 151