blob: 67a23fbeaaeeb2bc08bb5407f6c4216cf9b9d84d [file] [log] [blame]
/*
* ARM SMMUv3 support - Common API
*
* Copyright (C) 2014-2016 Broadcom Corporation
* Copyright (c) 2017 Red Hat, Inc.
* Written by Prem Mallappa, Eric Auger
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef HW_ARM_SMMUV3_COMMON_H
#define HW_ARM_SMMUV3_COMMON_H
#include "hw/core/registerfields.h"
/* Configuration Data */
/* STE Level 1 Descriptor */
typedef struct STEDesc {
uint32_t word[2];
} STEDesc;
/* CD Level 1 Descriptor */
typedef struct CDDesc {
uint32_t word[2];
} CDDesc;
/* Stream Table Entry(STE) */
typedef struct STE {
uint32_t word[16];
} STE;
/* Context Descriptor(CD) */
typedef struct CD {
uint32_t word[16];
} CD;
/* STE fields */
REG32(STE_0, 0)
FIELD(STE_0, VALID, 0, 1)
FIELD(STE_0, CONFIG, 1, 3)
FIELD(STE_0, S1FMT, 4, 2)
FIELD(STE_0, CTXPTR_LO, 6, 26)
REG32(STE_1, 4)
FIELD(STE_1, CTXPTR_HI, 0, 24)
FIELD(STE_1, S1CDMAX, 27, 5)
REG32(STE_2, 8)
FIELD(STE_2, S1STALLD, 27, 1)
FIELD(STE_2, EATS, 28, 2)
FIELD(STE_2, STRW, 30, 2)
REG32(STE_4, 16)
FIELD(STE_4, S2VMID, 0, 16)
REG32(STE_5, 20)
FIELD(STE_5, S2T0SZ, 0, 6)
FIELD(STE_5, S2SL0, 6, 2)
FIELD(STE_5, S2TG, 14, 2)
FIELD(STE_5, S2PS, 16, 3)
FIELD(STE_5, S2AA64, 19, 1)
FIELD(STE_5, S2ENDI, 20, 1)
FIELD(STE_5, S2AFFD, 21, 1)
FIELD(STE_5, S2HD, 23, 1)
FIELD(STE_5, S2HA, 24, 1)
FIELD(STE_5, S2S, 25, 1)
FIELD(STE_5, S2R, 26, 1)
REG32(STE_6, 24)
FIELD(STE_6, S2TTB_LO, 4, 28)
REG32(STE_7, 28)
FIELD(STE_7, S2TTB_HI, 0, 20)
/* Get STE fields */
#define STE_VALID(x) FIELD_EX32((x)->word[0], STE_0, VALID)
#define STE_CONFIG(x) FIELD_EX32((x)->word[0], STE_0, CONFIG)
#define STE_S1FMT(x) FIELD_EX32((x)->word[0], STE_0, S1FMT)
#define STE_CTXPTR(x) \
(((uint64_t)FIELD_EX32((x)->word[0], STE_0, CTXPTR_LO) << 6) | \
((uint64_t)FIELD_EX32((x)->word[1], STE_1, CTXPTR_HI) << 32))
#define STE_S1CDMAX(x) FIELD_EX32((x)->word[1], STE_1, S1CDMAX)
#define STE_S1STALLD(x) FIELD_EX32((x)->word[2], STE_2, S1STALLD)
#define STE_EATS(x) FIELD_EX32((x)->word[2], STE_2, EATS)
#define STE_STRW(x) FIELD_EX32((x)->word[2], STE_2, STRW)
#define STE_S2VMID(x) FIELD_EX32((x)->word[4], STE_4, S2VMID)
#define STE_S2T0SZ(x) FIELD_EX32((x)->word[5], STE_5, S2T0SZ)
#define STE_S2SL0(x) FIELD_EX32((x)->word[5], STE_5, S2SL0)
#define STE_S2TG(x) FIELD_EX32((x)->word[5], STE_5, S2TG)
#define STE_S2PS(x) FIELD_EX32((x)->word[5], STE_5, S2PS)
#define STE_S2AA64(x) FIELD_EX32((x)->word[5], STE_5, S2AA64)
#define STE_S2ENDI(x) FIELD_EX32((x)->word[5], STE_5, S2ENDI)
#define STE_S2AFFD(x) FIELD_EX32((x)->word[5], STE_5, S2AFFD)
#define STE_S2HD(x) FIELD_EX32((x)->word[5], STE_5, S2HD)
#define STE_S2HA(x) FIELD_EX32((x)->word[5], STE_5, S2HA)
#define STE_S2S(x) FIELD_EX32((x)->word[5], STE_5, S2S)
#define STE_S2R(x) FIELD_EX32((x)->word[5], STE_5, S2R)
#define STE_S2TTB(x) \
(((uint64_t)FIELD_EX32((x)->word[6], STE_6, S2TTB_LO) << 4) | \
((uint64_t)FIELD_EX32((x)->word[7], STE_7, S2TTB_HI) << 32))
#define STE_CFG_S1_ENABLED(config) (config & 0x1)
#define STE_CFG_S2_ENABLED(config) (config & 0x2)
#define STE_CFG_ABORT(config) (!(config & 0x4))
#define STE_CFG_BYPASS(config) (config == 0x4)
#define STE_CFG_S1_TRANSLATE(config) (config == 0x5)
#define SMMU_STE_VALID (1ULL << 0)
#define SMMU_STE_CFG_BYPASS (1ULL << 3)
#define STE0_V MAKE_64BIT_MASK(0, 1)
#define STE0_CONFIG MAKE_64BIT_MASK(1, 3)
#define STE0_S1FMT MAKE_64BIT_MASK(4, 2)
#define STE0_CTXPTR MAKE_64BIT_MASK(6, 50)
#define STE0_S1CDMAX MAKE_64BIT_MASK(59, 5)
#define STE0_MASK (STE0_S1CDMAX | STE0_CTXPTR | STE0_S1FMT | STE0_CONFIG | \
STE0_V)
#define STE1_S1DSS MAKE_64BIT_MASK(0, 2)
#define STE1_S1CIR MAKE_64BIT_MASK(2, 2)
#define STE1_S1COR MAKE_64BIT_MASK(4, 2)
#define STE1_S1CSH MAKE_64BIT_MASK(6, 2)
#define STE1_S1STALLD MAKE_64BIT_MASK(27, 1)
#define STE1_EATS MAKE_64BIT_MASK(28, 2)
#define STE1_MASK (STE1_EATS | STE1_S1STALLD | STE1_S1CSH | STE1_S1COR | \
STE1_S1CIR | STE1_S1DSS)
/* Update STE fields */
#define STE_SET_VALID(ste, v) \
((ste)->word[0] = FIELD_DP32((ste)->word[0], STE_0, VALID, (v)))
#define STE_SET_CONFIG(ste, v) \
((ste)->word[0] = FIELD_DP32((ste)->word[0], STE_0, CONFIG, (v)))
#define STE_SET_CTXPTR(ste, v) do { \
(ste)->word[0] = FIELD_DP32((ste)->word[0], STE_0, CTXPTR_LO, (v) >> 6); \
(ste)->word[1] = FIELD_DP32((ste)->word[1], STE_1, CTXPTR_HI, (v) >> 32); \
} while (0)
#define STE_SET_S2T0SZ(ste, v) \
((ste)->word[5] = FIELD_DP32((ste)->word[5], STE_5, S2T0SZ, (v)))
#define STE_SET_S2SL0(ste, v) \
((ste)->word[5] = FIELD_DP32((ste)->word[5], STE_5, S2SL0, (v)))
#define STE_SET_S2TG(ste, v) \
((ste)->word[5] = FIELD_DP32((ste)->word[5], STE_5, S2TG, (v)))
#define STE_SET_S2PS(ste, v) \
((ste)->word[5] = FIELD_DP32((ste)->word[5], STE_5, S2PS, (v)))
#define STE_SET_S2AA64(ste, v) \
((ste)->word[5] = FIELD_DP32((ste)->word[5], STE_5, S2AA64, (v)))
#define STE_SET_S2ENDI(ste, v) \
((ste)->word[5] = FIELD_DP32((ste)->word[5], STE_5, S2ENDI, (v)))
#define STE_SET_S2AFFD(ste, v) \
((ste)->word[5] = FIELD_DP32((ste)->word[5], STE_5, S2AFFD, (v)))
#define STE_SET_S2S(ste, v) \
((ste)->word[5] = FIELD_DP32((ste)->word[5], STE_5, S2S, (v)))
#define STE_SET_S2TTB(ste, v) do { \
(ste)->word[6] = FIELD_DP32((ste)->word[6], STE_6, S2TTB_LO, (v) >> 4); \
(ste)->word[7] = FIELD_DP32((ste)->word[7], STE_7, S2TTB_HI, (v) >> 32); \
} while (0)
/* CD fields */
REG32(CD_0, 0)
FIELD(CD_0, TSZ0, 0, 6)
FIELD(CD_0, TG0, 6, 2)
FIELD(CD_0, EPD0, 14, 1)
FIELD(CD_0, ENDI, 15, 1)
FIELD(CD_0, TSZ1, 16, 6)
FIELD(CD_0, TG1, 22, 2)
FIELD(CD_0, EPD1, 30, 1)
FIELD(CD_0, VALID, 31, 1)
REG32(CD_1, 4)
FIELD(CD_1, IPS, 0, 3)
FIELD(CD_1, AFFD, 3, 1)
FIELD(CD_1, TBI, 6, 2)
FIELD(CD_1, AARCH64, 9, 1)
FIELD(CD_1, HD, 10, 1)
FIELD(CD_1, HA, 11, 1)
FIELD(CD_1, S, 12, 1)
FIELD(CD_1, R, 13, 1)
FIELD(CD_1, A, 14, 1)
FIELD(CD_1, ASID, 16, 16)
REG32(CD_2, 8)
FIELD(CD_2, NSCFG0, 0, 1)
FIELD(CD_2, HAD0, 1, 1)
FIELD(CD_2, TTB0_LO, 4, 28)
REG32(CD_3, 12)
FIELD(CD_3, TTB0_HI, 0, 20)
REG32(CD_4, 16)
FIELD(CD_4, NSCFG1, 0, 1)
FIELD(CD_4, HAD1, 1, 1)
FIELD(CD_4, TTB1_LO, 4, 28)
REG32(CD_5, 20)
FIELD(CD_5, TTB1_HI, 0, 20)
/* Get CD fields */
#define CD_TSZ(x, sel) ((sel) ? \
FIELD_EX32((x)->word[0], CD_0, TSZ1) : \
FIELD_EX32((x)->word[0], CD_0, TSZ0))
#define CD_TG(x, sel) ((sel) ? \
FIELD_EX32((x)->word[0], CD_0, TG1) : \
FIELD_EX32((x)->word[0], CD_0, TG0))
#define CD_EPD(x, sel) ((sel) ? \
FIELD_EX32((x)->word[0], CD_0, EPD1) : \
FIELD_EX32((x)->word[0], CD_0, EPD0))
#define CD_ENDI(x) FIELD_EX32((x)->word[0], CD_0, ENDI)
#define CD_VALID(x) FIELD_EX32((x)->word[0], CD_0, VALID)
#define CD_IPS(x) FIELD_EX32((x)->word[1], CD_1, IPS)
#define CD_AFFD(x) FIELD_EX32((x)->word[1], CD_1, AFFD)
#define CD_TBI(x) FIELD_EX32((x)->word[1], CD_1, TBI)
#define CD_AARCH64(x) FIELD_EX32((x)->word[1], CD_1, AARCH64)
#define CD_HD(x) FIELD_EX32((x)->word[1], CD_1, HD)
#define CD_HA(x) FIELD_EX32((x)->word[1], CD_1, HA)
#define CD_S(x) FIELD_EX32((x)->word[1], CD_1, S)
#define CD_R(x) FIELD_EX32((x)->word[1], CD_1, R)
#define CD_A(x) FIELD_EX32((x)->word[1], CD_1, A)
#define CD_ASID(x) FIELD_EX32((x)->word[1], CD_1, ASID)
#define CD_NSCFG(x, sel) ((sel) ? \
FIELD_EX32((x)->word[4], CD_4, NSCFG1) : \
FIELD_EX32((x)->word[2], CD_2, NSCFG0))
#define CD_HAD(x, sel) ((sel) ? \
FIELD_EX32((x)->word[4], CD_4, HAD1) : \
FIELD_EX32((x)->word[2], CD_2, HAD0))
#define CD_TTB(x, sel) \
((sel) ? (((uint64_t)FIELD_EX32((x)->word[5], CD_5, TTB1_HI) << 32) | \
((uint64_t)FIELD_EX32((x)->word[4], CD_4, TTB1_LO) << 4)) : \
(((uint64_t)FIELD_EX32((x)->word[3], CD_3, TTB0_HI) << 32) | \
((uint64_t)FIELD_EX32((x)->word[2], CD_2, TTB0_LO) << 4)))
/* Update CD fields */
#define CD_SET_VALID(cd, v) \
((cd)->word[0] = FIELD_DP32((cd)->word[0], CD_0, VALID, (v)))
#define CD_SET_ASID(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, ASID, (v)))
#define CD_SET_TTB(cd, sel, v) do { \
if (sel) { \
(cd)->word[4] = FIELD_DP32((cd)->word[4], CD_4, TTB1_LO, (v) >> 4); \
(cd)->word[5] = FIELD_DP32((cd)->word[5], CD_5, TTB1_HI, (v) >> 32); \
} else { \
(cd)->word[2] = FIELD_DP32((cd)->word[2], CD_2, TTB0_LO, (v) >> 4); \
(cd)->word[3] = FIELD_DP32((cd)->word[3], CD_3, TTB0_HI, (v) >> 32); \
} \
} while (0)
#define CD_SET_TSZ(cd, sel, v) \
((cd)->word[0] = (sel) ? FIELD_DP32((cd)->word[0], CD_0, TSZ1, (v)) : \
FIELD_DP32((cd)->word[0], CD_0, TSZ0, (v)))
#define CD_SET_TG(cd, sel, v) \
((cd)->word[0] = (sel) ? FIELD_DP32((cd)->word[0], CD_0, TG1, (v)) : \
FIELD_DP32((cd)->word[0], CD_0, TG0, (v)))
#define CD_SET_EPD(cd, sel, v) \
((cd)->word[0] = (sel) ? FIELD_DP32((cd)->word[0], CD_0, EPD1, (v)) : \
FIELD_DP32((cd)->word[0], CD_0, EPD0, (v)))
#define CD_SET_ENDI(cd, v) \
((cd)->word[0] = FIELD_DP32((cd)->word[0], CD_0, ENDI, (v)))
#define CD_SET_IPS(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, IPS, (v)))
#define CD_SET_AFFD(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, AFFD, (v)))
#define CD_SET_TBI(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, TBI, (v)))
#define CD_SET_HD(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, HD, (v)))
#define CD_SET_HA(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, HA, (v)))
#define CD_SET_S(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, S, (v)))
#define CD_SET_R(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, R, (v)))
#define CD_SET_A(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, A, (v)))
#define CD_SET_AARCH64(cd, v) \
((cd)->word[1] = FIELD_DP32((cd)->word[1], CD_1, AARCH64, (v)))
#define CD_SET_NSCFG(cd, sel, v) \
((sel) ? ((cd)->word[4] = FIELD_DP32((cd)->word[4], CD_4, NSCFG1, (v))) : \
((cd)->word[2] = FIELD_DP32((cd)->word[2], CD_2, NSCFG0, (v))))
/* MMIO Registers */
REG32(IDR0, 0x0)
FIELD(IDR0, S2P, 0 , 1)
FIELD(IDR0, S1P, 1 , 1)
FIELD(IDR0, TTF, 2 , 2)
FIELD(IDR0, COHACC, 4 , 1)
FIELD(IDR0, BTM, 5 , 1)
FIELD(IDR0, HTTU, 6 , 2)
FIELD(IDR0, DORMHINT, 8 , 1)
FIELD(IDR0, HYP, 9 , 1)
FIELD(IDR0, ATS, 10, 1)
FIELD(IDR0, NS1ATS, 11, 1)
FIELD(IDR0, ASID16, 12, 1)
FIELD(IDR0, MSI, 13, 1)
FIELD(IDR0, SEV, 14, 1)
FIELD(IDR0, ATOS, 15, 1)
FIELD(IDR0, PRI, 16, 1)
FIELD(IDR0, VMW, 17, 1)
FIELD(IDR0, VMID16, 18, 1)
FIELD(IDR0, CD2L, 19, 1)
FIELD(IDR0, VATOS, 20, 1)
FIELD(IDR0, TTENDIAN, 21, 2)
FIELD(IDR0, ATSRECERR, 23, 1)
FIELD(IDR0, STALL_MODEL, 24, 2)
FIELD(IDR0, TERM_MODEL, 26, 1)
FIELD(IDR0, STLEVEL, 27, 2)
FIELD(IDR0, RME_IMPL, 30, 1)
REG32(IDR1, 0x4)
FIELD(IDR1, SIDSIZE, 0 , 6)
FIELD(IDR1, SSIDSIZE, 6 , 5)
FIELD(IDR1, PRIQS, 11, 5)
FIELD(IDR1, EVENTQS, 16, 5)
FIELD(IDR1, CMDQS, 21, 5)
FIELD(IDR1, ATTR_PERMS_OVR, 26, 1)
FIELD(IDR1, ATTR_TYPES_OVR, 27, 1)
FIELD(IDR1, REL, 28, 1)
FIELD(IDR1, QUEUES_PRESET, 29, 1)
FIELD(IDR1, TABLES_PRESET, 30, 1)
FIELD(IDR1, ECMDQ, 31, 1)
#define SMMU_SSID_MAX_BITS 20
#define SMMU_IDR1_SIDSIZE 16
#define SMMU_CMDQS 19
#define SMMU_EVENTQS 19
REG32(IDR2, 0x8)
FIELD(IDR2, BA_VATOS, 0, 10)
REG32(IDR3, 0xc)
FIELD(IDR3, HAD, 2, 1);
FIELD(IDR3, PBHA, 3, 1);
FIELD(IDR3, XNX, 4, 1);
FIELD(IDR3, PPS, 5, 1);
FIELD(IDR3, MPAM, 7, 1);
FIELD(IDR3, FWB, 8, 1);
FIELD(IDR3, STT, 9, 1);
FIELD(IDR3, RIL, 10, 1);
FIELD(IDR3, BBML, 11, 2);
FIELD(IDR3, E0PD, 13, 1);
FIELD(IDR3, PTWNNC, 14, 1);
FIELD(IDR3, DPT, 15, 1);
REG32(IDR4, 0x10)
REG32(IDR5, 0x14)
FIELD(IDR5, OAS, 0, 3);
FIELD(IDR5, GRAN4K, 4, 1);
FIELD(IDR5, GRAN16K, 5, 1);
FIELD(IDR5, GRAN64K, 6, 1);
FIELD(IDR5, VAX, 10, 2);
FIELD(IDR5, STALL_MAX, 16, 16);
#define SMMU_OAS_44BIT 44
#define SMMU_OAS_48BIT 48
#define SMMU_IDR5_OAS_44 4
#define SMMU_IDR5_OAS_48 5
REG32(IIDR, 0x18)
REG32(AIDR, 0x1c)
REG32(CR0, 0x20)
FIELD(CR0, SMMU_ENABLE, 0, 1)
FIELD(CR0, EVENTQEN, 2, 1)
FIELD(CR0, CMDQEN, 3, 1)
#define SMMU_CR0_RESERVED 0xFFFFFC20
REG32(CR0ACK, 0x24)
REG32(CR1, 0x28)
REG32(CR2, 0x2c)
REG32(STATUSR, 0x40)
REG32(GBPA, 0x44)
FIELD(GBPA, ABORT, 20, 1)
FIELD(GBPA, UPDATE, 31, 1)
/* Use incoming. */
#define SMMU_GBPA_RESET_VAL 0x1000
REG32(IRQ_CTRL, 0x50)
FIELD(IRQ_CTRL, GERROR_IRQEN, 0, 1)
FIELD(IRQ_CTRL, PRI_IRQEN, 1, 1)
FIELD(IRQ_CTRL, EVENTQ_IRQEN, 2, 1)
REG32(IRQ_CTRL_ACK, 0x54)
REG32(GERROR, 0x60)
FIELD(GERROR, CMDQ_ERR, 0, 1)
FIELD(GERROR, EVENTQ_ABT_ERR, 2, 1)
FIELD(GERROR, PRIQ_ABT_ERR, 3, 1)
FIELD(GERROR, MSI_CMDQ_ABT_ERR, 4, 1)
FIELD(GERROR, MSI_EVENTQ_ABT_ERR, 5, 1)
FIELD(GERROR, MSI_PRIQ_ABT_ERR, 6, 1)
FIELD(GERROR, MSI_GERROR_ABT_ERR, 7, 1)
FIELD(GERROR, MSI_SFM_ERR, 8, 1)
REG32(GERRORN, 0x64)
#define A_GERROR_IRQ_CFG0 0x68 /* 64b */
REG32(GERROR_IRQ_CFG1, 0x70)
REG32(GERROR_IRQ_CFG2, 0x74)
#define A_STRTAB_BASE 0x80 /* 64b */
#define SMMU_BASE_ADDR_MASK 0xfffffffffffc0
REG32(STRTAB_BASE_CFG, 0x88)
FIELD(STRTAB_BASE_CFG, FMT, 16, 2)
FIELD(STRTAB_BASE_CFG, SPLIT, 6 , 5)
FIELD(STRTAB_BASE_CFG, LOG2SIZE, 0 , 6)
#define A_CMDQ_BASE 0x90 /* 64b */
REG32(CMDQ_PROD, 0x98)
REG32(CMDQ_CONS, 0x9c)
FIELD(CMDQ_CONS, ERR, 24, 7)
#define A_EVENTQ_BASE 0xa0 /* 64b */
REG32(EVENTQ_PROD, 0xa8)
REG32(EVENTQ_CONS, 0xac)
#define A_EVENTQ_IRQ_CFG0 0xb0 /* 64b */
REG32(EVENTQ_IRQ_CFG1, 0xb8)
REG32(EVENTQ_IRQ_CFG2, 0xbc)
#define A_IDREGS 0xfd0
/* Commands */
typedef enum SMMUCommandType {
SMMU_CMD_NONE = 0x00,
SMMU_CMD_PREFETCH_CONFIG ,
SMMU_CMD_PREFETCH_ADDR,
SMMU_CMD_CFGI_STE,
SMMU_CMD_CFGI_STE_RANGE,
SMMU_CMD_CFGI_CD,
SMMU_CMD_CFGI_CD_ALL,
SMMU_CMD_CFGI_ALL,
SMMU_CMD_TLBI_NH_ALL = 0x10,
SMMU_CMD_TLBI_NH_ASID,
SMMU_CMD_TLBI_NH_VA,
SMMU_CMD_TLBI_NH_VAA,
SMMU_CMD_TLBI_EL3_ALL = 0x18,
SMMU_CMD_TLBI_EL3_VA = 0x1a,
SMMU_CMD_TLBI_EL2_ALL = 0x20,
SMMU_CMD_TLBI_EL2_ASID,
SMMU_CMD_TLBI_EL2_VA,
SMMU_CMD_TLBI_EL2_VAA,
SMMU_CMD_TLBI_S12_VMALL = 0x28,
SMMU_CMD_TLBI_S2_IPA = 0x2a,
SMMU_CMD_TLBI_NSNH_ALL = 0x30,
SMMU_CMD_ATC_INV = 0x40,
SMMU_CMD_PRI_RESP,
SMMU_CMD_RESUME = 0x44,
SMMU_CMD_STALL_TERM,
SMMU_CMD_SYNC,
} SMMUCommandType;
#endif /* HW_ARM_SMMUV3_COMMON_H */