1 /* 2 * Copyright (c) 2024, Arm Limited. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include "smmu_v3_drv.h" 8 9 #include <stddef.h> 10 #include <stdint.h> 11 12 #include "smmu_v3_memory_map.h" 13 #include "tfm_hal_device_header.h" 14 15 /* Root Control Page (note: contains some 64-bit registers) */ 16 __PACKED_STRUCT _smmu_root_ctrl_page_t { 17 __IM uint32_t idr0; /* 0x000 */ 18 const uint32_t reserved0[1]; 19 __IM uint32_t iidr; /* 0x008 */ 20 const uint32_t reserved1[5]; 21 __IOM uint32_t cr0; /* 0x020 */ 22 __IM uint32_t cr0ack; /* 0x024 */ 23 __IOM uint64_t gpt_base; /* 0x028-0x02C */ 24 __IOM uint64_t gpt_base_cfg; /* 0x030-0x034 */ 25 __IOM uint64_t gpf_far; /* 0x038-0x03C */ 26 __IOM uint64_t gpf_cfg_far; /* 0x040-0x044 */ 27 const uint32_t reserved2[2]; 28 __IOM uint64_t tlbi; /* 0x050-0x054 */ 29 __IOM uint32_t tlbi_ctrl; /* 0x058 */ 30 }; 31 32 #define SMMU_ROOT_CR0_ACCESSEN_POS (0U) 33 #define SMMU_ROOT_CR0_ACCESSEN (0x1UL << SMMU_ROOT_CR0_ACCESSEN_POS) 34 #define SMMU_ROOT_CR0_GPCEN_POS (1U) 35 #define SMMU_ROOT_CR0_GPCEN (0x1UL << SMMU_ROOT_CR0_GPCEN_POS) 36 37 /* Set bits of cr0 register and wait for signal from ack register */ smmu_cr0_setbits(struct smmu_dev_t * dev,uint32_t val)38static enum smmu_error_t smmu_cr0_setbits(struct smmu_dev_t *dev, uint32_t val) 39 { 40 struct _smmu_root_ctrl_page_t *root_page; 41 uint64_t timeout_counter; 42 uint32_t write_val; 43 44 if (dev == NULL || dev->smmu_base == NULL) { 45 return SMMU_ERR_INVALID_PARAM; 46 } 47 48 /* Get the root control registers page on TCU */ 49 root_page = (struct _smmu_root_ctrl_page_t *)(dev->smmu_base + 50 SMMU_TCU_BASE + SMMU_ROOT_CONTROL_REGISTERS_PAGE_BASE); 51 52 write_val = root_page->cr0 | val; 53 root_page->cr0 = write_val; 54 55 /* Update is not immediate so wait for SMMU to acknowledge change */ 56 timeout_counter = 0; 57 while (root_page->cr0ack != write_val) { 58 if (timeout_counter++ > dev->ack_timeout) { 59 return SMMU_ERR_TIMEOUT; 60 } 61 } 62 63 return SMMU_ERR_NONE; 64 } 65 66 /* Clear bits of cr0 register and wait for signal from ack register */ smmu_cr0_clearbits(struct smmu_dev_t * dev,uint32_t val)67static enum smmu_error_t smmu_cr0_clearbits(struct smmu_dev_t *dev, 68 uint32_t val) 69 { 70 struct _smmu_root_ctrl_page_t *root_page; 71 uint64_t timeout_counter; 72 uint32_t write_val; 73 74 if (dev == NULL || dev->smmu_base == NULL) { 75 return SMMU_ERR_INVALID_PARAM; 76 } 77 78 /* Get the root control registers page on TCU */ 79 root_page = (struct _smmu_root_ctrl_page_t *)(dev->smmu_base + 80 SMMU_TCU_BASE + SMMU_ROOT_CONTROL_REGISTERS_PAGE_BASE); 81 82 write_val = root_page->cr0 & ~val; 83 root_page->cr0 = write_val; 84 85 /* Update is not immediate so wait for SMMU to acknowledge change */ 86 timeout_counter = 0; 87 while (root_page->cr0ack != write_val) { 88 if (timeout_counter++ > dev->ack_timeout) { 89 return SMMU_ERR_TIMEOUT; 90 } 91 } 92 93 return SMMU_ERR_NONE; 94 } 95 smmu_gpc_enable(struct smmu_dev_t * dev)96enum smmu_error_t smmu_gpc_enable(struct smmu_dev_t *dev) 97 { 98 return smmu_cr0_setbits(dev, SMMU_ROOT_CR0_GPCEN); 99 } 100 smmu_gpc_disable(struct smmu_dev_t * dev)101enum smmu_error_t smmu_gpc_disable(struct smmu_dev_t *dev) 102 { 103 return smmu_cr0_clearbits(dev, SMMU_ROOT_CR0_GPCEN); 104 } 105 smmu_access_enable(struct smmu_dev_t * dev)106enum smmu_error_t smmu_access_enable(struct smmu_dev_t *dev) 107 { 108 return smmu_cr0_setbits(dev, SMMU_ROOT_CR0_ACCESSEN); 109 } 110 smmu_access_disable(struct smmu_dev_t * dev)111enum smmu_error_t smmu_access_disable(struct smmu_dev_t *dev) 112 { 113 return smmu_cr0_clearbits(dev, SMMU_ROOT_CR0_ACCESSEN); 114 } 115