]>
Commit | Line | Data |
---|---|---|
cdf2e941 AE |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. | |
4 | * Copyright (C) 2018-2020 Linaro Ltd. | |
5 | */ | |
6 | ||
7 | #include <linux/types.h> | |
8 | #include <linux/atomic.h> | |
9 | #include <linux/bitfield.h> | |
10 | #include <linux/device.h> | |
11 | #include <linux/bug.h> | |
12 | #include <linux/io.h> | |
13 | #include <linux/firmware.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/of.h> | |
16 | #include <linux/of_device.h> | |
17 | #include <linux/of_address.h> | |
18 | #include <linux/remoteproc.h> | |
19 | #include <linux/qcom_scm.h> | |
20 | #include <linux/soc/qcom/mdt_loader.h> | |
21 | ||
22 | #include "ipa.h" | |
23 | #include "ipa_clock.h" | |
24 | #include "ipa_data.h" | |
25 | #include "ipa_endpoint.h" | |
26 | #include "ipa_cmd.h" | |
27 | #include "ipa_reg.h" | |
28 | #include "ipa_mem.h" | |
29 | #include "ipa_table.h" | |
30 | #include "ipa_modem.h" | |
31 | #include "ipa_uc.h" | |
32 | #include "ipa_interrupt.h" | |
33 | #include "gsi_trans.h" | |
34 | ||
35 | /** | |
36 | * DOC: The IP Accelerator | |
37 | * | |
38 | * This driver supports the Qualcomm IP Accelerator (IPA), which is a | |
39 | * networking component found in many Qualcomm SoCs. The IPA is connected | |
40 | * to the application processor (AP), but is also connected (and partially | |
41 | * controlled by) other "execution environments" (EEs), such as a modem. | |
42 | * | |
43 | * The IPA is the conduit between the AP and the modem that carries network | |
44 | * traffic. This driver presents a network interface representing the | |
45 | * connection of the modem to external (e.g. LTE) networks. | |
46 | * | |
47 | * The IPA provides protocol checksum calculation, offloading this work | |
48 | * from the AP. The IPA offers additional functionality, including routing, | |
49 | * filtering, and NAT support, but that more advanced functionality is not | |
50 | * currently supported. Despite that, some resources--including routing | |
51 | * tables and filter tables--are defined in this driver because they must | |
52 | * be initialized even when the advanced hardware features are not used. | |
53 | * | |
54 | * There are two distinct layers that implement the IPA hardware, and this | |
55 | * is reflected in the organization of the driver. The generic software | |
56 | * interface (GSI) is an integral component of the IPA, providing a | |
57 | * well-defined communication layer between the AP subsystem and the IPA | |
58 | * core. The GSI implements a set of "channels" used for communication | |
59 | * between the AP and the IPA. | |
60 | * | |
61 | * The IPA layer uses GSI channels to implement its "endpoints". And while | |
62 | * a GSI channel carries data between the AP and the IPA, a pair of IPA | |
63 | * endpoints is used to carry traffic between two EEs. Specifically, the main | |
64 | * modem network interface is implemented by two pairs of endpoints: a TX | |
65 | * endpoint on the AP coupled with an RX endpoint on the modem; and another | |
66 | * RX endpoint on the AP receiving data from a TX endpoint on the modem. | |
67 | */ | |
68 | ||
69 | /* The name of the GSI firmware file relative to /lib/firmware */ | |
70 | #define IPA_FWS_PATH "ipa_fws.mdt" | |
71 | #define IPA_PAS_ID 15 | |
72 | ||
73 | /** | |
74 | * ipa_suspend_handler() - Handle the suspend IPA interrupt | |
75 | * @ipa: IPA pointer | |
76 | * @irq_id: IPA interrupt type (unused) | |
77 | * | |
8529b4b0 AE |
78 | * If an RX endpoint is in suspend state, and the IPA has a packet |
79 | * destined for that endpoint, the IPA generates a SUSPEND interrupt | |
80 | * to inform the AP that it should resume the endpoint. If we get | |
81 | * one of these interrupts we just resume everything. | |
cdf2e941 AE |
82 | */ |
83 | static void ipa_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) | |
84 | { | |
8529b4b0 AE |
85 | /* Just report the event, and let system resume handle the rest. |
86 | * More than one endpoint could signal this; if so, ignore | |
87 | * all but the first. | |
cdf2e941 | 88 | */ |
3c6ccdde | 89 | if (!test_and_set_bit(IPA_FLAG_RESUMED, ipa->flags)) |
8529b4b0 | 90 | pm_wakeup_dev_event(&ipa->pdev->dev, 0, true); |
cdf2e941 AE |
91 | |
92 | /* Acknowledge/clear the suspend interrupt on all endpoints */ | |
93 | ipa_interrupt_suspend_clear_all(ipa->interrupt); | |
94 | } | |
95 | ||
96 | /** | |
97 | * ipa_setup() - Set up IPA hardware | |
98 | * @ipa: IPA pointer | |
99 | * | |
100 | * Perform initialization that requires issuing immediate commands on | |
101 | * the command TX endpoint. If the modem is doing GSI firmware load | |
102 | * and initialization, this function will be called when an SMP2P | |
103 | * interrupt has been signaled by the modem. Otherwise it will be | |
104 | * called from ipa_probe() after GSI firmware has been successfully | |
105 | * loaded, authenticated, and started by Trust Zone. | |
106 | */ | |
107 | int ipa_setup(struct ipa *ipa) | |
108 | { | |
109 | struct ipa_endpoint *exception_endpoint; | |
110 | struct ipa_endpoint *command_endpoint; | |
8529b4b0 | 111 | struct device *dev = &ipa->pdev->dev; |
cdf2e941 AE |
112 | int ret; |
113 | ||
f86a1909 | 114 | /* Setup for IPA v3.5.1 has some slight differences */ |
cdf2e941 AE |
115 | ret = gsi_setup(&ipa->gsi, ipa->version == IPA_VERSION_3_5_1); |
116 | if (ret) | |
117 | return ret; | |
118 | ||
119 | ipa->interrupt = ipa_interrupt_setup(ipa); | |
120 | if (IS_ERR(ipa->interrupt)) { | |
121 | ret = PTR_ERR(ipa->interrupt); | |
122 | goto err_gsi_teardown; | |
123 | } | |
124 | ipa_interrupt_add(ipa->interrupt, IPA_IRQ_TX_SUSPEND, | |
125 | ipa_suspend_handler); | |
126 | ||
127 | ipa_uc_setup(ipa); | |
128 | ||
8529b4b0 AE |
129 | ret = device_init_wakeup(dev, true); |
130 | if (ret) | |
131 | goto err_uc_teardown; | |
132 | ||
cdf2e941 AE |
133 | ipa_endpoint_setup(ipa); |
134 | ||
135 | /* We need to use the AP command TX endpoint to perform other | |
136 | * initialization, so we enable first. | |
137 | */ | |
138 | command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; | |
139 | ret = ipa_endpoint_enable_one(command_endpoint); | |
140 | if (ret) | |
141 | goto err_endpoint_teardown; | |
142 | ||
143 | ret = ipa_mem_setup(ipa); | |
144 | if (ret) | |
145 | goto err_command_disable; | |
146 | ||
147 | ret = ipa_table_setup(ipa); | |
148 | if (ret) | |
149 | goto err_mem_teardown; | |
150 | ||
151 | /* Enable the exception handling endpoint, and tell the hardware | |
152 | * to use it by default. | |
153 | */ | |
154 | exception_endpoint = ipa->name_map[IPA_ENDPOINT_AP_LAN_RX]; | |
155 | ret = ipa_endpoint_enable_one(exception_endpoint); | |
156 | if (ret) | |
157 | goto err_table_teardown; | |
158 | ||
159 | ipa_endpoint_default_route_set(ipa, exception_endpoint->endpoint_id); | |
160 | ||
161 | /* We're all set. Now prepare for communication with the modem */ | |
162 | ret = ipa_modem_setup(ipa); | |
163 | if (ret) | |
164 | goto err_default_route_clear; | |
165 | ||
166 | ipa->setup_complete = true; | |
167 | ||
8529b4b0 | 168 | dev_info(dev, "IPA driver setup completed successfully\n"); |
cdf2e941 AE |
169 | |
170 | return 0; | |
171 | ||
172 | err_default_route_clear: | |
173 | ipa_endpoint_default_route_clear(ipa); | |
174 | ipa_endpoint_disable_one(exception_endpoint); | |
175 | err_table_teardown: | |
176 | ipa_table_teardown(ipa); | |
177 | err_mem_teardown: | |
178 | ipa_mem_teardown(ipa); | |
179 | err_command_disable: | |
180 | ipa_endpoint_disable_one(command_endpoint); | |
181 | err_endpoint_teardown: | |
182 | ipa_endpoint_teardown(ipa); | |
8529b4b0 AE |
183 | (void)device_init_wakeup(dev, false); |
184 | err_uc_teardown: | |
cdf2e941 AE |
185 | ipa_uc_teardown(ipa); |
186 | ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND); | |
187 | ipa_interrupt_teardown(ipa->interrupt); | |
188 | err_gsi_teardown: | |
189 | gsi_teardown(&ipa->gsi); | |
190 | ||
191 | return ret; | |
192 | } | |
193 | ||
194 | /** | |
195 | * ipa_teardown() - Inverse of ipa_setup() | |
196 | * @ipa: IPA pointer | |
197 | */ | |
198 | static void ipa_teardown(struct ipa *ipa) | |
199 | { | |
200 | struct ipa_endpoint *exception_endpoint; | |
201 | struct ipa_endpoint *command_endpoint; | |
202 | ||
203 | ipa_modem_teardown(ipa); | |
204 | ipa_endpoint_default_route_clear(ipa); | |
205 | exception_endpoint = ipa->name_map[IPA_ENDPOINT_AP_LAN_RX]; | |
206 | ipa_endpoint_disable_one(exception_endpoint); | |
207 | ipa_table_teardown(ipa); | |
208 | ipa_mem_teardown(ipa); | |
209 | command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; | |
210 | ipa_endpoint_disable_one(command_endpoint); | |
211 | ipa_endpoint_teardown(ipa); | |
8529b4b0 | 212 | (void)device_init_wakeup(&ipa->pdev->dev, false); |
cdf2e941 AE |
213 | ipa_uc_teardown(ipa); |
214 | ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND); | |
215 | ipa_interrupt_teardown(ipa->interrupt); | |
216 | gsi_teardown(&ipa->gsi); | |
217 | } | |
218 | ||
219 | /* Configure QMB Core Master Port selection */ | |
220 | static void ipa_hardware_config_comp(struct ipa *ipa) | |
221 | { | |
222 | u32 val; | |
223 | ||
224 | /* Nothing to configure for IPA v3.5.1 */ | |
225 | if (ipa->version == IPA_VERSION_3_5_1) | |
226 | return; | |
227 | ||
228 | val = ioread32(ipa->reg_virt + IPA_REG_COMP_CFG_OFFSET); | |
229 | ||
230 | if (ipa->version == IPA_VERSION_4_0) { | |
231 | val &= ~IPA_QMB_SELECT_CONS_EN_FMASK; | |
232 | val &= ~IPA_QMB_SELECT_PROD_EN_FMASK; | |
233 | val &= ~IPA_QMB_SELECT_GLOBAL_EN_FMASK; | |
234 | } else { | |
235 | val |= GSI_MULTI_AXI_MASTERS_DIS_FMASK; | |
236 | } | |
237 | ||
238 | val |= GSI_MULTI_INORDER_RD_DIS_FMASK; | |
239 | val |= GSI_MULTI_INORDER_WR_DIS_FMASK; | |
240 | ||
241 | iowrite32(val, ipa->reg_virt + IPA_REG_COMP_CFG_OFFSET); | |
242 | } | |
243 | ||
244 | /* Configure DDR and PCIe max read/write QSB values */ | |
245 | static void ipa_hardware_config_qsb(struct ipa *ipa) | |
246 | { | |
247 | u32 val; | |
248 | ||
249 | /* QMB_0 represents DDR; QMB_1 represents PCIe (not present in 4.2) */ | |
250 | val = u32_encode_bits(8, GEN_QMB_0_MAX_WRITES_FMASK); | |
251 | if (ipa->version == IPA_VERSION_4_2) | |
252 | val |= u32_encode_bits(0, GEN_QMB_1_MAX_WRITES_FMASK); | |
253 | else | |
254 | val |= u32_encode_bits(4, GEN_QMB_1_MAX_WRITES_FMASK); | |
255 | iowrite32(val, ipa->reg_virt + IPA_REG_QSB_MAX_WRITES_OFFSET); | |
256 | ||
257 | if (ipa->version == IPA_VERSION_3_5_1) { | |
258 | val = u32_encode_bits(8, GEN_QMB_0_MAX_READS_FMASK); | |
259 | val |= u32_encode_bits(12, GEN_QMB_1_MAX_READS_FMASK); | |
260 | } else { | |
261 | val = u32_encode_bits(12, GEN_QMB_0_MAX_READS_FMASK); | |
262 | if (ipa->version == IPA_VERSION_4_2) | |
263 | val |= u32_encode_bits(0, GEN_QMB_1_MAX_READS_FMASK); | |
264 | else | |
265 | val |= u32_encode_bits(12, GEN_QMB_1_MAX_READS_FMASK); | |
266 | /* GEN_QMB_0_MAX_READS_BEATS is 0 */ | |
267 | /* GEN_QMB_1_MAX_READS_BEATS is 0 */ | |
268 | } | |
269 | iowrite32(val, ipa->reg_virt + IPA_REG_QSB_MAX_READS_OFFSET); | |
270 | } | |
271 | ||
272 | static void ipa_idle_indication_cfg(struct ipa *ipa, | |
273 | u32 enter_idle_debounce_thresh, | |
274 | bool const_non_idle_enable) | |
275 | { | |
276 | u32 offset; | |
277 | u32 val; | |
278 | ||
279 | val = u32_encode_bits(enter_idle_debounce_thresh, | |
280 | ENTER_IDLE_DEBOUNCE_THRESH_FMASK); | |
281 | if (const_non_idle_enable) | |
282 | val |= CONST_NON_IDLE_ENABLE_FMASK; | |
283 | ||
284 | offset = ipa_reg_idle_indication_cfg_offset(ipa->version); | |
285 | iowrite32(val, ipa->reg_virt + offset); | |
286 | } | |
287 | ||
288 | /** | |
289 | * ipa_hardware_dcd_config() - Enable dynamic clock division on IPA | |
e3eea08e | 290 | * @ipa: IPA pointer |
cdf2e941 AE |
291 | * |
292 | * Configures when the IPA signals it is idle to the global clock | |
293 | * controller, which can respond by scalling down the clock to | |
294 | * save power. | |
295 | */ | |
296 | static void ipa_hardware_dcd_config(struct ipa *ipa) | |
297 | { | |
298 | /* Recommended values for IPA 3.5 according to IPA HPG */ | |
299 | ipa_idle_indication_cfg(ipa, 256, false); | |
300 | } | |
301 | ||
302 | static void ipa_hardware_dcd_deconfig(struct ipa *ipa) | |
303 | { | |
304 | /* Power-on reset values */ | |
305 | ipa_idle_indication_cfg(ipa, 0, true); | |
306 | } | |
307 | ||
308 | /** | |
309 | * ipa_hardware_config() - Primitive hardware initialization | |
310 | * @ipa: IPA pointer | |
311 | */ | |
312 | static void ipa_hardware_config(struct ipa *ipa) | |
313 | { | |
314 | u32 granularity; | |
315 | u32 val; | |
316 | ||
317 | /* Fill in backward-compatibility register, based on version */ | |
318 | val = ipa_reg_bcr_val(ipa->version); | |
319 | iowrite32(val, ipa->reg_virt + IPA_REG_BCR_OFFSET); | |
320 | ||
321 | if (ipa->version != IPA_VERSION_3_5_1) { | |
322 | /* Enable open global clocks (hardware workaround) */ | |
323 | val = GLOBAL_FMASK; | |
324 | val |= GLOBAL_2X_CLK_FMASK; | |
325 | iowrite32(val, ipa->reg_virt + IPA_REG_CLKON_CFG_OFFSET); | |
326 | ||
327 | /* Disable PA mask to allow HOLB drop (hardware workaround) */ | |
328 | val = ioread32(ipa->reg_virt + IPA_REG_TX_CFG_OFFSET); | |
329 | val &= ~PA_MASK_EN; | |
330 | iowrite32(val, ipa->reg_virt + IPA_REG_TX_CFG_OFFSET); | |
331 | } | |
332 | ||
333 | ipa_hardware_config_comp(ipa); | |
334 | ||
335 | /* Configure system bus limits */ | |
336 | ipa_hardware_config_qsb(ipa); | |
337 | ||
338 | /* Configure aggregation granularity */ | |
339 | val = ioread32(ipa->reg_virt + IPA_REG_COUNTER_CFG_OFFSET); | |
340 | granularity = ipa_aggr_granularity_val(IPA_AGGR_GRANULARITY); | |
341 | val = u32_encode_bits(granularity, AGGR_GRANULARITY); | |
342 | iowrite32(val, ipa->reg_virt + IPA_REG_COUNTER_CFG_OFFSET); | |
343 | ||
344 | /* Disable hashed IPv4 and IPv6 routing and filtering for IPA v4.2 */ | |
345 | if (ipa->version == IPA_VERSION_4_2) | |
346 | iowrite32(0, ipa->reg_virt + IPA_REG_FILT_ROUT_HASH_EN_OFFSET); | |
347 | ||
348 | /* Enable dynamic clock division */ | |
349 | ipa_hardware_dcd_config(ipa); | |
350 | } | |
351 | ||
352 | /** | |
353 | * ipa_hardware_deconfig() - Inverse of ipa_hardware_config() | |
354 | * @ipa: IPA pointer | |
355 | * | |
356 | * This restores the power-on reset values (even if they aren't different) | |
357 | */ | |
358 | static void ipa_hardware_deconfig(struct ipa *ipa) | |
359 | { | |
360 | /* Mostly we just leave things as we set them. */ | |
361 | ipa_hardware_dcd_deconfig(ipa); | |
362 | } | |
363 | ||
364 | #ifdef IPA_VALIDATION | |
365 | ||
366 | /* # IPA resources used based on version (see IPA_RESOURCE_GROUP_COUNT) */ | |
367 | static int ipa_resource_group_count(struct ipa *ipa) | |
368 | { | |
369 | switch (ipa->version) { | |
370 | case IPA_VERSION_3_5_1: | |
371 | return 3; | |
372 | ||
373 | case IPA_VERSION_4_0: | |
374 | case IPA_VERSION_4_1: | |
375 | return 4; | |
376 | ||
377 | case IPA_VERSION_4_2: | |
378 | return 1; | |
379 | ||
380 | default: | |
381 | return 0; | |
382 | } | |
383 | } | |
384 | ||
385 | static bool ipa_resource_limits_valid(struct ipa *ipa, | |
386 | const struct ipa_resource_data *data) | |
387 | { | |
388 | u32 group_count = ipa_resource_group_count(ipa); | |
389 | u32 i; | |
390 | u32 j; | |
391 | ||
392 | if (!group_count) | |
393 | return false; | |
394 | ||
395 | /* Return an error if a non-zero resource group limit is specified | |
396 | * for a resource not supported by hardware. | |
397 | */ | |
398 | for (i = 0; i < data->resource_src_count; i++) { | |
399 | const struct ipa_resource_src *resource; | |
400 | ||
401 | resource = &data->resource_src[i]; | |
402 | for (j = group_count; j < IPA_RESOURCE_GROUP_COUNT; j++) | |
403 | if (resource->limits[j].min || resource->limits[j].max) | |
404 | return false; | |
405 | } | |
406 | ||
407 | for (i = 0; i < data->resource_dst_count; i++) { | |
408 | const struct ipa_resource_dst *resource; | |
409 | ||
410 | resource = &data->resource_dst[i]; | |
411 | for (j = group_count; j < IPA_RESOURCE_GROUP_COUNT; j++) | |
412 | if (resource->limits[j].min || resource->limits[j].max) | |
413 | return false; | |
414 | } | |
415 | ||
416 | return true; | |
417 | } | |
418 | ||
419 | #else /* !IPA_VALIDATION */ | |
420 | ||
421 | static bool ipa_resource_limits_valid(struct ipa *ipa, | |
422 | const struct ipa_resource_data *data) | |
423 | { | |
424 | return true; | |
425 | } | |
426 | ||
427 | #endif /* !IPA_VALIDATION */ | |
428 | ||
429 | static void | |
430 | ipa_resource_config_common(struct ipa *ipa, u32 offset, | |
431 | const struct ipa_resource_limits *xlimits, | |
432 | const struct ipa_resource_limits *ylimits) | |
433 | { | |
434 | u32 val; | |
435 | ||
436 | val = u32_encode_bits(xlimits->min, X_MIN_LIM_FMASK); | |
437 | val |= u32_encode_bits(xlimits->max, X_MAX_LIM_FMASK); | |
438 | val |= u32_encode_bits(ylimits->min, Y_MIN_LIM_FMASK); | |
439 | val |= u32_encode_bits(ylimits->max, Y_MAX_LIM_FMASK); | |
440 | ||
441 | iowrite32(val, ipa->reg_virt + offset); | |
442 | } | |
443 | ||
444 | static void ipa_resource_config_src_01(struct ipa *ipa, | |
445 | const struct ipa_resource_src *resource) | |
446 | { | |
447 | u32 offset = IPA_REG_SRC_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource->type); | |
448 | ||
449 | ipa_resource_config_common(ipa, offset, | |
450 | &resource->limits[0], &resource->limits[1]); | |
451 | } | |
452 | ||
453 | static void ipa_resource_config_src_23(struct ipa *ipa, | |
454 | const struct ipa_resource_src *resource) | |
455 | { | |
456 | u32 offset = IPA_REG_SRC_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource->type); | |
457 | ||
458 | ipa_resource_config_common(ipa, offset, | |
459 | &resource->limits[2], &resource->limits[3]); | |
460 | } | |
461 | ||
462 | static void ipa_resource_config_dst_01(struct ipa *ipa, | |
463 | const struct ipa_resource_dst *resource) | |
464 | { | |
465 | u32 offset = IPA_REG_DST_RSRC_GRP_01_RSRC_TYPE_N_OFFSET(resource->type); | |
466 | ||
467 | ipa_resource_config_common(ipa, offset, | |
468 | &resource->limits[0], &resource->limits[1]); | |
469 | } | |
470 | ||
471 | static void ipa_resource_config_dst_23(struct ipa *ipa, | |
472 | const struct ipa_resource_dst *resource) | |
473 | { | |
474 | u32 offset = IPA_REG_DST_RSRC_GRP_23_RSRC_TYPE_N_OFFSET(resource->type); | |
475 | ||
476 | ipa_resource_config_common(ipa, offset, | |
477 | &resource->limits[2], &resource->limits[3]); | |
478 | } | |
479 | ||
480 | static int | |
481 | ipa_resource_config(struct ipa *ipa, const struct ipa_resource_data *data) | |
482 | { | |
483 | u32 i; | |
484 | ||
485 | if (!ipa_resource_limits_valid(ipa, data)) | |
486 | return -EINVAL; | |
487 | ||
488 | for (i = 0; i < data->resource_src_count; i++) { | |
489 | ipa_resource_config_src_01(ipa, &data->resource_src[i]); | |
490 | ipa_resource_config_src_23(ipa, &data->resource_src[i]); | |
491 | } | |
492 | ||
493 | for (i = 0; i < data->resource_dst_count; i++) { | |
494 | ipa_resource_config_dst_01(ipa, &data->resource_dst[i]); | |
495 | ipa_resource_config_dst_23(ipa, &data->resource_dst[i]); | |
496 | } | |
497 | ||
498 | return 0; | |
499 | } | |
500 | ||
501 | static void ipa_resource_deconfig(struct ipa *ipa) | |
502 | { | |
503 | /* Nothing to do */ | |
504 | } | |
505 | ||
506 | /** | |
507 | * ipa_config() - Configure IPA hardware | |
508 | * @ipa: IPA pointer | |
e3eea08e | 509 | * @data: IPA configuration data |
cdf2e941 AE |
510 | * |
511 | * Perform initialization requiring IPA clock to be enabled. | |
512 | */ | |
513 | static int ipa_config(struct ipa *ipa, const struct ipa_data *data) | |
514 | { | |
515 | int ret; | |
516 | ||
517 | /* Get a clock reference to allow initialization. This reference | |
518 | * is held after initialization completes, and won't get dropped | |
519 | * unless/until a system suspend request arrives. | |
520 | */ | |
cdf2e941 AE |
521 | ipa_clock_get(ipa); |
522 | ||
523 | ipa_hardware_config(ipa); | |
524 | ||
525 | ret = ipa_endpoint_config(ipa); | |
526 | if (ret) | |
527 | goto err_hardware_deconfig; | |
528 | ||
529 | ret = ipa_mem_config(ipa); | |
530 | if (ret) | |
531 | goto err_endpoint_deconfig; | |
532 | ||
533 | ipa_table_config(ipa); | |
534 | ||
535 | /* Assign resource limitation to each group */ | |
536 | ret = ipa_resource_config(ipa, data->resource_data); | |
537 | if (ret) | |
538 | goto err_table_deconfig; | |
539 | ||
540 | ret = ipa_modem_config(ipa); | |
541 | if (ret) | |
542 | goto err_resource_deconfig; | |
543 | ||
544 | return 0; | |
545 | ||
546 | err_resource_deconfig: | |
547 | ipa_resource_deconfig(ipa); | |
548 | err_table_deconfig: | |
549 | ipa_table_deconfig(ipa); | |
550 | ipa_mem_deconfig(ipa); | |
551 | err_endpoint_deconfig: | |
552 | ipa_endpoint_deconfig(ipa); | |
553 | err_hardware_deconfig: | |
554 | ipa_hardware_deconfig(ipa); | |
555 | ipa_clock_put(ipa); | |
cdf2e941 AE |
556 | |
557 | return ret; | |
558 | } | |
559 | ||
560 | /** | |
561 | * ipa_deconfig() - Inverse of ipa_config() | |
562 | * @ipa: IPA pointer | |
563 | */ | |
564 | static void ipa_deconfig(struct ipa *ipa) | |
565 | { | |
566 | ipa_modem_deconfig(ipa); | |
567 | ipa_resource_deconfig(ipa); | |
568 | ipa_table_deconfig(ipa); | |
569 | ipa_mem_deconfig(ipa); | |
570 | ipa_endpoint_deconfig(ipa); | |
571 | ipa_hardware_deconfig(ipa); | |
572 | ipa_clock_put(ipa); | |
cdf2e941 AE |
573 | } |
574 | ||
575 | static int ipa_firmware_load(struct device *dev) | |
576 | { | |
577 | const struct firmware *fw; | |
578 | struct device_node *node; | |
579 | struct resource res; | |
580 | phys_addr_t phys; | |
581 | ssize_t size; | |
582 | void *virt; | |
583 | int ret; | |
584 | ||
585 | node = of_parse_phandle(dev->of_node, "memory-region", 0); | |
586 | if (!node) { | |
587 | dev_err(dev, "DT error getting \"memory-region\" property\n"); | |
588 | return -EINVAL; | |
589 | } | |
590 | ||
591 | ret = of_address_to_resource(node, 0, &res); | |
592 | if (ret) { | |
593 | dev_err(dev, "error %d getting \"memory-region\" resource\n", | |
594 | ret); | |
595 | return ret; | |
596 | } | |
597 | ||
598 | ret = request_firmware(&fw, IPA_FWS_PATH, dev); | |
599 | if (ret) { | |
600 | dev_err(dev, "error %d requesting \"%s\"\n", ret, IPA_FWS_PATH); | |
601 | return ret; | |
602 | } | |
603 | ||
604 | phys = res.start; | |
605 | size = (size_t)resource_size(&res); | |
606 | virt = memremap(phys, size, MEMREMAP_WC); | |
607 | if (!virt) { | |
608 | dev_err(dev, "unable to remap firmware memory\n"); | |
609 | ret = -ENOMEM; | |
610 | goto out_release_firmware; | |
611 | } | |
612 | ||
613 | ret = qcom_mdt_load(dev, fw, IPA_FWS_PATH, IPA_PAS_ID, | |
614 | virt, phys, size, NULL); | |
615 | if (ret) | |
616 | dev_err(dev, "error %d loading \"%s\"\n", ret, IPA_FWS_PATH); | |
617 | else if ((ret = qcom_scm_pas_auth_and_reset(IPA_PAS_ID))) | |
618 | dev_err(dev, "error %d authenticating \"%s\"\n", ret, | |
619 | IPA_FWS_PATH); | |
620 | ||
621 | memunmap(virt); | |
622 | out_release_firmware: | |
623 | release_firmware(fw); | |
624 | ||
625 | return ret; | |
626 | } | |
627 | ||
628 | static const struct of_device_id ipa_match[] = { | |
629 | { | |
630 | .compatible = "qcom,sdm845-ipa", | |
631 | .data = &ipa_data_sdm845, | |
632 | }, | |
633 | { | |
634 | .compatible = "qcom,sc7180-ipa", | |
635 | .data = &ipa_data_sc7180, | |
636 | }, | |
637 | { }, | |
638 | }; | |
639 | MODULE_DEVICE_TABLE(of, ipa_match); | |
640 | ||
641 | static phandle of_property_read_phandle(const struct device_node *np, | |
642 | const char *name) | |
643 | { | |
644 | struct property *prop; | |
645 | int len = 0; | |
646 | ||
647 | prop = of_find_property(np, name, &len); | |
648 | if (!prop || len != sizeof(__be32)) | |
649 | return 0; | |
650 | ||
651 | return be32_to_cpup(prop->value); | |
652 | } | |
653 | ||
654 | /* Check things that can be validated at build time. This just | |
655 | * groups these things BUILD_BUG_ON() calls don't clutter the rest | |
656 | * of the code. | |
657 | * */ | |
658 | static void ipa_validate_build(void) | |
659 | { | |
660 | #ifdef IPA_VALIDATE | |
661 | /* We assume we're working on 64-bit hardware */ | |
662 | BUILD_BUG_ON(!IS_ENABLED(CONFIG_64BIT)); | |
663 | ||
664 | /* Code assumes the EE ID for the AP is 0 (zeroed structure field) */ | |
665 | BUILD_BUG_ON(GSI_EE_AP != 0); | |
666 | ||
667 | /* There's no point if we have no channels or event rings */ | |
668 | BUILD_BUG_ON(!GSI_CHANNEL_COUNT_MAX); | |
669 | BUILD_BUG_ON(!GSI_EVT_RING_COUNT_MAX); | |
670 | ||
671 | /* GSI hardware design limits */ | |
672 | BUILD_BUG_ON(GSI_CHANNEL_COUNT_MAX > 32); | |
673 | BUILD_BUG_ON(GSI_EVT_RING_COUNT_MAX > 31); | |
674 | ||
675 | /* The number of TREs in a transaction is limited by the channel's | |
676 | * TLV FIFO size. A transaction structure uses 8-bit fields | |
677 | * to represents the number of TREs it has allocated and used. | |
678 | */ | |
679 | BUILD_BUG_ON(GSI_TLV_MAX > U8_MAX); | |
680 | ||
681 | /* Exceeding 128 bytes makes the transaction pool *much* larger */ | |
682 | BUILD_BUG_ON(sizeof(struct gsi_trans) > 128); | |
683 | ||
684 | /* This is used as a divisor */ | |
685 | BUILD_BUG_ON(!IPA_AGGR_GRANULARITY); | |
317a5740 AE |
686 | |
687 | /* Aggregation granularity value can't be 0, and must fit */ | |
688 | BUILD_BUG_ON(!ipa_aggr_granularity_val(IPA_AGGR_GRANULARITY)); | |
689 | BUILD_BUG_ON(ipa_aggr_granularity_val(IPA_AGGR_GRANULARITY) > | |
690 | field_max(AGGR_GRANULARITY)); | |
cdf2e941 AE |
691 | #endif /* IPA_VALIDATE */ |
692 | } | |
693 | ||
694 | /** | |
695 | * ipa_probe() - IPA platform driver probe function | |
696 | * @pdev: Platform device pointer | |
697 | * | |
e3eea08e | 698 | * Return: 0 if successful, or a negative error code (possibly |
cdf2e941 AE |
699 | * EPROBE_DEFER) |
700 | * | |
701 | * This is the main entry point for the IPA driver. Initialization proceeds | |
702 | * in several stages: | |
703 | * - The "init" stage involves activities that can be initialized without | |
704 | * access to the IPA hardware. | |
705 | * - The "config" stage requires the IPA clock to be active so IPA registers | |
706 | * can be accessed, but does not require the use of IPA immediate commands. | |
707 | * - The "setup" stage uses IPA immediate commands, and so requires the GSI | |
708 | * layer to be initialized. | |
709 | * | |
710 | * A Boolean Device Tree "modem-init" property determines whether GSI | |
711 | * initialization will be performed by the AP (Trust Zone) or the modem. | |
712 | * If the AP does GSI initialization, the setup phase is entered after | |
713 | * this has completed successfully. Otherwise the modem initializes | |
714 | * the GSI layer and signals it has finished by sending an SMP2P interrupt | |
715 | * to the AP; this triggers the start if IPA setup. | |
716 | */ | |
717 | static int ipa_probe(struct platform_device *pdev) | |
718 | { | |
cdf2e941 AE |
719 | struct device *dev = &pdev->dev; |
720 | const struct ipa_data *data; | |
721 | struct ipa_clock *clock; | |
722 | struct rproc *rproc; | |
723 | bool modem_alloc; | |
724 | bool modem_init; | |
725 | struct ipa *ipa; | |
cdf2e941 | 726 | bool prefetch; |
84cec844 | 727 | phandle ph; |
cdf2e941 AE |
728 | int ret; |
729 | ||
730 | ipa_validate_build(); | |
731 | ||
732 | /* If we need Trust Zone, make sure it's available */ | |
733 | modem_init = of_property_read_bool(dev->of_node, "modem-init"); | |
734 | if (!modem_init) | |
735 | if (!qcom_scm_is_available()) | |
736 | return -EPROBE_DEFER; | |
737 | ||
738 | /* We rely on remoteproc to tell us about modem state changes */ | |
84cec844 AE |
739 | ph = of_property_read_phandle(dev->of_node, "modem-remoteproc"); |
740 | if (!ph) { | |
cdf2e941 AE |
741 | dev_err(dev, "DT missing \"modem-remoteproc\" property\n"); |
742 | return -EINVAL; | |
743 | } | |
744 | ||
84cec844 | 745 | rproc = rproc_get_by_phandle(ph); |
cdf2e941 AE |
746 | if (!rproc) |
747 | return -EPROBE_DEFER; | |
748 | ||
749 | /* The clock and interconnects might not be ready when we're | |
750 | * probed, so might return -EPROBE_DEFER. | |
751 | */ | |
752 | clock = ipa_clock_init(dev); | |
753 | if (IS_ERR(clock)) { | |
754 | ret = PTR_ERR(clock); | |
755 | goto err_rproc_put; | |
756 | } | |
757 | ||
758 | /* No more EPROBE_DEFER. Get our configuration data */ | |
759 | data = of_device_get_match_data(dev); | |
760 | if (!data) { | |
761 | /* This is really IPA_VALIDATE (should never happen) */ | |
762 | dev_err(dev, "matched hardware not supported\n"); | |
763 | ret = -ENOTSUPP; | |
764 | goto err_clock_exit; | |
765 | } | |
766 | ||
cdf2e941 AE |
767 | /* Allocate and initialize the IPA structure */ |
768 | ipa = kzalloc(sizeof(*ipa), GFP_KERNEL); | |
769 | if (!ipa) { | |
770 | ret = -ENOMEM; | |
8529b4b0 | 771 | goto err_clock_exit; |
cdf2e941 AE |
772 | } |
773 | ||
774 | ipa->pdev = pdev; | |
775 | dev_set_drvdata(dev, ipa); | |
776 | ipa->modem_rproc = rproc; | |
777 | ipa->clock = clock; | |
cdf2e941 AE |
778 | ipa->version = data->version; |
779 | ||
780 | ret = ipa_reg_init(ipa); | |
781 | if (ret) | |
782 | goto err_kfree_ipa; | |
783 | ||
3128aae8 | 784 | ret = ipa_mem_init(ipa, data->mem_data); |
cdf2e941 AE |
785 | if (ret) |
786 | goto err_reg_exit; | |
787 | ||
788 | /* GSI v2.0+ (IPA v4.0+) uses prefetch for the command channel */ | |
789 | prefetch = ipa->version != IPA_VERSION_3_5_1; | |
790 | /* IPA v4.2 requires the AP to allocate channels for the modem */ | |
791 | modem_alloc = ipa->version == IPA_VERSION_4_2; | |
792 | ||
793 | ret = gsi_init(&ipa->gsi, pdev, prefetch, data->endpoint_count, | |
794 | data->endpoint_data, modem_alloc); | |
795 | if (ret) | |
796 | goto err_mem_exit; | |
797 | ||
798 | /* Result is a non-zero mask endpoints that support filtering */ | |
799 | ipa->filter_map = ipa_endpoint_init(ipa, data->endpoint_count, | |
800 | data->endpoint_data); | |
801 | if (!ipa->filter_map) { | |
802 | ret = -EINVAL; | |
803 | goto err_gsi_exit; | |
804 | } | |
805 | ||
806 | ret = ipa_table_init(ipa); | |
807 | if (ret) | |
808 | goto err_endpoint_exit; | |
809 | ||
810 | ret = ipa_modem_init(ipa, modem_init); | |
811 | if (ret) | |
812 | goto err_table_exit; | |
813 | ||
814 | ret = ipa_config(ipa, data); | |
815 | if (ret) | |
816 | goto err_modem_exit; | |
817 | ||
818 | dev_info(dev, "IPA driver initialized"); | |
819 | ||
820 | /* If the modem is doing early initialization, it will trigger a | |
821 | * call to ipa_setup() call when it has finished. In that case | |
822 | * we're done here. | |
823 | */ | |
824 | if (modem_init) | |
825 | return 0; | |
826 | ||
827 | /* Otherwise we need to load the firmware and have Trust Zone validate | |
828 | * and install it. If that succeeds we can proceed with setup. | |
829 | */ | |
830 | ret = ipa_firmware_load(dev); | |
831 | if (ret) | |
832 | goto err_deconfig; | |
833 | ||
834 | ret = ipa_setup(ipa); | |
835 | if (ret) | |
836 | goto err_deconfig; | |
837 | ||
838 | return 0; | |
839 | ||
840 | err_deconfig: | |
841 | ipa_deconfig(ipa); | |
842 | err_modem_exit: | |
843 | ipa_modem_exit(ipa); | |
844 | err_table_exit: | |
845 | ipa_table_exit(ipa); | |
846 | err_endpoint_exit: | |
847 | ipa_endpoint_exit(ipa); | |
848 | err_gsi_exit: | |
849 | gsi_exit(&ipa->gsi); | |
850 | err_mem_exit: | |
851 | ipa_mem_exit(ipa); | |
852 | err_reg_exit: | |
853 | ipa_reg_exit(ipa); | |
854 | err_kfree_ipa: | |
855 | kfree(ipa); | |
cdf2e941 AE |
856 | err_clock_exit: |
857 | ipa_clock_exit(clock); | |
858 | err_rproc_put: | |
859 | rproc_put(rproc); | |
860 | ||
861 | return ret; | |
862 | } | |
863 | ||
864 | static int ipa_remove(struct platform_device *pdev) | |
865 | { | |
866 | struct ipa *ipa = dev_get_drvdata(&pdev->dev); | |
867 | struct rproc *rproc = ipa->modem_rproc; | |
868 | struct ipa_clock *clock = ipa->clock; | |
cdf2e941 AE |
869 | int ret; |
870 | ||
cdf2e941 AE |
871 | if (ipa->setup_complete) { |
872 | ret = ipa_modem_stop(ipa); | |
873 | if (ret) | |
874 | return ret; | |
875 | ||
876 | ipa_teardown(ipa); | |
877 | } | |
878 | ||
879 | ipa_deconfig(ipa); | |
880 | ipa_modem_exit(ipa); | |
881 | ipa_table_exit(ipa); | |
882 | ipa_endpoint_exit(ipa); | |
883 | gsi_exit(&ipa->gsi); | |
884 | ipa_mem_exit(ipa); | |
885 | ipa_reg_exit(ipa); | |
886 | kfree(ipa); | |
cdf2e941 AE |
887 | ipa_clock_exit(clock); |
888 | rproc_put(rproc); | |
889 | ||
890 | return 0; | |
891 | } | |
892 | ||
893 | /** | |
894 | * ipa_suspend() - Power management system suspend callback | |
895 | * @dev: IPA device structure | |
896 | * | |
e3eea08e | 897 | * Return: Always returns zero |
cdf2e941 AE |
898 | * |
899 | * Called by the PM framework when a system suspend operation is invoked. | |
dc6e6072 AE |
900 | * Suspends endpoints and releases the clock reference held to keep |
901 | * the IPA clock running until this point. | |
cdf2e941 AE |
902 | */ |
903 | static int ipa_suspend(struct device *dev) | |
904 | { | |
905 | struct ipa *ipa = dev_get_drvdata(dev); | |
906 | ||
3c6ccdde AE |
907 | /* When a suspended RX endpoint has a packet ready to receive, we |
908 | * get an IPA SUSPEND interrupt. We trigger a system resume in | |
909 | * that case, but only on the first such interrupt since suspend. | |
910 | */ | |
911 | __clear_bit(IPA_FLAG_RESUMED, ipa->flags); | |
912 | ||
dc6e6072 AE |
913 | ipa_endpoint_suspend(ipa); |
914 | ||
cdf2e941 | 915 | ipa_clock_put(ipa); |
cdf2e941 AE |
916 | |
917 | return 0; | |
918 | } | |
919 | ||
920 | /** | |
921 | * ipa_resume() - Power management system resume callback | |
922 | * @dev: IPA device structure | |
923 | * | |
e3eea08e | 924 | * Return: Always returns 0 |
cdf2e941 AE |
925 | * |
926 | * Called by the PM framework when a system resume operation is invoked. | |
dc6e6072 AE |
927 | * Takes an IPA clock reference to keep the clock running until suspend, |
928 | * and resumes endpoints. | |
cdf2e941 AE |
929 | */ |
930 | static int ipa_resume(struct device *dev) | |
931 | { | |
932 | struct ipa *ipa = dev_get_drvdata(dev); | |
933 | ||
934 | /* This clock reference will keep the IPA out of suspend | |
935 | * until we get a power management suspend request. | |
936 | */ | |
cdf2e941 AE |
937 | ipa_clock_get(ipa); |
938 | ||
dc6e6072 AE |
939 | ipa_endpoint_resume(ipa); |
940 | ||
cdf2e941 AE |
941 | return 0; |
942 | } | |
943 | ||
944 | static const struct dev_pm_ops ipa_pm_ops = { | |
a4f48458 AE |
945 | .suspend = ipa_suspend, |
946 | .resume = ipa_resume, | |
cdf2e941 AE |
947 | }; |
948 | ||
949 | static struct platform_driver ipa_driver = { | |
950 | .probe = ipa_probe, | |
951 | .remove = ipa_remove, | |
952 | .driver = { | |
953 | .name = "ipa", | |
cdf2e941 AE |
954 | .pm = &ipa_pm_ops, |
955 | .of_match_table = ipa_match, | |
956 | }, | |
957 | }; | |
958 | ||
959 | module_platform_driver(ipa_driver); | |
960 | ||
961 | MODULE_LICENSE("GPL v2"); | |
962 | MODULE_DESCRIPTION("Qualcomm IP Accelerator device driver"); |