blob: 8feefa0ac479ff4909fa4fe79d7fead8f1e19685 [file] [log] [blame]
/* Copyright (c) 2021 Intel Corporation
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_SOC_INTEL_ADSP_CAVS_IPC_REGS_H
#define ZEPHYR_SOC_INTEL_ADSP_CAVS_IPC_REGS_H
#include <stdint.h>
/* Inter Processor Communication: a distressingly heavyweight method
* for directing interrupts at software running on other processors.
* Used for sending interrupts to and receiving them from another
* device. cAVS uses it to talk to the host and the CSME. In general
* there is one of these blocks instantiated for each endpoint of a
* connection.
*
* There are actually three (!) interrupt channels on the link, all
* bidirectional, but they're somewhat nonorthogonal. Each can be
* independently masked via the CTL register.
*
* 1. When the IDR register is written with the high ("BUSY") bit set,
* the IDR value written is copied to the TDR register on the other
* end of the connection, where the BUSY bit acts as a
* level-triggered interrupt latch (and must therefore be cleared
* by the handler by writing a 1). The high bit ("DONE") also
* becomes set on the TDA register of the other endpoint.
* Additionally, the IDD register is copied to the TDD register on
* the other side. That data, and the remaining 31 bits of
* IDR/TDR, are uninspected by the hardware and are intended to be
* used as a "message" (but see below).
*
* 2. Writes to TDA on the receiving end of the connection with the
* high bit ("DONE") set to zero and (!) when the IDR BUSY bit is
* one on the other side of the connection (i.e. "when the other
* side has sent a message") cause an interrupt to be triggered on
* the other endpoint by setting its IDA high bit (which must be
* cleared to acknowledge the interrupt, again by writing a one
* bit). At the same time, the peer's IDR.BUSY is cleared. No
* data is copied with this interrupt mechanism.
*
* 3. When the CST register is written with a non-zero value, the
* value is copied to the CSR register on other side and an
* interrupt is triggered (to be cleared by writing CSR to zero).
* This is historically unused and unsupported by simulation tools.
*
* Note that while the scheme in #1 may look like an atomic message,
* there is no queuing in the hardware! This is just a regular level
* triggered interrupt with some scratch registers on which multiple
* contexts can race. The design intent is that the sender polls the
* IDR.BUSY bit (or waits for a return interrupt via #2) to be sure
* the link is available. And even then two independent initiators
* (cores, threads, whatever) trying to initiate a message may race if
* they have access to the same endpoint. Use with care.
*
* Note also that the ancestral cAVS 1.5 version of this interface is
* very similar (the registers had different names, but that's been
* unified here), but with a different layout and with DONE signaled
* via bit 30 of the TDD register when BUSY is cleared in TDR on the
* other side and not via a separate TDA/IDA. This means that it's
* not possible to defer completion of a message on cAVS 1.5 as the
* interrupt would remain active.
*/
struct cavs_ipc {
#ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V15
uint32_t tdr;
uint32_t tdd;
uint32_t idr;
uint32_t idd;
uint32_t ctl;
uint32_t ida; /* Fakes for source compatibility; these ... */
uint32_t tda; /* ... two registers don't exist in hardware. */
#else
uint32_t tdr;
uint32_t tda;
uint32_t tdd;
uint32_t unused0;
uint32_t idr;
uint32_t ida;
uint32_t idd;
uint32_t unused1;
uint32_t cst;
uint32_t csr;
uint32_t ctl;
#endif
};
#define CAVS_IPC_BUSY BIT(31)
#define CAVS_IPC_DONE BIT(31)
#define CAVS_IPC_IDD15_DONE BIT(30) /* v1.5 way to signal done */
#define CAVS_IPC_CTL_TBIE BIT(0)
#define CAVS_IPC_CTL_IDIE BIT(1) /* yesthatiswhattheyreallynamedit */
#endif /* ZEPHYR_SOC_INTEL_ADSP_CAVS_IPC_REGS_H */