1 /*
2 * Copyright (c) 2023-2024, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "discovery/ni_tower_discovery_drv.h"
9 #include "ni_tower_psam_drv.h"
10 #include "ni_tower_psam_reg.h"
11 #include "util/ni_tower_util.h"
12
13 #include <stddef.h>
14
15 #define NI_TOWER_PSAM_ADDRESS_GRAN (1ULL << 12)
16 #define NI_TOWER_PSAM_ADDRESS_MASK (~(NI_TOWER_PSAM_ADDRESS_GRAN - 1))
17 #define NI_TOWER_PSAM_ADDRESS_H(addr) ((addr) >> 32)
18 #define NI_TOWER_PSAM_ADDRESS_L(addr) ((addr) & NI_TOWER_PSAM_ADDRESS_MASK)
19
20 #define NI_TOWER_PSAM_GET64_BASE_ADDRESS(addr, high, low) \
21 addr = (((uint64_t)(high) << 32) | (low)) & NI_TOWER_PSAM_ADDRESS_MASK
22
23 #define NI_TOWER_PSAM_GET64_END_ADDRESS(addr, high, low) \
24 addr = (((uint64_t)(high) << 32) | (low)) | \
25 (NI_TOWER_PSAM_ADDRESS_GRAN - 1)
26
ni_tower_psam_dev_init(const struct ni_tower_dev * ni_tower_dev,const struct ni_tower_component_node * component,const uint64_t region_mapping_offset,struct ni_tower_psam_dev * dev)27 enum ni_tower_err ni_tower_psam_dev_init(
28 const struct ni_tower_dev *ni_tower_dev,
29 const struct ni_tower_component_node* component,
30 const uint64_t region_mapping_offset,
31 struct ni_tower_psam_dev *dev)
32 {
33 enum ni_tower_err err;
34 uint32_t off_addr;
35 struct ni_tower_discovery_node root = {
36 .node_type = NI_TOWER_CFGNI,
37 .node_id = 0,
38 .node_off_addr = 0x0
39 };
40
41 if (ni_tower_dev == NULL || ni_tower_dev->periphbase == (uintptr_t)NULL) {
42 return NI_TOWER_ERR_INVALID_ARG;
43 }
44
45 if (component == NULL || dev == NULL) {
46 return NI_TOWER_ERR_INVALID_ARG;
47 }
48
49 /* Discover offset address for the PSAM */
50 err = ni_tower_discover_offset(
51 ni_tower_dev, &root,
52 component->type,
53 component->id,
54 NI_TOWER_PSAM, &off_addr);
55 if (err != NI_TOWER_SUCCESS) {
56 return err;
57 }
58
59 dev->base = ni_tower_dev->periphbase + off_addr;
60 dev->region_mapping_offset = region_mapping_offset;
61
62 return NI_TOWER_SUCCESS;
63 }
64
ni_tower_psam_configure_nhregion(const struct ni_tower_psam_dev * dev,const struct ni_tower_psam_reg_cfg_info * cfg_info,const uint32_t region)65 enum ni_tower_err ni_tower_psam_configure_nhregion(
66 const struct ni_tower_psam_dev *dev,
67 const struct ni_tower_psam_reg_cfg_info *cfg_info,
68 const uint32_t region)
69 {
70 struct ni_tower_psam_reg_map* reg;
71 uint64_t base_addr, end_addr;
72 uint64_t temp_base_addr, temp_end_addr;
73 uint32_t r_idx;
74
75 if (dev == NULL || dev->base == (uintptr_t)NULL) {
76 return NI_TOWER_ERR_INVALID_ARG;
77 }
78
79 reg = (struct ni_tower_psam_reg_map*)dev->base;
80
81 if (cfg_info == NULL) {
82 return NI_TOWER_ERR_INVALID_ARG;
83 }
84
85 base_addr = cfg_info->base_addr + dev->region_mapping_offset;
86 end_addr = cfg_info->end_addr + dev->region_mapping_offset;
87
88 /* Checking alignment of base and end addresses */
89 if (((base_addr & (NI_TOWER_PSAM_ADDRESS_GRAN - 1)) != 0) ||
90 ((~end_addr & (NI_TOWER_PSAM_ADDRESS_GRAN - 1)) != 0)) {
91 return NI_TOWER_ERR_INVALID_ARG;
92 }
93
94 /* Disable region */
95 reg->nh_region[region].cfg0 &= ~NI_TOWER_NH_REGION_REGION_VALID;
96
97 /* Check whether region overlaps with another valid region */
98 for (r_idx = 0; r_idx < NI_TOWER_MAX_NH_REGIONS; ++r_idx) {
99 if (reg->nh_region[r_idx].cfg0 & NI_TOWER_NH_REGION_REGION_VALID) {
100 NI_TOWER_PSAM_GET64_BASE_ADDRESS(temp_base_addr,
101 reg->nh_region[r_idx].cfg1,
102 reg->nh_region[r_idx].cfg0);
103
104 NI_TOWER_PSAM_GET64_END_ADDRESS(temp_end_addr,
105 reg->nh_region[r_idx].cfg3,
106 reg->nh_region[r_idx].cfg2);
107
108 if (ni_tower_check_region_overlaps(base_addr, end_addr,
109 temp_base_addr, temp_end_addr) !=
110 NI_TOWER_SUCCESS) {
111 return NI_TOWER_ERR_REGION_OVERLAPS;
112 }
113 }
114 }
115
116 /* Set base address */
117 reg->nh_region[region].cfg0 = NI_TOWER_PSAM_ADDRESS_L(base_addr);
118 reg->nh_region[region].cfg1 = NI_TOWER_PSAM_ADDRESS_H(base_addr);
119 /* Set end address */
120 reg->nh_region[region].cfg2 = NI_TOWER_PSAM_ADDRESS_L(end_addr);
121 reg->nh_region[region].cfg3 = NI_TOWER_PSAM_ADDRESS_H(end_addr);
122 /* Set ID for the Target interface. */
123 reg->nh_region[region].cfg2 |= (cfg_info->target_id &
124 NI_TOWER_NH_REGION_TGT_ID_MSK);
125 /* Set region valid */
126 reg->nh_region[region].cfg0 |= NI_TOWER_NH_REGION_REGION_VALID;
127
128 return NI_TOWER_SUCCESS;
129 }
130
get_next_available_region(const struct ni_tower_psam_dev * dev,uint32_t * region)131 static enum ni_tower_err get_next_available_region(
132 const struct ni_tower_psam_dev *dev,
133 uint32_t *region)
134 {
135 struct ni_tower_psam_reg_map* reg;
136 uint32_t r_idx;
137
138 if (dev == NULL || dev->base == (uintptr_t)NULL) {
139 return NI_TOWER_ERR_INVALID_ARG;
140 }
141
142 reg = (struct ni_tower_psam_reg_map*)dev->base;
143
144 for (r_idx = 0; r_idx < NI_TOWER_MAX_NH_REGIONS; ++r_idx) {
145 if (!(reg->nh_region[r_idx].cfg0 & NI_TOWER_NH_REGION_REGION_VALID)) {
146 *region = r_idx;
147 return NI_TOWER_SUCCESS;
148 }
149 }
150
151 return NI_TOWER_ERR;
152 }
153
ni_tower_psam_configure_next_available_nhregion(const struct ni_tower_psam_dev * dev,const struct ni_tower_psam_reg_cfg_info * cfg_info)154 enum ni_tower_err ni_tower_psam_configure_next_available_nhregion(
155 const struct ni_tower_psam_dev *dev,
156 const struct ni_tower_psam_reg_cfg_info *cfg_info)
157 {
158 enum ni_tower_err err;
159 uint32_t next_available_region;
160
161 err = get_next_available_region(dev, &next_available_region);
162 if (err != NI_TOWER_SUCCESS) {
163 return err;
164 }
165
166 return ni_tower_psam_configure_nhregion(dev, cfg_info,
167 next_available_region);
168 }
169
ni_tower_psam_enable(const struct ni_tower_psam_dev * dev)170 enum ni_tower_err ni_tower_psam_enable(const struct ni_tower_psam_dev *dev)
171 {
172 struct ni_tower_psam_reg_map* reg;
173
174 if (dev == NULL || dev->base == (uintptr_t)NULL) {
175 return NI_TOWER_ERR_INVALID_ARG;
176 }
177
178 reg = (struct ni_tower_psam_reg_map*)dev->base;
179
180 reg->sam_status |= NI_TOWER_SAM_STATUS_SETUP_COMPLETE;
181
182 return NI_TOWER_SUCCESS;
183 }
184
ni_tower_psam_disable(const struct ni_tower_psam_dev * dev)185 enum ni_tower_err ni_tower_psam_disable(const struct ni_tower_psam_dev *dev)
186 {
187 struct ni_tower_psam_reg_map* reg;
188
189 if (dev == NULL || dev->base == (uintptr_t)NULL) {
190 return NI_TOWER_ERR_INVALID_ARG;
191 }
192
193 reg = (struct ni_tower_psam_reg_map*)dev->base;
194
195 reg->sam_status &= ~NI_TOWER_SAM_STATUS_SETUP_COMPLETE;
196
197 return NI_TOWER_SUCCESS;
198 }
199