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)38 static 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)67 static 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)96 enum 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)101 enum 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)106 enum 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)111 enum smmu_error_t smmu_access_disable(struct smmu_dev_t *dev)
112 {
113     return smmu_cr0_clearbits(dev, SMMU_ROOT_CR0_ACCESSEN);
114 }
115