xref: /aosp_15_r20/external/coreboot/src/drivers/wwan/fm/acpi_fm350gl.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <acpi/acpigen.h>
4 #include <acpi/acpi_device.h>
5 #include <gpio.h>
6 #include <stdio.h>
7 #include "chip.h"
8 #include "soc/intel/common/block/include/intelblocks/acpi.h"
9 #include "soc/intel/common/block/pcie/rtd3/chip.h"
10 
11 /* FCPO# to RESET# delay time during WWAN ON */
12 #define FM350GL_TN2B 20
13 /* RESET# to PERST# delay time during WWAN ON */
14 #define FM350GL_TB2R 80
15 /* The delay between de-assertion of PERST# to change of PDS state from 0 to 1 during WWAN ON */
16 #define FM350GL_TR2P 0
17 /* RESET# to FCPO# delay time during WWAN OFF */
18 #define FM350GL_TB2F 10
19 /* Time to allow the WWAN module to fully discharge any residual voltages before FCPO# could be
20    de-asserted again. */
21 #define FM350GL_TFDI 500
22 /* The delay between assertion and de-assertion RESET# during FLDR */
23 #define FM350GL_TBTG 10
24 /* The delay between de-assertion of RESET# and change of PDS state from 0 to 1 after FLDR */
25 #define FM350GL_TBTP 170
26 /* PERST# to RESET# delay time during WWAN OFF */
27 #define FM350GL_TR2B 10
28 /* 20s HW initialization needed after de-assertion of PERST#
29    However, it is not required and is not proper place to ensure HW initialization in ACPI. The
30    delay here is to ensure the following reset or RTD3 _OFF method won't be called immediately.
31  */
32 #define FM350GL_TIME_HW_INIT 100
33 
34 enum reset_type {
35 	RESET_TYPE_WARM = 0,
36 	RESET_TYPE_COLD = 1
37 };
38 
39 /*
40  *  Returns the RTD3 PM methods requested and available to the device.
41  */
42 static enum acpi_pcie_rp_pm_emit
wwan_fm350gl_get_rtd3_method_support(const struct drivers_wwan_fm_config * config)43 wwan_fm350gl_get_rtd3_method_support(const struct drivers_wwan_fm_config *config)
44 {
45 	const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
46 
47 	rtd3_config = config_of(config->rtd3dev);
48 
49 	return rtd3_config->ext_pm_support;
50 }
51 
52 /*
53  *  Generate first half reset flow (FHRF) method.
54  *  Arg0 = 0; RESET_TYPE_WARM: warm reset
55  *  Arg0 = 1; RESET_TYPE_COLD: cold reset
56  */
wwan_fm350gl_acpi_method_fhrf(const struct device * parent_dev,const struct drivers_wwan_fm_config * config)57 static void wwan_fm350gl_acpi_method_fhrf(const struct device *parent_dev,
58 	const struct drivers_wwan_fm_config *config)
59 {
60 	acpigen_write_method_serialized("FHRF", 1);
61 	{
62 		char mutex_path[128];
63 		const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
64 
65 		rtd3_config = config_of(config->rtd3dev);
66 		if (rtd3_config->use_rp_mutex) {
67 			snprintf(mutex_path, sizeof(mutex_path), "%s",
68 				acpi_device_path_join(parent_dev, RP_MUTEX_NAME));
69 			/* Acquire root port mutex in case FHRF is called directly and not called from _RST */
70 			acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT);
71 		}
72 
73 		/* LOCAL0 = PERST# */
74 		acpigen_get_tx_gpio(&config->perst_gpio);
75 		acpigen_write_if_lequal_op_int(LOCAL0_OP, 0);
76 		{
77 			if (wwan_fm350gl_get_rtd3_method_support(config) &
78 				ACPI_PCIE_RP_EMIT_L23) {
79 				acpigen_emit_namestring(acpi_device_path_join(parent_dev,
80 					"DL23"));
81 			}
82 			/* assert PERST# pin */
83 			acpigen_enable_tx_gpio(&config->perst_gpio);
84 		}
85 		acpigen_write_if_end(); /* If */
86 		acpigen_write_sleep(FM350GL_TR2B);
87 		/* assert RESET# pin */
88 		acpigen_enable_tx_gpio(&config->reset_gpio);
89 		/* warm reset */
90 		acpigen_write_if_lequal_op_int(ARG0_OP, RESET_TYPE_WARM);
91 		{
92 			acpigen_write_sleep(FM350GL_TBTG);
93 		}
94 		/* cold reset */
95 		acpigen_write_else();
96 		{
97 			acpigen_write_if_lequal_op_int(ARG0_OP, RESET_TYPE_COLD);
98 			{
99 				/* disable source clock */
100 				if (wwan_fm350gl_get_rtd3_method_support(config) &
101 					ACPI_PCIE_RP_EMIT_SRCK) {
102 					acpigen_emit_namestring(acpi_device_path_join(
103 						parent_dev, "SRCK"));
104 					acpigen_emit_byte(ZERO_OP);
105 				}
106 				acpigen_write_sleep(FM350GL_TB2F);
107 				/* assert FCPO# pin */
108 				acpigen_enable_tx_gpio(&config->fcpo_gpio);
109 				acpigen_write_sleep(FM350GL_TFDI);
110 			}
111 			acpigen_write_if_end(); /* If */
112 		}
113 		acpigen_pop_len(); /* Else */
114 
115 		if (rtd3_config->use_rp_mutex)
116 			acpigen_write_release(mutex_path);
117 	}
118 	acpigen_write_method_end(); /* Method */
119 }
120 
121 /*
122  *  Generate second half reset flow (SHRF) method.
123  */
wwan_fm350gl_acpi_method_shrf(const struct device * parent_dev,const struct drivers_wwan_fm_config * config)124 static void wwan_fm350gl_acpi_method_shrf(const struct device *parent_dev,
125 		const struct drivers_wwan_fm_config *config)
126 {
127 	acpigen_write_method_serialized("SHRF", 0);
128 	{
129 		char mutex_path[128];
130 		const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
131 
132 		rtd3_config = config_of(config->rtd3dev);
133 		if (rtd3_config->use_rp_mutex) {
134 			snprintf(mutex_path, sizeof(mutex_path), "%s",
135 				acpi_device_path_join(parent_dev, RP_MUTEX_NAME));
136 			/* Acquire root port mutex */
137 			acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT);
138 		}
139 
140 		/* call rtd3 method to Disable ModPHY Power Gating. */
141 		if (wwan_fm350gl_get_rtd3_method_support(config) &
142 			ACPI_PCIE_RP_EMIT_PSD0) {
143 			acpigen_emit_namestring(acpi_device_path_join(parent_dev,
144 				"PSD0"));
145 		}
146 		/* call rtd3 method to Enable SRC Clock. */
147 		if (wwan_fm350gl_get_rtd3_method_support(config) &
148 			ACPI_PCIE_RP_EMIT_SRCK) {
149 			acpigen_emit_namestring(acpi_device_path_join(parent_dev,
150 				"SRCK"));
151 			acpigen_emit_byte(ONE_OP);
152 		}
153 		/* De-assert FCPO# GPIO. */
154 		acpigen_disable_tx_gpio(&config->fcpo_gpio);
155 		acpigen_write_sleep(FM350GL_TN2B);
156 		/* De-assert RESET# GPIO. */
157 		acpigen_disable_tx_gpio(&config->reset_gpio);
158 		acpigen_write_sleep(FM350GL_TB2R);
159 		/* De-assert PERST# GPIO. */
160 		acpigen_disable_tx_gpio(&config->perst_gpio);
161 		/* Call rtd3 method to trigger L2/L3 ready exit flow in root port */
162 		if (wwan_fm350gl_get_rtd3_method_support(config) &
163 			ACPI_PCIE_RP_EMIT_L23) {
164 			acpigen_emit_namestring(acpi_device_path_join(parent_dev,
165 				"L23D"));
166 		}
167 		acpigen_write_sleep(FM350GL_TIME_HW_INIT);
168 
169 		if (rtd3_config->use_rp_mutex)
170 			acpigen_write_release(mutex_path);
171 	}
172 	acpigen_write_method_end(); /* Method */
173 }
174 
175 /*
176  * Generate _RST method. This is to perform a soft reset. It is added under
177  * PXSX. This is called during device driver removal.
178  */
wwan_fm350gl_acpi_method_rst(const struct device * parent_dev,const struct drivers_wwan_fm_config * config)179 static void wwan_fm350gl_acpi_method_rst(const struct device *parent_dev,
180 			 const struct drivers_wwan_fm_config *config)
181 {
182 	acpigen_write_method_serialized("_RST", 0);
183 	{
184 		char mutex_path[128];
185 		const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
186 
187 		rtd3_config = config_of(config->rtd3dev);
188 		if (rtd3_config->use_rp_mutex) {
189 			snprintf(mutex_path, sizeof(mutex_path), "%s",
190 				acpi_device_path_join(parent_dev, RP_MUTEX_NAME));
191 			/* Acquire root port mutex */
192 			acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT);
193 		}
194 
195 		/* Perform 1st Half of FLDR Flow for soft reset: FHRF(0) */
196 		acpigen_emit_namestring("FHRF");
197 		acpigen_emit_byte(RESET_TYPE_WARM);
198 		/* Perform 2nd Half of FLDR Flow: SHRF() */
199 		acpigen_emit_namestring("SHRF");
200 		/* Indicates that the following _Off will be skipped. */
201 		acpigen_emit_byte(INCREMENT_OP);
202 		acpigen_emit_namestring(acpi_device_path_join(parent_dev, "RTD3.OFSK"));
203 
204 		if (rtd3_config->use_rp_mutex)
205 			acpigen_write_release(mutex_path);
206 	}
207 	acpigen_write_method_end(); /* Method */
208 }
209 
210 /*
211  * Generate _RST method. This is to perform a cold reset. This reset will be
212  * included under PXSX.MRST. This method is used during device firmware update.
213  */
wwan_fm350gl_acpi_method_mrst_rst(const struct device * parent_dev,const struct drivers_wwan_fm_config * config)214 static void wwan_fm350gl_acpi_method_mrst_rst(const struct device *parent_dev,
215 			 const struct drivers_wwan_fm_config *config)
216 {
217 	acpigen_write_method_serialized("_RST", 0);
218 	{
219 		char mutex_path[128];
220 		const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
221 
222 		rtd3_config = config_of(config->rtd3dev);
223 		if (rtd3_config->use_rp_mutex) {
224 			snprintf(mutex_path, sizeof(mutex_path), "%s",
225 				acpi_device_path_join(parent_dev, RP_MUTEX_NAME));
226 			/* Acquire root port mutex */
227 			acpigen_write_acquire(mutex_path, ACPI_MUTEX_NO_TIMEOUT);
228 		}
229 
230 		/* Perform 1st Half of FLDR Flow for cold reset: FHRF (1) */
231 		acpigen_emit_namestring("FHRF");
232 		acpigen_emit_byte(RESET_TYPE_COLD);
233 		/* Perform 2nd Half of FLDR Flow: SHRF () */
234 		acpigen_emit_namestring("SHRF");
235 		/* Indicate kernel ACPI PM to skip _off RTD3 after reset at the end of
236 		   driver removal */
237 		acpigen_emit_byte(INCREMENT_OP);
238 		acpigen_emit_namestring(acpi_device_path_join(parent_dev, "RTD3.OFSK"));
239 
240 		if (rtd3_config->use_rp_mutex)
241 			acpigen_write_release(mutex_path);
242 	}
243 	acpigen_write_method_end(); /* Method */
244 }
245 
246 /*
247  * Generate DPTS (Device Prepare To Seep) Method. This is called in
248  *  \.SB.MPTS Method.
249  */
wwan_fm350gl_acpi_method_dpts(const struct device * parent_dev,const struct drivers_wwan_fm_config * config)250 static void wwan_fm350gl_acpi_method_dpts(const struct device *parent_dev,
251 			 const struct drivers_wwan_fm_config *config)
252 {
253 	acpigen_write_method_serialized("DPTS", 1);
254 	{
255 		/* Perform 1st Half of FLDR Flow for cold reset: FHRF (1) */
256 		acpigen_emit_namestring("FHRF");
257 		acpigen_emit_byte(RESET_TYPE_COLD);
258 	}
259 	acpigen_write_method_end(); /* Method */
260 }
261 
wwan_fm350gl_acpi_name(const struct device * dev)262 static const char *wwan_fm350gl_acpi_name(const struct device *dev)
263 {
264 	/* Attached device name must be "PXSX" for the Linux Kernel to recognize it. */
265 	return "PXSX";
266 }
267 
268 static void
wwan_fm350gl_acpi_event_interrupts(const struct acpi_gpio * wake_gpio)269 wwan_fm350gl_acpi_event_interrupts(const struct acpi_gpio *wake_gpio)
270 {
271 	acpigen_write_name("_AEI");
272 	acpigen_write_resourcetemplate_header();
273 	acpi_device_write_gpio(wake_gpio);
274 	acpigen_write_resourcetemplate_footer();
275 }
276 
277 static void
wwan_fm350gl_acpi_event_method(const struct device * dev,const struct acpi_gpio * wake_gpio)278 wwan_fm350gl_acpi_event_method(const struct device *dev,
279 			       const struct acpi_gpio *wake_gpio)
280 {
281 	char name[5];
282 	uint16_t pin;
283 
284 	pin = wake_gpio->pins[0];
285 	if (CONFIG(GENERIC_GPIO_LIB))
286 		pin = gpio_acpi_pin(pin);
287 
288 	if (pin > 0xff) {
289 		printk(BIOS_ERR, "%s: pins above 0xFF are unsupported (pin %u)\n",
290 		       __func__, pin);
291 		return;
292 	}
293 
294 	snprintf(name, sizeof(name), "_%c%02X",
295 		 wake_gpio->irq.mode == ACPI_IRQ_EDGE_TRIGGERED ? 'E' : 'L', pin);
296 
297 	acpigen_write_method_serialized(name, 0);
298 	acpigen_notify(acpi_device_path(dev), 0x02); /* NOTIFY_DEVICE_WAKE */
299 	acpigen_write_method_end();
300 }
301 
wwan_fm350gl_acpi_gpio_events(const struct device * dev)302 static void wwan_fm350gl_acpi_gpio_events(const struct device *dev)
303 {
304 	const struct drivers_wwan_fm_config *config = config_of(dev);
305 	const struct acpi_gpio *wake_gpio = &config->wake_gpio;
306 
307 	/* Write into GPIO controller's scope */
308 	if (CONFIG(GENERIC_GPIO_LIB))
309 		acpigen_write_scope(wake_gpio->resource ? : gpio_acpi_path(wake_gpio->pins[0]));
310 	else
311 		acpigen_write_scope(wake_gpio->resource);
312 	wwan_fm350gl_acpi_event_interrupts(wake_gpio);
313 	wwan_fm350gl_acpi_event_method(dev, wake_gpio);
314 	acpigen_write_scope_end();
315 }
316 
wwan_fm350gl_acpi_fill_ssdt(const struct device * dev)317 static void wwan_fm350gl_acpi_fill_ssdt(const struct device *dev)
318 {
319 	const struct drivers_wwan_fm_config *config = config_of(dev);
320 	const struct device *parent = dev->upstream->dev;
321 	const char *scope = acpi_device_path(parent);
322 	const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
323 
324 	if (!is_dev_enabled(parent)) {
325 		printk(BIOS_ERR, "%s: root port not enabled\n", __func__);
326 		return;
327 	}
328 	if (!scope) {
329 		printk(BIOS_ERR, "%s: root port scope not found\n", __func__);
330 		return;
331 	}
332 	if (!config->fcpo_gpio.pin_count && !config->reset_gpio.pin_count &&
333 		!config->perst_gpio.pin_count) {
334 		printk(BIOS_ERR, "%s: FCPO, RESET, PERST GPIO required for %s.\n",
335 			 __func__, scope);
336 		return;
337 	}
338 
339 	rtd3_config = config_of(config->rtd3dev);
340 	if (!rtd3_config->use_rp_mutex)
341 		printk(BIOS_WARNING, "%s: RTD3 must use root port mutex.\n",
342 			__func__);
343 
344 	printk(BIOS_INFO, "%s: Enable WWAN for %s (%s)\n", scope, dev_path(parent),
345 		config->desc ?: dev->chip_ops->name);
346 	acpigen_write_scope(scope);
347 	{
348 		acpigen_write_device(wwan_fm350gl_acpi_name(dev));
349 		{
350 			acpigen_write_ADR(0);
351 			if (config->name)
352 				acpigen_write_name_string("_DDN", config->name);
353 			if (config->desc)
354 				acpigen_write_name_unicode("_STR", config->desc);
355 			wwan_fm350gl_acpi_method_fhrf(parent, config);
356 			wwan_fm350gl_acpi_method_shrf(parent, config);
357 			wwan_fm350gl_acpi_method_rst(parent, config);
358 			wwan_fm350gl_acpi_method_dpts(parent, config);
359 
360 			if (config->add_acpi_dma_property)
361 				acpi_device_add_dma_property(NULL);
362 
363 			/* NOTE: the 5G driver will call MRST._RST to trigger a cold reset
364 			 * during firmware update.
365 			 */
366 			acpigen_write_device("MRST");
367 			{
368 				acpigen_write_ADR(0);
369 				wwan_fm350gl_acpi_method_mrst_rst(parent, config);
370 			}
371 
372 			acpigen_write_device_end(); /* Device */
373 		}
374 		acpigen_write_device_end(); /* Device */
375 	}
376 	acpigen_write_scope_end(); /* Scope */
377 
378 	if (config->wake_gpio.pin_count && config->wake_gpio.type == ACPI_GPIO_TYPE_INTERRUPT)
379 		wwan_fm350gl_acpi_gpio_events(dev);
380 }
381 
382 static struct device_operations wwan_fm350gl_ops = {
383 	.read_resources  = noop_read_resources,
384 	.set_resources   = noop_set_resources,
385 	.acpi_fill_ssdt  = wwan_fm350gl_acpi_fill_ssdt,
386 	.acpi_name       = wwan_fm350gl_acpi_name
387 };
388 
wwan_fm350gl_acpi_enable(struct device * dev)389 static void wwan_fm350gl_acpi_enable(struct device *dev)
390 {
391 	dev->ops = &wwan_fm350gl_ops;
392 }
393 
394 struct chip_operations drivers_wwan_fm_ops = {
395 	 .name = "Fibocom FM-350-GL",
396 	.enable_dev = wwan_fm350gl_acpi_enable
397 };
398