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