blob: 15d0ecc8590af505a6a08a549d160485a2561b9c [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.
51 * Arg0 = RESET_TYPE_WARM: warm reset
52 * Arg0 = 1RESET_TYPE_COLD: cold reset
53 */
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 {
63 if (wwan_fm350gl_get_rtd3_method_support(config) |
64 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 */
86 if (wwan_fm350gl_get_rtd3_method_support(config) |
87 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. */
113 if (wwan_fm350gl_get_rtd3_method_support(config) |
114 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. */
119 if (wwan_fm350gl_get_rtd3_method_support(config) |
120 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 */
134 if (wwan_fm350gl_get_rtd3_method_support(config) |
135 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
187static const char *wwan_fm350gl_acpi_name(const struct device *dev)
188{
189 /* Attached device name must be "PXSX" for the Linux Kernel to recognize it. */
190 return "PXSX";
191}
192
193static void wwan_fm350gl_acpi_fill_ssdt(const struct device *dev)
194{
195 const struct drivers_wwan_fm_config *config = config_of(dev);
196 const struct device *parent = dev->bus->dev;
197 const char *scope = acpi_device_path(parent);
198
199 if (!is_dev_enabled(parent)) {
200 printk(BIOS_ERR, "%s: root port not enabled\n", __func__);
201 return;
202 }
203 if (!scope) {
204 printk(BIOS_ERR, "%s: root port scope not found\n", __func__);
205 return;
206 }
207 if (!config->fcpo_gpio.pin_count && !config->reset_gpio.pin_count &&
208 !config->perst_gpio.pin_count) {
209 printk(BIOS_ERR, "%s: FCPO, RESET, PERST GPIO required for %s.\n",
210 __func__, scope);
211 return;
212 }
213 printk(BIOS_INFO, "%s: Enable WWAN for %s (%s)\n", scope, dev_path(parent),
214 config->desc ?: dev->chip_ops->name);
215 acpigen_write_scope(scope);
216 {
217 acpigen_write_device(wwan_fm350gl_acpi_name(dev));
218 {
219 acpigen_write_ADR(0);
220 if (config->name)
221 acpigen_write_name_string("_DDN", config->name);
222 if (config->desc)
223 acpigen_write_name_unicode("_STR", config->desc);
224 wwan_fm350gl_acpi_method_fhrf(parent, config);
225 wwan_fm350gl_acpi_method_shrf(parent, config);
226 wwan_fm350gl_acpi_method_rst(parent, config);
227 /* NOTE: the 5G driver will call MRST._RST to trigger a cold reset
228 * during firmware update.
229 */
230 acpigen_write_device("MRST");
231 {
232 acpigen_write_ADR(0);
233 wwan_fm350gl_acpi_method_mrst_rst(parent, config);
234 }
235 acpigen_write_device_end(); /* Device */
236 }
237 acpigen_write_device_end(); /* Device */
238 }
239 acpigen_write_scope_end(); /* Scope */
240}
241
242static struct device_operations wwan_fm350gl_ops = {
243 .read_resources = noop_read_resources,
244 .set_resources = noop_set_resources,
245 .acpi_fill_ssdt = wwan_fm350gl_acpi_fill_ssdt,
246 .acpi_name = wwan_fm350gl_acpi_name,
247};
248
249static void wwan_fm350gl_acpi_enable(struct device *dev)
250{
251 dev->ops = &wwan_fm350gl_ops;
252}
253
254struct chip_operations drivers_wwan_fm_ops = {
255 CHIP_NAME("Fibocom FM-350-GL")
256 .enable_dev = wwan_fm350gl_acpi_enable
257};