blob: df91389f2297521beb2abad3c841ba5d93f3c0e7 [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"
6#include "soc/intel/common/block/pcie/rtd3/chip.h"
7
8/* FCPO# to RESET# delay time during WWAN ON */
9#define FM350GL_TN2B 20
10/* RESET# to PERST# delay time during WWAN ON */
11#define FM350GL_TB2R 80
12/* The delay between de-assertion of PERST# to change of PDS state from 0 to 1 during WWAN ON */
13#define FM350GL_TR2P 0
14/* RESET# to FCPO# delay time during WWAN OFF */
15#define FM350GL_TB2F 10
16/* Time to allow the WWAN module to fully discharge any residual voltages before FCPO# could be
17 de-asserted again. */
18#define FM350GL_TFDI 500
19/* The delay between assertion and de-assertion RESET# during FLDR */
20#define FM350GL_TBTG 10
21/* The delay between de-assertion of RESET# and change of PDS state from 0 to 1 after FLDR */
22#define FM350GL_TBTP 170
23/* PERST# to RESET# delay time during WWAN OFF */
24#define FM350GL_TR2B 10
25/* 20s HW initialization needed after de-assertion of PERST#
26 However, it is not required and is not proper place to ensure HW initialization in ACPI. The
27 delay here is to ensure the following reset or RTD3 _OFF method won't be called immediately.
28 */
29#define FM350GL_TIME_HW_INIT 100
30
31enum reset_type {
32 RESET_TYPE_WARM = 0,
33 RESET_TYPE_COLD = 1
34};
35
36/*
37 * Returns the RTD3 PM methods requested and available to the device.
38 */
39static enum acpi_pcie_rp_pm_emit
40wwan_fm350gl_get_rtd3_method_support(const struct drivers_wwan_fm_config *config)
41{
42 const struct soc_intel_common_block_pcie_rtd3_config *rtd3_config;
43
44 rtd3_config = config_of(config->rtd3dev);
45
46 return rtd3_config->ext_pm_support;
47}
48
49/*
50 * Generate first half reset flow (FHRF) method.
Subrata Banikb5fc0c42022-12-13 15:23:38 +053051 * Arg0 = 0; RESET_TYPE_WARM: warm reset
52 * Arg0 = 1; RESET_TYPE_COLD: cold reset
Cliff Huang7e653d82022-01-21 17:36:20 -080053 */
54static void wwan_fm350gl_acpi_method_fhrf(const struct device *parent_dev,
55 const struct drivers_wwan_fm_config *config)
56{
57 acpigen_write_method_serialized("FHRF", 1);
58 {
59 /* LOCAL0 = PERST# */
60 acpigen_get_tx_gpio(&config->perst_gpio);
61 acpigen_write_if_lequal_op_int(LOCAL0_OP, 0);
62 {
Angel Pons92d44992022-02-13 13:37:04 +010063 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -080064 ACPI_PCIE_RP_EMIT_L23) {
65 acpigen_emit_namestring(acpi_device_path_join(parent_dev,
66 "DL23"));
67 }
68 /* assert PERST# pin */
69 acpigen_enable_tx_gpio(&config->perst_gpio);
70 }
71 acpigen_write_if_end(); /* If */
72 acpigen_write_sleep(FM350GL_TR2B);
73 /* assert RESET# pin */
74 acpigen_enable_tx_gpio(&config->reset_gpio);
75 /* warm reset */
76 acpigen_write_if_lequal_op_int(ARG0_OP, RESET_TYPE_WARM);
77 {
78 acpigen_write_sleep(FM350GL_TBTG);
79 }
80 /* cold reset */
81 acpigen_write_else();
82 {
83 acpigen_write_if_lequal_op_int(ARG0_OP, RESET_TYPE_COLD);
84 {
85 /* disable source clock */
Angel Pons92d44992022-02-13 13:37:04 +010086 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -080087 ACPI_PCIE_RP_EMIT_SRCK) {
88 acpigen_emit_namestring(acpi_device_path_join(
89 parent_dev, "SRCK"));
90 acpigen_emit_byte(ZERO_OP);
91 }
92 acpigen_write_sleep(FM350GL_TB2F);
93 /* assert FCPO# pin */
94 acpigen_enable_tx_gpio(&config->fcpo_gpio);
95 acpigen_write_sleep(FM350GL_TFDI);
96 }
97 acpigen_write_if_end(); /* If */
98 }
99 acpigen_pop_len(); /* Else */
100 }
101 acpigen_write_method_end(); /* Method */
102}
103
104/*
105 * Generate second half reset flow (SHRF) method.
106 */
107static void wwan_fm350gl_acpi_method_shrf(const struct device *parent_dev,
108 const struct drivers_wwan_fm_config *config)
109{
110 acpigen_write_method_serialized("SHRF", 0);
111 {
112 /* call rtd3 method to Disable ModPHY Power Gating. */
Angel Pons92d44992022-02-13 13:37:04 +0100113 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -0800114 ACPI_PCIE_RP_EMIT_PSD0) {
115 acpigen_emit_namestring(acpi_device_path_join(parent_dev,
116 "PSD0"));
117 }
118 /* call rtd3 method to Enable SRC Clock. */
Angel Pons92d44992022-02-13 13:37:04 +0100119 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -0800120 ACPI_PCIE_RP_EMIT_SRCK) {
121 acpigen_emit_namestring(acpi_device_path_join(parent_dev,
122 "SRCK"));
123 acpigen_emit_byte(ONE_OP);
124 }
125 /* De-assert FCPO# GPIO. */
126 acpigen_disable_tx_gpio(&config->fcpo_gpio);
127 acpigen_write_sleep(FM350GL_TN2B);
128 /* De-assert RESET# GPIO. */
129 acpigen_disable_tx_gpio(&config->reset_gpio);
130 acpigen_write_sleep(FM350GL_TB2R);
131 /* De-assert PERST# GPIO. */
132 acpigen_disable_tx_gpio(&config->perst_gpio);
133 /* Call rtd3 method to trigger L2/L3 ready exit flow in root port */
Angel Pons92d44992022-02-13 13:37:04 +0100134 if (wwan_fm350gl_get_rtd3_method_support(config) &
Cliff Huang7e653d82022-01-21 17:36:20 -0800135 ACPI_PCIE_RP_EMIT_L23) {
136 acpigen_emit_namestring(acpi_device_path_join(parent_dev,
137 "L23D"));
138 }
139 acpigen_write_sleep(FM350GL_TIME_HW_INIT);
140 }
141 acpigen_write_method_end(); /* Method */
142}
143
144/*
145 * Generate _RST method. This is to perform a soft reset. It is added under
146 * PXSX. This is called during device driver removal.
147 */
148static void wwan_fm350gl_acpi_method_rst(const struct device *parent_dev,
149 const struct drivers_wwan_fm_config *config)
150{
151 acpigen_write_method_serialized("_RST", 0);
152 {
153 /* Perform 1st Half of FLDR Flow for soft reset: FHRF(0) */
154 acpigen_emit_namestring("FHRF");
155 acpigen_emit_byte(RESET_TYPE_WARM);
156 /* Perform 2nd Half of FLDR Flow: SHRF() */
157 acpigen_emit_namestring("SHRF");
158 /* Indicates that the following _Off will be skipped. */
159 acpigen_emit_byte(INCREMENT_OP);
160 acpigen_emit_namestring(acpi_device_path_join(parent_dev, "RTD3.OFSK"));
161 }
162 acpigen_write_method_end(); /* Method */
163}
164
165/*
166 * Generate _RST method. This is to perform a cold reset. This reset will be
167 * included under PXSX.MRST. This method is used during device firmware update.
168 */
169static void wwan_fm350gl_acpi_method_mrst_rst(const struct device *parent_dev,
170 const struct drivers_wwan_fm_config *config)
171{
172 acpigen_write_method_serialized("_RST", 0);
173 {
174 /* Perform 1st Half of FLDR Flow for cold reset: FHRF (1) */
175 acpigen_emit_namestring("FHRF");
176 acpigen_emit_byte(RESET_TYPE_COLD);
177 /* Perform 2nd Half of FLDR Flow: SHRF () */
178 acpigen_emit_namestring("SHRF");
179 /* Indicate kernel ACPI PM to skip _off RTD3 after reset at the end of
180 driver removal */
181 acpigen_emit_byte(INCREMENT_OP);
182 acpigen_emit_namestring(acpi_device_path_join(parent_dev, "RTD3.OFSK"));
183 }
184 acpigen_write_method_end(); /* Method */
185}
186
Cliff Huang96bb0ba2022-02-11 17:46:00 -0800187/*
188 * Generate DPTS (Device Prepare To Seep) Method. This is called in
189 * \.SB.MPTS Method.
190 */
191static void wwan_fm350gl_acpi_method_dpts(const struct device *parent_dev,
192 const struct drivers_wwan_fm_config *config)
193{
194 acpigen_write_method_serialized("DPTS", 1);
195 {
196 /* Perform 1st Half of FLDR Flow for cold reset: FHRF (1) */
197 acpigen_emit_namestring("FHRF");
198 acpigen_emit_byte(RESET_TYPE_COLD);
199 }
200 acpigen_write_method_end(); /* Method */
201}
202
Cliff Huang7e653d82022-01-21 17:36:20 -0800203static const char *wwan_fm350gl_acpi_name(const struct device *dev)
204{
205 /* Attached device name must be "PXSX" for the Linux Kernel to recognize it. */
206 return "PXSX";
207}
208
209static void wwan_fm350gl_acpi_fill_ssdt(const struct device *dev)
210{
211 const struct drivers_wwan_fm_config *config = config_of(dev);
212 const struct device *parent = dev->bus->dev;
213 const char *scope = acpi_device_path(parent);
214
215 if (!is_dev_enabled(parent)) {
216 printk(BIOS_ERR, "%s: root port not enabled\n", __func__);
217 return;
218 }
219 if (!scope) {
220 printk(BIOS_ERR, "%s: root port scope not found\n", __func__);
221 return;
222 }
223 if (!config->fcpo_gpio.pin_count && !config->reset_gpio.pin_count &&
224 !config->perst_gpio.pin_count) {
225 printk(BIOS_ERR, "%s: FCPO, RESET, PERST GPIO required for %s.\n",
226 __func__, scope);
227 return;
228 }
229 printk(BIOS_INFO, "%s: Enable WWAN for %s (%s)\n", scope, dev_path(parent),
230 config->desc ?: dev->chip_ops->name);
231 acpigen_write_scope(scope);
232 {
233 acpigen_write_device(wwan_fm350gl_acpi_name(dev));
234 {
235 acpigen_write_ADR(0);
236 if (config->name)
237 acpigen_write_name_string("_DDN", config->name);
238 if (config->desc)
239 acpigen_write_name_unicode("_STR", config->desc);
240 wwan_fm350gl_acpi_method_fhrf(parent, config);
241 wwan_fm350gl_acpi_method_shrf(parent, config);
242 wwan_fm350gl_acpi_method_rst(parent, config);
Cliff Huang96bb0ba2022-02-11 17:46:00 -0800243 wwan_fm350gl_acpi_method_dpts(parent, config);
Tim Wawrzynczak02927032022-02-28 08:57:09 -0700244
Kapil Porwal0b20a172022-11-26 20:10:47 +0530245 if (config->add_acpi_dma_property)
246 acpi_device_add_dma_property(NULL);
Tim Wawrzynczak02927032022-02-28 08:57:09 -0700247
Cliff Huang7e653d82022-01-21 17:36:20 -0800248 /* NOTE: the 5G driver will call MRST._RST to trigger a cold reset
249 * during firmware update.
250 */
251 acpigen_write_device("MRST");
252 {
253 acpigen_write_ADR(0);
254 wwan_fm350gl_acpi_method_mrst_rst(parent, config);
255 }
Tim Wawrzynczak02927032022-02-28 08:57:09 -0700256
Cliff Huang7e653d82022-01-21 17:36:20 -0800257 acpigen_write_device_end(); /* Device */
258 }
259 acpigen_write_device_end(); /* Device */
260 }
261 acpigen_write_scope_end(); /* Scope */
262}
263
264static struct device_operations wwan_fm350gl_ops = {
265 .read_resources = noop_read_resources,
266 .set_resources = noop_set_resources,
267 .acpi_fill_ssdt = wwan_fm350gl_acpi_fill_ssdt,
Cliff Huang96bb0ba2022-02-11 17:46:00 -0800268 .acpi_name = wwan_fm350gl_acpi_name
Cliff Huang7e653d82022-01-21 17:36:20 -0800269};
270
271static void wwan_fm350gl_acpi_enable(struct device *dev)
272{
273 dev->ops = &wwan_fm350gl_ops;
274}
275
276struct chip_operations drivers_wwan_fm_ops = {
277 CHIP_NAME("Fibocom FM-350-GL")
278 .enable_dev = wwan_fm350gl_acpi_enable
279};