*/
#include <asm/regs.h>
+#include <xen/iocap.h>
#include <xen/sched.h>
#include <asm/smccc.h>
#include <asm/platforms/xilinx-zynqmp-eemi.h>
+#include <asm/platforms/xilinx-zynqmp-mm.h>
/*
* EEMI firmware API:
* IPI firmware API:
* https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h
*
- * Power domain node_ids identify the area of effect of the power
- * management operations. They are the first parameter passed to power
- * management EEMI calls.
+ * Allthough the details of the setup are configurable, in the common case
+ * the PMU lives in the Secure world. NS World cannot directly communicate
+ * with it and must use proxy services from ARM Trusted Firmware to reach
+ * the PMU.
*
- * Reset IDs identify the area of effect of a reset operation. They are
- * the first parameter passed to reset EEMI calls.
+ * Power Management on the ZynqMP is implemented in a layered manner.
+ * The PMU knows about various masters and will enforce access controls
+ * based on a pre-configured partitioning. This configuration dictates
+ * which devices are owned by the various masters and the PMU FW makes sure
+ * that a given master cannot turn off a device that it does not own or that
+ * is in use by other masters.
*
- * For now, let the hardware domain access to all power domain nodes and
- * all reset lines. In the future, we'll check for ownership of
- * resources by specific virtual machines.
+ * The PMU is not aware of multiple execution states in masters.
+ * For example, it treats the ARMv8 cores as single units and does not
+ * distinguish between Secure vs NS OS:s nor does it know about Hypervisors
+ * and multiple guests. It is up to software on the ARMv8 cores to present
+ * a unified view of its power requirements.
+ *
+ * To implement this unified view, ARM Trusted Firmware at EL3 provides
+ * access to the PM API via SMC calls. ARM Trusted Firmware is responsible
+ * for mediating between the Secure and the NS world, rejecting SMC calls
+ * that request changes that are not allowed.
+ *
+ * Xen running above ATF owns the NS world and is responsible for presenting
+ * unified PM requests taking all guests and the hypervisor into account.
+ *
+ * Implementation:
+ * The PM API contains different classes of calls.
+ * Certain calls are harmless to expose to any guest.
+ * These include calls to get the PM API Version, or to read out the version
+ * of the chip we're running on.
+ *
+ * Other calls are more problematic. Here're some:
+ * * Power requests for nodes (i.e turn on or off a given device)
+ * * Reset line control (i.e reset a given device)
+ * * MMIO access (i.e directly access clock and reset registers)
+ *
+ * Power requests for nodes:
+ * In order to correctly mediate these calls, we need to know if
+ * guests issuing these calls have ownership of the given device.
+ * The approach taken here is to map PM API Nodes identifying
+ * a device into base addresses for registers that belong to that
+ * same device.
+ *
+ * If the guest has access to a devices registers, we give the guest
+ * access to PM API calls that affect that device. This is implemented
+ * by pm_node_access and domain_has_node_access().
+ *
+ * Reset lines:
+ * Reset lines are identified by a list of identifiers that do not relate
+ * to device nodes. We can use the same approach here as for nodes, except
+ * that we need a separate table mapping reset lines to base addresses.
+ * This is implemented by pm_reset_access.
+ *
+ * MMIO access:
+ * These calls allow guests to access certain memory ranges. These ranges
+ * are typically protected for secure-world access only and also from
+ * certain masters only, so guests cannot access them directly.
+ * Registers within the memory regions affect certain nodes. In this case,
+ * our imput is an address and we map that address into a node. If the
+ * guest has ownership of that node, the access is allowed.
+ * Some registers contain bitfields and a single register may contain
+ * bits that affect multiple nodes.
+ *
+ * Some of the calls act on more global state. For example acting on
+ * NODE_PS, which affects many a lot of nodes. This higher level
+ * orchestrating is left for the hardware-domain only.
*/
-static inline bool domain_has_node_access(struct domain *d, uint32_t nodeid)
+
+struct pm_access
{
- return is_hardware_domain(d);
+ uint64_t addr;
+ bool hwdom_access; /* HW domain gets access regardless. */
+};
+
+/*
+ * This table maps a node into a memory address.
+ * If a guest has access to the address, it has enough control
+ * over the node to grant it access to EEMI calls for that node.
+ */
+static const struct pm_access pm_node_access[] = {
+ /* MM_RPU grants access to alll RPU Nodes. */
+ [NODE_RPU] = { MM_RPU },
+ [NODE_RPU_0] = { MM_RPU },
+ [NODE_RPU_1] = { MM_RPU },
+ [NODE_IPI_RPU_0] = { MM_RPU },
+
+ /* GPU nodes. */
+ [NODE_GPU] = { MM_GPU },
+ [NODE_GPU_PP_0] = { MM_GPU },
+ [NODE_GPU_PP_1] = { MM_GPU },
+
+ [NODE_USB_0] = { MM_USB3_0 },
+ [NODE_USB_1] = { MM_USB3_1 },
+ [NODE_TTC_0] = { MM_TTC0 },
+ [NODE_TTC_1] = { MM_TTC1 },
+ [NODE_TTC_2] = { MM_TTC2 },
+ [NODE_TTC_3] = { MM_TTC3 },
+ [NODE_SATA] = { MM_SATA_AHCI_HBA },
+ [NODE_ETH_0] = { MM_GEM0 },
+ [NODE_ETH_1] = { MM_GEM1 },
+ [NODE_ETH_2] = { MM_GEM2 },
+ [NODE_ETH_3] = { MM_GEM3 },
+ [NODE_UART_0] = { MM_UART0 },
+ [NODE_UART_1] = { MM_UART1 },
+ [NODE_SPI_0] = { MM_SPI0 },
+ [NODE_SPI_1] = { MM_SPI1 },
+ [NODE_I2C_0] = { MM_I2C0 },
+ [NODE_I2C_1] = { MM_I2C1 },
+ [NODE_SD_0] = { MM_SD0 },
+ [NODE_SD_1] = { MM_SD1 },
+ [NODE_DP] = { MM_DP },
+
+ /* Guest with GDMA Channel 0 gets PM access. Other guests don't. */
+ [NODE_GDMA] = { MM_GDMA_CH0 },
+ /* Guest with ADMA Channel 0 gets PM access. Other guests don't. */
+ [NODE_ADMA] = { MM_ADMA_CH0 },
+
+ [NODE_NAND] = { MM_NAND },
+ [NODE_QSPI] = { MM_QSPI },
+ [NODE_GPIO] = { MM_GPIO },
+ [NODE_CAN_0] = { MM_CAN0 },
+ [NODE_CAN_1] = { MM_CAN1 },
+
+ /* Only for the hardware domain. */
+ [NODE_AFI] = { .hwdom_access = true },
+ [NODE_APLL] = { .hwdom_access = true },
+ [NODE_VPLL] = { .hwdom_access = true },
+ [NODE_DPLL] = { .hwdom_access = true },
+ [NODE_RPLL] = { .hwdom_access = true },
+ [NODE_IOPLL] = { .hwdom_access = true },
+ [NODE_DDR] = { .hwdom_access = true },
+ [NODE_IPI_APU] = { .hwdom_access = true },
+ [NODE_PCAP] = { .hwdom_access = true },
+
+ [NODE_PCIE] = { MM_PCIE_ATTRIB },
+ [NODE_RTC] = { MM_RTC },
+};
+
+/*
+ * This table maps reset line IDs into a memory address.
+ * If a guest has access to the address, it has enough control
+ * over the affected node to grant it access to EEMI calls for
+ * resetting that node.
+ */
+#define PM_RESET_IDX(n) (n - PM_RESET_PCIE_CFG)
+static const struct pm_access pm_reset_access[] = {
+ [PM_RESET_IDX(PM_RESET_PCIE_CFG)] = { MM_AXIPCIE_MAIN },
+ [PM_RESET_IDX(PM_RESET_PCIE_BRIDGE)] = { MM_PCIE_ATTRIB },
+ [PM_RESET_IDX(PM_RESET_PCIE_CTRL)] = { MM_PCIE_ATTRIB },
+
+ [PM_RESET_IDX(PM_RESET_DP)] = { MM_DP },
+ [PM_RESET_IDX(PM_RESET_SWDT_CRF)] = { MM_SWDT },
+ [PM_RESET_IDX(PM_RESET_AFI_FM5)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_AFI_FM4)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_AFI_FM3)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_AFI_FM2)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_AFI_FM1)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_AFI_FM0)] = { .hwdom_access = true },
+
+ /* Channel 0 grants PM access. */
+ [PM_RESET_IDX(PM_RESET_GDMA)] = { MM_GDMA_CH0 },
+ [PM_RESET_IDX(PM_RESET_GPU_PP1)] = { MM_GPU },
+ [PM_RESET_IDX(PM_RESET_GPU_PP0)] = { MM_GPU },
+ [PM_RESET_IDX(PM_RESET_GT)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_SATA)] = { MM_SATA_AHCI_HBA },
+
+ /* We don't allow anyone to turn on/off the ACPUs. */
+ [PM_RESET_IDX(PM_RESET_ACPU3_PWRON)] = { 0 },
+ [PM_RESET_IDX(PM_RESET_ACPU2_PWRON)] = { 0 },
+ [PM_RESET_IDX(PM_RESET_ACPU1_PWRON)] = { 0 },
+ [PM_RESET_IDX(PM_RESET_ACPU0_PWRON)] = { 0 },
+ [PM_RESET_IDX(PM_RESET_APU_L2)] = { 0 },
+ [PM_RESET_IDX(PM_RESET_ACPU3)] = { 0 },
+ [PM_RESET_IDX(PM_RESET_ACPU2)] = { 0 },
+ [PM_RESET_IDX(PM_RESET_ACPU1)] = { 0 },
+ [PM_RESET_IDX(PM_RESET_ACPU0)] = { 0 },
+
+ [PM_RESET_IDX(PM_RESET_DDR)] = { 0 },
+
+ [PM_RESET_IDX(PM_RESET_APM_FPD)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_SOFT)] = { .hwdom_access = true },
+
+ [PM_RESET_IDX(PM_RESET_GEM0)] = { MM_GEM0 },
+ [PM_RESET_IDX(PM_RESET_GEM1)] = { MM_GEM1 },
+ [PM_RESET_IDX(PM_RESET_GEM2)] = { MM_GEM2 },
+ [PM_RESET_IDX(PM_RESET_GEM3)] = { MM_GEM3 },
+
+ [PM_RESET_IDX(PM_RESET_QSPI)] = { MM_QSPI },
+ [PM_RESET_IDX(PM_RESET_UART0)] = { MM_UART0 },
+ [PM_RESET_IDX(PM_RESET_UART1)] = { MM_UART1 },
+ [PM_RESET_IDX(PM_RESET_SPI0)] = { MM_SPI0 },
+ [PM_RESET_IDX(PM_RESET_SPI1)] = { MM_SPI1 },
+ [PM_RESET_IDX(PM_RESET_SDIO0)] = { MM_SD0 },
+ [PM_RESET_IDX(PM_RESET_SDIO1)] = { MM_SD1 },
+ [PM_RESET_IDX(PM_RESET_CAN0)] = { MM_CAN0 },
+ [PM_RESET_IDX(PM_RESET_CAN1)] = { MM_CAN1 },
+ [PM_RESET_IDX(PM_RESET_I2C0)] = { MM_I2C0 },
+ [PM_RESET_IDX(PM_RESET_I2C1)] = { MM_I2C1 },
+ [PM_RESET_IDX(PM_RESET_TTC0)] = { MM_TTC0 },
+ [PM_RESET_IDX(PM_RESET_TTC1)] = { MM_TTC1 },
+ [PM_RESET_IDX(PM_RESET_TTC2)] = { MM_TTC2 },
+ [PM_RESET_IDX(PM_RESET_TTC3)] = { MM_TTC3 },
+ [PM_RESET_IDX(PM_RESET_SWDT_CRL)] = { MM_SWDT },
+ [PM_RESET_IDX(PM_RESET_NAND)] = { MM_NAND },
+ /* ADMA Channel 0 grants access to pull the reset signal. */
+ [PM_RESET_IDX(PM_RESET_ADMA)] = { MM_ADMA_CH0 },
+ [PM_RESET_IDX(PM_RESET_GPIO)] = { MM_GPIO },
+ /* FIXME: What is this? */
+ [PM_RESET_IDX(PM_RESET_IOU_CC)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_TIMESTAMP)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_RPU_R50)] = { MM_RPU },
+ [PM_RESET_IDX(PM_RESET_RPU_R51)] = { MM_RPU },
+ [PM_RESET_IDX(PM_RESET_RPU_AMBA)] = { MM_RPU },
+ [PM_RESET_IDX(PM_RESET_OCM)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_RPU_PGE)] = { MM_RPU },
+
+ [PM_RESET_IDX(PM_RESET_USB0_CORERESET)] = { MM_USB3_0 },
+ [PM_RESET_IDX(PM_RESET_USB0_HIBERRESET)] = { MM_USB3_0 },
+ [PM_RESET_IDX(PM_RESET_USB0_APB)] = { MM_USB3_0 },
+
+ [PM_RESET_IDX(PM_RESET_USB1_CORERESET)] = { MM_USB3_1 },
+ [PM_RESET_IDX(PM_RESET_USB1_HIBERRESET)] = { MM_USB3_1 },
+ [PM_RESET_IDX(PM_RESET_USB1_APB)] = { MM_USB3_1 },
+
+ [PM_RESET_IDX(PM_RESET_IPI)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_APM_LPD)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_RTC)] = { MM_RTC },
+ [PM_RESET_IDX(PM_RESET_SYSMON)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_AFI_FM6)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_LPD_SWDT)] = { MM_SWDT },
+ [PM_RESET_IDX(PM_RESET_FPD)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_RPU_DBG1)] = { MM_RPU },
+ [PM_RESET_IDX(PM_RESET_RPU_DBG0)] = { MM_RPU },
+ [PM_RESET_IDX(PM_RESET_DBG_LPD)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_DBG_FPD)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_APLL)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_DPLL)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_VPLL)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_IOPLL)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_RPLL)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_0)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_1)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_2)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_3)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_4)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_5)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_6)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_7)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_8)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_9)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_10)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_11)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_12)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_13)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_14)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_15)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_16)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_17)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_18)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_19)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_20)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_21)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_22)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_23)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_24)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_25)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_26)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_27)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_28)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_29)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_30)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_GPO3_PL_31)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_RPU_LS)] = { MM_RPU },
+ [PM_RESET_IDX(PM_RESET_PS_ONLY)] = { .hwdom_access = true },
+ [PM_RESET_IDX(PM_RESET_PL)] = { .hwdom_access = true },
+};
+
+/*
+ * This table maps reset line IDs into a memory address.
+ * If a guest has access to the address, it has enough control
+ * over the affected node to grant it access to EEMI calls for
+ * resetting that node.
+ */
+static const struct {
+ uint64_t start;
+ uint64_t end; /* Inclusive. If not set, single reg entry. */
+ uint32_t mask; /* Zero means no mask, i.e all bits. */
+ enum pm_node_id node;
+ bool hwdom_access;
+ bool readonly;
+} pm_mmio_access[] = {
+ {
+ .start = MM_CRF_APB + R_CRF_APLL_CTRL,
+ .end = MM_CRF_APB + R_CRF_ACPU_CTRL,
+ .hwdom_access = true
+ },
+ {
+ .start = MM_CRL_APB + R_CRL_IOPLL_CTRL,
+ .end = MM_CRL_APB + R_CRL_RPLL_TO_FPD_CTRL,
+ .hwdom_access = true
+ },
+ { .start = MM_CRF_APB + R_CRF_DP_VIDEO_REF_CTRL, .node = NODE_DP },
+ { .start = MM_CRF_APB + R_CRF_DP_STC_REF_CTRL, .node = NODE_DP },
+ { .start = MM_CRF_APB + R_CRF_GPU_REF_CTRL, .node = NODE_GPU },
+ { .start = MM_CRF_APB + R_CRF_SATA_REF_CTRL, .node = NODE_SATA },
+ { .start = MM_CRF_APB + R_CRF_PCIE_REF_CTRL, .node = NODE_PCIE },
+ { .start = MM_CRF_APB + R_CRF_GDMA_REF_CTRL, .node = NODE_GDMA },
+ { .start = MM_CRF_APB + R_CRF_DPDMA_REF_CTRL, .node = NODE_DP },
+ { .start = MM_CRL_APB + R_CRL_USB3_DUAL_REF_CTRL, .node = NODE_USB_0 },
+ { .start = MM_CRL_APB + R_CRL_USB0_BUS_REF_CTRL, .node = NODE_USB_0 },
+ { .start = MM_CRL_APB + R_CRL_USB1_BUS_REF_CTRL, .node = NODE_USB_1 },
+ { .start = MM_CRL_APB + R_CRL_USB1_BUS_REF_CTRL, .node = NODE_USB_1 },
+ { .start = MM_CRL_APB + R_CRL_GEM0_REF_CTRL, .node = NODE_ETH_0 },
+ { .start = MM_CRL_APB + R_CRL_GEM1_REF_CTRL, .node = NODE_ETH_1 },
+ { .start = MM_CRL_APB + R_CRL_GEM2_REF_CTRL, .node = NODE_ETH_2 },
+ { .start = MM_CRL_APB + R_CRL_GEM3_REF_CTRL, .node = NODE_ETH_3 },
+ { .start = MM_CRL_APB + R_CRL_QSPI_REF_CTRL, .node = NODE_QSPI },
+ { .start = MM_CRL_APB + R_CRL_SDIO0_REF_CTRL, .node = NODE_SD_0 },
+ { .start = MM_CRL_APB + R_CRL_SDIO1_REF_CTRL, .node = NODE_SD_1 },
+ { .start = MM_CRL_APB + R_CRL_UART0_REF_CTRL, .node = NODE_UART_0 },
+ { .start = MM_CRL_APB + R_CRL_UART1_REF_CTRL, .node = NODE_UART_1 },
+ { .start = MM_CRL_APB + R_CRL_SPI0_REF_CTRL, .node = NODE_SPI_0 },
+ { .start = MM_CRL_APB + R_CRL_SPI1_REF_CTRL, .node = NODE_SPI_1 },
+ { .start = MM_CRL_APB + R_CRL_CAN0_REF_CTRL, .node = NODE_CAN_0 },
+ { .start = MM_CRL_APB + R_CRL_CAN1_REF_CTRL, .node = NODE_CAN_1 },
+ { .start = MM_CRL_APB + R_CRL_CPU_R5_CTRL, .node = NODE_RPU },
+ { .start = MM_CRL_APB + R_CRL_IOU_SWITCH_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_CSU_PLL_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PCAP_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_LPD_SWITCH_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_LPD_LSBUS_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_DBG_LPD_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_NAND_REF_CTRL, .node = NODE_NAND },
+ { .start = MM_CRL_APB + R_CRL_ADMA_REF_CTRL, .node = NODE_ADMA },
+ { .start = MM_CRL_APB + R_CRL_PL0_REF_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL1_REF_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL2_REF_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL3_REF_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL0_THR_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL1_THR_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL2_THR_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL3_THR_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL0_THR_CNT, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL1_THR_CNT, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL2_THR_CNT, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_PL3_THR_CNT, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_GEM_TSU_REF_CTRL, .node = NODE_ETH_0 },
+ { .start = MM_CRL_APB + R_CRL_DLL_REF_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_AMS_REF_CTRL, .hwdom_access = true },
+ { .start = MM_CRL_APB + R_CRL_I2C0_REF_CTRL, .node = NODE_I2C_0 },
+ { .start = MM_CRL_APB + R_CRL_I2C1_REF_CTRL, .node = NODE_I2C_1 },
+ { .start = MM_CRL_APB + R_CRL_TIMESTAMP_REF_CTRL, .hwdom_access = true },
+ /* MIOs are controlled by the hardware domain. */
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_MIO_PIN_0,
+ .end = MM_IOU_SLCR + R_IOU_SLCR_MIO_MST_TRI2,
+ .hwdom_access = true
+ },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_WDT_CLK_SEL, .hwdom_access = true },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_CAN_MIO_CTRL,
+ .mask = 0x1ff, .node = NODE_CAN_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_CAN_MIO_CTRL,
+ .mask = 0x1ff << 15, .node = NODE_CAN_1
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CLK_CTRL,
+ .mask = 0xf, .node = NODE_ETH_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CLK_CTRL,
+ .mask = 0xf << 5, .node = NODE_ETH_1
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CLK_CTRL,
+ .mask = 0xf << 10, .node = NODE_ETH_2
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CLK_CTRL,
+ .mask = 0xf << 15, .node = NODE_ETH_3
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CLK_CTRL,
+ .mask = 0x7 << 20, .hwdom_access = true
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_SDIO_CLK_CTRL,
+ .mask = 0x7, .node = NODE_SD_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_SDIO_CLK_CTRL,
+ .mask = 0x7 << 17, .node = NODE_SD_1
+ },
+
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_CTRL_REG_SD,
+ .mask = 0x1, .node = NODE_SD_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_CTRL_REG_SD,
+ .mask = 0x1 << 15, .node = NODE_SD_1
+ },
+ /* A series of SD regs with the same layout. */
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_SD_ITAPDLY,
+ .end = MM_IOU_SLCR + R_IOU_SLCR_SD_CDN_CTRL,
+ .mask = 0x3ff << 0, .node = NODE_SD_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_SD_ITAPDLY,
+ .end = MM_IOU_SLCR + R_IOU_SLCR_SD_CDN_CTRL,
+ .mask = 0x3ff << 16, .node = NODE_SD_1
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CTRL,
+ .mask = 0x3 << 0, .node = NODE_ETH_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CTRL,
+ .mask = 0x3 << 2, .node = NODE_ETH_1
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CTRL,
+ .mask = 0x3 << 4, .node = NODE_ETH_2
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_GEM_CTRL,
+ .mask = 0x3 << 6, .node = NODE_ETH_3
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_TTC_APB_CLK,
+ .mask = 0x3 << 0, .node = NODE_TTC_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_TTC_APB_CLK,
+ .mask = 0x3 << 2, .node = NODE_TTC_1
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_TTC_APB_CLK,
+ .mask = 0x3 << 4, .node = NODE_TTC_2
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_TTC_APB_CLK,
+ .mask = 0x3 << 6, .node = NODE_TTC_3
+ },
+
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_TAPDLY_BYPASS,
+ .mask = 0x3, .node = NODE_NAND
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_TAPDLY_BYPASS,
+ .mask = 0x1 << 2, .node = NODE_QSPI
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_COHERENT_CTRL,
+ .mask = 0xf << 0, .node = NODE_ETH_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_COHERENT_CTRL,
+ .mask = 0xf << 4, .node = NODE_ETH_1
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_COHERENT_CTRL,
+ .mask = 0xf << 8, .node = NODE_ETH_2
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_COHERENT_CTRL,
+ .mask = 0xf << 12, .node = NODE_ETH_3
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_COHERENT_CTRL,
+ .mask = 0xf << 16, .node = NODE_SD_0
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_COHERENT_CTRL,
+ .mask = 0xf << 20, .node = NODE_SD_1
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_COHERENT_CTRL,
+ .mask = 0xf << 24, .node = NODE_NAND
+ },
+ {
+ .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_COHERENT_CTRL,
+ .mask = 0xf << 28, .node = NODE_QSPI
+ },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_VIDEO_PSS_CLK_SEL, .hwdom_access = true },
+ /* No access to R_IOU_SLCR_IOU_INTERCONNECT_ROUTE at all. */
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_GEM0, .node = NODE_ETH_0 },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_GEM1, .node = NODE_ETH_1 },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_GEM2, .node = NODE_ETH_2 },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_GEM3, .node = NODE_ETH_3 },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_SD0, .node = NODE_SD_0 },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_SD1, .node = NODE_SD_1 },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_CAN0, .node = NODE_CAN_0 },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_CAN1, .node = NODE_CAN_1 },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_LQSPI, .node = NODE_QSPI },
+ { .start = MM_IOU_SLCR + R_IOU_SLCR_IOU_RAM_NAND, .node = NODE_NAND },
+ {
+ .start = MM_PMU_GLOBAL + R_PMU_GLOBAL_PWR_STATE,
+ .readonly = true,
+ },
+ {
+ .start = MM_PMU_GLOBAL + R_PMU_GLOBAL_GLOBAL_GEN_STORAGE0,
+ .end = MM_PMU_GLOBAL + R_PMU_GLOBAL_PERS_GLOB_GEN_STORAGE7,
+ .readonly = true,
+ },
+ {
+ /* Universal read-only access to CRF. Linux CCF needs this. */
+ .start = MM_CRF_APB, .end = MM_CRF_APB + 0x104,
+ .readonly = true,
+ },
+ {
+ /* Universal read-only access to CRL. Linux CCF needs this. */
+ .start = MM_CRL_APB, .end = MM_CRL_APB + 0x284,
+ .readonly = true,
+ }
+};
+
+static bool pm_check_access(const struct pm_access *acl, struct domain *d, int idx)
+{
+ unsigned long mfn;
+
+ if ( acl[idx].hwdom_access && is_hardware_domain(d) )
+ return true;
+
+ mfn = paddr_to_pfn(acl[idx].addr);
+ if ( !mfn )
+ return false;
+
+ return iomem_access_permitted(d, mfn, mfn);
}
-static inline bool domain_has_reset_access(struct domain *d, uint32_t rst)
+/* Check if a domain has access to a node. */
+static bool domain_has_node_access(struct domain *d, enum pm_node_id node)
{
- return is_hardware_domain(d);
+ if ( node < 0 || node > ARRAY_SIZE(pm_node_access) )
+ return false;
+
+ /* NODE_UNKNOWN is treated as a wildcard. */
+ if ( node == NODE_UNKNOWN )
+ return true;
+
+ return pm_check_access(pm_node_access, d, node);
+}
+
+/* Check if a domain has access to a reset line. */
+static bool domain_has_reset_access(struct domain *d, enum pm_reset rst)
+{
+ int rst_idx = PM_RESET_IDX(rst);
+
+ if ( rst_idx < 0 || rst_idx > ARRAY_SIZE(pm_reset_access) )
+ return false;
+
+ return pm_check_access(pm_reset_access, d, rst_idx);
+}
+
+/*
+ * Check if a given domain has access to perform an indirect
+ * MMIO access.
+ *
+ * If the provided mask is invalid, it will be fixed up.
+ */
+static bool domain_mediate_mmio_access(struct domain *d,
+ bool write, uint64_t addr,
+ uint32_t *mask)
+{
+ unsigned int i;
+ bool ret = false;
+ uint32_t prot_mask = 0;
+
+ ASSERT(mask);
+
+ /*
+ * The hardware domain gets read access to everything.
+ * Lower layers will do further filtering.
+ */
+ if ( !write && is_hardware_domain(d) )
+ return true;
+
+ /* Scan the ACL. */
+ for ( i = 0; i < ARRAY_SIZE(pm_mmio_access); i++ ) {
+ bool r;
+
+ /* Check if the address is OK. */
+ if ( pm_mmio_access[i].end ) {
+ /* Memory range. */
+ if ( addr < pm_mmio_access[i].start )
+ continue;
+ if ( addr > pm_mmio_access[i].end )
+ continue;
+ } else {
+ /* Single register. */
+ if ( addr != pm_mmio_access[i].start )
+ continue;
+ }
+
+ if ( write && pm_mmio_access[i].readonly )
+ continue;
+ if ( pm_mmio_access[i].hwdom_access && !is_hardware_domain(d) )
+ continue;
+
+ /* Unlimited access is represented by a zero mask. */
+ ASSERT( pm_mmio_access[i].mask != 0xFFFFFFFF );
+
+ r = domain_has_node_access(d, pm_mmio_access[i].node);
+ if ( r ) {
+ /* We've got access to this reg (or parts of it). */
+ ret = true;
+ /* Masking only applies to writes, so reads can exit here. */
+ if ( !write )
+ break;
+
+ /* Permit write access to selected bits. */
+ prot_mask |= pm_mmio_access[i].mask ? pm_mmio_access[i].mask : ~0;
+ if ( prot_mask == 0xFFFFFFFF )
+ break; /* Full access, we're done. */
+ } else {
+ if ( !pm_mmio_access[i].mask ) {
+ /*
+ * The entire reg is tied to a device that we don't have
+ * access to. No point in continuing.
+ */
+ return false;
+ }
+ }
+ }
+
+ /* Masking only applies to writes. */
+ if ( write )
+ *mask &= prot_mask;
+ return ret;
}
bool zynqmp_eemi(struct cpu_user_regs *regs)
uint32_t nodeid = get_user_reg(regs, 1);
unsigned int pm_fn = fid & 0xFFFF;
enum pm_ret_status ret;
+ bool is_mmio_write = false;
+ uint32_t mmio_mask = get_user_reg(regs, 1) >> 32;
switch ( fid )
{
case EEMI_FID(PM_GET_CHIPID):
goto forward_to_fw;
+ case ZYNQMP_SIP_SVC_CALL_COUNT:
+ case ZYNQMP_SIP_SVC_UID:
+ case ZYNQMP_SIP_SVC_VERSION:
+ goto forward_to_fw;
+
/* No MMIO access is allowed from non-secure domains */
case EEMI_FID(PM_MMIO_WRITE):
+ is_mmio_write = true;
+ /* Fallthrough. */
case EEMI_FID(PM_MMIO_READ):
- gprintk(XENLOG_WARNING,
- "zynqmp-pm: fn=%u No MMIO access to %u\n", pm_fn, nodeid);
- ret = XST_PM_NO_ACCESS;
- goto done;
+ if ( !domain_mediate_mmio_access(current->domain,
+ is_mmio_write,
+ nodeid, &mmio_mask) ) {
+ printk("eemi: fn=%d No access to MMIO %s %x\n",
+ pm_fn, is_mmio_write ? "write" : "read", nodeid);
+ ret = XST_PM_NO_ACCESS;
+ goto done;
+ }
+ goto forward_to_fw;
/* Exclusive to the hardware domain. */
case EEMI_FID(PM_INIT):
--- /dev/null
+/*
+ * Merge of various auto-generated memory map and register
+ * definition files.
+ */
+
+/* Selected set of memory-map definitions: */
+#define MM_IOU_S 0xff000000
+#define MM_IPI 0xff300000
+#define MM_LPD_SLCR 0xff410000
+#define MM_LPD_SLCR_SECURE 0xff4b0000
+#define MM_CRL_APB 0xff5e0000
+#define MM_OCM 0xff960000
+#define MM_LPD_XPPU 0xff980000
+#define MM_RPU 0xff9a0000
+#define MM_AFIFM6 0xff9b0000
+#define MM_LPD_XPPU_SINK 0xff9c0000
+#define MM_USB3_0 0xff9d0000
+#define MM_USB3_1 0xff9e0000
+#define MM_APM_INTC_OCM 0xffa00000
+#define MM_APM_LPD_FPD 0xffa10000
+#define MM_AMS_CTRL 0xffa50000
+#define MM_AMS_PS_SYSMON 0xffa50800
+#define MM_AMS_PL_SYSMON 0xffa50c00
+#define MM_RTC 0xffa60000
+#define MM_OCM_XMPU_CFG 0xffa70000
+#define MM_ADMA_CH0 0xffa80000
+#define MM_ADMA_CH1 0xffa90000
+#define MM_ADMA_CH2 0xffaa0000
+#define MM_ADMA_CH3 0xffab0000
+#define MM_ADMA_CH4 0xffac0000
+#define MM_ADMA_CH5 0xffad0000
+#define MM_ADMA_CH6 0xffae0000
+
+#define MM_IOU_GPV 0xfe0fffff
+#define MM_LPD_GPV 0xfe1fffff
+#define MM_USB3_0_XHCI 0xfe2fffff
+#define MM_USB3_1_XHCI 0xfe3fffff
+#define MM_CORESIGHT_SOC_ROM 0xfe80ffff
+#define MM_CORESIGHT_SOC_TSGEN 0xfe90ffff
+#define MM_CORESIGHT_SOC_FUNN_0 0xfe91ffff
+#define MM_CORESIGHT_SOC_FUNN_1 0xfe92ffff
+#define MM_CORESIGHT_SOC_FUNN_2 0xfe93ffff
+#define MM_CORESIGHT_SOC_ETF_1 0xfe94ffff
+#define MM_CORESIGHT_SOC_ETF_2 0xfe95ffff
+#define MM_CORESIGHT_SOC_REPLIC 0xfe96ffff
+#define MM_CORESIGHT_SOC_ETR 0xfe97ffff
+#define MM_CORESIGHT_SOC_TPIU 0xfe98ffff
+#define MM_CORESIGHT_SOC_CTI_0 0xfe99ffff
+#define MM_CORESIGHT_SOC_CTI_1 0xfe9affff
+#define MM_CORESIGHT_SOC_CTI_2 0xfe9bffff
+#define MM_CORESIGHT_SOC_STM 0xfe9cffff
+#define MM_CORESIGHT_SOC_FTM 0xfe9dffff
+#define MM_CORESIGHT_SOC_ATM_0 0xfe9effff
+#define MM_CORESIGHT_SOC_ATM_1 0xfe9fffff
+#define MM_CORESIGHT_R5_ROM 0xfebe0fff
+#define MM_CORESIGHT_R5_DBG_0 0xfebf0fff
+#define MM_CORESIGHT_R5_PMU_0 0xfebf1fff
+#define MM_CORESIGHT_R5_DBG_1 0xfebf2fff
+#define MM_CORESIGHT_R5_PMU_1 0xfebf3fff
+#define MM_CORESIGHT_R5_CTI_0 0xfebf8fff
+#define MM_CORESIGHT_R5_CTI_1 0xfebf9fff
+#define MM_CORESIGHT_R5_ETM_0 0xfebfcfff
+#define MM_CORESIGHT_R5_ETM_1 0xfebfdfff
+#define MM_CORESIGHT_A53_ROM 0xfec0ffff
+#define MM_CORESIGHT_A53_DBG_0 0xfec1ffff
+#define MM_CORESIGHT_A53_CTI_0 0xfec2ffff
+#define MM_CORESIGHT_A53_PMU_0 0xfec3ffff
+#define MM_CORESIGHT_A53_ETM_0 0xfec4ffff
+#define MM_CORESIGHT_A53_DBG_1 0xfed1ffff
+#define MM_CORESIGHT_A53_CTI_1 0xfed2ffff
+#define MM_CORESIGHT_A53_PMU_1 0xfed3ffff
+#define MM_CORESIGHT_A53_ETM_1 0xfed4ffff
+#define MM_CORESIGHT_A53_DBG_2 0xfee1ffff
+#define MM_CORESIGHT_A53_CTI_2 0xfee2ffff
+#define MM_CORESIGHT_A53_PMU_2 0xfee3ffff
+#define MM_CORESIGHT_A53_ETM_2 0xfee4ffff
+#define MM_CORESIGHT_A53_DBG_3 0xfef1ffff
+#define MM_CORESIGHT_A53_CTI_3 0xfef2ffff
+#define MM_CORESIGHT_A53_PMU_3 0xfef3ffff
+
+#define MM_DDRSS 0xfd000000
+#define MM_SATA_AHCI_HBA 0xfd0c0000
+#define MM_SATA_AHCI_VENDOR 0xfd0c00a0
+#define MM_SATA_AHCI_PORT0_CNTRL 0xfd0c0100
+#define MM_SATA_AHCI_PORT1_CNTRL 0xfd0c0180
+#define MM_AXIPCIE_MAIN 0xfd0e0000
+#define MM_AXIPCIE_INGRESS0 0xfd0e0800
+#define MM_AXIPCIE_INGRESS1 0xfd0e0820
+#define MM_AXIPCIE_INGRESS2 0xfd0e0840
+#define MM_AXIPCIE_INGRESS3 0xfd0e0860
+#define MM_AXIPCIE_INGRESS4 0xfd0e0880
+#define MM_AXIPCIE_INGRESS5 0xfd0e08a0
+#define MM_AXIPCIE_INGRESS6 0xfd0e08c0
+#define MM_AXIPCIE_INGRESS7 0xfd0e08e0
+#define MM_AXIPCIE_EGRESS0 0xfd0e0c00
+#define MM_AXIPCIE_EGRESS1 0xfd0e0c20
+#define MM_AXIPCIE_EGRESS2 0xfd0e0c40
+#define MM_AXIPCIE_EGRESS3 0xfd0e0c60
+#define MM_AXIPCIE_EGRESS4 0xfd0e0c80
+#define MM_AXIPCIE_EGRESS5 0xfd0e0ca0
+#define MM_AXIPCIE_EGRESS6 0xfd0e0cc0
+#define MM_AXIPCIE_EGRESS7 0xfd0e0ce0
+#define MM_AXIPCIE_DMA0 0xfd0f0000
+#define MM_AXIPCIE_DMA1 0xfd0f0080
+#define MM_AXIPCIE_DMA2 0xfd0f0100
+#define MM_AXIPCIE_DMA3 0xfd0f0180
+#define MM_AXIPCIE_MSIX_TABLE 0xfd0f1000
+#define MM_AXIPCIE_MSIX_PBA 0xfd0f2000
+#define MM_CRF_APB 0xfd1a0000
+#define MM_AFIFM0 0xfd360000
+#define MM_AFIFM1 0xfd370000
+#define MM_AFIFM2 0xfd380000
+#define MM_AFIFM3 0xfd390000
+#define MM_AFIFM4 0xfd3a0000
+#define MM_AFIFM5 0xfd3b0000
+#define MM_SIOU 0xfd3d0000
+#define MM_SERDES 0xfd400000
+#define MM_PCIE_ATTRIB 0xfd480000
+#define MM_APM_CCI_INTC 0xfd490000
+#define MM_DP 0xfd4a0000
+#define MM_GPU 0xfd4b0000
+#define MM_DPDMA 0xfd4c0000
+#define MM_WDT 0xfd4d0000
+#define MM_FPD_XMPU_SINK 0xfd4f0000
+#define MM_GDMA_CH0 0xfd500000
+#define MM_GDMA_CH1 0xfd510000
+#define MM_GDMA_CH2 0xfd520000
+#define MM_GDMA_CH3 0xfd530000
+#define MM_GDMA_CH4 0xfd540000
+#define MM_GDMA_CH5 0xfd550000
+#define MM_GDMA_CH6 0xfd560000
+#define MM_GDMA_CH7 0xfd570000
+#define MM_APU 0xfd5c0000
+#define MM_FPD_XMPU_CFG 0xfd5d0000
+#define MM_CCI_REG 0xfd5e0000
+#define MM_SMMU_REG 0xfd5f0000
+#define MM_FPD_SLCR 0xfd610000
+#define MM_FPD_SLCR_SECURE 0xfd690000
+#define MM_CCI_GPV 0xfd6e0000
+#define MM_FPD_GPV 0xfd700000
+
+#define MM_QSPI_Linear_Address 0xc0000000
+#define MM_UART0 0xff000000
+#define MM_UART1 0xff010000
+#define MM_I2C0 0xff020000
+#define MM_I2C1 0xff030000
+#define MM_SPI0 0xff040000
+#define MM_SPI1 0xff050000
+#define MM_CAN0 0xff060000
+#define MM_CAN1 0xff070000
+#define MM_GPIO 0xff0a0000
+#define MM_GEM0 0xff0b0000
+#define MM_GEM1 0xff0c0000
+#define MM_GEM2 0xff0d0000
+#define MM_GEM3 0xff0e0000
+#define MM_QSPI 0xff0f0000
+#define MM_NAND 0xff100000
+#define MM_TTC0 0xff110000
+#define MM_TTC1 0xff120000
+#define MM_TTC2 0xff130000
+#define MM_TTC3 0xff140000
+#define MM_SWDT 0xff150000
+#define MM_SD0 0xff160000
+#define MM_SD1 0xff170000
+#define MM_IOU_SLCR 0xff180000
+#define MM_IOU_SECURE_SLCR 0xff240000
+#define MM_IOU_SCNTR 0xff250000
+
+#define MM_alg_vcu_enc_top 0xa0000000
+#define MM_alg_vcu_dec_top 0xa0020000
+
+#define MM_PMU_GLOBAL 0xffd80000
+#define MM_CSU 0xffca0000
+
+/* Selected set of register definitions: */
+#define R_CRF_APLL_CTRL 0x20
+#define R_CRF_ACPU_CTRL 0x60
+#define R_CRF_DP_VIDEO_REF_CTRL 0x70
+#define R_CRF_DP_STC_REF_CTRL 0x7c
+#define R_CRF_GPU_REF_CTRL 0x84
+#define R_CRF_SATA_REF_CTRL 0xa0
+#define R_CRF_PCIE_REF_CTRL 0xb4
+#define R_CRF_GDMA_REF_CTRL 0xb8
+#define R_CRF_DPDMA_REF_CTRL 0xbc
+
+#define R_CRL_IOPLL_CTRL 0x20
+#define R_CRL_IOPLL_CFG 0x24
+#define R_CRL_IOPLL_FRAC_CFG 0x28
+#define R_CRL_RPLL_CTRL 0x30
+#define R_CRL_RPLL_CFG 0x34
+#define R_CRL_RPLL_FRAC_CFG 0x38
+#define R_CRL_PLL_STATUS 0x40
+#define R_CRL_IOPLL_TO_FPD_CTRL 0x44
+#define R_CRL_RPLL_TO_FPD_CTRL 0x48
+#define R_CRL_USB3_DUAL_REF_CTRL 0x4c
+#define R_CRL_GEM0_REF_CTRL 0x50
+#define R_CRL_GEM1_REF_CTRL 0x54
+#define R_CRL_GEM2_REF_CTRL 0x58
+#define R_CRL_GEM3_REF_CTRL 0x5c
+#define R_CRL_USB0_BUS_REF_CTRL 0x60
+#define R_CRL_USB1_BUS_REF_CTRL 0x64
+#define R_CRL_QSPI_REF_CTRL 0x68
+#define R_CRL_SDIO0_REF_CTRL 0x6c
+#define R_CRL_SDIO1_REF_CTRL 0x70
+#define R_CRL_UART0_REF_CTRL 0x74
+#define R_CRL_UART1_REF_CTRL 0x78
+#define R_CRL_SPI0_REF_CTRL 0x7c
+#define R_CRL_SPI1_REF_CTRL 0x80
+#define R_CRL_CAN0_REF_CTRL 0x84
+#define R_CRL_CAN1_REF_CTRL 0x88
+#define R_CRL_CPU_R5_CTRL 0x90
+#define R_CRL_IOU_SWITCH_CTRL 0x9c
+#define R_CRL_CSU_PLL_CTRL 0xa0
+#define R_CRL_PCAP_CTRL 0xa4
+#define R_CRL_LPD_SWITCH_CTRL 0xa8
+#define R_CRL_LPD_LSBUS_CTRL 0xac
+#define R_CRL_DBG_LPD_CTRL 0xb0
+#define R_CRL_NAND_REF_CTRL 0xb4
+#define R_CRL_ADMA_REF_CTRL 0xb8
+#define R_CRL_PL0_REF_CTRL 0xc0
+#define R_CRL_PL1_REF_CTRL 0xc4
+#define R_CRL_PL2_REF_CTRL 0xc8
+#define R_CRL_PL3_REF_CTRL 0xcc
+#define R_CRL_PL0_THR_CTRL 0xd0
+#define R_CRL_PL0_THR_CNT 0xd4
+#define R_CRL_PL1_THR_CTRL 0xd8
+#define R_CRL_PL1_THR_CNT 0xdc
+#define R_CRL_PL2_THR_CTRL 0xe0
+#define R_CRL_PL2_THR_CNT 0xe4
+#define R_CRL_PL3_THR_CTRL 0xe8
+#define R_CRL_PL3_THR_CNT 0xfc
+#define R_CRL_GEM_TSU_REF_CTRL 0x100
+#define R_CRL_DLL_REF_CTRL 0x104
+#define R_CRL_AMS_REF_CTRL 0x108
+#define R_CRL_I2C0_REF_CTRL 0x120
+#define R_CRL_I2C1_REF_CTRL 0x124
+#define R_CRL_TIMESTAMP_REF_CTRL 0x128
+
+#define R_PMU_GLOBAL_GLOBAL_GEN_STORAGE0 0x30
+#define R_PMU_GLOBAL_PERS_GLOB_GEN_STORAGE7 0x6c
+
+#define R_PMU_GLOBAL_PWR_STATE 0x100
+
+#define R_CSU_IDCODE 0x40
+
+#define R_IOU_SLCR_MIO_PIN_0 0x0
+#define R_IOU_SLCR_MIO_MST_TRI2 0x20c
+#define R_IOU_SLCR_WDT_CLK_SEL 0x300
+#define R_IOU_SLCR_CAN_MIO_CTRL 0x304
+#define R_IOU_SLCR_GEM_CLK_CTRL 0x308
+#define R_IOU_SLCR_SDIO_CLK_CTRL 0x30c
+#define R_IOU_SLCR_CTRL_REG_SD 0x310
+#define R_IOU_SLCR_SD_ITAPDLY 0x314
+#define R_IOU_SLCR_SD_OTAPDLYSEL 0x318
+#define R_IOU_SLCR_SD_CONFIG_REG1 0x31c
+#define R_IOU_SLCR_SD_CONFIG_REG2 0x320
+#define R_IOU_SLCR_SD_CONFIG_REG3 0x324
+#define R_IOU_SLCR_SD_INITPRESET 0x328
+#define R_IOU_SLCR_SD_DSPPRESET 0x32c
+#define R_IOU_SLCR_SD_HSPDPRESET 0x330
+#define R_IOU_SLCR_SD_SDR12PRESET 0x334
+#define R_IOU_SLCR_SD_SDR25PRESET 0x338
+#define R_IOU_SLCR_SD_SDR50PRSET 0x33c
+#define R_IOU_SLCR_SD_SDR104PRST 0x340
+#define R_IOU_SLCR_SD_DDR50PRESET 0x344
+#define R_IOU_SLCR_SD_MAXCUR1P8 0x34c
+#define R_IOU_SLCR_SD_MAXCUR3P0 0x350
+#define R_IOU_SLCR_SD_MAXCUR3P3 0x354
+#define R_IOU_SLCR_SD_DLL_CTRL 0x358
+#define R_IOU_SLCR_SD_CDN_CTRL 0x35c
+#define R_IOU_SLCR_GEM_CTRL 0x360
+#define R_IOU_SLCR_IOU_TTC_APB_CLK 0x380
+#define R_IOU_SLCR_IOU_TAPDLY_BYPASS 0x390
+#define R_IOU_SLCR_IOU_COHERENT_CTRL 0x400
+#define R_IOU_SLCR_VIDEO_PSS_CLK_SEL 0x404
+#define R_IOU_SLCR_IOU_INTERCONNECT_ROUTE 0x408
+#define R_IOU_SLCR_IOU_RAM_GEM0 0x500
+#define R_IOU_SLCR_IOU_RAM_GEM1 0x504
+#define R_IOU_SLCR_IOU_RAM_GEM2 0x508
+#define R_IOU_SLCR_IOU_RAM_GEM3 0x50c
+#define R_IOU_SLCR_IOU_RAM_SD0 0x510
+#define R_IOU_SLCR_IOU_RAM_SD1 0x514
+#define R_IOU_SLCR_IOU_RAM_CAN0 0x518
+#define R_IOU_SLCR_IOU_RAM_CAN1 0x51c
+#define R_IOU_SLCR_IOU_RAM_LQSPI 0x520
+#define R_IOU_SLCR_IOU_RAM_NAND 0x524