1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * PCIe Integration Control module.
9 */
10
11 #include "pcie_integ_ctrl_reg.h"
12
13 #include <mod_apremap.h>
14 #include <mod_clock.h>
15 #include <mod_pcie_integ_ctrl.h>
16
17 #include <fwk_assert.h>
18 #include <fwk_event.h>
19 #include <fwk_id.h>
20 #include <fwk_log.h>
21 #include <fwk_mm.h>
22 #include <fwk_module.h>
23 #include <fwk_module_idx.h>
24 #include <fwk_notification.h>
25 #include <fwk_status.h>
26
27 #define MOD_NAME "[PCIE_INTEG_CTRL] "
28
29 static const struct mod_apremap_cmn_atrans_api *apremap_cmn_atrans_api;
30
31 /* Module context */
32 struct mod_pcie_integ_ctrl_ctx {
33 /* Pointer to the element configuration pointers (table) */
34 const struct mod_pcie_integ_ctrl_config *config;
35 };
36
37 static struct mod_pcie_integ_ctrl_ctx *ctx_table;
38
39 /*
40 * Static helpers
41 */
get_ctx(fwk_id_t id)42 static struct mod_pcie_integ_ctrl_ctx *get_ctx(fwk_id_t id)
43 {
44 fwk_assert(fwk_module_is_valid_element_id(id));
45
46 return (&ctx_table[fwk_id_get_element_idx(id)]);
47 }
48
pcie_integ_ctrl_configure_registers(struct pcie_ctrl_reg_set * reg,const struct pcie_ecam_mmio_mmap * cfg)49 static inline void pcie_integ_ctrl_configure_registers(
50 struct pcie_ctrl_reg_set *reg,
51 const struct pcie_ecam_mmio_mmap *cfg)
52 {
53 reg->ECAM1_START_ADDR = PCIE_INTEG_CTRL_REG_START_ADDR_EN(
54 cfg->ecam1_start_addr, cfg->allow_ns_access);
55 reg->ECAM1_END_ADDR = PCIE_INTEG_CTRL_REG_END_ADDR(cfg->ecam1_end_addr);
56
57 reg->MMIOL_START_ADDR = PCIE_INTEG_CTRL_REG_START_ADDR_EN(
58 cfg->mmiol_start_addr, cfg->allow_ns_access);
59 reg->MMIOL_END_ADDR = PCIE_INTEG_CTRL_REG_END_ADDR(cfg->mmiol_end_addr);
60
61 reg->MMIOH_START_ADDR = PCIE_INTEG_CTRL_REG_START_ADDR_EN(
62 cfg->mmioh_start_addr, cfg->allow_ns_access);
63 reg->MMIOH_END_ADDR = PCIE_INTEG_CTRL_REG_END_ADDR(cfg->mmioh_end_addr);
64 }
65
configure_pcie_ecam_mmio_space(unsigned int index,const struct mod_pcie_integ_ctrl_config * config)66 static void configure_pcie_ecam_mmio_space(
67 unsigned int index,
68 const struct mod_pcie_integ_ctrl_config *config)
69 {
70 const struct pcie_ecam_mmio_mmap *cfg;
71 struct pcie_ctrl_reg *pcie_integ_ctrl_reg;
72 struct pcie_ctrl_reg_set *reg;
73
74 /* Disable CMN address translation to access the NCI GPV memory space */
75 apremap_cmn_atrans_api->disable();
76
77 pcie_integ_ctrl_reg = (struct pcie_ctrl_reg *)(config->reg_base);
78
79 FWK_LOG_INFO(MOD_NAME "Configuring PCIe integ ctrl reg set: %d", index);
80
81 reg = &pcie_integ_ctrl_reg->pcie_ctrl_x4_0;
82 cfg = &config->x4_0_ecam_mmio_mmap;
83
84 if (cfg->valid) {
85 /* Configure address routing on x4_0 */
86 pcie_integ_ctrl_configure_registers(reg, cfg);
87 }
88
89 reg = &pcie_integ_ctrl_reg->pcie_ctrl_x4_1;
90 cfg = &config->x4_1_ecam_mmio_mmap;
91
92 if (cfg->valid) {
93 /* Configure address routing on x4_1 */
94 pcie_integ_ctrl_configure_registers(reg, cfg);
95 }
96
97 reg = &pcie_integ_ctrl_reg->pcie_ctrl_x8;
98 cfg = &config->x8_ecam_mmio_mmap;
99
100 if (cfg->valid) {
101 /* Configure address routing on x8 */
102 pcie_integ_ctrl_configure_registers(reg, cfg);
103 }
104
105 reg = &pcie_integ_ctrl_reg->pcie_ctrl_x16;
106 cfg = &config->x16_ecam_mmio_mmap;
107
108 if (cfg->valid) {
109 /* Configure address routing on x16 */
110 pcie_integ_ctrl_configure_registers(reg, cfg);
111 }
112 }
113
114 /*
115 * Framework handlers
116 */
117
pcie_integ_ctrl_init(fwk_id_t module_id,unsigned int element_count,const void * unused)118 static int pcie_integ_ctrl_init(
119 fwk_id_t module_id,
120 unsigned int element_count,
121 const void *unused)
122 {
123 if (element_count == 0) {
124 /* There must be at least one pcie integ config data */
125 fwk_unexpected();
126 return FWK_E_PARAM;
127 }
128
129 ctx_table = fwk_mm_calloc(element_count, sizeof(ctx_table[0]));
130
131 return FWK_SUCCESS;
132 }
133
pcie_integ_ctrl_element_init(fwk_id_t element_id,unsigned int unused,const void * data)134 static int pcie_integ_ctrl_element_init(
135 fwk_id_t element_id,
136 unsigned int unused,
137 const void *data)
138 {
139 const struct mod_pcie_integ_ctrl_config *config;
140 struct mod_pcie_integ_ctrl_ctx *ctx;
141
142 config = (struct mod_pcie_integ_ctrl_config *)data;
143 if ((config == NULL) || (config->reg_base == 0)) {
144 fwk_unexpected();
145 return FWK_E_DATA;
146 }
147
148 ctx = &ctx_table[fwk_id_get_element_idx(element_id)];
149 ctx->config = config;
150
151 return FWK_SUCCESS;
152 }
153
pcie_integ_ctrl_start(fwk_id_t id)154 static int pcie_integ_ctrl_start(fwk_id_t id)
155 {
156 const struct mod_pcie_integ_ctrl_config *config;
157 struct mod_pcie_integ_ctrl_ctx *ctx;
158
159 /* Nothing to be done for module start call */
160 if (fwk_id_get_type(id) == FWK_ID_TYPE_MODULE) {
161 return FWK_SUCCESS;
162 }
163
164 ctx = get_ctx(id);
165
166 config = ctx->config;
167
168 /* Register the element for clock state notifications */
169 return fwk_notification_subscribe(
170 mod_clock_notification_id_state_changed, config->clock_id, id);
171 }
172
pcie_integ_ctrl_bind(fwk_id_t id,unsigned int round)173 static int pcie_integ_ctrl_bind(fwk_id_t id, unsigned int round)
174 {
175 return fwk_module_bind(
176 FWK_ID_MODULE(FWK_MODULE_IDX_APREMAP),
177 FWK_ID_API(FWK_MODULE_IDX_APREMAP, MOD_APREMAP_API_IDX_CMN_ATRANS),
178 &apremap_cmn_atrans_api);
179 }
180
pcie_integ_ctrl_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)181 static int pcie_integ_ctrl_process_notification(
182 const struct fwk_event *event,
183 struct fwk_event *resp_event)
184 {
185 struct mod_pcie_integ_ctrl_ctx *ctx;
186 struct clock_notification_params *params;
187
188 fwk_assert(
189 fwk_id_is_equal(event->id, mod_clock_notification_id_state_changed));
190 fwk_assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_ELEMENT));
191
192 params = (struct clock_notification_params *)event->params;
193
194 if (params->new_state == MOD_CLOCK_STATE_RUNNING) {
195 ctx = get_ctx(event->target_id);
196
197 /* Configure the PCIe integration config registers */
198 configure_pcie_ecam_mmio_space(
199 fwk_id_get_element_idx(event->target_id), ctx->config);
200
201 /* Unsubscribe to the notification */
202 return fwk_notification_unsubscribe(
203 event->id, event->source_id, event->target_id);
204 }
205
206 return FWK_SUCCESS;
207 }
208
209 const struct fwk_module module_pcie_integ_ctrl = {
210 .type = FWK_MODULE_TYPE_DRIVER,
211 .init = pcie_integ_ctrl_init,
212 .element_init = pcie_integ_ctrl_element_init,
213 .bind = pcie_integ_ctrl_bind,
214 .start = pcie_integ_ctrl_start,
215 .process_notification = pcie_integ_ctrl_process_notification,
216 };
217