
Add functions for checking SMMU bypass status and matching valid hardware device Stream ID in SMMU Stream Mapping Registers.
Signed-off-by: Chee Hong Ang chee.hong.ang@intel.com Signed-off-by: Jit Loon Lim jit.loon.lim@intel.com --- arch/arm/mach-socfpga/include/mach/smmu_s10.h | 65 ++++++++++ arch/arm/mach-socfpga/smmu_s10.c | 118 ++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 arch/arm/mach-socfpga/include/mach/smmu_s10.h create mode 100644 arch/arm/mach-socfpga/smmu_s10.c
diff --git a/arch/arm/mach-socfpga/include/mach/smmu_s10.h b/arch/arm/mach-socfpga/include/mach/smmu_s10.h new file mode 100644 index 0000000000..dfcc99f82a --- /dev/null +++ b/arch/arm/mach-socfpga/include/mach/smmu_s10.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved + * + * SPDX-License-Identifier: GPL-2.0 + */ + +/* SMMU registers */ +#define SMMU_SCR0 0 +#define SMMU_SIDR0 0x20 +#define SMMU_SIDR1 0x24 + +#define SMMU_SCR0_CLIENTPD BIT(0) +#define SMMU_SIDR0_NUMSMRG_MASK GENMASK(7, 0) +#define SMMU_SIDR1_NUMCB_MASK GENMASK(7, 0) + +/* Stream mapping registers */ +#define SMMU_GR0_SMR(n) (0x800 + ((n) << 2)) +#define SMMU_SMR_VALID BIT(31) +#define SMMU_SMR_MASK GENMASK(30, 16) +#define SMMU_SMR_ID GENMASK(14, 0) + +#define SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) +#define SMMU_S2CR_TYPE GENMASK(17, 16) +#define SMMU_S2CR_CBNDX GENMASK(7, 0) + +/* Register groups for Context Bank */ +#define SMMU_GR0_CB(n, r) (0x20000 + ((n) << 12) + ((r) << 2)) +#define SMMU_CB_SCTLR 0 +#define SMMU_CB_SCTLR_M BIT(0) + +#define SMMU_SID_SDM2HPS_PSI_BE 0 + +void socfpga_init_smmu(void); +int is_smmu_bypass(void); +int is_smmu_stream_id_enabled(u32 stream_id); + +#define SMMU_SET_STREAMID(x, r, w) ((x << r) | (x << w)) + +#define SYSMGR_EMAC0_SID_ADDR 0xffd12050 /* EMAC0 (emac0_ace) */ +#define SYSMGR_EMAC1_SID_ADDR 0xffd12054 /* EMAC0 (emac1_ace) */ +#define SYSMGR_EMAC2_SID_ADDR 0xffd12058 /* EMAC0 (emac2_ace) */ +#define SYSMGR_NAND_SID_ADDR 0xffd1205c /* NAND (nand_axuser) */ +#define SYSMGR_SDMMC_SID_ADDR 0xffd1202c /* SDMMC (sdmmcgrp_l3master) */ +#define SYSMGR_USB0_SID_ADDR 0xffd12038 /* USB0 (usb0_l3master) */ +#define SYSMGR_USB1_SID_ADDR 0xffd1203c /* USB0 (usb1_l3master) */ +#define SYSMGR_DMA_SID_ADDR 0xffd12074 /* DMA (dma_l3master) */ +#define SYSMGR_ETR_SID_ADDR 0xffd12078 /* ETR (etr_l3master) */ +/* Stream ID field offsets */ +#define EMAC_W_OFST 20 +#define EMAC_R_OFST 8 +#define NAND_W_OFST 0 +#define NAND_R_OFST 16 +#define SDMMC_OFST 16 +#define USB_OFST 16 +#define DMA_W_OFST 0 +#define DMA_R_OFST 16 +#define ETR_W_OFST 0 +#define ETR_R_OFST 16 +struct smmu_stream_id { + unsigned long addr; + u32 sid; + u32 r_bit_ofst; + u32 w_bit_ofst; + u32 secure_bit_offset; +}; \ No newline at end of file diff --git a/arch/arm/mach-socfpga/smmu_s10.c b/arch/arm/mach-socfpga/smmu_s10.c new file mode 100644 index 0000000000..d6ab39755d --- /dev/null +++ b/arch/arm/mach-socfpga/smmu_s10.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/firewall.h> +#include <asm/arch/smmu_s10.h> +#include <asm/arch/system_manager.h> +DECLARE_GLOBAL_DATA_PTR; +static const struct smmu_stream_id dev_stream_id[] = { + {SYSMGR_EMAC0_SID_ADDR, 0x01, EMAC_W_OFST, EMAC_R_OFST}, + {SYSMGR_EMAC1_SID_ADDR, 0x02, EMAC_W_OFST, EMAC_R_OFST}, + {SYSMGR_EMAC2_SID_ADDR, 0x03, EMAC_W_OFST, EMAC_R_OFST}, + {SYSMGR_NAND_SID_ADDR, 0x04, NAND_W_OFST, NAND_R_OFST}, + {SYSMGR_SDMMC_SID_ADDR, 0x05, SDMMC_OFST, SDMMC_OFST}, + {SYSMGR_USB0_SID_ADDR, 0x06, USB_OFST, USB_OFST}, + {SYSMGR_USB1_SID_ADDR, 0x07, USB_OFST, USB_OFST}, + {SYSMGR_DMA_SID_ADDR, 0x08, DMA_W_OFST, DMA_R_OFST}, + {SYSMGR_ETR_SID_ADDR, 0x09, ETR_W_OFST, ETR_R_OFST}, +}; +static void set_smmu_streamid(void) +{ + int i; + for (i = 0; i < ARRAY_SIZE(dev_stream_id); i++) { + u32 mask = SMMU_SET_STREAMID(0x3FF, + dev_stream_id[i].r_bit_ofst, + dev_stream_id[i].w_bit_ofst); + u32 value = SMMU_SET_STREAMID(dev_stream_id[i].sid, + dev_stream_id[i].r_bit_ofst, + dev_stream_id[i].w_bit_ofst); + clrbits_le32(dev_stream_id[i].addr, mask); + setbits_le32(dev_stream_id[i].addr, value); + } +} +/* + * Need to set the Secure bit (to make it non-secure) on each peripheral + * so that SMMU can access the peripheral + */ +static void set_smmu_accessible_reg(void) +{ + setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_EMAC0, + BIT(27) | BIT(25)); + setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_EMAC1, + BIT(27) | BIT(25)); + setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_EMAC2, + BIT(27) | BIT(25)); + setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_NANDGRP_L3MASTER, + BIT(21) | BIT(17)); + setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_SDMMC_L3MASTER, + BIT(5)); + setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_USB0_L3MASTER, + BIT(9)); + setbits_le32(socfpga_get_sysmgr_addr() + SYSMGR_SOC64_USB1_L3MASTER, + BIT(9)); +} +static inline void setup_smmu_firewall(void) +{ + /* Enable nonsecure SMMU accesses */ + writel(FIREWALL_L4_DISABLE_ALL, SOCFPGA_FIREWALL_TCU); +} +void socfpga_init_smmu(void) +{ + setup_smmu_firewall(); + set_smmu_streamid(); + set_smmu_accessible_reg(); +} + +int is_smmu_bypass(void) +{ + return readl(SOCFPGA_SMMU_ADDRESS + SMMU_SCR0) & SMMU_SCR0_CLIENTPD; +} + +int is_smmu_stream_id_enabled(u32 stream_id) +{ + int i; + u32 smrg_num; + u32 smr, s2cr, sid_mask; + u32 cb, cb_index, cb_num; + + if (is_smmu_bypass()) + return 0; + + /* Get number of Stream Mapping Register Groups */ + smrg_num = readl(SOCFPGA_SMMU_ADDRESS + SMMU_SIDR0) & + SMMU_SIDR0_NUMSMRG_MASK; + + /* Get number of Context Bank */ + cb_num = readl(SOCFPGA_SMMU_ADDRESS + SMMU_SIDR1) & + SMMU_SIDR1_NUMCB_MASK; + + for (i = 0; i < smrg_num; i++) { + smr = readl(SOCFPGA_SMMU_ADDRESS + SMMU_GR0_SMR((u64)i)); + sid_mask = (smr & SMMU_SMR_MASK) >> 16; + + /* Skip if Stream ID is invalid or not matched */ + if (!(smr & SMMU_SMR_VALID) || (smr & sid_mask) != stream_id) + continue; + + /* Get Context Bank index from valid matching Stream ID */ + s2cr = readl(SOCFPGA_SMMU_ADDRESS + SMMU_GR0_S2CR((u64)i)); + cb_index = s2cr & SMMU_S2CR_CBNDX; + + /* Skip if Context Bank is invalid or not Translation mode */ + if (cb_index >= cb_num || (s2cr & SMMU_S2CR_TYPE)) + continue; + + cb = readl(SOCFPGA_SMMU_ADDRESS + SMMU_GR0_CB((u64)cb_index, + SMMU_CB_SCTLR)); + /* Return MMU enable status for this Context Bank */ + return (cb & SMMU_CB_SCTLR_M); + } + + return 0; +} \ No newline at end of file