diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 6c84315123..5e282d6124 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -513,6 +513,7 @@ config XLNX_VERSAL default y depends on TCG && AARCH64 select ARM_GIC + select ARM_SMMU500 select CPU_CLUSTER select DEVICE_TREE select PL011 @@ -641,6 +642,9 @@ config FSL_IMX7 select SDHCI select UNIMP +config ARM_SMMU500 + bool + config ARM_SMMUV3 bool diff --git a/hw/arm/meson.build b/hw/arm/meson.build index fb7eea11b2..3b2d3e01b7 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -56,6 +56,7 @@ arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c')) arm_ss.add(when: 'CONFIG_MUSCA', if_true: files('musca.c')) arm_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c')) arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c')) +arm_ss.add(when: 'CONFIG_ARM_SMMU500', if_true: files('smmu500.c')) arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) diff --git a/hw/arm/smmu500.c b/hw/arm/smmu500.c new file mode 100644 index 0000000000..73344be1a5 --- /dev/null +++ b/hw/arm/smmu500.c @@ -0,0 +1,2317 @@ +/* + * QEMU model of the ARM SMMU-500 + * + * Copyright (c) 2014 Xilinx Inc. + * + * Partially autogenerated by xregqemu.py 2014-08-25. + * Written by Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/register.h" +#include "hw/irq.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "sysemu/dma.h" +#include "migration/vmstate.h" +#include "hw/qdev-properties.h" +#include "hw/arm/smmu500.h" + +#ifndef XILINX_SMMU500_ERR_DEBUG +#define XILINX_SMMU500_ERR_DEBUG 0 +#endif + +#define XILINX_SMMU500(obj) \ + OBJECT_CHECK(SMMU500State, (obj), TYPE_XILINX_SMMU500) + +#define DEBUG_DEV_SMMU 0 +#define DEBUG_DEV_SMMU_PTW 0 + +#define D(...) do { \ + if (DEBUG_DEV_SMMU) { \ + qemu_log(__VA_ARGS__); \ + } \ +} while (0); + +#define D_PTW(...) do { \ + if (DEBUG_DEV_SMMU_PTW) { \ + qemu_log(__VA_ARGS__); \ + } \ +} while (0); + + +REG32(SMMU_SCR0, 0x0) + FIELD(SMMU_SCR0, NSCFG, 28, 2) + FIELD(SMMU_SCR0, WACFG, 26, 2) + FIELD(SMMU_SCR0, RACFG, 24, 2) + FIELD(SMMU_SCR0, SHCFG, 22, 2) + FIELD(SMMU_SCR0, SMCFCFG, 21, 1) + FIELD(SMMU_SCR0, MTCFG, 20, 1) + FIELD(SMMU_SCR0, MEMATTR, 16, 4) + FIELD(SMMU_SCR0, BSU, 14, 2) + FIELD(SMMU_SCR0, FB, 13, 1) + FIELD(SMMU_SCR0, PTM, 12, 1) + FIELD(SMMU_SCR0, USFCFG, 10, 1) + FIELD(SMMU_SCR0, GSE, 9, 1) + FIELD(SMMU_SCR0, STALLD, 8, 1) + FIELD(SMMU_SCR0, TRANSIENTCFG, 6, 2) + FIELD(SMMU_SCR0, GCFGFIE, 5, 1) + FIELD(SMMU_SCR0, GCFGFRE, 4, 1) + FIELD(SMMU_SCR0, GFIE, 2, 1) + FIELD(SMMU_SCR0, GFRE, 1, 1) + FIELD(SMMU_SCR0, CLIENTPD, 0, 1) +REG32(SMMU_SCR1, 0x4) + FIELD(SMMU_SCR1, NSCAFRO, 28, 1) + FIELD(SMMU_SCR1, SPMEN, 27, 1) + FIELD(SMMU_SCR1, SIF, 26, 1) + FIELD(SMMU_SCR1, GEFRO, 25, 1) + FIELD(SMMU_SCR1, GASRAE, 24, 1) + FIELD(SMMU_SCR1, NSNUMIRPTO, 16, 8) + FIELD(SMMU_SCR1, NSNUMSMRGO, 8, 8) + FIELD(SMMU_SCR1, NSNUMCBO, 0, 8) +REG32(SMMU_SACR, 0x10) + FIELD(SMMU_SACR, NORMALIZE, 27, 1) + FIELD(SMMU_SACR, CACHE_LOCK, 26, 1) + FIELD(SMMU_SACR, SMMU_PAGESIZE, 16, 1) + FIELD(SMMU_SACR, S2CRB_TLBEN, 10, 1) + FIELD(SMMU_SACR, MMUDISB_TLBEN, 9, 1) + FIELD(SMMU_SACR, SMTNMB_TLBEN, 8, 1) + FIELD(SMMU_SACR, S1WC2EN, 2, 1) +REG32(SMMU_SIDR0, 0x20) + FIELD(SMMU_SIDR0, SES, 31, 1) + FIELD(SMMU_SIDR0, S1TS, 30, 1) + FIELD(SMMU_SIDR0, S2TS, 29, 1) + FIELD(SMMU_SIDR0, NTS, 28, 1) + FIELD(SMMU_SIDR0, SMS, 27, 1) + FIELD(SMMU_SIDR0, ATOSNS, 26, 1) + FIELD(SMMU_SIDR0, PTFS, 24, 2) + FIELD(SMMU_SIDR0, NUMIRPT, 16, 8) + FIELD(SMMU_SIDR0, CTTW, 14, 1) + FIELD(SMMU_SIDR0, BTM, 13, 1) + FIELD(SMMU_SIDR0, NUMSIDB, 9, 4) + FIELD(SMMU_SIDR0, NUMSMRG, 0, 8) +REG32(SMMU_SIDR1, 0x24) + FIELD(SMMU_SIDR1, SMMU_PAGESIZE, 31, 1) + FIELD(SMMU_SIDR1, NUMPAGENDXB, 28, 3) + FIELD(SMMU_SIDR1, NUMS2CB, 16, 8) + FIELD(SMMU_SIDR1, SMCD, 15, 1) + FIELD(SMMU_SIDR1, SSDTP, 12, 1) + FIELD(SMMU_SIDR1, NUMSSDNDXB, 8, 4) + FIELD(SMMU_SIDR1, NUMCB, 0, 8) +REG32(SMMU_SIDR2, 0x28) + FIELD(SMMU_SIDR2, PTFSV8_64KB, 14, 1) + FIELD(SMMU_SIDR2, PTFSV8_16KB, 13, 1) + FIELD(SMMU_SIDR2, TFSV8_4KB, 12, 1) + FIELD(SMMU_SIDR2, UBS, 8, 4) + FIELD(SMMU_SIDR2, OAS, 4, 4) + FIELD(SMMU_SIDR2, IAS, 0, 4) +REG32(SMMU_SIDR7, 0x3c) + FIELD(SMMU_SIDR7, MAJOR, 4, 4) + FIELD(SMMU_SIDR7, MINOR, 0, 4) +REG32(SMMU_SGFAR_LOW, 0x40) +REG32(SMMU_SGFAR_HIGH, 0x44) + FIELD(SMMU_SGFAR_HIGH, FADDR, 0, 17) +REG32(SMMU_SGFSR, 0x48) + FIELD(SMMU_SGFSR, MULTI, 31, 1) + FIELD(SMMU_SGFSR, UUT, 8, 1) + FIELD(SMMU_SGFSR, PF, 7, 1) + FIELD(SMMU_SGFSR, EF, 6, 1) + FIELD(SMMU_SGFSR, CAF, 5, 1) + FIELD(SMMU_SGFSR, UCIF, 4, 1) + FIELD(SMMU_SGFSR, UCBF, 3, 1) + FIELD(SMMU_SGFSR, SMCF, 2, 1) + FIELD(SMMU_SGFSR, USF, 1, 1) + FIELD(SMMU_SGFSR, ICF, 0, 1) +REG32(SMMU_SGFSRRESTORE, 0x4c) + FIELD(SMMU_SGFSRRESTORE, MULTI, 31, 1) + FIELD(SMMU_SGFSRRESTORE, UUT, 8, 1) + FIELD(SMMU_SGFSRRESTORE, PF, 7, 1) + FIELD(SMMU_SGFSRRESTORE, EF, 6, 1) + FIELD(SMMU_SGFSRRESTORE, CAF, 5, 1) + FIELD(SMMU_SGFSRRESTORE, UCIF, 4, 1) + FIELD(SMMU_SGFSRRESTORE, UCBF, 3, 1) + FIELD(SMMU_SGFSRRESTORE, SMCF, 2, 1) + FIELD(SMMU_SGFSRRESTORE, USF, 1, 1) + FIELD(SMMU_SGFSRRESTORE, ICF, 0, 1) +REG32(SMMU_SGFSYNR0, 0x50) + FIELD(SMMU_SGFSYNR0, ATS, 6, 1) + FIELD(SMMU_SGFSYNR0, NSATTR, 5, 1) + FIELD(SMMU_SGFSYNR0, NSSTATE, 4, 1) + FIELD(SMMU_SGFSYNR0, IND, 3, 1) + FIELD(SMMU_SGFSYNR0, PNU, 2, 1) + FIELD(SMMU_SGFSYNR0, WNR, 1, 1) +REG32(SMMU_SGFSYNR1, 0x54) + FIELD(SMMU_SGFSYNR1, SSD_INDEX, 16, 15) + FIELD(SMMU_SGFSYNR1, STREAMID, 0, 15) +REG32(SMMU_STLBIALL, 0x60) +REG32(SMMU_TLBIVMID, 0x64) + FIELD(SMMU_TLBIVMID, VMID, 0, 8) +REG32(SMMU_TLBIALLNSNH, 0x68) +REG32(SMMU_STLBGSYNC, 0x70) +REG32(SMMU_STLBGSTATUS, 0x74) + FIELD(SMMU_STLBGSTATUS, GSACTIVE, 0, 1) +REG32(SMMU_DBGRPTRTBU, 0x80) + FIELD(SMMU_DBGRPTRTBU, TBU_ID, 24, 3) + FIELD(SMMU_DBGRPTRTBU, TLB_POINTER, 4, 12) + FIELD(SMMU_DBGRPTRTBU, TLB_ENTRY_POINTER, 0, 4) +REG32(SMMU_DBGRDATATBU, 0x84) +REG32(SMMU_DBGRPTRTCU, 0x88) + FIELD(SMMU_DBGRPTRTCU, DATASRC, 26, 2) + FIELD(SMMU_DBGRPTRTCU, WAY_RAM, 24, 2) + FIELD(SMMU_DBGRPTRTCU, TLB_POINTER, 4, 9) + FIELD(SMMU_DBGRPTRTCU, TLB_ENTRY_POINTER, 0, 4) +REG32(SMMU_DBGRDATATCU, 0x8c) +REG32(SMMU_STLBIVALM_LOW, 0xa0) +REG32(SMMU_STLBIVALM_HIGH, 0xa4) + FIELD(SMMU_STLBIVALM_HIGH, ADDRESS, 0, 5) +REG32(SMMU_STLBIVAM_LOW, 0xa8) +REG32(SMMU_STLBIVAM_HIGH, 0xac) + FIELD(SMMU_STLBIVAM_HIGH, ADDRESS, 0, 5) +REG32(SMMU_STLBIALLM, 0xbc) +REG32(SMMU_NSCR0, 0x400) + FIELD(SMMU_NSCR0, WACFG, 26, 2) + FIELD(SMMU_NSCR0, RACFG, 24, 2) + FIELD(SMMU_NSCR0, SHCFG, 22, 2) + FIELD(SMMU_NSCR0, SMCFCFG, 21, 1) + FIELD(SMMU_NSCR0, MTCFG, 20, 1) + FIELD(SMMU_NSCR0, MEMATTR, 16, 4) + FIELD(SMMU_NSCR0, BSU, 14, 2) + FIELD(SMMU_NSCR0, FB, 13, 1) + FIELD(SMMU_NSCR0, PTM, 12, 1) + FIELD(SMMU_NSCR0, VMIDPNE, 11, 1) + FIELD(SMMU_NSCR0, USFCFG, 10, 1) + FIELD(SMMU_NSCR0, GSE, 9, 1) + FIELD(SMMU_NSCR0, STALLD, 8, 1) + FIELD(SMMU_NSCR0, TRANSIENTCFG, 6, 2) + FIELD(SMMU_NSCR0, GCFGFIE, 5, 1) + FIELD(SMMU_NSCR0, GCFGFRE, 4, 1) + FIELD(SMMU_NSCR0, GFIE, 2, 1) + FIELD(SMMU_NSCR0, GFRE, 1, 1) + FIELD(SMMU_NSCR0, CLIENTPD, 0, 1) +REG32(SMMU_NSACR, 0x410) + FIELD(SMMU_NSACR, CACHE_LOCK, 26, 1) + FIELD(SMMU_NSACR, DP4K_TBUDISB, 25, 1) + FIELD(SMMU_NSACR, DP4K_TCUDISB, 24, 1) + FIELD(SMMU_NSACR, S2CRB_TLBEN, 10, 1) + FIELD(SMMU_NSACR, MMUDISB_TLBEN, 9, 1) + FIELD(SMMU_NSACR, SMTNMB_TLBEN, 8, 1) + FIELD(SMMU_NSACR, IPA2PA_CEN, 4, 1) + FIELD(SMMU_NSACR, S2WC2EN, 3, 1) + FIELD(SMMU_NSACR, S1WC2EN, 2, 1) +REG32(SMMU_NSGFAR_LOW, 0x440) +REG32(SMMU_NSGFAR_HIGH, 0x444) + FIELD(SMMU_NSGFAR_HIGH, FADDR, 0, 17) +REG32(SMMU_NSGFSR, 0x448) + FIELD(SMMU_NSGFSR, MULTI, 31, 1) + FIELD(SMMU_NSGFSR, UUT, 8, 1) + FIELD(SMMU_NSGFSR, EF, 6, 1) + FIELD(SMMU_NSGFSR, CAF, 5, 1) + FIELD(SMMU_NSGFSR, UCIF, 4, 1) + FIELD(SMMU_NSGFSR, UCBF, 3, 1) + FIELD(SMMU_NSGFSR, SMCF, 2, 1) + FIELD(SMMU_NSGFSR, USF, 1, 1) + FIELD(SMMU_NSGFSR, ICF, 0, 1) +REG32(SMMU_NSGFSRRESTORE, 0x44c) + FIELD(SMMU_NSGFSRRESTORE, MULTI, 31, 1) + FIELD(SMMU_NSGFSRRESTORE, UUT, 8, 1) + FIELD(SMMU_NSGFSRRESTORE, EF, 6, 1) + FIELD(SMMU_NSGFSRRESTORE, CAF, 5, 1) + FIELD(SMMU_NSGFSRRESTORE, UCIF, 4, 1) + FIELD(SMMU_NSGFSRRESTORE, UCBF, 3, 1) + FIELD(SMMU_NSGFSRRESTORE, SMCF, 2, 1) + FIELD(SMMU_NSGFSRRESTORE, USF, 1, 1) + FIELD(SMMU_NSGFSRRESTORE, ICF, 0, 1) +REG32(SMMU_NSGFSYNR0, 0x450) + FIELD(SMMU_NSGFSYNR0, ATS, 6, 1) + FIELD(SMMU_NSGFSYNR0, IND, 3, 1) + FIELD(SMMU_NSGFSYNR0, PNU, 2, 1) + FIELD(SMMU_NSGFSYNR0, WNR, 1, 1) + FIELD(SMMU_NSGFSYNR0, NESTED, 0, 1) +REG32(SMMU_NSGFSYNDR1, 0x454) + FIELD(SMMU_NSGFSYNDR1, SSD_INDEX, 16, 15) + FIELD(SMMU_NSGFSYNDR1, STREAMID, 0, 15) +REG32(SMMU_NSTLBGSYNC, 0x470) +REG32(SMMU_NSTLBGSTATUS, 0x474) + FIELD(SMMU_NSTLBGSTATUS, GSACTIVE, 0, 1) +REG32(SMMU_SMR0, 0x800) + FIELD(SMMU_SMR0, VALID, 31, 1) + FIELD(SMMU_SMR0, MASK, 16, 15) + FIELD(SMMU_SMR0, ID, 0, 15) +REG32(SMMU_S2CR0, 0xc00) + FIELD(SMMU_S2CR0, TRANSIENTCFG, 28, 2) + FIELD(SMMU_S2CR0, INSTCFG_1, 27, 1) + FIELD(SMMU_S2CR0, INSTCFG_0_FB, 26, 1) + FIELD(SMMU_S2CR0, PRIVCFG_BSU, 24, 2) + FIELD(SMMU_S2CR0, WACFG, 22, 2) + FIELD(SMMU_S2CR0, RACFG, 20, 2) + FIELD(SMMU_S2CR0, NSCFG, 18, 2) + FIELD(SMMU_S2CR0, TYPE, 16, 2) + FIELD(SMMU_S2CR0, MEM_ATTR, 12, 4) + FIELD(SMMU_S2CR0, MTCFG, 11, 1) + FIELD(SMMU_S2CR0, SHCFG, 8, 2) + FIELD(SMMU_S2CR0, CBNDX_VMID, 0, 8) +REG32(SMMU_PIDR4, 0xfd0) + FIELD(SMMU_PIDR4, FOURKB_COUNT, 4, 4) + FIELD(SMMU_PIDR4, JEP106_CONTINUATION_CODE, 0, 4) +REG32(SMMU_PIDR5, 0xfd4) +REG32(SMMU_PIDR6, 0xfd8) +REG32(SMMU_PIDR7, 0xfdc) +REG32(SMMU_PIDR0, 0xfe0) + FIELD(SMMU_PIDR0, PARTNUMBER0, 0, 8) +REG32(SMMU_PIDR1, 0xfe4) + FIELD(SMMU_PIDR1, JEP106_IDENTITY_CODE, 4, 4) + FIELD(SMMU_PIDR1, PARTNUMBER1, 0, 4) +REG32(SMMU_PIDR2, 0xfe8) + FIELD(SMMU_PIDR2, ARCHITECTURE_REVISION, 4, 4) + FIELD(SMMU_PIDR2, JEDEC, 3, 1) + FIELD(SMMU_PIDR2, JEP106_IDENTITY_CODE, 0, 3) +REG32(SMMU_PIDR3, 0xfec) + FIELD(SMMU_PIDR3, REVAND, 4, 4) + FIELD(SMMU_PIDR3, CUSTOMER_MODIFIED, 0, 4) +REG32(SMMU_CIDR0, 0xff0) + FIELD(SMMU_CIDR0, PREAMBLE, 0, 8) +REG32(SMMU_CIDR1, 0xff4) + FIELD(SMMU_CIDR1, PREAMBLE, 0, 8) +REG32(SMMU_CIDR2, 0xff8) + FIELD(SMMU_CIDR2, PREAMBLE, 0, 8) +REG32(SMMU_CIDR3, 0xffc) + FIELD(SMMU_CIDR3, PREAMBLE, 0, 8) +REG32(SMMU_CBAR0, 0x1000) + FIELD(SMMU_CBAR0, IRPTNDX, 24, 8) + FIELD(SMMU_CBAR0, WACFG, 22, 2) + FIELD(SMMU_CBAR0, RACFG, 20, 2) + FIELD(SMMU_CBAR0, BSU, 18, 2) + FIELD(SMMU_CBAR0, TYPE, 16, 2) + FIELD(SMMU_CBAR0, MEMATTR_CBNDX_7_4, 12, 4) + FIELD(SMMU_CBAR0, FB_CBNDX_3, 11, 1) + FIELD(SMMU_CBAR0, HYPC_CBNDX_2, 10, 1) + FIELD(SMMU_CBAR0, BPSHCFG_CBNDX_1_0, 8, 2) + FIELD(SMMU_CBAR0, VMID, 0, 8) +REG32(SMMU_CBFRSYNRA0, 0x1400) + FIELD(SMMU_CBFRSYNRA0, SSD_INDEX, 16, 15) + FIELD(SMMU_CBFRSYNRA0, STREAMID, 0, 15) +REG32(SMMU_CBA2R0, 0x1800) + FIELD(SMMU_CBA2R0, MONC, 1, 1) + FIELD(SMMU_CBA2R0, VA64, 0, 1) +REG32(SMMU_ITCTRL, 0x2000) + FIELD(SMMU_ITCTRL, TBU_INDEX, 4, 3) + FIELD(SMMU_ITCTRL, MODULE, 3, 1) + FIELD(SMMU_ITCTRL, RAM_DATA, 2, 1) + FIELD(SMMU_ITCTRL, RAM_MODE, 1, 1) + FIELD(SMMU_ITCTRL, INTGMODE, 0, 1) +REG32(SMMU_ITIP, 0x2004) + FIELD(SMMU_ITIP, SPINDEN, 0, 1) +REG32(SMMU_ITOP_GLBL, 0x2008) + FIELD(SMMU_ITOP_GLBL, TCU_RAM_DATA, 16, 4) + FIELD(SMMU_ITOP_GLBL, GLBLSF1, 9, 1) + FIELD(SMMU_ITOP_GLBL, GLBLNSF1, 1, 1) +REG32(SMMU_ITOP_PERF_INDEX, 0x200c) + FIELD(SMMU_ITOP_PERF_INDEX, WAY_IPA2PA_PF, 30, 2) + FIELD(SMMU_ITOP_PERF_INDEX, IPA2PA_PF_INDEX, 16, 7) + FIELD(SMMU_ITOP_PERF_INDEX, WAY_MTLB_WC, 14, 2) + FIELD(SMMU_ITOP_PERF_INDEX, MTLB_WC_INDEX, 0, 12) +REG32(SMMU_ITOP_CXT0TO31_RAM0, 0x2010) +REG32(SMMU_TBUQOS0, 0x2100) + FIELD(SMMU_TBUQOS0, QOSTBU5, 20, 4) + FIELD(SMMU_TBUQOS0, QOSTBU4, 16, 4) + FIELD(SMMU_TBUQOS0, QOSTBU3, 12, 4) + FIELD(SMMU_TBUQOS0, QOSTBU2, 8, 4) + FIELD(SMMU_TBUQOS0, QOSTBU1, 4, 4) + FIELD(SMMU_TBUQOS0, QOSTBU0, 0, 4) +REG32(SMMU_PER, 0x2200) + FIELD(SMMU_PER, PER_TCU, 8, 8) + FIELD(SMMU_PER, PER_TBU, 0, 8) +REG32(SMMU_TBU_PWR_STATUS, 0x2204) +REG32(PMEVCNTR0, 0x3000) +REG32(PMEVCNTR1, 0x3004) +REG32(PMEVCNTR2, 0x3008) +REG32(PMEVCNTR3, 0x300c) +REG32(PMEVCNTR4, 0x3010) +REG32(PMEVCNTR5, 0x3014) +REG32(PMEVCNTR6, 0x3018) +REG32(PMEVCNTR7, 0x301c) +REG32(PMEVCNTR8, 0x3020) +REG32(PMEVCNTR9, 0x3024) +REG32(PMEVCNTR10, 0x3028) +REG32(PMEVCNTR11, 0x302c) +REG32(PMEVCNTR12, 0x3030) +REG32(PMEVCNTR13, 0x3034) +REG32(PMEVCNTR14, 0x3038) +REG32(PMEVCNTR15, 0x303c) +REG32(PMEVCNTR16, 0x3040) +REG32(PMEVCNTR17, 0x3044) +REG32(PMEVCNTR18, 0x3048) +REG32(PMEVCNTR19, 0x304c) +REG32(PMEVCNTR20, 0x3050) +REG32(PMEVCNTR21, 0x3054) +REG32(PMEVCNTR22, 0x3058) +REG32(PMEVCNTR23, 0x305c) +REG32(PMEVTYPER0, 0x3400) + FIELD(PMEVTYPER0, P, 31, 1) + FIELD(PMEVTYPER0, U, 30, 1) + FIELD(PMEVTYPER0, NSP, 29, 1) + FIELD(PMEVTYPER0, NSU, 28, 1) + FIELD(PMEVTYPER0, EVENT, 0, 5) +REG32(PMEVTYPER1, 0x3404) + FIELD(PMEVTYPER1, P, 31, 1) + FIELD(PMEVTYPER1, U, 30, 1) + FIELD(PMEVTYPER1, NSP, 29, 1) + FIELD(PMEVTYPER1, NSU, 28, 1) + FIELD(PMEVTYPER1, EVENT, 0, 5) +REG32(PMEVTYPER2, 0x3408) + FIELD(PMEVTYPER2, P, 31, 1) + FIELD(PMEVTYPER2, U, 30, 1) + FIELD(PMEVTYPER2, NSP, 29, 1) + FIELD(PMEVTYPER2, NSU, 28, 1) + FIELD(PMEVTYPER2, EVENT, 0, 5) +REG32(PMEVTYPER3, 0x340c) + FIELD(PMEVTYPER3, P, 31, 1) + FIELD(PMEVTYPER3, U, 30, 1) + FIELD(PMEVTYPER3, NSP, 29, 1) + FIELD(PMEVTYPER3, NSU, 28, 1) + FIELD(PMEVTYPER3, EVENT, 0, 5) +REG32(PMEVTYPER4, 0x3410) + FIELD(PMEVTYPER4, P, 31, 1) + FIELD(PMEVTYPER4, U, 30, 1) + FIELD(PMEVTYPER4, NSP, 29, 1) + FIELD(PMEVTYPER4, NSU, 28, 1) + FIELD(PMEVTYPER4, EVENT, 0, 5) +REG32(PMEVTYPER5, 0x3414) + FIELD(PMEVTYPER5, P, 31, 1) + FIELD(PMEVTYPER5, U, 30, 1) + FIELD(PMEVTYPER5, NSP, 29, 1) + FIELD(PMEVTYPER5, NSU, 28, 1) + FIELD(PMEVTYPER5, EVENT, 0, 5) +REG32(PMEVTYPER6, 0x3418) + FIELD(PMEVTYPER6, P, 31, 1) + FIELD(PMEVTYPER6, U, 30, 1) + FIELD(PMEVTYPER6, NSP, 29, 1) + FIELD(PMEVTYPER6, NSU, 28, 1) + FIELD(PMEVTYPER6, EVENT, 0, 5) +REG32(PMEVTYPER7, 0x341c) + FIELD(PMEVTYPER7, P, 31, 1) + FIELD(PMEVTYPER7, U, 30, 1) + FIELD(PMEVTYPER7, NSP, 29, 1) + FIELD(PMEVTYPER7, NSU, 28, 1) + FIELD(PMEVTYPER7, EVENT, 0, 5) +REG32(PMEVTYPER8, 0x3420) + FIELD(PMEVTYPER8, P, 31, 1) + FIELD(PMEVTYPER8, U, 30, 1) + FIELD(PMEVTYPER8, NSP, 29, 1) + FIELD(PMEVTYPER8, NSU, 28, 1) + FIELD(PMEVTYPER8, EVENT, 0, 5) +REG32(PMEVTYPER9, 0x3424) + FIELD(PMEVTYPER9, P, 31, 1) + FIELD(PMEVTYPER9, U, 30, 1) + FIELD(PMEVTYPER9, NSP, 29, 1) + FIELD(PMEVTYPER9, NSU, 28, 1) + FIELD(PMEVTYPER9, EVENT, 0, 5) +REG32(PMEVTYPER10, 0x3428) + FIELD(PMEVTYPER10, P, 31, 1) + FIELD(PMEVTYPER10, U, 30, 1) + FIELD(PMEVTYPER10, NSP, 29, 1) + FIELD(PMEVTYPER10, NSU, 28, 1) + FIELD(PMEVTYPER10, EVENT, 0, 5) +REG32(PMEVTYPER11, 0x342c) + FIELD(PMEVTYPER11, P, 31, 1) + FIELD(PMEVTYPER11, U, 30, 1) + FIELD(PMEVTYPER11, NSP, 29, 1) + FIELD(PMEVTYPER11, NSU, 28, 1) + FIELD(PMEVTYPER11, EVENT, 0, 5) +REG32(PMEVTYPER12, 0x3430) + FIELD(PMEVTYPER12, P, 31, 1) + FIELD(PMEVTYPER12, U, 30, 1) + FIELD(PMEVTYPER12, NSP, 29, 1) + FIELD(PMEVTYPER12, NSU, 28, 1) + FIELD(PMEVTYPER12, EVENT, 0, 5) +REG32(PMEVTYPER13, 0x3434) + FIELD(PMEVTYPER13, P, 31, 1) + FIELD(PMEVTYPER13, U, 30, 1) + FIELD(PMEVTYPER13, NSP, 29, 1) + FIELD(PMEVTYPER13, NSU, 28, 1) + FIELD(PMEVTYPER13, EVENT, 0, 5) +REG32(PMEVTYPER14, 0x3438) + FIELD(PMEVTYPER14, P, 31, 1) + FIELD(PMEVTYPER14, U, 30, 1) + FIELD(PMEVTYPER14, NSP, 29, 1) + FIELD(PMEVTYPER14, NSU, 28, 1) + FIELD(PMEVTYPER14, EVENT, 0, 5) +REG32(PMEVTYPER15, 0x343c) + FIELD(PMEVTYPER15, P, 31, 1) + FIELD(PMEVTYPER15, U, 30, 1) + FIELD(PMEVTYPER15, NSP, 29, 1) + FIELD(PMEVTYPER15, NSU, 28, 1) + FIELD(PMEVTYPER15, EVENT, 0, 5) +REG32(PMEVTYPER16, 0x3440) + FIELD(PMEVTYPER16, P, 31, 1) + FIELD(PMEVTYPER16, U, 30, 1) + FIELD(PMEVTYPER16, NSP, 29, 1) + FIELD(PMEVTYPER16, NSU, 28, 1) + FIELD(PMEVTYPER16, EVENT, 0, 5) +REG32(PMEVTYPER17, 0x3444) + FIELD(PMEVTYPER17, P, 31, 1) + FIELD(PMEVTYPER17, U, 30, 1) + FIELD(PMEVTYPER17, NSP, 29, 1) + FIELD(PMEVTYPER17, NSU, 28, 1) + FIELD(PMEVTYPER17, EVENT, 0, 5) +REG32(PMEVTYPER18, 0x3448) + FIELD(PMEVTYPER18, P, 31, 1) + FIELD(PMEVTYPER18, U, 30, 1) + FIELD(PMEVTYPER18, NSP, 29, 1) + FIELD(PMEVTYPER18, NSU, 28, 1) + FIELD(PMEVTYPER18, EVENT, 0, 5) +REG32(PMEVTYPER19, 0x344c) + FIELD(PMEVTYPER19, P, 31, 1) + FIELD(PMEVTYPER19, U, 30, 1) + FIELD(PMEVTYPER19, NSP, 29, 1) + FIELD(PMEVTYPER19, NSU, 28, 1) + FIELD(PMEVTYPER19, EVENT, 0, 5) +REG32(PMEVTYPER20, 0x3450) + FIELD(PMEVTYPER20, P, 31, 1) + FIELD(PMEVTYPER20, U, 30, 1) + FIELD(PMEVTYPER20, NSP, 29, 1) + FIELD(PMEVTYPER20, NSU, 28, 1) + FIELD(PMEVTYPER20, EVENT, 0, 5) +REG32(PMEVTYPER21, 0x3454) + FIELD(PMEVTYPER21, P, 31, 1) + FIELD(PMEVTYPER21, U, 30, 1) + FIELD(PMEVTYPER21, NSP, 29, 1) + FIELD(PMEVTYPER21, NSU, 28, 1) + FIELD(PMEVTYPER21, EVENT, 0, 5) +REG32(PMEVTYPER22, 0x3458) + FIELD(PMEVTYPER22, P, 31, 1) + FIELD(PMEVTYPER22, U, 30, 1) + FIELD(PMEVTYPER22, NSP, 29, 1) + FIELD(PMEVTYPER22, NSU, 28, 1) + FIELD(PMEVTYPER22, EVENT, 0, 5) +REG32(PMEVTYPER23, 0x345c) + FIELD(PMEVTYPER23, P, 31, 1) + FIELD(PMEVTYPER23, U, 30, 1) + FIELD(PMEVTYPER23, NSP, 29, 1) + FIELD(PMEVTYPER23, NSU, 28, 1) + FIELD(PMEVTYPER23, EVENT, 0, 5) +REG32(PMCGCR0, 0x3800) + FIELD(PMCGCR0, CGNC, 24, 4) + FIELD(PMCGCR0, SIDG, 16, 7) + FIELD(PMCGCR0, X, 12, 1) + FIELD(PMCGCR0, E, 11, 1) + FIELD(PMCGCR0, CBAEN, 10, 1) + FIELD(PMCGCR0, TCEFCFG, 8, 2) + FIELD(PMCGCR0, NDX, 0, 4) +REG32(PMCGCR1, 0x3804) + FIELD(PMCGCR1, CGNC, 24, 4) + FIELD(PMCGCR1, SIDG, 16, 7) + FIELD(PMCGCR1, X, 12, 1) + FIELD(PMCGCR1, E, 11, 1) + FIELD(PMCGCR1, CBAEN, 10, 1) + FIELD(PMCGCR1, TCEFCFG, 8, 2) + FIELD(PMCGCR1, NDX, 0, 4) +REG32(PMCGCR2, 0x3808) + FIELD(PMCGCR2, CGNC, 24, 4) + FIELD(PMCGCR2, SIDG, 16, 7) + FIELD(PMCGCR2, X, 12, 1) + FIELD(PMCGCR2, E, 11, 1) + FIELD(PMCGCR2, CBAEN, 10, 1) + FIELD(PMCGCR2, TCEFCFG, 8, 2) + FIELD(PMCGCR2, NDX, 0, 4) +REG32(PMCGCR3, 0x380c) + FIELD(PMCGCR3, CGNC, 24, 4) + FIELD(PMCGCR3, SIDG, 16, 7) + FIELD(PMCGCR3, X, 12, 1) + FIELD(PMCGCR3, E, 11, 1) + FIELD(PMCGCR3, CBAEN, 10, 1) + FIELD(PMCGCR3, TCEFCFG, 8, 2) + FIELD(PMCGCR3, NDX, 0, 4) +REG32(PMCGCR4, 0x3810) + FIELD(PMCGCR4, CGNC, 24, 4) + FIELD(PMCGCR4, SIDG, 16, 7) + FIELD(PMCGCR4, X, 12, 1) + FIELD(PMCGCR4, E, 11, 1) + FIELD(PMCGCR4, CBAEN, 10, 1) + FIELD(PMCGCR4, TCEFCFG, 8, 2) + FIELD(PMCGCR4, NDX, 0, 4) +REG32(PMCGCR5, 0x3814) + FIELD(PMCGCR5, CGNC, 24, 4) + FIELD(PMCGCR5, SIDG, 16, 7) + FIELD(PMCGCR5, X, 12, 1) + FIELD(PMCGCR5, E, 11, 1) + FIELD(PMCGCR5, CBAEN, 10, 1) + FIELD(PMCGCR5, TCEFCFG, 8, 2) + FIELD(PMCGCR5, NDX, 0, 4) +REG32(PMCGSMR0, 0x3a00) + FIELD(PMCGSMR0, MASK, 16, 10) + FIELD(PMCGSMR0, ID, 0, 10) +REG32(PMCGSMR1, 0x3a04) + FIELD(PMCGSMR1, MASK, 16, 10) + FIELD(PMCGSMR1, ID, 0, 10) +REG32(PMCGSMR2, 0x3a08) + FIELD(PMCGSMR2, MASK, 16, 10) + FIELD(PMCGSMR2, ID, 0, 10) +REG32(PMCGSMR3, 0x3a0c) + FIELD(PMCGSMR3, MASK, 16, 10) + FIELD(PMCGSMR3, ID, 0, 10) +REG32(PMCGSMR4, 0x3a10) + FIELD(PMCGSMR4, MASK, 16, 10) + FIELD(PMCGSMR4, ID, 0, 10) +REG32(PMCGSMR5, 0x3a14) + FIELD(PMCGSMR5, MASK, 16, 10) + FIELD(PMCGSMR5, ID, 0, 10) +REG32(PMCNTENSET, 0x3c00) + FIELD(PMCNTENSET, P23, 23, 1) + FIELD(PMCNTENSET, P22, 22, 1) + FIELD(PMCNTENSET, P21, 21, 1) + FIELD(PMCNTENSET, P20, 20, 1) + FIELD(PMCNTENSET, P19, 19, 1) + FIELD(PMCNTENSET, P18, 18, 1) + FIELD(PMCNTENSET, P17, 17, 1) + FIELD(PMCNTENSET, P16, 16, 1) + FIELD(PMCNTENSET, P15, 15, 1) + FIELD(PMCNTENSET, P14, 14, 1) + FIELD(PMCNTENSET, P13, 13, 1) + FIELD(PMCNTENSET, P12, 12, 1) + FIELD(PMCNTENSET, P11, 11, 1) + FIELD(PMCNTENSET, P10, 10, 1) + FIELD(PMCNTENSET, P9, 9, 1) + FIELD(PMCNTENSET, P8, 8, 1) + FIELD(PMCNTENSET, P7, 7, 1) + FIELD(PMCNTENSET, P6, 6, 1) + FIELD(PMCNTENSET, P5, 5, 1) + FIELD(PMCNTENSET, P4, 4, 1) + FIELD(PMCNTENSET, P3, 3, 1) + FIELD(PMCNTENSET, P2, 2, 1) + FIELD(PMCNTENSET, P1, 1, 1) + FIELD(PMCNTENSET, P0, 0, 1) +REG32(PMCNTENCLR, 0x3c20) + FIELD(PMCNTENCLR, P23, 23, 1) + FIELD(PMCNTENCLR, P22, 22, 1) + FIELD(PMCNTENCLR, P21, 21, 1) + FIELD(PMCNTENCLR, P20, 20, 1) + FIELD(PMCNTENCLR, P19, 19, 1) + FIELD(PMCNTENCLR, P18, 18, 1) + FIELD(PMCNTENCLR, P17, 17, 1) + FIELD(PMCNTENCLR, P16, 16, 1) + FIELD(PMCNTENCLR, P15, 15, 1) + FIELD(PMCNTENCLR, P14, 14, 1) + FIELD(PMCNTENCLR, P13, 13, 1) + FIELD(PMCNTENCLR, P12, 12, 1) + FIELD(PMCNTENCLR, P11, 11, 1) + FIELD(PMCNTENCLR, P10, 10, 1) + FIELD(PMCNTENCLR, P9, 9, 1) + FIELD(PMCNTENCLR, P8, 8, 1) + FIELD(PMCNTENCLR, P7, 7, 1) + FIELD(PMCNTENCLR, P6, 6, 1) + FIELD(PMCNTENCLR, P5, 5, 1) + FIELD(PMCNTENCLR, P4, 4, 1) + FIELD(PMCNTENCLR, P3, 3, 1) + FIELD(PMCNTENCLR, P2, 2, 1) + FIELD(PMCNTENCLR, P1, 1, 1) + FIELD(PMCNTENCLR, P0, 0, 1) +REG32(PMINTENSET, 0x3c40) + FIELD(PMINTENSET, P23, 23, 1) + FIELD(PMINTENSET, P22, 22, 1) + FIELD(PMINTENSET, P21, 21, 1) + FIELD(PMINTENSET, P20, 20, 1) + FIELD(PMINTENSET, P19, 19, 1) + FIELD(PMINTENSET, P18, 18, 1) + FIELD(PMINTENSET, P17, 17, 1) + FIELD(PMINTENSET, P16, 16, 1) + FIELD(PMINTENSET, P15, 15, 1) + FIELD(PMINTENSET, P14, 14, 1) + FIELD(PMINTENSET, P13, 13, 1) + FIELD(PMINTENSET, P12, 12, 1) + FIELD(PMINTENSET, P11, 11, 1) + FIELD(PMINTENSET, P10, 10, 1) + FIELD(PMINTENSET, P9, 9, 1) + FIELD(PMINTENSET, P8, 8, 1) + FIELD(PMINTENSET, P7, 7, 1) + FIELD(PMINTENSET, P6, 6, 1) + FIELD(PMINTENSET, P5, 5, 1) + FIELD(PMINTENSET, P4, 4, 1) + FIELD(PMINTENSET, P3, 3, 1) + FIELD(PMINTENSET, P2, 2, 1) + FIELD(PMINTENSET, P1, 1, 1) + FIELD(PMINTENSET, P0, 0, 1) +REG32(PMINTENCLR, 0x3c60) + FIELD(PMINTENCLR, P23, 23, 1) + FIELD(PMINTENCLR, P22, 22, 1) + FIELD(PMINTENCLR, P21, 21, 1) + FIELD(PMINTENCLR, P20, 20, 1) + FIELD(PMINTENCLR, P19, 19, 1) + FIELD(PMINTENCLR, P18, 18, 1) + FIELD(PMINTENCLR, P17, 17, 1) + FIELD(PMINTENCLR, P16, 16, 1) + FIELD(PMINTENCLR, P15, 15, 1) + FIELD(PMINTENCLR, P14, 14, 1) + FIELD(PMINTENCLR, P13, 13, 1) + FIELD(PMINTENCLR, P12, 12, 1) + FIELD(PMINTENCLR, P11, 11, 1) + FIELD(PMINTENCLR, P10, 10, 1) + FIELD(PMINTENCLR, P9, 9, 1) + FIELD(PMINTENCLR, P8, 8, 1) + FIELD(PMINTENCLR, P7, 7, 1) + FIELD(PMINTENCLR, P6, 6, 1) + FIELD(PMINTENCLR, P5, 5, 1) + FIELD(PMINTENCLR, P4, 4, 1) + FIELD(PMINTENCLR, P3, 3, 1) + FIELD(PMINTENCLR, P2, 2, 1) + FIELD(PMINTENCLR, P1, 1, 1) + FIELD(PMINTENCLR, P0, 0, 1) +REG32(PMOVSCLR, 0x3c80) + FIELD(PMOVSCLR, P23, 23, 1) + FIELD(PMOVSCLR, P22, 22, 1) + FIELD(PMOVSCLR, P21, 21, 1) + FIELD(PMOVSCLR, P20, 20, 1) + FIELD(PMOVSCLR, P19, 19, 1) + FIELD(PMOVSCLR, P18, 18, 1) + FIELD(PMOVSCLR, P17, 17, 1) + FIELD(PMOVSCLR, P16, 16, 1) + FIELD(PMOVSCLR, P15, 15, 1) + FIELD(PMOVSCLR, P14, 14, 1) + FIELD(PMOVSCLR, P13, 13, 1) + FIELD(PMOVSCLR, P12, 12, 1) + FIELD(PMOVSCLR, P11, 11, 1) + FIELD(PMOVSCLR, P10, 10, 1) + FIELD(PMOVSCLR, P9, 9, 1) + FIELD(PMOVSCLR, P8, 8, 1) + FIELD(PMOVSCLR, P7, 7, 1) + FIELD(PMOVSCLR, P6, 6, 1) + FIELD(PMOVSCLR, P5, 5, 1) + FIELD(PMOVSCLR, P4, 4, 1) + FIELD(PMOVSCLR, P3, 3, 1) + FIELD(PMOVSCLR, P2, 2, 1) + FIELD(PMOVSCLR, P1, 1, 1) + FIELD(PMOVSCLR, P0, 0, 1) +REG32(PMOVSSET, 0x3cc0) + FIELD(PMOVSSET, P23, 23, 1) + FIELD(PMOVSSET, P22, 22, 1) + FIELD(PMOVSSET, P21, 21, 1) + FIELD(PMOVSSET, P20, 20, 1) + FIELD(PMOVSSET, P19, 19, 1) + FIELD(PMOVSSET, P18, 18, 1) + FIELD(PMOVSSET, P17, 17, 1) + FIELD(PMOVSSET, P16, 16, 1) + FIELD(PMOVSSET, P15, 15, 1) + FIELD(PMOVSSET, P14, 14, 1) + FIELD(PMOVSSET, P13, 13, 1) + FIELD(PMOVSSET, P12, 12, 1) + FIELD(PMOVSSET, P11, 11, 1) + FIELD(PMOVSSET, P10, 10, 1) + FIELD(PMOVSSET, P9, 9, 1) + FIELD(PMOVSSET, P8, 8, 1) + FIELD(PMOVSSET, P7, 7, 1) + FIELD(PMOVSSET, P6, 6, 1) + FIELD(PMOVSSET, P5, 5, 1) + FIELD(PMOVSSET, P4, 4, 1) + FIELD(PMOVSSET, P3, 3, 1) + FIELD(PMOVSSET, P2, 2, 1) + FIELD(PMOVSSET, P1, 1, 1) + FIELD(PMOVSSET, P0, 0, 1) +REG32(PMCFGR, 0x3e00) + FIELD(PMCFGR, NCG, 24, 8) + FIELD(PMCFGR, UEN, 19, 1) + FIELD(PMCFGR, EX, 16, 1) + FIELD(PMCFGR, CCD, 15, 1) + FIELD(PMCFGR, CC, 14, 1) + FIELD(PMCFGR, SIZE, 8, 6) + FIELD(PMCFGR, N, 0, 8) +REG32(PMCR, 0x3e04) + FIELD(PMCR, IMP, 24, 8) + FIELD(PMCR, X, 4, 1) + FIELD(PMCR, P, 1, 1) + FIELD(PMCR, E, 0, 1) +REG32(PMCEID0, 0x3e20) + FIELD(PMCEID0, EVENT0X12, 17, 1) + FIELD(PMCEID0, EVENT0X11, 16, 1) + FIELD(PMCEID0, EVENT0X10, 15, 1) + FIELD(PMCEID0, EVENT0X0A, 9, 1) + FIELD(PMCEID0, EVENT0X09, 8, 1) + FIELD(PMCEID0, EVENT0X08, 7, 1) + FIELD(PMCEID0, EVENT0X01, 1, 1) + FIELD(PMCEID0, EVENT0X00, 0, 1) +REG32(PMAUTHSTATUS, 0x3fb8) + FIELD(PMAUTHSTATUS, SNI, 7, 1) + FIELD(PMAUTHSTATUS, SNE, 6, 1) + FIELD(PMAUTHSTATUS, SI, 5, 1) + FIELD(PMAUTHSTATUS, SE, 4, 1) + FIELD(PMAUTHSTATUS, NSNI, 3, 1) + FIELD(PMAUTHSTATUS, NSNE, 2, 1) + FIELD(PMAUTHSTATUS, NSI, 1, 1) + FIELD(PMAUTHSTATUS, NSE, 0, 1) +REG32(PMDEVTYPE, 0x3fcc) + FIELD(PMDEVTYPE, T, 4, 4) + FIELD(PMDEVTYPE, C, 0, 4) + +/* The following CB regs are based off zero. */ +REG32(SMMU_CB0_SCTLR, 0x0) + FIELD(SMMU_CB0_SCTLR, NSCFG, 28, 2) + FIELD(SMMU_CB0_SCTLR, WACFG, 26, 2) + FIELD(SMMU_CB0_SCTLR, RACFG, 24, 2) + FIELD(SMMU_CB0_SCTLR, SHCFG, 22, 2) + FIELD(SMMU_CB0_SCTLR, FB, 21, 1) + FIELD(SMMU_CB0_SCTLR, MTCFG, 20, 1) + FIELD(SMMU_CB0_SCTLR, MEMATTR, 16, 4) + FIELD(SMMU_CB0_SCTLR, TRANSIENTCFG, 14, 2) + FIELD(SMMU_CB0_SCTLR, PTW, 13, 1) + FIELD(SMMU_CB0_SCTLR, ASIDPNE, 12, 1) + FIELD(SMMU_CB0_SCTLR, UWXN, 10, 1) + FIELD(SMMU_CB0_SCTLR, WXN, 9, 1) + FIELD(SMMU_CB0_SCTLR, HUPCF, 8, 1) + FIELD(SMMU_CB0_SCTLR, CFCFG, 7, 1) + FIELD(SMMU_CB0_SCTLR, CFIE, 6, 1) + FIELD(SMMU_CB0_SCTLR, CFRE, 5, 1) + FIELD(SMMU_CB0_SCTLR, E, 4, 1) + FIELD(SMMU_CB0_SCTLR, AFFD, 3, 1) + FIELD(SMMU_CB0_SCTLR, AFE, 2, 1) + FIELD(SMMU_CB0_SCTLR, TRE, 1, 1) + FIELD(SMMU_CB0_SCTLR, M, 0, 1) +REG32(SMMU_CB0_ACTLR, 0x4) + FIELD(SMMU_CB0_ACTLR, CPRE, 1, 1) + FIELD(SMMU_CB0_ACTLR, CMTLB, 0, 1) +REG32(SMMU_CB0_RESUME, 0x8) + FIELD(SMMU_CB0_RESUME, TNR, 0, 1) +REG32(SMMU_CB0_TCR2, 0x10) + FIELD(SMMU_CB0_TCR2, NSCFG1, 30, 1) + FIELD(SMMU_CB0_TCR2, SEP, 15, 3) + FIELD(SMMU_CB0_TCR2, NSCFG0, 14, 1) + FIELD(SMMU_CB0_TCR2, TBI1, 6, 1) + FIELD(SMMU_CB0_TCR2, TBI0, 5, 1) + FIELD(SMMU_CB0_TCR2, AS, 4, 1) + FIELD(SMMU_CB0_TCR2, PASIZE, 0, 3) +REG32(SMMU_CB0_TTBR0_LOW, 0x20) + FIELD(SMMU_CB0_TTBR0_LOW, ADDRESS_31_7, 7, 25) + FIELD(SMMU_CB0_TTBR0_LOW, ADDRESS_6_IRGN0, 6, 1) + FIELD(SMMU_CB0_TTBR0_LOW, ADDRESS_5_NOS, 5, 1) + FIELD(SMMU_CB0_TTBR0_LOW, ADDRESS_4_3_RGN, 3, 2) + FIELD(SMMU_CB0_TTBR0_LOW, ADDRESS_2, 2, 1) + FIELD(SMMU_CB0_TTBR0_LOW, ADDRESS_1_S, 1, 1) + FIELD(SMMU_CB0_TTBR0_LOW, ADDRESS_0_IRGN1, 0, 1) +REG32(SMMU_CB0_TTBR0_HIGH, 0x24) + FIELD(SMMU_CB0_TTBR0_HIGH, ASID, 16, 16) + FIELD(SMMU_CB0_TTBR0_HIGH, ADDRESS, 0, 16) +REG32(SMMU_CB0_TTBR1_LOW, 0x28) + FIELD(SMMU_CB0_TTBR1_LOW, ADDRESS_31_7, 7, 25) + FIELD(SMMU_CB0_TTBR1_LOW, ADDRESS_6_IRGN0, 6, 1) + FIELD(SMMU_CB0_TTBR1_LOW, ADDRESS_5_NOS, 5, 1) + FIELD(SMMU_CB0_TTBR1_LOW, ADDRESS_4_3_RGN, 3, 2) + FIELD(SMMU_CB0_TTBR1_LOW, ADDRESS_2, 2, 1) + FIELD(SMMU_CB0_TTBR1_LOW, ADDRESS_1_S, 1, 1) + FIELD(SMMU_CB0_TTBR1_LOW, ADDRESS_0_IRGN1, 0, 1) +REG32(SMMU_CB0_TTBR1_HIGH, 0x2c) + FIELD(SMMU_CB0_TTBR1_HIGH, ASID, 16, 16) + FIELD(SMMU_CB0_TTBR1_HIGH, ADDRESS, 0, 16) +REG32(SMMU_CB0_TCR_LPAE, 0x30) + FIELD(SMMU_CB0_TCR_LPAE, EAE, 31, 1) + FIELD(SMMU_CB0_TCR_LPAE, NSCFG1_TG1, 30, 1) + FIELD(SMMU_CB0_TCR_LPAE, SH1, 28, 2) + FIELD(SMMU_CB0_TCR_LPAE, ORGN1, 26, 2) + FIELD(SMMU_CB0_TCR_LPAE, IRGN1, 24, 2) + FIELD(SMMU_CB0_TCR_LPAE, EPD1, 23, 1) + FIELD(SMMU_CB0_TCR_LPAE, A1, 22, 1) + FIELD(SMMU_CB0_TCR_LPAE, T1SZ_5_3, 19, 3) + FIELD(SMMU_CB0_TCR_LPAE, T1SZ_2_0_PASIZE, 16, 3) + FIELD(SMMU_CB0_TCR_LPAE, NSCFG0_TG0, 14, 1) + FIELD(SMMU_CB0_TCR_LPAE, SH0, 12, 2) + FIELD(SMMU_CB0_TCR_LPAE, ORGN0, 10, 2) + FIELD(SMMU_CB0_TCR_LPAE, IRGN0, 8, 2) + FIELD(SMMU_CB0_TCR_LPAE, SL0_1_EPD0, 7, 1) + FIELD(SMMU_CB0_TCR_LPAE, SL0_0, 6, 1) + FIELD(SMMU_CB0_TCR_LPAE, PD1_T0SZ_5, 5, 1) + FIELD(SMMU_CB0_TCR_LPAE, S_PD0_T0SZ_4, 4, 1) + FIELD(SMMU_CB0_TCR_LPAE, T0SZ_3_0, 0, 4) +REG32(SMMU_CB0_CONTEXTIDR, 0x34) + FIELD(SMMU_CB0_CONTEXTIDR, PROCID, 8, 24) + FIELD(SMMU_CB0_CONTEXTIDR, ASID, 0, 8) +REG32(SMMU_CB0_PRRR_MAIR0, 0x38) + FIELD(SMMU_CB0_PRRR_MAIR0, NOS7, 31, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NOS6, 30, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NOS5, 29, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NOS4, 28, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NOS3, 27, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NOS2, 26, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NOS1, 25, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NOS0, 24, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NS1, 19, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, NS0, 18, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, DS1, 17, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, DS0, 16, 1) + FIELD(SMMU_CB0_PRRR_MAIR0, TR7, 14, 2) + FIELD(SMMU_CB0_PRRR_MAIR0, TR6, 12, 2) + FIELD(SMMU_CB0_PRRR_MAIR0, TR5, 10, 2) + FIELD(SMMU_CB0_PRRR_MAIR0, TR4, 8, 2) + FIELD(SMMU_CB0_PRRR_MAIR0, TR3, 6, 2) + FIELD(SMMU_CB0_PRRR_MAIR0, TR2, 4, 2) + FIELD(SMMU_CB0_PRRR_MAIR0, TR1, 2, 2) + FIELD(SMMU_CB0_PRRR_MAIR0, TR0, 0, 2) +REG32(SMMU_CB0_NMRR_MAIR1, 0x3c) + FIELD(SMMU_CB0_NMRR_MAIR1, OR7, 30, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, OR6, 28, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, OR5, 26, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, OR4, 24, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, OR3, 22, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, OR2, 20, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, OR1, 18, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, OR0, 16, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, IR7, 14, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, IR6, 12, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, IR5, 10, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, IR4, 8, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, IR3, 6, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, IR2, 4, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, IR1, 2, 2) + FIELD(SMMU_CB0_NMRR_MAIR1, IR0, 0, 2) +REG32(SMMU_CB0_FSR, 0x58) + FIELD(SMMU_CB0_FSR, MULTI, 31, 1) + FIELD(SMMU_CB0_FSR, SS, 30, 1) + FIELD(SMMU_CB0_FSR, FORMAT, 9, 2) + FIELD(SMMU_CB0_FSR, UUT, 8, 1) + FIELD(SMMU_CB0_FSR, ASF, 7, 1) + FIELD(SMMU_CB0_FSR, TLBLKF, 6, 1) + FIELD(SMMU_CB0_FSR, TLBMCF, 5, 1) + FIELD(SMMU_CB0_FSR, EF, 4, 1) + FIELD(SMMU_CB0_FSR, PF, 3, 1) + FIELD(SMMU_CB0_FSR, AFF, 2, 1) + FIELD(SMMU_CB0_FSR, TF, 1, 1) +REG32(SMMU_CB0_FSRRESTORE, 0x5c) +REG32(SMMU_CB0_FAR_LOW, 0x60) +REG32(SMMU_CB0_FAR_HIGH, 0x64) + FIELD(SMMU_CB0_FAR_HIGH, BITS, 0, 17) +REG32(SMMU_CB0_FSYNR0, 0x68) + FIELD(SMMU_CB0_FSYNR0, S1CBNDX, 16, 4) + FIELD(SMMU_CB0_FSYNR0, AFR, 11, 1) + FIELD(SMMU_CB0_FSYNR0, PTWF, 10, 1) + FIELD(SMMU_CB0_FSYNR0, ATOF, 9, 1) + FIELD(SMMU_CB0_FSYNR0, NSATTR, 8, 1) + FIELD(SMMU_CB0_FSYNR0, IND, 6, 1) + FIELD(SMMU_CB0_FSYNR0, PNU, 5, 1) + FIELD(SMMU_CB0_FSYNR0, WNR, 4, 1) + FIELD(SMMU_CB0_FSYNR0, PLVL, 0, 2) +REG32(SMMU_CB0_IPAFAR_LOW, 0x70) + FIELD(SMMU_CB0_IPAFAR_LOW, IPAFAR_L, 12, 20) + FIELD(SMMU_CB0_IPAFAR_LOW, FAR_RO, 0, 12) +REG32(SMMU_CB0_IPAFAR_HIGH, 0x74) + FIELD(SMMU_CB0_IPAFAR_HIGH, BITS, 0, 16) +REG32(SMMU_CB0_TLBIVA_LOW, 0x600) +REG32(SMMU_CB0_TLBIVA_HIGH, 0x604) + FIELD(SMMU_CB0_TLBIVA_HIGH, ASID, 16, 16) + FIELD(SMMU_CB0_TLBIVA_HIGH, ADDRESS, 0, 5) +REG32(SMMU_CB0_TLBIVAA_LOW, 0x608) +REG32(SMMU_CB0_TLBIVAA_HIGH, 0x60c) + FIELD(SMMU_CB0_TLBIVAA_HIGH, ASID, 16, 16) + FIELD(SMMU_CB0_TLBIVAA_HIGH, ADDRESS, 0, 5) +REG32(SMMU_CB0_TLBIASID, 0x610) + FIELD(SMMU_CB0_TLBIASID, ASID, 0, 16) +REG32(SMMU_CB0_TLBIALL, 0x618) +REG32(SMMU_CB0_TLBIVAL_LOW, 0x620) +REG32(SMMU_CB0_TLBIVAL_HIGH, 0x624) + FIELD(SMMU_CB0_TLBIVAL_HIGH, ASID, 16, 16) + FIELD(SMMU_CB0_TLBIVAL_HIGH, ADDRESS, 0, 5) +REG32(SMMU_CB0_TLBIVAAL_LOW, 0x628) +REG32(SMMU_CB0_TLBIVAAL_HIGH, 0x62c) + FIELD(SMMU_CB0_TLBIVAAL_HIGH, ASID, 16, 16) + FIELD(SMMU_CB0_TLBIVAAL_HIGH, ADDRESS, 0, 5) +REG32(SMMU_CB0_TLBIIPAS2_LOW, 0x630) +REG32(SMMU_CB0_TLBIIPAS2_HIGH, 0x634) + FIELD(SMMU_CB0_TLBIIPAS2_HIGH, ADDRESS, 0, 4) +REG32(SMMU_CB0_TLBIIPAS2L_LOW, 0x638) +REG32(SMMU_CB0_TLBIIPAS2L_HIGH, 0x63c) + FIELD(SMMU_CB0_TLBIIPAS2L_HIGH, ADDRESS, 0, 4) +REG32(SMMU_CB0_TLBSYNC, 0x7f0) +REG32(SMMU_CB0_TLBSTATUS, 0x7f4) + FIELD(SMMU_CB0_TLBSTATUS, SACTIVE, 0, 1) +REG32(SMMU_CB0_PMEVCNTR0, 0xe00) +REG32(SMMU_CB0_PMEVCNTR1, 0xe04) +REG32(SMMU_CB0_PMEVCNTR2, 0xe08) +REG32(SMMU_CB0_PMEVCNTR3, 0xe0c) +REG32(SMMU_CB0_PMEVTYPER0, 0xe80) + FIELD(SMMU_CB0_PMEVTYPER0, P, 31, 1) + FIELD(SMMU_CB0_PMEVTYPER0, U, 30, 1) + FIELD(SMMU_CB0_PMEVTYPER0, NSP, 29, 1) + FIELD(SMMU_CB0_PMEVTYPER0, NSU, 28, 1) + FIELD(SMMU_CB0_PMEVTYPER0, EVENT, 0, 5) +REG32(SMMU_CB0_PMEVTYPER1, 0xe84) + FIELD(SMMU_CB0_PMEVTYPER1, P, 31, 1) + FIELD(SMMU_CB0_PMEVTYPER1, U, 30, 1) + FIELD(SMMU_CB0_PMEVTYPER1, NSP, 29, 1) + FIELD(SMMU_CB0_PMEVTYPER1, NSU, 28, 1) + FIELD(SMMU_CB0_PMEVTYPER1, EVENT, 0, 5) +REG32(SMMU_CB0_PMEVTYPER2, 0xe88) + FIELD(SMMU_CB0_PMEVTYPER2, P, 31, 1) + FIELD(SMMU_CB0_PMEVTYPER2, U, 30, 1) + FIELD(SMMU_CB0_PMEVTYPER2, NSP, 29, 1) + FIELD(SMMU_CB0_PMEVTYPER2, NSU, 28, 1) + FIELD(SMMU_CB0_PMEVTYPER2, EVENT, 0, 5) +REG32(SMMU_CB0_PMEVTYPER3, 0xe8c) + FIELD(SMMU_CB0_PMEVTYPER3, P, 31, 1) + FIELD(SMMU_CB0_PMEVTYPER3, U, 30, 1) + FIELD(SMMU_CB0_PMEVTYPER3, NSP, 29, 1) + FIELD(SMMU_CB0_PMEVTYPER3, NSU, 28, 1) + FIELD(SMMU_CB0_PMEVTYPER3, EVENT, 0, 5) +REG32(SMMU_CB0_PMCFGR, 0xf00) + FIELD(SMMU_CB0_PMCFGR, NCG, 24, 8) + FIELD(SMMU_CB0_PMCFGR, UEN, 19, 1) + FIELD(SMMU_CB0_PMCFGR, EX, 16, 1) + FIELD(SMMU_CB0_PMCFGR, CCD, 15, 1) + FIELD(SMMU_CB0_PMCFGR, CC, 14, 1) + FIELD(SMMU_CB0_PMCFGR, SIZE, 8, 6) + FIELD(SMMU_CB0_PMCFGR, N, 0, 8) +REG32(SMMU_CB0_PMCR, 0xf04) + FIELD(SMMU_CB0_PMCR, IMP, 24, 8) + FIELD(SMMU_CB0_PMCR, X, 4, 1) + FIELD(SMMU_CB0_PMCR, P, 1, 1) + FIELD(SMMU_CB0_PMCR, E, 0, 1) +REG32(SMMU_CB0_PMCEID, 0xf20) + FIELD(SMMU_CB0_PMCEID, EVENT0X12, 17, 1) + FIELD(SMMU_CB0_PMCEID, EVENT0X11, 16, 1) + FIELD(SMMU_CB0_PMCEID, EVENT0X10, 15, 1) + FIELD(SMMU_CB0_PMCEID, EVENT0X0A, 9, 1) + FIELD(SMMU_CB0_PMCEID, EVENT0X09, 8, 1) + FIELD(SMMU_CB0_PMCEID, EVENT0X08, 7, 1) + FIELD(SMMU_CB0_PMCEID, EVENT0X01, 1, 1) + FIELD(SMMU_CB0_PMCEID, EVENT0X00, 0, 1) +REG32(SMMU_CB0_PMCNTENSE, 0xf40) + FIELD(SMMU_CB0_PMCNTENSE, P3, 3, 1) + FIELD(SMMU_CB0_PMCNTENSE, P2, 2, 1) + FIELD(SMMU_CB0_PMCNTENSE, P1, 1, 1) + FIELD(SMMU_CB0_PMCNTENSE, P0, 0, 1) +REG32(SMMU_CB0_PMCNTENCLR, 0xf44) + FIELD(SMMU_CB0_PMCNTENCLR, P3, 3, 1) + FIELD(SMMU_CB0_PMCNTENCLR, P2, 2, 1) + FIELD(SMMU_CB0_PMCNTENCLR, P1, 1, 1) + FIELD(SMMU_CB0_PMCNTENCLR, P0, 0, 1) +REG32(SMMU_CB0_PMCNTENSET, 0xf48) + FIELD(SMMU_CB0_PMCNTENSET, P3, 3, 1) + FIELD(SMMU_CB0_PMCNTENSET, P2, 2, 1) + FIELD(SMMU_CB0_PMCNTENSET, P1, 1, 1) + FIELD(SMMU_CB0_PMCNTENSET, P0, 0, 1) +REG32(SMMU_CB0_PMINTENCLR, 0xf4c) + FIELD(SMMU_CB0_PMINTENCLR, P3, 3, 1) + FIELD(SMMU_CB0_PMINTENCLR, P2, 2, 1) + FIELD(SMMU_CB0_PMINTENCLR, P1, 1, 1) + FIELD(SMMU_CB0_PMINTENCLR, P0, 0, 1) +REG32(SMMU_CB0_PMOVSCLR, 0xf50) + FIELD(SMMU_CB0_PMOVSCLR, P3, 3, 1) + FIELD(SMMU_CB0_PMOVSCLR, P2, 2, 1) + FIELD(SMMU_CB0_PMOVSCLR, P1, 1, 1) + FIELD(SMMU_CB0_PMOVSCLR, P0, 0, 1) +REG32(SMMU_CB0_PMOVSSET, 0xf58) + FIELD(SMMU_CB0_PMOVSSET, P3, 3, 1) + FIELD(SMMU_CB0_PMOVSSET, P2, 2, 1) + FIELD(SMMU_CB0_PMOVSSET, P1, 1, 1) + FIELD(SMMU_CB0_PMOVSSET, P0, 0, 1) +REG32(SMMU_CB0_PMAUTHSTATUS, 0xfb8) + FIELD(SMMU_CB0_PMAUTHSTATUS, SNI, 7, 1) + FIELD(SMMU_CB0_PMAUTHSTATUS, SNE, 6, 1) + FIELD(SMMU_CB0_PMAUTHSTATUS, SI, 5, 1) + FIELD(SMMU_CB0_PMAUTHSTATUS, SE, 4, 1) + FIELD(SMMU_CB0_PMAUTHSTATUS, NSNI, 3, 1) + FIELD(SMMU_CB0_PMAUTHSTATUS, NSNE, 2, 1) + FIELD(SMMU_CB0_PMAUTHSTATUS, NSI, 1, 1) + FIELD(SMMU_CB0_PMAUTHSTATUS, NSE, 0, 1) + +/* Missing from the regspec. */ +REG32(SMMU_GATS1PR, 0x110) +REG32(SMMU_GATS1PR_H, 0x114) +REG32(SMMU_GATS1PW, 0x118) +REG32(SMMU_GATS1PW_H, 0x11C) +REG32(SMMU_GATS12PR, 0x130) +REG32(SMMU_GATS12PR_H, 0x134) +REG32(SMMU_GATS12PW, 0x138) +REG32(SMMU_GATS12PW_H, 0x13C) +REG32(SMMU_GPAR, 0x180) +REG32(SMMU_GPAR_H, 0x184) +REG32(SMMU_GATSR, 0x188) + +/* Generic page attributes. */ +typedef struct PageAttr { + uint64_t pa; + unsigned int block : 1; + unsigned int rd : 1; + unsigned int wr : 1; + unsigned int ns : 1; +} PageAttr; + +typedef struct TransReq { + uint64_t va; + uint64_t tcr[3]; + uint64_t ttbr[3][2]; + uint32_t access; + unsigned int stage; + bool s2_enabled; + unsigned int s2_cb; + + uint64_t pa; + uint32_t prot; + + bool err; +} TransReq; + +/* Compute the base offset (index into s->regs) for a given CB. */ +static unsigned int smmu_cb_offset(SMMU500State *s, unsigned int cb) +{ + return ((s->cfg.num_pages + cb) * SMMU_PAGESIZE) / 4; +} + +static void smmu_update_ctx_irq(SMMU500State *s, unsigned int cb) +{ + unsigned int cb_offset = smmu_cb_offset(s, cb); + uint32_t sctlr; + uint32_t fsr; + bool ie, tf; + bool pending; + + fsr = s->regs[R_SMMU_CB0_FSR + cb_offset]; + sctlr = s->regs[R_SMMU_CB0_SCTLR + cb_offset]; + + tf = FIELD_EX32(fsr, SMMU_CB0_FSR, TF); + ie = FIELD_EX32(sctlr, SMMU_CB0_SCTLR, CFIE); + pending = tf && ie; + qemu_set_irq(s->irq.context[cb], pending); +} + +static void smmu_fault(SMMU500State *s, unsigned int cb, TransReq *req, uint64_t syn) +{ + unsigned int cb_offset = smmu_cb_offset(s, cb); + + s->regs[R_SMMU_CB0_FSR + cb_offset] |= 1 << 1; + + req->err = true; + s->regs[R_SMMU_CB0_IPAFAR_LOW + cb_offset] = req->va; + s->regs[R_SMMU_CB0_IPAFAR_HIGH + cb_offset] = req->va >> 32; + if (req->stage == 2) { + s->regs[R_SMMU_CB0_FAR_LOW + cb_offset] = req->va; + s->regs[R_SMMU_CB0_FAR_HIGH + cb_offset] = req->va >> 32; + } + smmu_update_ctx_irq(s, cb); +} + +static int smmu_stream_id_match(SMMU500State *s, uint32_t stream_id) +{ + unsigned int nr_smr = ARRAY_FIELD_EX32(s->regs, SMMU_SIDR0, NUMSMRG); + unsigned int i; + uint32_t s2cr; + unsigned int cbndx = -1; + + for (i = 0; i < nr_smr; i++) { + uint32_t v = s->regs[R_SMMU_SMR0 + i]; + bool valid = FIELD_EX32(v, SMMU_SMR0, VALID); + uint16_t mask = FIELD_EX32(v, SMMU_SMR0, MASK); + uint16_t id = FIELD_EX32(v, SMMU_SMR0, ID); + + + if (valid && (~mask & id) == (~mask & stream_id)) { + s2cr = s->regs[R_SMMU_S2CR0 + i]; + cbndx = FIELD_EX32(s2cr, SMMU_S2CR0, CBNDX_VMID); + break; + } + } + + D("SMMU StreamID 0x%x -> CB%d\n", stream_id, cbndx); + return cbndx; +} + +static bool check_s2_startlevel(bool is_aa64, unsigned int pamax, int level, + int inputsize, int stride) +{ + /* Negative levels are never allowed. */ + if (level < 0) { + return false; + } + + if (is_aa64) { + switch (stride) { + case 13: /* 64KB Pages. */ + if (level == 0 || (level == 1 && pamax <= 42)) { + return false; + } + break; + case 11: /* 16KB Pages. */ + if (level == 0 || (level == 1 && pamax <= 40)) { + return false; + } + break; + case 9: /* 4KB Pages. */ + if (level == 0 && pamax <= 42) { + return false; + } + break; + default: + g_assert_not_reached(); + } + } else { + const int grainsize = stride + 3; + int startsizecheck; + + /* AArch32 only supports 4KB pages. Assert on that. */ + assert(stride == 9); + + if (level == 0) { + return false; + } + + startsizecheck = inputsize - ((3 - level) * stride + grainsize); + if (startsizecheck < 1 || startsizecheck > stride + 4) { + return false; + } + } + return true; +} + +static bool check_out_addr(uint64_t addr, unsigned int outputsize) +{ + if (outputsize != 48 && extract64(addr, outputsize, 48 - outputsize)) { + return false; + } + return true; +} + +static void smmu_ptw64(SMMU500State *s, unsigned int cb, TransReq *req) +{ + static const unsigned int outsize_map[] = { + [0] = 32, + [1] = 36, + [2] = 40, + [3] = 42, + [4] = 44, + [5] = 48, + [6] = 48, + [7] = 48, + }; + unsigned int cb_offset = smmu_cb_offset(s, cb); + uint32_t sctlr; + unsigned int tsz; + unsigned int t0sz; + unsigned int t1sz; + unsigned int inputsize; + unsigned int outputsize; + unsigned int grainsize = -1; + unsigned int stride; + int level = 0; + unsigned int firstblocklevel = 0; + unsigned int tg; + unsigned int ps; + unsigned int baselowerbound; + unsigned int stage = req->stage; + bool blocktranslate = false; + bool epd = false; + bool va64; + bool type64; + uint32_t tableattrs = 0; + uint32_t attrs; + uint32_t s2attrs; + uint64_t descmask; + uint64_t ttbr; + uint64_t desc; + + req->err = false; + sctlr = s->regs[R_SMMU_CB0_SCTLR + cb_offset]; + + if (FIELD_EX32(sctlr, SMMU_CB0_SCTLR, M) == 0) { + req->pa = req->va; + req->prot = IOMMU_RW; + D("SMMU disabled for context %d sctlr=%x\n", cb, sctlr); + return; + } + + ttbr = req->ttbr[stage][0]; + tg = extract32(req->tcr[stage], 14, 2); + if (stage == 1) { + ps = extract64(req->tcr[stage], 32, 3); + } else { + ps = extract64(req->tcr[stage], 16, 3); + } + t0sz = extract32(req->tcr[stage], 0, 6); + tsz = t0sz; + req->pa = req->va; + + va64 = s->regs[R_SMMU_CBA2R0 + cb] & 1; + if (req->stage == 1) { + type64 = va64 || extract32(req->tcr[1], 31, 1); + /* We don't support 32bit page-tables yet. */ + assert(type64); + + if ((req->va & (1ULL << 63)) == 0) { + } else { + static const unsigned int tg1map[] = { + [0] = 3, + [1] = 2, + [2] = 0, + [3] = 1, + }; + if (!va64 && type64) { + /* LPAE uses 4K pages. */ + tg = extract32(req->tcr[stage], 30, 2); + tg = tg1map[tg]; + t1sz = extract32(req->tcr[stage], 16, 6); + } else { + /* Default to 4K. */ + tg = 0; + t1sz = extract32(req->tcr[stage], 16, 3); + } + ttbr = req->ttbr[stage][1]; + tsz = t1sz; + } + epd = extract32(req->tcr[1], 7, 1); + } else { + type64 = true; + } + + if (epd) { + /* We've already missed the TLB at this stage so fault. */ + goto do_fault; + } + + inputsize = 64 - tsz; + switch (tg) { + case 1: + /* 64KB pages. */ + grainsize = 16; + level = 3; + firstblocklevel = 2; + break; + case 2: + /* 16KB pages. */ + grainsize = 14; + level = 3; + firstblocklevel = 2; + break; + case 0: + /* 4KB pages. */ + grainsize = 12; + level = 2; + firstblocklevel = 1; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "SMMU: Wrong pagesize\n"); + break; + } + + outputsize = outsize_map[ps]; + if (outputsize > s->cfg.pamax) { + outputsize = s->cfg.pamax; + } + + stride = grainsize - 3; + if (req->stage == 1) { + if (grainsize < 16 && (inputsize > (grainsize + 3 * stride))) { + level = 0; + } else if (inputsize > (grainsize + 2 * stride)) { + level = 1; + } else if (inputsize > (grainsize + stride)) { + level = 2; + } + + if (inputsize < 25 || inputsize > 48 + || extract64(req->va, inputsize, 64 - inputsize)) { + goto do_fault; + } + } else { + unsigned int startlevel = extract32(req->tcr[stage], 6, 2); + bool ok; + + level = 3 - startlevel; + if (grainsize == 12) { + level = 2 - startlevel; + } + + ok = check_s2_startlevel(true, outputsize, level, inputsize, stride); + if (!ok) { + goto do_fault; + } + } + + baselowerbound = 3 + inputsize - ((3 - level) * stride + grainsize); + ttbr = extract64(ttbr, 0, 48); + ttbr &= ~((1ULL << baselowerbound) - 1); + + if (!check_out_addr(ttbr, outputsize)) { + goto do_fault; + } + + descmask = (1ULL << grainsize) - 1; + do { + unsigned int addrselectbottom = (3 - level) * stride + grainsize; + uint64_t index; + uint64_t descaddr; + unsigned int type; + + index = (req->va >> (addrselectbottom - 3)) & descmask; + index &= ~7ULL; + descaddr = ttbr | index; + + /* S1 PTW through the S2 system. */ + if (req->stage == 1 && req->s2_enabled) { + TransReq s2req = *req; + + s2req.stage = 2; + s2req.va = descaddr; + smmu_ptw64(s, s2req.s2_cb, &s2req); + if (req->err) { + s->regs[R_SMMU_CB0_IPAFAR_LOW] = descaddr; + s->regs[R_SMMU_CB0_IPAFAR_HIGH] = descaddr >> 32; + goto do_fault; + } + descaddr = s2req.pa; + } + dma_memory_read(&s->dma_as, descaddr, &desc, sizeof(desc), MEMTXATTRS_UNSPECIFIED); + type = desc & 3; + + D_PTW("smmu: S%d L%d va=0x%"PRIx64" gz=%d descaddr=0x%"PRIx64" " + "desc=0x%"PRIx64" asb=%d index=0x%"PRIx64" osize=%d\n", + req->stage, level, req->va, grainsize, descaddr, desc, + addrselectbottom, index, outputsize); + ttbr = extract64(desc, 0, 48); + ttbr &= ~descmask; + + /* special case. */ + if (!(type & 2) && level == 3) { + D("smmu: bad level 3 desc\n"); + goto do_fault; + } + + if (level == 3) { + break; + } + switch (type) { + case 2: + case 0: + /* Invalid. */ + D("smmu: bad desc\n"); + goto do_fault; + break; + case 1: + blocktranslate = true; + if (level < firstblocklevel) { + goto do_fault; + } + break; + case 3: + tableattrs |= extract64(desc, 59, 5); + if (!check_out_addr(ttbr, outputsize)) { + goto do_fault; + } + level++; + break; + } + } while (!blocktranslate); + + if (!check_out_addr(ttbr, outputsize)) { + goto do_fault; + } + + { + unsigned long page_size; + page_size = (1ULL << ((stride * (4 - level)) + 3)); + ttbr |= (req->va & (page_size - 1)); + } + + s2attrs = attrs = extract64(desc, 2, 10) + | (extract64(desc, 52, 12) << 10); + if (req->stage == 1) { + attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */ + attrs |= extract32(tableattrs, 3, 1) << 5; /* APTable[1] => AP[2] */ + /* The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1 + * means "force PL1 access only", which means forcing AP[1] to 0. + * + * This only applies for multi-regime tables (EL0/EL1) which we don't + * support so disable APTable[0] propagation. + */ + if (0 && extract32(tableattrs, 2, 1)) { + attrs &= ~(1 << 4); + } + } + + req->prot = IOMMU_RW; + if ((attrs & (1 << 8)) == 0) { + /* Access flag */ + D("smmu: access forbidden %x\n", attrs); + goto do_fault; + } + + if (req->stage == 1) { + /* AP[1] SBO. */ + if (!(attrs & (1 << 4))) { + D("smmu: AP[1] should be one but set to zero!\n"); + goto do_fault; + } + + if (attrs & (1 << 5)) { + /* Write access forbidden */ + if (req->access == IOMMU_WO) { + D("smmu: Write access forbidden %x\n", attrs); + goto do_fault; + } + req->prot &= ~IOMMU_WO; + } + } else { + switch ((s2attrs >> 4) & 3) { + /* None. */ + case 0: + goto do_fault; + break; + /* RO. */ + case 1: + if (req->access == IOMMU_WO) { + goto do_fault; + } + req->prot &= ~IOMMU_WO; + break; + /* WO. */ + case 2: + if (req->access == IOMMU_RO) { + goto do_fault; + } + req->prot &= ~IOMMU_RO; + break; + /* RW. */ + case 3: + break; + } + } + + req->pa = ttbr; + D("SMMU: 0x%"PRIx64" -> 0x%"PRIx64"\n", req->va, req->pa); + return; + +do_fault: + D("smmu fault\n"); + smmu_fault(s, cb, req, level); +} + +static bool smmu500_at64(SMMU500State *s, unsigned int cb, hwaddr va, + bool wr, bool s2, hwaddr *pa, int *prot) +{ + unsigned int cb_offset = smmu_cb_offset(s, cb); + unsigned int cb2_offset = 0; + TransReq req; + uint32_t v; + unsigned int t; + + v = s->regs[R_SMMU_CBAR0 + cb]; + t = FIELD_EX32(v, SMMU_CBAR0, TYPE); + switch (t) { + case 0: + req.stage = 2; + req.s2_enabled = true; + req.s2_cb = cb; + cb2_offset = cb_offset; + break; + case 1: + req.stage = 1; + req.s2_enabled = false; + break; + case 2: + req.stage = 1; + req.s2_enabled = false; + /* Invalid ??? */ + break; + case 3: + req.stage = 1; + req.s2_enabled = true; + req.s2_cb = extract32(v, 8, 8); + cb2_offset = smmu_cb_offset(s, req.s2_cb); + break; + } + + req.va = va; + req.tcr[1] = s->regs[R_SMMU_CB0_TCR2 + cb_offset]; + req.tcr[1] <<= 32; + req.tcr[1] |= s->regs[R_SMMU_CB0_TCR_LPAE + cb_offset]; + + req.ttbr[1][0] = s->regs[R_SMMU_CB0_TTBR0_HIGH + cb_offset]; + req.ttbr[1][0] <<= 32; + req.ttbr[1][0] |= s->regs[R_SMMU_CB0_TTBR0_LOW + cb_offset]; + + req.ttbr[1][1] = s->regs[R_SMMU_CB0_TTBR1_HIGH + cb_offset]; + req.ttbr[1][1] <<= 32; + req.ttbr[1][1] |= s->regs[R_SMMU_CB0_TTBR1_LOW + cb_offset]; + + if (req.s2_enabled) { + req.tcr[2] = s->regs[R_SMMU_CB0_TCR_LPAE + cb2_offset]; + req.ttbr[2][0] = s->regs[R_SMMU_CB0_TTBR0_HIGH + cb2_offset]; + req.ttbr[2][0] <<= 32; + req.ttbr[2][0] |= s->regs[R_SMMU_CB0_TTBR0_LOW + cb2_offset]; + } + + req.access = wr ? IOMMU_WO : IOMMU_RO; + + if (req.stage == 1) { + smmu_ptw64(s, cb, &req); + req.stage++; + } else { + req.pa = req.va; + } + + if (s2 && req.s2_enabled) { + req.va = req.pa; + + smmu_ptw64(s, cb, &req); + } + + *pa = req.pa; + *prot = req.prot; + return req.err; +} + +static bool smmu500_at(SMMU500State *s, unsigned int cb, hwaddr va, + bool wr, bool s2, hwaddr *pa, int *prot) +{ + return smmu500_at64(s, cb, va, wr, s2, pa, prot); +} + +#define ADDRMASK ((1ULL << 12) - 1) + +static void smmu500_gat(SMMU500State *s, uint64_t v, bool wr, bool s2) +{ + uint64_t va = v & ~ADDRMASK; + unsigned int cb = v & ADDRMASK; + hwaddr pa; + int prot; + bool err; + + D("ATS: va=0x%"PRIx64" cb=%d wr=%d s2=%d\n", va, cb, wr, s2); + err = smmu500_at(s, cb, va, wr, s2, &pa, &prot); + + s->regs[R_SMMU_GPAR] = pa | err; + s->regs[R_SMMU_GPAR_H] = pa >> 32; +} + +static void smmu_gats1pr(RegisterInfo *reg, uint64_t val) +{ + SMMU500State *s = XILINX_SMMU500(reg->opaque); + + val <<= 32; + val |= s->regs[(reg->access->addr / 4) - 1]; + smmu500_gat(s, val, false, false); +} + +static void smmu_gats1pw(RegisterInfo *reg, uint64_t val) +{ + SMMU500State *s = XILINX_SMMU500(reg->opaque); + + val <<= 32; + val |= s->regs[(reg->access->addr / 4) - 1]; + smmu500_gat(s, val, true, false); +} + +static void smmu_gats12pr(RegisterInfo *reg, uint64_t val) +{ + SMMU500State *s = XILINX_SMMU500(reg->opaque); + + val <<= 32; + val |= s->regs[(reg->access->addr / 4) - 1]; + smmu500_gat(s, val, false, true); +} + +static void smmu_gats12pw(RegisterInfo *reg, uint64_t val) +{ + SMMU500State *s = XILINX_SMMU500(reg->opaque); + + val <<= 32; + val |= s->regs[(reg->access->addr / 4) - 1]; + smmu500_gat(s, val, true, true); +} + +static void smmu_nscr0_pw(RegisterInfo *reg, uint64_t val) +{ + SMMU500State *s = XILINX_SMMU500(reg->opaque); + + /* FIXME: Take care of secure vs non-secure accesses. */ + s->regs[R_SMMU_SCR0] = val; + s->regs[R_SMMU_NSCR0] = val; +} + +static int smmu_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs) +{ + uint16_t master_id = attrs.requester_id & 0xffff; + + return (master_id << 1) | attrs.secure; +} + +static int smmu_num_indexes(IOMMUMemoryRegion *iommu) +{ + return (1 << 17) - 1; +} + +static IOMMUTLBEntry smmu_translate(IOMMUMemoryRegion *mr, hwaddr addr, + IOMMUAccessFlags flags, int iommu_idx) + +{ + TBU *tbu = container_of(mr, TBU, iommu); + SMMU500State *s = tbu->smmu; + IOMMUTLBEntry ret = { + .target_as = tbu->as, + .translated_addr = addr, + .addr_mask = (1ULL << 12) - 1, + .perm = IOMMU_RW, + }; + int cb; + uint64_t va = addr & ~ADDRMASK; + hwaddr pa = va; + int prot; + bool err = false; + uint16_t master_id = iommu_idx >> 1; + bool clientpd = ARRAY_FIELD_EX32(s->regs, SMMU_SCR0, CLIENTPD); + + if (clientpd) { + return ret; + } + + cb = smmu_stream_id_match(s, master_id); + + if (cb >= 0) { + err = smmu500_at(s, cb, va, false, true, &pa, &prot); + ret.translated_addr = pa; + ret.perm = prot; + if (err) { + memset(&ret, 0, sizeof ret); + ret.perm = IOMMU_NONE; + } + } + return ret; +} + +static void smmu_fsr_pw(RegisterInfo *reg, uint64_t val) +{ + SMMU500State *s = XILINX_SMMU500(reg->opaque); + unsigned int i; + + for (i = 0; i < 16; i++) { + smmu_update_ctx_irq(s, i); + } +} + +static const RegisterAccessInfo smmu500_regs_info[] = { + /* Manually added. */ + { .name = "SMMU_GATS1PR", .addr = A_SMMU_GATS1PR, + }, + { .name = "SMMU_GATS1PR_H", .addr = A_SMMU_GATS1PR_H, + .post_write = smmu_gats1pr, + }, + { .name = "SMMU_GATS1PW", .addr = A_SMMU_GATS1PW, + }, + { .name = "SMMU_GATS1PW_H", .addr = A_SMMU_GATS1PW_H, + .post_write = smmu_gats1pw, + }, + + { .name = "SMMU_GATS12PR", .addr = A_SMMU_GATS12PR, + }, + { .name = "SMMU_GATS12PR_H", .addr = A_SMMU_GATS12PR_H, + .post_write = smmu_gats12pr, + }, + + { .name = "SMMU_GATS12PW", .addr = A_SMMU_GATS12PW, + }, + { .name = "SMMU_GATS12PW_H", .addr = A_SMMU_GATS12PW_H, + .post_write = smmu_gats12pw, + }, + + { .name = "SMMU_GPAR", .addr = A_SMMU_GPAR, }, + { .name = "SMMU_GPAR_H", .addr = A_SMMU_GPAR_H, }, + { .name = "SMMU_GATSR", .addr = A_SMMU_GATSR, }, + + { .name = "SMMU_SCR0", .addr = A_SMMU_SCR0, + .reset = 0x200001, + .ro = 0x200330, + },{ .name = "SMMU_SCR1", .addr = A_SMMU_SCR1, + .reset = 0x2013010, + .ro = 0x10ff0000, + },{ .name = "SMMU_SACR", .addr = A_SMMU_SACR, + .reset = 0x4000004, + },{ .name = "SMMU_SIDR0", .addr = A_SMMU_SIDR0, + .reset = 0xfc013e30, + .ro = 0xffff7eff, + },{ .name = "SMMU_SIDR1", .addr = A_SMMU_SIDR1, + .reset = 0x30000f10, + .ro = 0xf0ff9fff, + },{ .name = "SMMU_SIDR2", .addr = A_SMMU_SIDR2, + .reset = 0x5555, + .ro = 0x7fff, + },{ .name = "SMMU_SIDR7", .addr = A_SMMU_SIDR7, + .reset = 0x21, + .ro = 0xff, + },{ .name = "SMMU_SGFAR_LOW", .addr = A_SMMU_SGFAR_LOW, + },{ .name = "SMMU_SGFAR_HIGH", .addr = A_SMMU_SGFAR_HIGH, + },{ .name = "SMMU_SGFSR", .addr = A_SMMU_SGFSR, + },{ .name = "SMMU_SGFSRRESTORE", .addr = A_SMMU_SGFSRRESTORE, + },{ .name = "SMMU_SGFSYNR0", .addr = A_SMMU_SGFSYNR0, + .ro = 0x40, + },{ .name = "SMMU_SGFSYNR1", .addr = A_SMMU_SGFSYNR1, + },{ .name = "SMMU_STLBIALL", .addr = A_SMMU_STLBIALL, + },{ .name = "SMMU_TLBIVMID", .addr = A_SMMU_TLBIVMID, + },{ .name = "SMMU_TLBIALLNSNH", .addr = A_SMMU_TLBIALLNSNH, + },{ .name = "SMMU_STLBGSYNC", .addr = A_SMMU_STLBGSYNC, + },{ .name = "SMMU_STLBGSTATUS", .addr = A_SMMU_STLBGSTATUS, + .ro = 0x1, + },{ .name = "SMMU_DBGRPTRTBU", .addr = A_SMMU_DBGRPTRTBU, + },{ .name = "SMMU_DBGRDATATBU", .addr = A_SMMU_DBGRDATATBU, + .ro = 0xffffffff, + },{ .name = "SMMU_DBGRPTRTCU", .addr = A_SMMU_DBGRPTRTCU, + },{ .name = "SMMU_DBGRDATATCU", .addr = A_SMMU_DBGRDATATCU, + .ro = 0xffffffff, + },{ .name = "SMMU_STLBIVALM_LOW", .addr = A_SMMU_STLBIVALM_LOW, + },{ .name = "SMMU_STLBIVALM_HIGH", .addr = A_SMMU_STLBIVALM_HIGH, + },{ .name = "SMMU_STLBIVAM_LOW", .addr = A_SMMU_STLBIVAM_LOW, + },{ .name = "SMMU_STLBIVAM_HIGH", .addr = A_SMMU_STLBIVAM_HIGH, + },{ .name = "SMMU_STLBIALLM", .addr = A_SMMU_STLBIALLM, + },{ .name = "SMMU_NSCR0", .addr = A_SMMU_NSCR0, + .reset = 0x200001, + .ro = 0x200330, + .post_write = smmu_nscr0_pw, + },{ .name = "SMMU_NSACR", .addr = A_SMMU_NSACR, + .reset = 0x400001c, + },{ .name = "SMMU_NSGFAR_LOW", .addr = A_SMMU_NSGFAR_LOW, + },{ .name = "SMMU_NSGFAR_HIGH", .addr = A_SMMU_NSGFAR_HIGH, + },{ .name = "SMMU_NSGFSR", .addr = A_SMMU_NSGFSR, + },{ .name = "SMMU_NSGFSRRESTORE", .addr = A_SMMU_NSGFSRRESTORE, + },{ .name = "SMMU_NSGFSYNR0", .addr = A_SMMU_NSGFSYNR0, + .ro = 0x40, + },{ .name = "SMMU_NSGFSYNDR1", .addr = A_SMMU_NSGFSYNDR1, + .ro = 0x7fff0000, + },{ .name = "SMMU_NSTLBGSYNC", .addr = A_SMMU_NSTLBGSYNC, + },{ .name = "SMMU_NSTLBGSTATUS", .addr = A_SMMU_NSTLBGSTATUS, + .ro = 0x1, + },{ .name = "SMMU_PIDR4", .addr = A_SMMU_PIDR4, + .reset = 0x4, + .ro = 0xff, + },{ .name = "SMMU_PIDR5", .addr = A_SMMU_PIDR5, + .ro = 0xffffffff, + },{ .name = "SMMU_PIDR6", .addr = A_SMMU_PIDR6, + .ro = 0xffffffff, + },{ .name = "SMMU_PIDR7", .addr = A_SMMU_PIDR7, + .ro = 0xffffffff, + },{ .name = "SMMU_PIDR0", .addr = A_SMMU_PIDR0, + .reset = 0x81, + .ro = 0xff, + },{ .name = "SMMU_PIDR1", .addr = A_SMMU_PIDR1, + .reset = 0xb4, + .ro = 0xff, + },{ .name = "SMMU_PIDR2", .addr = A_SMMU_PIDR2, + .reset = 0x1b, + .ro = 0xff, + },{ .name = "SMMU_PIDR3", .addr = A_SMMU_PIDR3, + .ro = 0xff, + },{ .name = "SMMU_CIDR0", .addr = A_SMMU_CIDR0, + .reset = 0xd, + .ro = 0xff, + },{ .name = "SMMU_CIDR1", .addr = A_SMMU_CIDR1, + .reset = 0xf0, + .ro = 0xff, + },{ .name = "SMMU_CIDR2", .addr = A_SMMU_CIDR2, + .reset = 0x5, + .ro = 0xff, + },{ .name = "SMMU_CIDR3", .addr = A_SMMU_CIDR3, + .reset = 0xb1, + .ro = 0xff, + },{ .name = "SMMU_ITCTRL", .addr = A_SMMU_ITCTRL, + },{ .name = "SMMU_ITIP", .addr = A_SMMU_ITIP, + .ro = 0x1, + },{ .name = "SMMU_ITOP_GLBL", .addr = A_SMMU_ITOP_GLBL, + .ro = 0x202, + },{ .name = "SMMU_ITOP_PERF_INDEX", .addr = A_SMMU_ITOP_PERF_INDEX, + },{ .name = "SMMU_ITOP_CXT0TO31_RAM0", .addr = A_SMMU_ITOP_CXT0TO31_RAM0, + },{ .name = "SMMU_TBUQOS0", .addr = A_SMMU_TBUQOS0, + },{ .name = "SMMU_PER", .addr = A_SMMU_PER, + .ro = 0xffff, + },{ .name = "SMMU_TBU_PWR_STATUS", .addr = A_SMMU_TBU_PWR_STATUS, + .ro = 0xffffffff, + },{ .name = "PMEVCNTR0", .addr = A_PMEVCNTR0, + },{ .name = "PMEVCNTR1", .addr = A_PMEVCNTR1, + },{ .name = "PMEVCNTR2", .addr = A_PMEVCNTR2, + },{ .name = "PMEVCNTR3", .addr = A_PMEVCNTR3, + },{ .name = "PMEVCNTR4", .addr = A_PMEVCNTR4, + },{ .name = "PMEVCNTR5", .addr = A_PMEVCNTR5, + },{ .name = "PMEVCNTR6", .addr = A_PMEVCNTR6, + },{ .name = "PMEVCNTR7", .addr = A_PMEVCNTR7, + },{ .name = "PMEVCNTR8", .addr = A_PMEVCNTR8, + },{ .name = "PMEVCNTR9", .addr = A_PMEVCNTR9, + },{ .name = "PMEVCNTR10", .addr = A_PMEVCNTR10, + },{ .name = "PMEVCNTR11", .addr = A_PMEVCNTR11, + },{ .name = "PMEVCNTR12", .addr = A_PMEVCNTR12, + },{ .name = "PMEVCNTR13", .addr = A_PMEVCNTR13, + },{ .name = "PMEVCNTR14", .addr = A_PMEVCNTR14, + },{ .name = "PMEVCNTR15", .addr = A_PMEVCNTR15, + },{ .name = "PMEVCNTR16", .addr = A_PMEVCNTR16, + },{ .name = "PMEVCNTR17", .addr = A_PMEVCNTR17, + },{ .name = "PMEVCNTR18", .addr = A_PMEVCNTR18, + },{ .name = "PMEVCNTR19", .addr = A_PMEVCNTR19, + },{ .name = "PMEVCNTR20", .addr = A_PMEVCNTR20, + },{ .name = "PMEVCNTR21", .addr = A_PMEVCNTR21, + },{ .name = "PMEVCNTR22", .addr = A_PMEVCNTR22, + },{ .name = "PMEVCNTR23", .addr = A_PMEVCNTR23, + },{ .name = "PMEVTYPER0", .addr = A_PMEVTYPER0, + },{ .name = "PMEVTYPER1", .addr = A_PMEVTYPER1, + },{ .name = "PMEVTYPER2", .addr = A_PMEVTYPER2, + },{ .name = "PMEVTYPER3", .addr = A_PMEVTYPER3, + },{ .name = "PMEVTYPER4", .addr = A_PMEVTYPER4, + },{ .name = "PMEVTYPER5", .addr = A_PMEVTYPER5, + },{ .name = "PMEVTYPER6", .addr = A_PMEVTYPER6, + },{ .name = "PMEVTYPER7", .addr = A_PMEVTYPER7, + },{ .name = "PMEVTYPER8", .addr = A_PMEVTYPER8, + },{ .name = "PMEVTYPER9", .addr = A_PMEVTYPER9, + },{ .name = "PMEVTYPER10", .addr = A_PMEVTYPER10, + },{ .name = "PMEVTYPER11", .addr = A_PMEVTYPER11, + },{ .name = "PMEVTYPER12", .addr = A_PMEVTYPER12, + },{ .name = "PMEVTYPER13", .addr = A_PMEVTYPER13, + },{ .name = "PMEVTYPER14", .addr = A_PMEVTYPER14, + },{ .name = "PMEVTYPER15", .addr = A_PMEVTYPER15, + },{ .name = "PMEVTYPER16", .addr = A_PMEVTYPER16, + },{ .name = "PMEVTYPER17", .addr = A_PMEVTYPER17, + },{ .name = "PMEVTYPER18", .addr = A_PMEVTYPER18, + },{ .name = "PMEVTYPER19", .addr = A_PMEVTYPER19, + },{ .name = "PMEVTYPER20", .addr = A_PMEVTYPER20, + },{ .name = "PMEVTYPER21", .addr = A_PMEVTYPER21, + },{ .name = "PMEVTYPER22", .addr = A_PMEVTYPER22, + },{ .name = "PMEVTYPER23", .addr = A_PMEVTYPER23, + },{ .name = "PMCGCR0", .addr = A_PMCGCR0, + .reset = 0x4000000, + .ro = 0xf7f0000, + },{ .name = "PMCGCR1", .addr = A_PMCGCR1, + .reset = 0x4010000, + .ro = 0xf7f0000, + },{ .name = "PMCGCR2", .addr = A_PMCGCR2, + .reset = 0x4020000, + .ro = 0xf7f0000, + },{ .name = "PMCGCR3", .addr = A_PMCGCR3, + .reset = 0x4030000, + .ro = 0xf7f0000, + },{ .name = "PMCGCR4", .addr = A_PMCGCR4, + .reset = 0x4040000, + .ro = 0xf7f0000, + },{ .name = "PMCGCR5", .addr = A_PMCGCR5, + .reset = 0x4050000, + .ro = 0xf7f0000, + },{ .name = "PMCGSMR0", .addr = A_PMCGSMR0, + },{ .name = "PMCGSMR1", .addr = A_PMCGSMR1, + },{ .name = "PMCGSMR2", .addr = A_PMCGSMR2, + },{ .name = "PMCGSMR3", .addr = A_PMCGSMR3, + },{ .name = "PMCGSMR4", .addr = A_PMCGSMR4, + },{ .name = "PMCGSMR5", .addr = A_PMCGSMR5, + },{ .name = "PMCNTENSET", .addr = A_PMCNTENSET, + },{ .name = "PMCNTENCLR", .addr = A_PMCNTENCLR, + },{ .name = "PMINTENSET", .addr = A_PMINTENSET, + },{ .name = "PMINTENCLR", .addr = A_PMINTENCLR, + },{ .name = "PMOVSCLR", .addr = A_PMOVSCLR, + },{ .name = "PMOVSSET", .addr = A_PMOVSSET, + },{ .name = "PMCFGR", .addr = A_PMCFGR, + .reset = 0x5011f17, + .ro = 0xff09ffff, + },{ .name = "PMCR", .addr = A_PMCR, + .ro = 0xff000002, + },{ .name = "PMCEID0", .addr = A_PMCEID0, + .reset = 0x30303, + .ro = 0x38383, + },{ .name = "PMAUTHSTATUS", .addr = A_PMAUTHSTATUS, + .reset = 0x80, + .ro = 0xff, + },{ .name = "PMDEVTYPE", .addr = A_PMDEVTYPE, + .reset = 0x56, + .ro = 0xff, + } +}; + +static const RegisterAccessInfo smmu_cb_regs_info[] = { + { .name = "AR", .addr = A_SMMU_CBAR0, + .reset = 0x20000, + .ro = 0xff000000, + },{ .name = "FRSYNRA", .addr = A_SMMU_CBFRSYNRA0, + .ro = 0x7fff0000, + },{ .name = "A2R", .addr = A_SMMU_CBA2R0, + } +}; + +static const RegisterAccessInfo smmu_cb_page_regs_info[] = { + { .name = "SCTLR", .addr = A_SMMU_CB0_SCTLR, + .reset = 0x100, + .ro = 0x1000, + },{ .name = "ACTLR", .addr = A_SMMU_CB0_ACTLR, + .reset = 0x3, + },{ .name = "RESUME", .addr = A_SMMU_CB0_RESUME, + },{ .name = "TCR2", .addr = A_SMMU_CB0_TCR2, + .reset = 0x60, + .ro = 0x60, + },{ .name = "TTBR0_LOW", .addr = A_SMMU_CB0_TTBR0_LOW, + .ro = 0x4, + },{ .name = "TTBR0_HIGH", .addr = A_SMMU_CB0_TTBR0_HIGH, + },{ .name = "TTBR1_LOW", .addr = A_SMMU_CB0_TTBR1_LOW, + },{ .name = "TTBR1_HIGH", .addr = A_SMMU_CB0_TTBR1_HIGH, + },{ .name = "TCR_LPAE", .addr = A_SMMU_CB0_TCR_LPAE, + },{ .name = "CONTEXTIDR", .addr = A_SMMU_CB0_CONTEXTIDR, + },{ .name = "PRRR_MAIR0", .addr = A_SMMU_CB0_PRRR_MAIR0, + },{ .name = "NMRR_MAIR1", .addr = A_SMMU_CB0_NMRR_MAIR1, + },{ .name = "FSR", .addr = A_SMMU_CB0_FSR, + .w1c = 0xffffffff, + .post_write = smmu_fsr_pw, + },{ .name = "FSRRESTORE", .addr = A_SMMU_CB0_FSRRESTORE, + },{ .name = "FAR_LOW", .addr = A_SMMU_CB0_FAR_LOW, + },{ .name = "FAR_HIGH", .addr = A_SMMU_CB0_FAR_HIGH, + },{ .name = "FSYNR0", .addr = A_SMMU_CB0_FSYNR0, + .ro = 0x200, + },{ .name = "IPAFAR_LOW", .addr = A_SMMU_CB0_IPAFAR_LOW, + .ro = 0xfff, + },{ .name = "IPAFAR_HIGH", .addr = A_SMMU_CB0_IPAFAR_HIGH, + },{ .name = "TLBIVA_LOW", .addr = A_SMMU_CB0_TLBIVA_LOW, + },{ .name = "TLBIVA_HIGH", .addr = A_SMMU_CB0_TLBIVA_HIGH, + },{ .name = "TLBIVAA_LOW", .addr = A_SMMU_CB0_TLBIVAA_LOW, + },{ .name = "TLBIVAA_HIGH", .addr = A_SMMU_CB0_TLBIVAA_HIGH, + },{ .name = "TLBIASID", .addr = A_SMMU_CB0_TLBIASID, + },{ .name = "TLBIALL", .addr = A_SMMU_CB0_TLBIALL, + },{ .name = "TLBIVAL_LOW", .addr = A_SMMU_CB0_TLBIVAL_LOW, + },{ .name = "TLBIVAL_HIGH", .addr = A_SMMU_CB0_TLBIVAL_HIGH, + },{ .name = "TLBIVAAL_LOW", .addr = A_SMMU_CB0_TLBIVAAL_LOW, + },{ .name = "TLBIVAAL_HIGH", .addr = A_SMMU_CB0_TLBIVAAL_HIGH, + },{ .name = "TLBIIPAS2_LOW", .addr = A_SMMU_CB0_TLBIIPAS2_LOW, + },{ .name = "TLBIIPAS2_HIGH", .addr = A_SMMU_CB0_TLBIIPAS2_HIGH, + },{ .name = "TLBIIPAS2L_LOW", .addr = A_SMMU_CB0_TLBIIPAS2L_LOW, + },{ .name = "TLBIIPAS2L_HIGH", .addr = A_SMMU_CB0_TLBIIPAS2L_HIGH, + },{ .name = "TLBSYNC", .addr = A_SMMU_CB0_TLBSYNC, + },{ .name = "TLBSTATUS", .addr = A_SMMU_CB0_TLBSTATUS, + .ro = 0x1, + },{ .name = "PMEVCNTR0", .addr = A_SMMU_CB0_PMEVCNTR0, + },{ .name = "PMEVCNTR1", .addr = A_SMMU_CB0_PMEVCNTR1, + },{ .name = "PMEVCNTR2", .addr = A_SMMU_CB0_PMEVCNTR2, + },{ .name = "PMEVCNTR3", .addr = A_SMMU_CB0_PMEVCNTR3, + },{ .name = "PMEVTYPER0", .addr = A_SMMU_CB0_PMEVTYPER0, + },{ .name = "PMEVTYPER1", .addr = A_SMMU_CB0_PMEVTYPER1, + },{ .name = "PMEVTYPER2", .addr = A_SMMU_CB0_PMEVTYPER2, + },{ .name = "PMEVTYPER3", .addr = A_SMMU_CB0_PMEVTYPER3, + },{ .name = "PMCFGR", .addr = A_SMMU_CB0_PMCFGR, + .reset = 0x11f03, + .ro = 0xff09ffff, + },{ .name = "PMCR", .addr = A_SMMU_CB0_PMCR, + .ro = 0xff000002, + },{ .name = "PMCEID", .addr = A_SMMU_CB0_PMCEID, + .reset = 0x30303, + .ro = 0x38383, + },{ .name = "PMCNTENSE", .addr = A_SMMU_CB0_PMCNTENSE, + },{ .name = "PMCNTENCLR", .addr = A_SMMU_CB0_PMCNTENCLR, + },{ .name = "PMCNTENSET", .addr = A_SMMU_CB0_PMCNTENSET, + },{ .name = "PMINTENCLR", .addr = A_SMMU_CB0_PMINTENCLR, + },{ .name = "PMOVSCLR", .addr = A_SMMU_CB0_PMOVSCLR, + },{ .name = "PMOVSSET", .addr = A_SMMU_CB0_PMOVSSET, + },{ .name = "PMAUTHSTATUS", .addr = A_SMMU_CB0_PMAUTHSTATUS, + .reset = 0x80, + .ro = 0xff, + } +}; + +#define NUM_REGS_PER_CB (ARRAY_SIZE(smmu_cb_page_regs_info) + \ + ARRAY_SIZE(smmu_cb_regs_info)) + +static void smmu500_reset(DeviceState *dev) +{ + SMMU500State *s = XILINX_SMMU500(dev); + unsigned int num_pages_log2 = 31 - clz32(s->cfg.num_cb); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) { + register_reset(&s->regs_info[i]); + } + + ARRAY_FIELD_DP32(s->regs, SMMU_SIDR0, ATOSNS, s->cfg.ato); + ARRAY_FIELD_DP32(s->regs, SMMU_SIDR0, NUMSMRG, s->cfg.num_smr); + ARRAY_FIELD_DP32(s->regs, SMMU_SIDR1, NUMCB, s->cfg.num_cb); + ARRAY_FIELD_DP32(s->regs, SMMU_SIDR1, NUMPAGENDXB, num_pages_log2 - 1); + ARRAY_FIELD_DP32(s->regs, SMMU_SCR1, NSNUMCBO, s->cfg.num_cb); + ARRAY_FIELD_DP32(s->regs, SMMU_SCR1, NSNUMSMRGO, s->cfg.num_smr); + s->regs[R_SMMU_SIDR7] = s->cfg.version; + s->regs[R_SMMU_TBU_PWR_STATUS] = (1 << s->num_tbu) - 1; +} + +static const MemoryRegionOps smmu500_ops = { + .read = register_read_memory, + .write = register_write_memory, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, +}; + +static int smmu_populate_regarray(SMMU500State *s, + RegisterInfoArray *r_array, int pos, + const RegisterAccessInfo *rae, + int num_rae) +{ + int i; + + for (i = 0; i < num_rae; i++) { + int index = rae[i].addr / 4; + RegisterInfo *r = &s->regs_info[index]; + + object_initialize((void *)r, sizeof(*r), TYPE_REGISTER); + + *r = (RegisterInfo) { + .data = &s->regs[index], + .data_size = sizeof(uint32_t), + .access = &rae[i], + .opaque = OBJECT(s), + }; + + r_array->r[i + pos] = r; + } + + return i + pos; +} + +static void smmu_create_rai_smr(SMMU500State *s) +{ + int i; + + s->rai_smr = g_new0(RegisterAccessInfo, s->cfg.num_smr * 2); + for (i = 0; i < s->cfg.num_smr; i++) { + s->rai_smr[i * 2].name = g_strdup_printf("SMMU_SMR%d", i); + s->rai_smr[i * 2].addr = A_SMMU_SMR0 + i * 4; + s->rai_smr[i * 2 + 1].name = g_strdup_printf("SMMU_S2CR%d", i); + s->rai_smr[i * 2 + 1].addr = A_SMMU_S2CR0 + i * 4; + } +} + +static void smmu_create_rai_cb(SMMU500State *s) +{ + int cb; + + s->rai_cb = g_new0(RegisterAccessInfo, s->cfg.num_cb * NUM_REGS_PER_CB); + + for (cb = 0; cb < s->cfg.num_cb; cb++) { + int pos = cb * NUM_REGS_PER_CB; + int i; + + memcpy(s->rai_cb + pos, smmu_cb_regs_info, sizeof smmu_cb_regs_info); + for (i = 0; i < ARRAY_SIZE(smmu_cb_regs_info); i++) { + const char *name = smmu_cb_regs_info[i].name; + uint64_t addr = smmu_cb_regs_info[i].addr; + + s->rai_cb[i + pos].name = g_strdup_printf("SMMU_CB%s%d", name, cb); + s->rai_cb[i + pos].addr = addr + cb * 4; + } + pos += 3; + + /* Initialize with CB template. */ + memcpy(s->rai_cb + pos, smmu_cb_page_regs_info, + sizeof smmu_cb_page_regs_info); + + /* Generate context specific names. */ + for (i = 0; i < ARRAY_SIZE(smmu_cb_page_regs_info); i++) { + const char *name = smmu_cb_page_regs_info[i].name; + uint64_t addr = smmu_cb_page_regs_info[i].addr; + unsigned int cb_base = smmu_cb_offset(s, cb) * 4; + + s->rai_cb[i + pos].name = g_strdup_printf("SMMU_CB%d_%s", + cb, name); + s->rai_cb[i + pos].addr = cb_base + addr; + } + } +} + +static RegisterInfoArray *smmu_create_regarray(SMMU500State *s) +{ + const char *device_prefix = object_get_typename(OBJECT(s)); + uint64_t memory_size = SMMU_R_MAX * 4; + RegisterInfoArray *r_array; + int num_regs; + int pos = 0; + + if (s->cfg.num_smr < 1 || s->cfg.num_smr > 127) { + error_report("num-smr %d must be between 1 - 127", s->cfg.num_smr); + exit(EXIT_FAILURE); + } + + if (s->cfg.num_cb < 4 || s->cfg.num_cb > MAX_CB + || s->cfg.num_cb > s->cfg.num_pages) { + error_report("num-cb %d must be between 4 - 128 and <= num-pages %d", + s->cfg.num_cb, s->cfg.num_pages); + exit(EXIT_FAILURE); + } + + if (s->cfg.num_pages < 4 || !is_power_of_2(s->cfg.num_pages)) { + error_report("num-pages %d must be > 4 and a power of 2", + s->cfg.num_pages); + exit(EXIT_FAILURE); + } + + smmu_create_rai_smr(s); + smmu_create_rai_cb(s); + + num_regs = ARRAY_SIZE(smmu500_regs_info); + num_regs += s->cfg.num_smr * 2; + num_regs += s->cfg.num_cb * NUM_REGS_PER_CB; + + r_array = g_new0(RegisterInfoArray, 1); + r_array->r = g_new0(RegisterInfo *, num_regs); + r_array->num_elements = num_regs; + r_array->debug = XILINX_SMMU500_ERR_DEBUG; + r_array->prefix = device_prefix; + + pos = smmu_populate_regarray(s, r_array, pos, + smmu500_regs_info, + ARRAY_SIZE(smmu500_regs_info)); + + pos = smmu_populate_regarray(s, r_array, pos, + s->rai_smr, s->cfg.num_smr * 2); + + pos = smmu_populate_regarray(s, r_array, pos, + s->rai_cb, s->cfg.num_cb * NUM_REGS_PER_CB); + + memory_region_init_io(&r_array->mem, OBJECT(s), &smmu500_ops, r_array, + device_prefix, memory_size); + return r_array; +} + +static void smmu500_realize(DeviceState *dev, Error **errp) +{ + SMMU500State *s = XILINX_SMMU500(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + RegisterInfoArray *reg_array; + unsigned int i; + + memory_region_init(&s->iomem, OBJECT(dev), TYPE_XILINX_SMMU500, SMMU_R_MAX * 4); + reg_array = smmu_create_regarray(s); + memory_region_add_subregion(&s->iomem, + 0x0, + ®_array->mem); + sysbus_init_mmio(sbd, &s->iomem); + + address_space_init(&s->dma_as, + s->dma_mr ? s->dma_mr : get_system_memory(), NULL); + + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq.global); + for (i = 0; i < s->cfg.num_cb; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq.context[i]); + } +} + +static void smmu500_init(Object *obj) +{ + SMMU500State *s = XILINX_SMMU500(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + int i; + + object_property_add_link(obj, "dma", TYPE_MEMORY_REGION, + (Object **)&s->dma_mr, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_STRONG); + + for (i = 0; i < MAX_TBU; i++) { + char *name = g_strdup_printf("smmu-tbu%d", i); + + s->tbu[i].as = g_new0(AddressSpace, 1); + memory_region_init_iommu(&s->tbu[i].iommu, sizeof(s->tbu[i].iommu), + TYPE_XILINX_SMMU500_IOMMU_MEMORY_REGION, + OBJECT(sbd), + name, UINT64_MAX); + address_space_init(s->tbu[i].as, + MEMORY_REGION(&s->tbu[i].iommu), + name); + g_free(name); + s->tbu[i].smmu = s; + } + + s->num_tbu = MAX_TBU; +} + +static void smmu_free_rai(SMMU500State *s, RegisterAccessInfo *rai, int num) +{ + int i; + + if (!rai) { + return; + } + + for (i = 0; i < num; i++) { + g_free((void *) rai->name); + } + g_free(rai); +} + +static void smmu500_finalize(Object *obj) +{ + SMMU500State *s = XILINX_SMMU500(obj); + + smmu_free_rai(s, s->rai_smr, s->cfg.num_smr * 2); + smmu_free_rai(s, s->rai_cb, s->cfg.num_cb * NUM_REGS_PER_CB); +} + +static Property smmu_properties[] = { + DEFINE_PROP_UINT32("pamax", SMMU500State, cfg.pamax, 48), + DEFINE_PROP_UINT16("num-smr", SMMU500State, cfg.num_smr, 48), + DEFINE_PROP_UINT16("num-cb", SMMU500State, cfg.num_cb, 16), + DEFINE_PROP_UINT16("num-pages", SMMU500State, cfg.num_pages, 16), + DEFINE_PROP_BOOL("ato", SMMU500State, cfg.ato, true), + DEFINE_PROP_UINT8("version", SMMU500State, cfg.version, 0x21), + DEFINE_PROP_END_OF_LIST(), +}; + +static const VMStateDescription vmstate_smmu500 = { + .name = TYPE_XILINX_SMMU500, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, SMMU500State, SMMU_R_MAX), + VMSTATE_END_OF_LIST(), + } +}; + +static void smmu500_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = smmu500_reset; + dc->realize = smmu500_realize; + dc->vmsd = &vmstate_smmu500; + device_class_set_props(dc, smmu_properties); +} + +static void smmu500_iommu_memory_region_class_init(ObjectClass *klass, + void *data) +{ + IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); + + imrc->translate = smmu_translate; + imrc->attrs_to_index = smmu_attrs_to_index; + imrc->num_indexes = smmu_num_indexes; +} + +static const TypeInfo smmu500_info = { + .name = TYPE_XILINX_SMMU500, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SMMU500State), + .class_init = smmu500_class_init, + .instance_init = smmu500_init, + .instance_finalize = smmu500_finalize, +}; + +static const TypeInfo smmu500_iommu_memory_region_info = { + .name = TYPE_XILINX_SMMU500_IOMMU_MEMORY_REGION, + .parent = TYPE_IOMMU_MEMORY_REGION, + .class_init = smmu500_iommu_memory_region_class_init, +}; + + +static void smmu500_register_types(void) +{ + type_register_static(&smmu500_info); + type_register_static(&smmu500_iommu_memory_region_info); +} + +type_init(smmu500_register_types) diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 53d9704845..4dcde65f35 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -48,6 +48,7 @@ struct VersalVirt { uint32_t usb; uint32_t dwc; uint32_t canfd[2]; + uint32_t smmu; } phandle; struct arm_boot_info binfo; @@ -79,6 +80,7 @@ static void fdt_create(VersalVirt *s) s->phandle.usb = qemu_fdt_alloc_phandle(s->fdt); s->phandle.dwc = qemu_fdt_alloc_phandle(s->fdt); + s->phandle.smmu = qemu_fdt_alloc_phandle(s->fdt); /* Create /chosen node for load_dtb. */ qemu_fdt_add_subnode(s->fdt, "/chosen"); @@ -147,6 +149,23 @@ static void fdt_add_gic_nodes(VersalVirt *s) g_free(nodename); } +static void fdt_add_smmu_nodes(VersalVirt *s) +{ + char *node; + const char compat[] = "arm,smmuv2"; + + node = g_strdup_printf("/smmu@%" PRIx32, MM_FPD_SMMU); + qemu_fdt_add_subnode(s->fdt, node); + qemu_fdt_setprop(s->fdt, node, "compatible", compat, sizeof(compat)); + qemu_fdt_setprop_sized_cells(s->fdt, node, "reg", + 2, MM_FPD_SMMU, + 2, MM_FPD_SMMU_SIZE); + qemu_fdt_setprop_cells(s->fdt, node, "interrupts", + GIC_FDT_IRQ_TYPE_SPI, VERSAL_SMMU_IRQ, GIC_FDT_IRQ_FLAGS_LEVEL_HI); + qemu_fdt_setprop_cell(s->fdt, node, "phandle", s->phandle.smmu); + g_free(node); +} + static void fdt_add_timer_nodes(VersalVirt *s) { const char compat[] = "arm,armv8-timer"; @@ -710,6 +729,7 @@ static void versal_virt_init(MachineState *machine) fdt_add_uart_nodes(s); fdt_add_canfd_nodes(s); fdt_add_gic_nodes(s); + fdt_add_smmu_nodes(s); fdt_add_timer_nodes(s); fdt_add_zdma_nodes(s); fdt_add_usb_xhci_nodes(s); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index c12513264f..003222bebf 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -790,6 +790,22 @@ static void versal_create_crl(Versal *s, qemu_irq *pic) sysbus_connect_irq(sbd, 0, pic[VERSAL_CRL_IRQ]); } +static void versal_create_smmu(Versal *s, qemu_irq *pic) +{ + SysBusDevice *sbd; + MemoryRegion *mr; + + object_initialize_child(OBJECT(s), "mmu-500", &s->fpd.smmu, + TYPE_XILINX_SMMU500); + sbd = SYS_BUS_DEVICE(&s->fpd.smmu); + sysbus_realize(sbd, &error_fatal); + + mr = sysbus_mmio_get_region(sbd, 0); + + memory_region_add_subregion(&s->mr_ps, MM_FPD_SMMU, mr); + sysbus_connect_irq(sbd, 0, pic[VERSAL_SMMU_IRQ]); +} + /* This takes the board allocated linear DDR memory and creates aliases * for each split DDR range/aperture on the Versal address map. */ @@ -919,6 +935,7 @@ static void versal_realize(DeviceState *dev, Error **errp) versal_create_rpu_cpus(s); versal_create_uarts(s, pic); versal_create_canfds(s, pic); + versal_create_smmu(s, pic); versal_create_usbs(s, pic); versal_create_gems(s, pic); versal_create_admas(s, pic); diff --git a/include/hw/arm/smmu500.h b/include/hw/arm/smmu500.h new file mode 100644 index 0000000000..1f775f5b00 --- /dev/null +++ b/include/hw/arm/smmu500.h @@ -0,0 +1,100 @@ +/* + * smmu500.h, ARM MMU-500 SMMU model + * + * Copyright (c) 2024 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Copyright (c) 2014 Xilinx Inc. + * + * Partially autogenerated by xregqemu.py 2014-08-25. + * Written by Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "qom/object.h" + +#define TYPE_XILINX_SMMU500 "arm.mmu-500" +#define TYPE_XILINX_SMMU500_IOMMU_MEMORY_REGION "arm.mmu-500-iommu-memory-region" + +OBJECT_DECLARE_SIMPLE_TYPE(SMMU500State, XILINX_SMMU500) + +/* This should be configurable per instance. */ +#define SMMU_PAGESIZE 4096 + +/* Maximum number of Context Banks supported by this model */ +#define MAX_CB 128 + +/* Maximum number of TBUs supported by this model. */ +#define MAX_TBU 16 + +#define SMMU_R_MAX (2 * MAX_CB * SMMU_PAGESIZE) + +/* Forward declaration */ +struct SMMU500State; + +typedef struct TBU { + SMMU500State *smmu; + IOMMUMemoryRegion iommu; + AddressSpace *as; +} TBU; + +typedef struct SMMU500State { + SysBusDevice parent_obj; + MemoryRegion iomem; + + MemoryRegion *dma_mr; + AddressSpace dma_as; + + TBU tbu[MAX_TBU]; + uint8_t num_tbu; + + struct { + qemu_irq global; + qemu_irq context[MAX_CB]; + } irq; + + struct { + uint32_t pamax; + uint16_t num_smr; + uint16_t num_cb; + uint16_t num_pages; + bool ato; + uint8_t version; + } cfg; + + RegisterAccessInfo *rai_smr; + RegisterAccessInfo *rai_cb; + uint32_t regs[SMMU_R_MAX]; + RegisterInfo regs_info[SMMU_R_MAX]; +} SMMU500State; diff --git a/include/hw/arm/xlnx-versal.h b/include/hw/arm/xlnx-versal.h index 4ff18ad3fa..be6e466a5a 100644 --- a/include/hw/arm/xlnx-versal.h +++ b/include/hw/arm/xlnx-versal.h @@ -18,6 +18,7 @@ #include "hw/sd/sdhci.h" #include "hw/intc/arm_gicv3.h" #include "hw/char/pl011.h" +#include "hw/arm/smmu500.h" #include "hw/dma/xlnx-zdma.h" #include "hw/net/cadence_gem.h" #include "hw/rtc/xlnx-zynqmp-rtc.h" @@ -63,6 +64,8 @@ struct Versal { ARMCPU cpu[XLNX_VERSAL_NR_ACPUS]; GICv3State gic; } apu; + + SMMU500State smmu; } fpd; MemoryRegion mr_ps; @@ -161,10 +164,11 @@ struct Versal { #define VERSAL_PMC_APB_IRQ 121 #define VERSAL_OSPI_IRQ 124 #define VERSAL_SD0_IRQ_0 126 -#define VERSAL_EFUSE_IRQ 139 -#define VERSAL_TRNG_IRQ 141 -#define VERSAL_RTC_ALARM_IRQ 142 -#define VERSAL_RTC_SECONDS_IRQ 143 +#define VERSAL_SMMU_IRQ 139 +#define VERSAL_EFUSE_IRQ 171 +#define VERSAL_TRNG_IRQ 173 +#define VERSAL_RTC_ALARM_IRQ 174 +#define VERSAL_RTC_SECONDS_IRQ 175 /* Architecturally reserved IRQs suitable for virtualization. */ #define VERSAL_RSVD_IRQ_FIRST 111 @@ -231,6 +235,9 @@ struct Versal { #define MM_FPD_FPD_APU 0xfd5c0000 #define MM_FPD_FPD_APU_SIZE 0x100 +#define MM_FPD_SMMU 0xfd800000U +#define MM_FPD_SMMU_SIZE 0x40000 + #define MM_PMC_PMC_IOU_SLCR 0xf1060000 #define MM_PMC_PMC_IOU_SLCR_SIZE 0x10000