blob: 139fd15047ec1b8c09bfaca32c95fe756377ce6e [file] [log] [blame]
Cliff Huang7e653d82022-01-21 17:36:20 -08001/* SPDX-License-Identifier: GPL-2.0-or-later */
2
3#include <acpi/acpigen.h>
4#include <acpi/acpi_device.h>
5#include "chip.h"
Cliff Huangca344f22023-03-02 10:08:17 -08006#include "soc/intel/common/block/include/intelblocks/acpi.h"
Cliff Huang7e653d82022-01-21 17:36:20 -08007#include "soc/intel/common/block/pcie/rtd3/chip.h"
8
9/* FCPO# to RESET# delay time during WWAN ON */
10#define FM350GL_TN2B 20
11/* RESET# to PERST# delay time during WWAN ON */
12#define FM350GL_TB2R 80
13/* The delay between de-assertion of PERST# to change of PDS state from 0 to 1 during WWAN ON */
14#define FM350GL_TR2P 0
15/* RESET# to FCPO# delay time during WWAN OFF */
16#define FM350GL_TB2F 10
17/* Time to allow the WWAN module to fully discharge any residual voltages before FCPO# could be
18 de-asserted again. */
19#define FM350GL_TFDI 500
20/* The delay between assertion and de-assertion RESET# during FLDR */
21#define FM350GL_TBTG 10
22/* The delay between de-assertion of RESET# and change of PDS state from 0 to 1 after FLDR */
23#define FM350GL_TBTP 170
24/* PERST# to RESET# delay time during WWAN OFF */
25#define FM350GL_TR2B 10
26/* 20s HW initialization needed after de-assertion of PERST#
27 However, it is not required and is not proper place to ensure HW initialization in ACPI. The
28 delay here is to ensure the following reset or RTD3 _OFF method won't be called immediately.
29 */
30#define FM350GL_TIME_HW_INIT 100
31
32enum reset_type {
33 RESET_TYPE_WARM = 0,
34 RESET_TYPE_COLD = 1
35};
36
37/*
38 * Returns the RTD3 PM methods requested and available to the device.
39 */
40static enum acpi_pcie_rp_pm_emit
41wwan_fm350gl_get_rtd3_method_support(const struct drivers_wwan_fm_config *config)
42{
43 const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
44
45 rtd3_config = config_of(config->rtd3dev);
46
47 return rtd3_config->ext_pm_support;
48}
49
50/*
51 * Generate first half reset flow (FHRF) method.
Subrata Banikb5fc0c42022-12-13 15:23:38 +053052 * Arg0 = 0; RESET_TYPE_WARM: warm reset
53 * Arg0 = 1; RESET_TYPE_COLD: cold reset
Cliff Huang7e653d82022-01-21 17:36:20 -080054 */
55static void wwan_fm350gl_acpi_method_fhrf(const struct device *parent_dev,
56 const struct drivers_wwan_fm_config *config)
57{
58 acpigen_write_method_serialized("FHRF", 1);
59 {
Cliff Huangca344f22023-03-02 10:08:17 -080060 char mutex_path[128];
61 const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
62
63 rtd3_config = config_of(config->rtd3dev);
64 if (rtd3_config->use_rp_mutex) {
Jamie Ryu6c0961a2023-06-08 10:41:11 -070065 snprintf(mutex_path, sizeof(mutex_path), "%s",
66 acpi_device_path_join(parent_dev, RP_MUTEX_NAME));
Cliff Huangca344f22023-03-02 10:08:17 -080067 /* Acquire root port mutex in case FHRF is called directly and not called from _RST */
68 acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT);
69 }
70
Cliff Huang7e653d82022-01-21 17:36:20 -080071 /* LOCAL0 = PERST# */
72 acpigen_get_tx_gpio(&config->perst_gpio);
73 acpigen_write_if_lequal_op_int(LOCAL0_OP, 0);
74 {
Angel Pons92d44992022-02-13 13:37:04 +010075 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -080076 ACPI_PCIE_RP_EMIT_L23) {
77 acpigen_emit_namestring(acpi_device_path_join(parent_dev,
78 "DL23"));
79 }
80 /* assert PERST# pin */
81 acpigen_enable_tx_gpio(&config->perst_gpio);
82 }
83 acpigen_write_if_end(); /* If */
84 acpigen_write_sleep(FM350GL_TR2B);
85 /* assert RESET# pin */
86 acpigen_enable_tx_gpio(&config->reset_gpio);
87 /* warm reset */
88 acpigen_write_if_lequal_op_int(ARG0_OP, RESET_TYPE_WARM);
89 {
90 acpigen_write_sleep(FM350GL_TBTG);
91 }
92 /* cold reset */
93 acpigen_write_else();
94 {
95 acpigen_write_if_lequal_op_int(ARG0_OP, RESET_TYPE_COLD);
96 {
97 /* disable source clock */
Angel Pons92d44992022-02-13 13:37:04 +010098 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -080099 ACPI_PCIE_RP_EMIT_SRCK) {
100 acpigen_emit_namestring(acpi_device_path_join(
101 parent_dev, "SRCK"));
102 acpigen_emit_byte(ZERO_OP);
103 }
104 acpigen_write_sleep(FM350GL_TB2F);
105 /* assert FCPO# pin */
106 acpigen_enable_tx_gpio(&config->fcpo_gpio);
107 acpigen_write_sleep(FM350GL_TFDI);
108 }
109 acpigen_write_if_end(); /* If */
110 }
111 acpigen_pop_len(); /* Else */
Cliff Huangca344f22023-03-02 10:08:17 -0800112
113 if (rtd3_config->use_rp_mutex)
114 acpigen_write_release(mutex_path);
Cliff Huang7e653d82022-01-21 17:36:20 -0800115 }
116 acpigen_write_method_end(); /* Method */
117}
118
119/*
120 * Generate second half reset flow (SHRF) method.
121 */
122static void wwan_fm350gl_acpi_method_shrf(const struct device *parent_dev,
123 const struct drivers_wwan_fm_config *config)
124{
125 acpigen_write_method_serialized("SHRF", 0);
126 {
Cliff Huangca344f22023-03-02 10:08:17 -0800127 char mutex_path[128];
128 const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
129
130 rtd3_config = config_of(config->rtd3dev);
131 if (rtd3_config->use_rp_mutex) {
Jamie Ryu6c0961a2023-06-08 10:41:11 -0700132 snprintf(mutex_path, sizeof(mutex_path), "%s",
133 acpi_device_path_join(parent_dev, RP_MUTEX_NAME));
Cliff Huangca344f22023-03-02 10:08:17 -0800134 /* Acquire root port mutex */
135 acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT);
136 }
137
Cliff Huang7e653d82022-01-21 17:36:20 -0800138 /* call rtd3 method to Disable ModPHY Power Gating. */
Angel Pons92d44992022-02-13 13:37:04 +0100139 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -0800140 ACPI_PCIE_RP_EMIT_PSD0) {
141 acpigen_emit_namestring(acpi_device_path_join(parent_dev,
142 "PSD0"));
143 }
144 /* call rtd3 method to Enable SRC Clock. */
Angel Pons92d44992022-02-13 13:37:04 +0100145 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -0800146 ACPI_PCIE_RP_EMIT_SRCK) {
147 acpigen_emit_namestring(acpi_device_path_join(parent_dev,
148 "SRCK"));
149 acpigen_emit_byte(ONE_OP);
150 }
151 /* De-assert FCPO# GPIO. */
152 acpigen_disable_tx_gpio(&config->fcpo_gpio);
153 acpigen_write_sleep(FM350GL_TN2B);
154 /* De-assert RESET# GPIO. */
155 acpigen_disable_tx_gpio(&config->reset_gpio);
156 acpigen_write_sleep(FM350GL_TB2R);
157 /* De-assert PERST# GPIO. */
158 acpigen_disable_tx_gpio(&config->perst_gpio);
159 /* Call rtd3 method to trigger L2/L3 ready exit flow in root port */
Angel Pons92d44992022-02-13 13:37:04 +0100160 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -0800161 ACPI_PCIE_RP_EMIT_L23) {
162 acpigen_emit_namestring(acpi_device_path_join(parent_dev,
163 "L23D"));
164 }
165 acpigen_write_sleep(FM350GL_TIME_HW_INIT);
Cliff Huangca344f22023-03-02 10:08:17 -0800166
167 if (rtd3_config->use_rp_mutex)
168 acpigen_write_release(mutex_path);
Cliff Huang7e653d82022-01-21 17:36:20 -0800169 }
170 acpigen_write_method_end(); /* Method */
171}
172
173/*
174 * Generate _RST method. This is to perform a soft reset. It is added under
175 * PXSX. This is called during device driver removal.
176 */
177static void wwan_fm350gl_acpi_method_rst(const struct device *parent_dev,
178 const struct drivers_wwan_fm_config *config)
179{
180 acpigen_write_method_serialized("_RST", 0);
181 {
Cliff Huangca344f22023-03-02 10:08:17 -0800182 char mutex_path[128];
183 const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
184
185 rtd3_config = config_of(config->rtd3dev);
186 if (rtd3_config->use_rp_mutex) {
Jamie Ryu6c0961a2023-06-08 10:41:11 -0700187 snprintf(mutex_path, sizeof(mutex_path), "%s",
188 acpi_device_path_join(parent_dev, RP_MUTEX_NAME));
Cliff Huangca344f22023-03-02 10:08:17 -0800189 /* Acquire root port mutex */
190 acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT);
191 }
192
Cliff Huang7e653d82022-01-21 17:36:20 -0800193 /* Perform 1st Half of FLDR Flow for soft reset: FHRF(0) */
194 acpigen_emit_namestring("FHRF");
195 acpigen_emit_byte(RESET_TYPE_WARM);
196 /* Perform 2nd Half of FLDR Flow: SHRF() */
197 acpigen_emit_namestring("SHRF");
198 /* Indicates that the following _Off will be skipped. */
199 acpigen_emit_byte(INCREMENT_OP);
200 acpigen_emit_namestring(acpi_device_path_join(parent_dev, "RTD3.OFSK"));
Cliff Huangca344f22023-03-02 10:08:17 -0800201
202 if (rtd3_config->use_rp_mutex)
203 acpigen_write_release(mutex_path);
Cliff Huang7e653d82022-01-21 17:36:20 -0800204 }
205 acpigen_write_method_end(); /* Method */
206}
207
208/*
209 * Generate _RST method. This is to perform a cold reset. This reset will be
210 * included under PXSX.MRST. This method is used during device firmware update.
211 */
212static void wwan_fm350gl_acpi_method_mrst_rst(const struct device *parent_dev,
213 const struct drivers_wwan_fm_config *config)
214{
215 acpigen_write_method_serialized("_RST", 0);
216 {
Cliff Huangca344f22023-03-02 10:08:17 -0800217 char mutex_path[128];
218 const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
219
220 rtd3_config = config_of(config->rtd3dev);
221 if (rtd3_config->use_rp_mutex) {
Jamie Ryu6c0961a2023-06-08 10:41:11 -0700222 snprintf(mutex_path, sizeof(mutex_path), "%s",
223 acpi_device_path_join(parent_dev, RP_MUTEX_NAME));
Cliff Huangca344f22023-03-02 10:08:17 -0800224 /* Acquire root port mutex */
225 acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT);
226 }
227
Cliff Huang7e653d82022-01-21 17:36:20 -0800228 /* Perform 1st Half of FLDR Flow for cold reset: FHRF (1) */
229 acpigen_emit_namestring("FHRF");
230 acpigen_emit_byte(RESET_TYPE_COLD);
231 /* Perform 2nd Half of FLDR Flow: SHRF () */
232 acpigen_emit_namestring("SHRF");
233 /* Indicate kernel ACPI PM to skip _off RTD3 after reset at the end of
234 driver removal */
235 acpigen_emit_byte(INCREMENT_OP);
236 acpigen_emit_namestring(acpi_device_path_join(parent_dev, "RTD3.OFSK"));
Cliff Huangca344f22023-03-02 10:08:17 -0800237
238 if (rtd3_config->use_rp_mutex)
239 acpigen_write_release(mutex_path);
Cliff Huang7e653d82022-01-21 17:36:20 -0800240 }
241 acpigen_write_method_end(); /* Method */
242}
243
Cliff Huang96bb0ba2022-02-11 17:46:00 -0800244/*
245 * Generate DPTS (Device Prepare To Seep) Method. This is called in
246 * \.SB.MPTS Method.
247 */
248static void wwan_fm350gl_acpi_method_dpts(const struct device *parent_dev,
249 const struct drivers_wwan_fm_config *config)
250{
251 acpigen_write_method_serialized("DPTS", 1);
252 {
253 /* Perform 1st Half of FLDR Flow for cold reset: FHRF (1) */
254 acpigen_emit_namestring("FHRF");
255 acpigen_emit_byte(RESET_TYPE_COLD);
256 }
257 acpigen_write_method_end(); /* Method */
258}
259
Cliff Huang7e653d82022-01-21 17:36:20 -0800260static const char *wwan_fm350gl_acpi_name(const struct device *dev)
261{
262 /* Attached device name must be "PXSX" for the Linux Kernel to recognize it. */
263 return "PXSX";
264}
265
266static void wwan_fm350gl_acpi_fill_ssdt(const struct device *dev)
267{
268 const struct drivers_wwan_fm_config *config = config_of(dev);
269 const struct device *parent = dev->bus->dev;
270 const char *scope = acpi_device_path(parent);
Cliff Huangca344f22023-03-02 10:08:17 -0800271 const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
Cliff Huang7e653d82022-01-21 17:36:20 -0800272
273 if (!is_dev_enabled(parent)) {
274 printk(BIOS_ERR, "%s: root port not enabled\n", __func__);
275 return;
276 }
277 if (!scope) {
278 printk(BIOS_ERR, "%s: root port scope not found\n", __func__);
279 return;
280 }
281 if (!config->fcpo_gpio.pin_count && !config->reset_gpio.pin_count &&
282 !config->perst_gpio.pin_count) {
283 printk(BIOS_ERR, "%s: FCPO, RESET, PERST GPIO required for %s.\n",
284 __func__, scope);
285 return;
286 }
Cliff Huangca344f22023-03-02 10:08:17 -0800287
288 rtd3_config = config_of(config->rtd3dev);
289 if (!rtd3_config->use_rp_mutex)
290 printk(BIOS_WARNING, "%s: RTD3 must use root port mutex.\n",
291 __func__);
292
Cliff Huang7e653d82022-01-21 17:36:20 -0800293 printk(BIOS_INFO, "%s: Enable WWAN for %s (%s)\n", scope, dev_path(parent),
294 config->desc ?: dev->chip_ops->name);
295 acpigen_write_scope(scope);
296 {
297 acpigen_write_device(wwan_fm350gl_acpi_name(dev));
298 {
299 acpigen_write_ADR(0);
300 if (config->name)
301 acpigen_write_name_string("_DDN", config->name);
302 if (config->desc)
303 acpigen_write_name_unicode("_STR", config->desc);
304 wwan_fm350gl_acpi_method_fhrf(parent, config);
305 wwan_fm350gl_acpi_method_shrf(parent, config);
306 wwan_fm350gl_acpi_method_rst(parent, config);
Cliff Huang96bb0ba2022-02-11 17:46:00 -0800307 wwan_fm350gl_acpi_method_dpts(parent, config);
Tim Wawrzynczak02927032022-02-28 08:57:09 -0700308
Kapil Porwal0b20a172022-11-26 20:10:47 +0530309 if (config->add_acpi_dma_property)
310 acpi_device_add_dma_property(NULL);
Tim Wawrzynczak02927032022-02-28 08:57:09 -0700311
Cliff Huang7e653d82022-01-21 17:36:20 -0800312 /* NOTE: the 5G driver will call MRST._RST to trigger a cold reset
313 * during firmware update.
314 */
315 acpigen_write_device("MRST");
316 {
317 acpigen_write_ADR(0);
318 wwan_fm350gl_acpi_method_mrst_rst(parent, config);
319 }
Tim Wawrzynczak02927032022-02-28 08:57:09 -0700320
Cliff Huang7e653d82022-01-21 17:36:20 -0800321 acpigen_write_device_end(); /* Device */
322 }
323 acpigen_write_device_end(); /* Device */
324 }
325 acpigen_write_scope_end(); /* Scope */
326}
327
328static struct device_operations wwan_fm350gl_ops = {
329 .read_resources = noop_read_resources,
330 .set_resources = noop_set_resources,
331 .acpi_fill_ssdt = wwan_fm350gl_acpi_fill_ssdt,
Cliff Huang96bb0ba2022-02-11 17:46:00 -0800332 .acpi_name = wwan_fm350gl_acpi_name
Cliff Huang7e653d82022-01-21 17:36:20 -0800333};
334
335static void wwan_fm350gl_acpi_enable(struct device *dev)
336{
337 dev->ops = &wwan_fm350gl_ops;
338}
339
340struct chip_operations drivers_wwan_fm_ops = {
341 CHIP_NAME("Fibocom FM-350-GL")
342 .enable_dev = wwan_fm350gl_acpi_enable
343};