Commit | Line | Data |
---|---|---|
ad51f287 | 1 | // SPDX-License-Identifier: GPL-2.0 |
b740d2e9 RB |
2 | /* |
3 | * Intel Core SoC Power Management Controller Driver | |
4 | * | |
5 | * Copyright (c) 2016, Intel Corporation. | |
6 | * All Rights Reserved. | |
7 | * | |
8 | * Authors: Rajneesh Bhardwaj <rajneesh.bhardwaj@intel.com> | |
9 | * Vishwanath Somayaji <vishwanath.somayaji@intel.com> | |
b740d2e9 RB |
10 | */ |
11 | ||
21ae4357 SP |
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
13 | ||
745698c3 | 14 | #include <linux/acpi.h> |
8122e7cd | 15 | #include <linux/bitfield.h> |
b740d2e9 | 16 | #include <linux/debugfs.h> |
9c2ee199 | 17 | #include <linux/delay.h> |
238f9c11 | 18 | #include <linux/dmi.h> |
b740d2e9 | 19 | #include <linux/io.h> |
2854a0aa | 20 | #include <linux/module.h> |
661405bd | 21 | #include <linux/pci.h> |
6c96a78c | 22 | #include <linux/platform_device.h> |
267fc714 | 23 | #include <linux/slab.h> |
2ac8d46d | 24 | #include <linux/suspend.h> |
9c2ee199 | 25 | #include <linux/uaccess.h> |
42813136 | 26 | #include <linux/uuid.h> |
b740d2e9 | 27 | |
42813136 | 28 | #include <acpi/acpi_bus.h> |
b740d2e9 | 29 | #include <asm/cpu_device_id.h> |
70e0d117 | 30 | #include <asm/intel-family.h> |
8aba056a | 31 | #include <asm/msr.h> |
c09c6071 | 32 | #include <asm/tsc.h> |
b740d2e9 RB |
33 | |
34 | #include "intel_pmc_core.h" | |
35 | ||
42813136 GK |
36 | #define ACPI_S0IX_DSM_UUID "57a6512e-3979-4e9d-9708-ff13b2508972" |
37 | #define ACPI_GET_LOW_MODE_REGISTERS 1 | |
38 | ||
8aba056a RB |
39 | /* PKGC MSRs are common across Intel Core SoCs */ |
40 | static const struct pmc_bit_map msr_map[] = { | |
41 | {"Package C2", MSR_PKG_C2_RESIDENCY}, | |
42 | {"Package C3", MSR_PKG_C3_RESIDENCY}, | |
43 | {"Package C6", MSR_PKG_C6_RESIDENCY}, | |
44 | {"Package C7", MSR_PKG_C7_RESIDENCY}, | |
45 | {"Package C8", MSR_PKG_C8_RESIDENCY}, | |
46 | {"Package C9", MSR_PKG_C9_RESIDENCY}, | |
47 | {"Package C10", MSR_PKG_C10_RESIDENCY}, | |
48 | {} | |
49 | }; | |
50 | ||
fe748227 RB |
51 | static const struct pmc_bit_map spt_pll_map[] = { |
52 | {"MIPI PLL", SPT_PMC_BIT_MPHY_CMN_LANE0}, | |
53 | {"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1}, | |
54 | {"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2}, | |
55 | {"SATA PLL", SPT_PMC_BIT_MPHY_CMN_LANE3}, | |
b1cb33da | 56 | {} |
fe748227 RB |
57 | }; |
58 | ||
173943b3 RB |
59 | static const struct pmc_bit_map spt_mphy_map[] = { |
60 | {"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0}, | |
61 | {"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1}, | |
62 | {"MPHY CORE LANE 2", SPT_PMC_BIT_MPHY_LANE2}, | |
63 | {"MPHY CORE LANE 3", SPT_PMC_BIT_MPHY_LANE3}, | |
64 | {"MPHY CORE LANE 4", SPT_PMC_BIT_MPHY_LANE4}, | |
65 | {"MPHY CORE LANE 5", SPT_PMC_BIT_MPHY_LANE5}, | |
66 | {"MPHY CORE LANE 6", SPT_PMC_BIT_MPHY_LANE6}, | |
67 | {"MPHY CORE LANE 7", SPT_PMC_BIT_MPHY_LANE7}, | |
68 | {"MPHY CORE LANE 8", SPT_PMC_BIT_MPHY_LANE8}, | |
69 | {"MPHY CORE LANE 9", SPT_PMC_BIT_MPHY_LANE9}, | |
70 | {"MPHY CORE LANE 10", SPT_PMC_BIT_MPHY_LANE10}, | |
71 | {"MPHY CORE LANE 11", SPT_PMC_BIT_MPHY_LANE11}, | |
72 | {"MPHY CORE LANE 12", SPT_PMC_BIT_MPHY_LANE12}, | |
73 | {"MPHY CORE LANE 13", SPT_PMC_BIT_MPHY_LANE13}, | |
74 | {"MPHY CORE LANE 14", SPT_PMC_BIT_MPHY_LANE14}, | |
75 | {"MPHY CORE LANE 15", SPT_PMC_BIT_MPHY_LANE15}, | |
b1cb33da | 76 | {} |
173943b3 RB |
77 | }; |
78 | ||
0bdfaf42 RB |
79 | static const struct pmc_bit_map spt_pfear_map[] = { |
80 | {"PMC", SPT_PMC_BIT_PMC}, | |
81 | {"OPI-DMI", SPT_PMC_BIT_OPI}, | |
82 | {"SPI / eSPI", SPT_PMC_BIT_SPI}, | |
83 | {"XHCI", SPT_PMC_BIT_XHCI}, | |
84 | {"SPA", SPT_PMC_BIT_SPA}, | |
85 | {"SPB", SPT_PMC_BIT_SPB}, | |
86 | {"SPC", SPT_PMC_BIT_SPC}, | |
87 | {"GBE", SPT_PMC_BIT_GBE}, | |
88 | {"SATA", SPT_PMC_BIT_SATA}, | |
89 | {"HDA-PGD0", SPT_PMC_BIT_HDA_PGD0}, | |
90 | {"HDA-PGD1", SPT_PMC_BIT_HDA_PGD1}, | |
91 | {"HDA-PGD2", SPT_PMC_BIT_HDA_PGD2}, | |
92 | {"HDA-PGD3", SPT_PMC_BIT_HDA_PGD3}, | |
93 | {"RSVD", SPT_PMC_BIT_RSVD_0B}, | |
94 | {"LPSS", SPT_PMC_BIT_LPSS}, | |
95 | {"LPC", SPT_PMC_BIT_LPC}, | |
96 | {"SMB", SPT_PMC_BIT_SMB}, | |
97 | {"ISH", SPT_PMC_BIT_ISH}, | |
98 | {"P2SB", SPT_PMC_BIT_P2SB}, | |
99 | {"DFX", SPT_PMC_BIT_DFX}, | |
100 | {"SCC", SPT_PMC_BIT_SCC}, | |
101 | {"RSVD", SPT_PMC_BIT_RSVD_0C}, | |
102 | {"FUSE", SPT_PMC_BIT_FUSE}, | |
103 | {"CAMERA", SPT_PMC_BIT_CAMREA}, | |
104 | {"RSVD", SPT_PMC_BIT_RSVD_0D}, | |
105 | {"USB3-OTG", SPT_PMC_BIT_USB3_OTG}, | |
106 | {"EXI", SPT_PMC_BIT_EXI}, | |
107 | {"CSE", SPT_PMC_BIT_CSE}, | |
108 | {"CSME_KVM", SPT_PMC_BIT_CSME_KVM}, | |
109 | {"CSME_PMT", SPT_PMC_BIT_CSME_PMT}, | |
110 | {"CSME_CLINK", SPT_PMC_BIT_CSME_CLINK}, | |
111 | {"CSME_PTIO", SPT_PMC_BIT_CSME_PTIO}, | |
112 | {"CSME_USBR", SPT_PMC_BIT_CSME_USBR}, | |
113 | {"CSME_SUSRAM", SPT_PMC_BIT_CSME_SUSRAM}, | |
114 | {"CSME_SMT", SPT_PMC_BIT_CSME_SMT}, | |
115 | {"RSVD", SPT_PMC_BIT_RSVD_1A}, | |
116 | {"CSME_SMS2", SPT_PMC_BIT_CSME_SMS2}, | |
117 | {"CSME_SMS1", SPT_PMC_BIT_CSME_SMS1}, | |
118 | {"CSME_RTC", SPT_PMC_BIT_CSME_RTC}, | |
119 | {"CSME_PSF", SPT_PMC_BIT_CSME_PSF}, | |
b1cb33da | 120 | {} |
0bdfaf42 RB |
121 | }; |
122 | ||
e3985478 | 123 | static const struct pmc_bit_map *ext_spt_pfear_map[] = { |
3976c6e3 GK |
124 | /* |
125 | * Check intel_pmc_core_ids[] users of spt_reg_map for | |
126 | * a list of core SoCs using this. | |
127 | */ | |
e3985478 GK |
128 | spt_pfear_map, |
129 | NULL | |
130 | }; | |
131 | ||
2eb15055 RB |
132 | static const struct pmc_bit_map spt_ltr_show_map[] = { |
133 | {"SOUTHPORT_A", SPT_PMC_LTR_SPA}, | |
134 | {"SOUTHPORT_B", SPT_PMC_LTR_SPB}, | |
135 | {"SATA", SPT_PMC_LTR_SATA}, | |
136 | {"GIGABIT_ETHERNET", SPT_PMC_LTR_GBE}, | |
137 | {"XHCI", SPT_PMC_LTR_XHCI}, | |
2a13096a | 138 | {"Reserved", SPT_PMC_LTR_RESERVED}, |
2eb15055 RB |
139 | {"ME", SPT_PMC_LTR_ME}, |
140 | /* EVA is Enterprise Value Add, doesn't really exist on PCH */ | |
141 | {"EVA", SPT_PMC_LTR_EVA}, | |
142 | {"SOUTHPORT_C", SPT_PMC_LTR_SPC}, | |
143 | {"HD_AUDIO", SPT_PMC_LTR_AZ}, | |
144 | {"LPSS", SPT_PMC_LTR_LPSS}, | |
145 | {"SOUTHPORT_D", SPT_PMC_LTR_SPD}, | |
146 | {"SOUTHPORT_E", SPT_PMC_LTR_SPE}, | |
147 | {"CAMERA", SPT_PMC_LTR_CAM}, | |
148 | {"ESPI", SPT_PMC_LTR_ESPI}, | |
149 | {"SCC", SPT_PMC_LTR_SCC}, | |
150 | {"ISH", SPT_PMC_LTR_ISH}, | |
151 | /* Below two cannot be used for LTR_IGNORE */ | |
152 | {"CURRENT_PLATFORM", SPT_PMC_LTR_CUR_PLT}, | |
153 | {"AGGREGATED_SYSTEM", SPT_PMC_LTR_CUR_ASLT}, | |
154 | {} | |
155 | }; | |
156 | ||
0bdfaf42 | 157 | static const struct pmc_reg_map spt_reg_map = { |
e3985478 | 158 | .pfear_sts = ext_spt_pfear_map, |
173943b3 | 159 | .mphy_sts = spt_mphy_map, |
fe748227 | 160 | .pll_sts = spt_pll_map, |
2eb15055 | 161 | .ltr_show_sts = spt_ltr_show_map, |
8aba056a | 162 | .msr_sts = msr_map, |
c977b98b | 163 | .slp_s0_offset = SPT_PMC_SLP_S0_RES_COUNTER_OFFSET, |
025f26de | 164 | .slp_s0_res_counter_step = SPT_PMC_SLP_S0_RES_COUNTER_STEP, |
c977b98b SP |
165 | .ltr_ignore_offset = SPT_PMC_LTR_IGNORE_OFFSET, |
166 | .regmap_length = SPT_PMC_MMIO_REG_LEN, | |
167 | .ppfear0_offset = SPT_PMC_XRAM_PPFEAR0A, | |
168 | .ppfear_buckets = SPT_PPFEAR_NUM_ENTRIES, | |
169 | .pm_cfg_offset = SPT_PMC_PM_CFG_OFFSET, | |
170 | .pm_read_disable_bit = SPT_PMC_READ_DISABLE_BIT, | |
2d649d97 | 171 | .ltr_ignore_max = SPT_NUM_IP_IGN_ALLOWED, |
238f9c11 | 172 | .pm_vric1_offset = SPT_PMC_VRIC1_OFFSET, |
0bdfaf42 RB |
173 | }; |
174 | ||
43e82d8a | 175 | /* Cannon Lake: PGD PFET Enable Ack Status Register(s) bitmap */ |
291101f6 RB |
176 | static const struct pmc_bit_map cnp_pfear_map[] = { |
177 | {"PMC", BIT(0)}, | |
178 | {"OPI-DMI", BIT(1)}, | |
179 | {"SPI/eSPI", BIT(2)}, | |
180 | {"XHCI", BIT(3)}, | |
181 | {"SPA", BIT(4)}, | |
182 | {"SPB", BIT(5)}, | |
183 | {"SPC", BIT(6)}, | |
184 | {"GBE", BIT(7)}, | |
185 | ||
186 | {"SATA", BIT(0)}, | |
187 | {"HDA_PGD0", BIT(1)}, | |
188 | {"HDA_PGD1", BIT(2)}, | |
189 | {"HDA_PGD2", BIT(3)}, | |
190 | {"HDA_PGD3", BIT(4)}, | |
191 | {"SPD", BIT(5)}, | |
192 | {"LPSS", BIT(6)}, | |
193 | {"LPC", BIT(7)}, | |
194 | ||
195 | {"SMB", BIT(0)}, | |
196 | {"ISH", BIT(1)}, | |
197 | {"P2SB", BIT(2)}, | |
198 | {"NPK_VNN", BIT(3)}, | |
199 | {"SDX", BIT(4)}, | |
200 | {"SPE", BIT(5)}, | |
201 | {"Fuse", BIT(6)}, | |
6769fdbe | 202 | {"SBR8", BIT(7)}, |
291101f6 RB |
203 | |
204 | {"CSME_FSC", BIT(0)}, | |
205 | {"USB3_OTG", BIT(1)}, | |
206 | {"EXI", BIT(2)}, | |
207 | {"CSE", BIT(3)}, | |
6769fdbe RB |
208 | {"CSME_KVM", BIT(4)}, |
209 | {"CSME_PMT", BIT(5)}, | |
210 | {"CSME_CLINK", BIT(6)}, | |
211 | {"CSME_PTIO", BIT(7)}, | |
212 | ||
213 | {"CSME_USBR", BIT(0)}, | |
214 | {"CSME_SUSRAM", BIT(1)}, | |
215 | {"CSME_SMT1", BIT(2)}, | |
291101f6 | 216 | {"CSME_SMT4", BIT(3)}, |
6769fdbe RB |
217 | {"CSME_SMS2", BIT(4)}, |
218 | {"CSME_SMS1", BIT(5)}, | |
219 | {"CSME_RTC", BIT(6)}, | |
220 | {"CSME_PSF", BIT(7)}, | |
291101f6 RB |
221 | |
222 | {"SBR0", BIT(0)}, | |
223 | {"SBR1", BIT(1)}, | |
224 | {"SBR2", BIT(2)}, | |
225 | {"SBR3", BIT(3)}, | |
226 | {"SBR4", BIT(4)}, | |
227 | {"SBR5", BIT(5)}, | |
228 | {"CSME_PECI", BIT(6)}, | |
229 | {"PSF1", BIT(7)}, | |
230 | ||
231 | {"PSF2", BIT(0)}, | |
232 | {"PSF3", BIT(1)}, | |
233 | {"PSF4", BIT(2)}, | |
234 | {"CNVI", BIT(3)}, | |
235 | {"UFS0", BIT(4)}, | |
236 | {"EMMC", BIT(5)}, | |
d6827015 | 237 | {"SPF", BIT(6)}, |
291101f6 RB |
238 | {"SBR6", BIT(7)}, |
239 | ||
240 | {"SBR7", BIT(0)}, | |
241 | {"NPK_AON", BIT(1)}, | |
242 | {"HDA_PGD4", BIT(2)}, | |
243 | {"HDA_PGD5", BIT(3)}, | |
244 | {"HDA_PGD6", BIT(4)}, | |
6769fdbe RB |
245 | {"PSF6", BIT(5)}, |
246 | {"PSF7", BIT(6)}, | |
247 | {"PSF8", BIT(7)}, | |
e3985478 GK |
248 | {} |
249 | }; | |
250 | ||
251 | static const struct pmc_bit_map *ext_cnp_pfear_map[] = { | |
3976c6e3 GK |
252 | /* |
253 | * Check intel_pmc_core_ids[] users of cnp_reg_map for | |
254 | * a list of core SoCs using this. | |
255 | */ | |
e3985478 GK |
256 | cnp_pfear_map, |
257 | NULL | |
258 | }; | |
6769fdbe | 259 | |
e3985478 | 260 | static const struct pmc_bit_map icl_pfear_map[] = { |
6769fdbe RB |
261 | {"RES_65", BIT(0)}, |
262 | {"RES_66", BIT(1)}, | |
263 | {"RES_67", BIT(2)}, | |
264 | {"TAM", BIT(3)}, | |
265 | {"GBETSN", BIT(4)}, | |
266 | {"TBTLSX", BIT(5)}, | |
267 | {"RES_71", BIT(6)}, | |
268 | {"RES_72", BIT(7)}, | |
291101f6 RB |
269 | {} |
270 | }; | |
271 | ||
e3985478 | 272 | static const struct pmc_bit_map *ext_icl_pfear_map[] = { |
3976c6e3 GK |
273 | /* |
274 | * Check intel_pmc_core_ids[] users of icl_reg_map for | |
275 | * a list of core SoCs using this. | |
276 | */ | |
e3985478 GK |
277 | cnp_pfear_map, |
278 | icl_pfear_map, | |
279 | NULL | |
280 | }; | |
281 | ||
49a43794 | 282 | static const struct pmc_bit_map tgl_pfear_map[] = { |
49a43794 GK |
283 | {"PSF9", BIT(0)}, |
284 | {"RES_66", BIT(1)}, | |
285 | {"RES_67", BIT(2)}, | |
286 | {"RES_68", BIT(3)}, | |
287 | {"RES_69", BIT(4)}, | |
288 | {"RES_70", BIT(5)}, | |
289 | {"TBTLSX", BIT(6)}, | |
290 | {} | |
291 | }; | |
292 | ||
293 | static const struct pmc_bit_map *ext_tgl_pfear_map[] = { | |
3976c6e3 GK |
294 | /* |
295 | * Check intel_pmc_core_ids[] users of tgl_reg_map for | |
296 | * a list of core SoCs using this. | |
297 | */ | |
49a43794 GK |
298 | cnp_pfear_map, |
299 | tgl_pfear_map, | |
300 | NULL | |
301 | }; | |
302 | ||
4cf2afd6 BD |
303 | static const struct pmc_bit_map cnp_slps0_dbg0_map[] = { |
304 | {"AUDIO_D3", BIT(0)}, | |
305 | {"OTG_D3", BIT(1)}, | |
306 | {"XHCI_D3", BIT(2)}, | |
307 | {"LPIO_D3", BIT(3)}, | |
308 | {"SDX_D3", BIT(4)}, | |
309 | {"SATA_D3", BIT(5)}, | |
310 | {"UFS0_D3", BIT(6)}, | |
311 | {"UFS1_D3", BIT(7)}, | |
312 | {"EMMC_D3", BIT(8)}, | |
313 | {} | |
314 | }; | |
315 | ||
316 | static const struct pmc_bit_map cnp_slps0_dbg1_map[] = { | |
317 | {"SDIO_PLL_OFF", BIT(0)}, | |
318 | {"USB2_PLL_OFF", BIT(1)}, | |
319 | {"AUDIO_PLL_OFF", BIT(2)}, | |
320 | {"OC_PLL_OFF", BIT(3)}, | |
321 | {"MAIN_PLL_OFF", BIT(4)}, | |
322 | {"XOSC_OFF", BIT(5)}, | |
323 | {"LPC_CLKS_GATED", BIT(6)}, | |
324 | {"PCIE_CLKREQS_IDLE", BIT(7)}, | |
325 | {"AUDIO_ROSC_OFF", BIT(8)}, | |
326 | {"HPET_XOSC_CLK_REQ", BIT(9)}, | |
327 | {"PMC_ROSC_SLOW_CLK", BIT(10)}, | |
328 | {"AON2_ROSC_GATED", BIT(11)}, | |
329 | {"CLKACKS_DEASSERTED", BIT(12)}, | |
330 | {} | |
331 | }; | |
332 | ||
333 | static const struct pmc_bit_map cnp_slps0_dbg2_map[] = { | |
334 | {"MPHY_CORE_GATED", BIT(0)}, | |
335 | {"CSME_GATED", BIT(1)}, | |
336 | {"USB2_SUS_GATED", BIT(2)}, | |
337 | {"DYN_FLEX_IO_IDLE", BIT(3)}, | |
338 | {"GBE_NO_LINK", BIT(4)}, | |
339 | {"THERM_SEN_DISABLED", BIT(5)}, | |
340 | {"PCIE_LOW_POWER", BIT(6)}, | |
341 | {"ISH_VNNAON_REQ_ACT", BIT(7)}, | |
342 | {"ISH_VNN_REQ_ACT", BIT(8)}, | |
343 | {"CNV_VNNAON_REQ_ACT", BIT(9)}, | |
344 | {"CNV_VNN_REQ_ACT", BIT(10)}, | |
345 | {"NPK_VNNON_REQ_ACT", BIT(11)}, | |
346 | {"PMSYNC_STATE_IDLE", BIT(12)}, | |
347 | {"ALST_GT_THRES", BIT(13)}, | |
348 | {"PMC_ARC_PG_READY", BIT(14)}, | |
349 | {} | |
350 | }; | |
351 | ||
352 | static const struct pmc_bit_map *cnp_slps0_dbg_maps[] = { | |
353 | cnp_slps0_dbg0_map, | |
354 | cnp_slps0_dbg1_map, | |
355 | cnp_slps0_dbg2_map, | |
b1cb33da | 356 | NULL |
4cf2afd6 BD |
357 | }; |
358 | ||
2eb15055 RB |
359 | static const struct pmc_bit_map cnp_ltr_show_map[] = { |
360 | {"SOUTHPORT_A", CNP_PMC_LTR_SPA}, | |
361 | {"SOUTHPORT_B", CNP_PMC_LTR_SPB}, | |
362 | {"SATA", CNP_PMC_LTR_SATA}, | |
363 | {"GIGABIT_ETHERNET", CNP_PMC_LTR_GBE}, | |
364 | {"XHCI", CNP_PMC_LTR_XHCI}, | |
2a13096a | 365 | {"Reserved", CNP_PMC_LTR_RESERVED}, |
2eb15055 RB |
366 | {"ME", CNP_PMC_LTR_ME}, |
367 | /* EVA is Enterprise Value Add, doesn't really exist on PCH */ | |
368 | {"EVA", CNP_PMC_LTR_EVA}, | |
369 | {"SOUTHPORT_C", CNP_PMC_LTR_SPC}, | |
370 | {"HD_AUDIO", CNP_PMC_LTR_AZ}, | |
371 | {"CNV", CNP_PMC_LTR_CNV}, | |
372 | {"LPSS", CNP_PMC_LTR_LPSS}, | |
373 | {"SOUTHPORT_D", CNP_PMC_LTR_SPD}, | |
374 | {"SOUTHPORT_E", CNP_PMC_LTR_SPE}, | |
375 | {"CAMERA", CNP_PMC_LTR_CAM}, | |
376 | {"ESPI", CNP_PMC_LTR_ESPI}, | |
377 | {"SCC", CNP_PMC_LTR_SCC}, | |
378 | {"ISH", CNP_PMC_LTR_ISH}, | |
379 | {"UFSX2", CNP_PMC_LTR_UFSX2}, | |
380 | {"EMMC", CNP_PMC_LTR_EMMC}, | |
3976c6e3 GK |
381 | /* |
382 | * Check intel_pmc_core_ids[] users of cnp_reg_map for | |
383 | * a list of core SoCs using this. | |
384 | */ | |
6769fdbe | 385 | {"WIGIG", ICL_PMC_LTR_WIGIG}, |
43ef6c22 GK |
386 | {"THC0", TGL_PMC_LTR_THC0}, |
387 | {"THC1", TGL_PMC_LTR_THC1}, | |
2eb15055 RB |
388 | /* Below two cannot be used for LTR_IGNORE */ |
389 | {"CURRENT_PLATFORM", CNP_PMC_LTR_CUR_PLT}, | |
390 | {"AGGREGATED_SYSTEM", CNP_PMC_LTR_CUR_ASLT}, | |
391 | {} | |
392 | }; | |
393 | ||
291101f6 | 394 | static const struct pmc_reg_map cnp_reg_map = { |
e3985478 | 395 | .pfear_sts = ext_cnp_pfear_map, |
291101f6 | 396 | .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, |
025f26de | 397 | .slp_s0_res_counter_step = SPT_PMC_SLP_S0_RES_COUNTER_STEP, |
4cf2afd6 | 398 | .slps0_dbg_maps = cnp_slps0_dbg_maps, |
2eb15055 | 399 | .ltr_show_sts = cnp_ltr_show_map, |
8aba056a | 400 | .msr_sts = msr_map, |
4cf2afd6 | 401 | .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET, |
291101f6 RB |
402 | .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, |
403 | .regmap_length = CNP_PMC_MMIO_REG_LEN, | |
404 | .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, | |
405 | .ppfear_buckets = CNP_PPFEAR_NUM_ENTRIES, | |
406 | .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, | |
407 | .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, | |
2d649d97 | 408 | .ltr_ignore_max = CNP_NUM_IP_IGN_ALLOWED, |
ee7abc10 | 409 | .etr3_offset = ETR3_OFFSET, |
291101f6 RB |
410 | }; |
411 | ||
6769fdbe | 412 | static const struct pmc_reg_map icl_reg_map = { |
e3985478 | 413 | .pfear_sts = ext_icl_pfear_map, |
6769fdbe | 414 | .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, |
025f26de | 415 | .slp_s0_res_counter_step = ICL_PMC_SLP_S0_RES_COUNTER_STEP, |
6769fdbe RB |
416 | .slps0_dbg_maps = cnp_slps0_dbg_maps, |
417 | .ltr_show_sts = cnp_ltr_show_map, | |
8aba056a | 418 | .msr_sts = msr_map, |
6769fdbe RB |
419 | .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET, |
420 | .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, | |
421 | .regmap_length = CNP_PMC_MMIO_REG_LEN, | |
422 | .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, | |
423 | .ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES, | |
424 | .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, | |
425 | .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, | |
426 | .ltr_ignore_max = ICL_NUM_IP_IGN_ALLOWED, | |
ee7abc10 | 427 | .etr3_offset = ETR3_OFFSET, |
6769fdbe RB |
428 | }; |
429 | ||
e973f1d3 | 430 | static const struct pmc_bit_map tgl_clocksource_status_map[] = { |
f632817d GK |
431 | {"USB2PLL_OFF_STS", BIT(18)}, |
432 | {"PCIe/USB3.1_Gen2PLL_OFF_STS", BIT(19)}, | |
433 | {"PCIe_Gen3PLL_OFF_STS", BIT(20)}, | |
434 | {"OPIOPLL_OFF_STS", BIT(21)}, | |
435 | {"OCPLL_OFF_STS", BIT(22)}, | |
cd85b55c | 436 | {"MainPLL_OFF_STS", BIT(23)}, |
f632817d GK |
437 | {"MIPIPLL_OFF_STS", BIT(24)}, |
438 | {"Fast_XTAL_Osc_OFF_STS", BIT(25)}, | |
439 | {"AC_Ring_Osc_OFF_STS", BIT(26)}, | |
440 | {"MC_Ring_Osc_OFF_STS", BIT(27)}, | |
441 | {"SATAPLL_OFF_STS", BIT(29)}, | |
442 | {"XTAL_USB2PLL_OFF_STS", BIT(31)}, | |
443 | {} | |
444 | }; | |
445 | ||
e973f1d3 | 446 | static const struct pmc_bit_map tgl_power_gating_status_map[] = { |
652036bd GK |
447 | {"CSME_PG_STS", BIT(0)}, |
448 | {"SATA_PG_STS", BIT(1)}, | |
449 | {"xHCI_PG_STS", BIT(2)}, | |
450 | {"UFSX2_PG_STS", BIT(3)}, | |
451 | {"OTG_PG_STS", BIT(5)}, | |
452 | {"SPA_PG_STS", BIT(6)}, | |
453 | {"SPB_PG_STS", BIT(7)}, | |
454 | {"SPC_PG_STS", BIT(8)}, | |
455 | {"SPD_PG_STS", BIT(9)}, | |
456 | {"SPE_PG_STS", BIT(10)}, | |
457 | {"SPF_PG_STS", BIT(11)}, | |
458 | {"LSX_PG_STS", BIT(13)}, | |
459 | {"P2SB_PG_STS", BIT(14)}, | |
460 | {"PSF_PG_STS", BIT(15)}, | |
461 | {"SBR_PG_STS", BIT(16)}, | |
462 | {"OPIDMI_PG_STS", BIT(17)}, | |
463 | {"THC0_PG_STS", BIT(18)}, | |
464 | {"THC1_PG_STS", BIT(19)}, | |
465 | {"GBETSN_PG_STS", BIT(20)}, | |
466 | {"GBE_PG_STS", BIT(21)}, | |
467 | {"LPSS_PG_STS", BIT(22)}, | |
468 | {"MMP_UFSX2_PG_STS", BIT(23)}, | |
469 | {"MMP_UFSX2B_PG_STS", BIT(24)}, | |
470 | {"FIA_PG_STS", BIT(25)}, | |
f632817d GK |
471 | {} |
472 | }; | |
473 | ||
e973f1d3 | 474 | static const struct pmc_bit_map tgl_d3_status_map[] = { |
f632817d GK |
475 | {"ADSP_D3_STS", BIT(0)}, |
476 | {"SATA_D3_STS", BIT(1)}, | |
477 | {"xHCI0_D3_STS", BIT(2)}, | |
478 | {"xDCI1_D3_STS", BIT(5)}, | |
479 | {"SDX_D3_STS", BIT(6)}, | |
480 | {"EMMC_D3_STS", BIT(7)}, | |
481 | {"IS_D3_STS", BIT(8)}, | |
482 | {"THC0_D3_STS", BIT(9)}, | |
483 | {"THC1_D3_STS", BIT(10)}, | |
484 | {"GBE_D3_STS", BIT(11)}, | |
485 | {"GBE_TSN_D3_STS", BIT(12)}, | |
486 | {} | |
487 | }; | |
488 | ||
e973f1d3 | 489 | static const struct pmc_bit_map tgl_vnn_req_status_map[] = { |
f632817d GK |
490 | {"GPIO_COM0_VNN_REQ_STS", BIT(1)}, |
491 | {"GPIO_COM1_VNN_REQ_STS", BIT(2)}, | |
492 | {"GPIO_COM2_VNN_REQ_STS", BIT(3)}, | |
493 | {"GPIO_COM3_VNN_REQ_STS", BIT(4)}, | |
494 | {"GPIO_COM4_VNN_REQ_STS", BIT(5)}, | |
495 | {"GPIO_COM5_VNN_REQ_STS", BIT(6)}, | |
496 | {"Audio_VNN_REQ_STS", BIT(7)}, | |
497 | {"ISH_VNN_REQ_STS", BIT(8)}, | |
498 | {"CNVI_VNN_REQ_STS", BIT(9)}, | |
499 | {"eSPI_VNN_REQ_STS", BIT(10)}, | |
500 | {"Display_VNN_REQ_STS", BIT(11)}, | |
501 | {"DTS_VNN_REQ_STS", BIT(12)}, | |
502 | {"SMBUS_VNN_REQ_STS", BIT(14)}, | |
503 | {"CSME_VNN_REQ_STS", BIT(15)}, | |
504 | {"SMLINK0_VNN_REQ_STS", BIT(16)}, | |
505 | {"SMLINK1_VNN_REQ_STS", BIT(17)}, | |
506 | {"CLINK_VNN_REQ_STS", BIT(20)}, | |
507 | {"DCI_VNN_REQ_STS", BIT(21)}, | |
508 | {"ITH_VNN_REQ_STS", BIT(22)}, | |
509 | {"CSME_VNN_REQ_STS", BIT(24)}, | |
510 | {"GBE_VNN_REQ_STS", BIT(25)}, | |
511 | {} | |
512 | }; | |
513 | ||
e973f1d3 | 514 | static const struct pmc_bit_map tgl_vnn_misc_status_map[] = { |
f632817d GK |
515 | {"CPU_C10_REQ_STS_0", BIT(0)}, |
516 | {"PCIe_LPM_En_REQ_STS_3", BIT(3)}, | |
517 | {"ITH_REQ_STS_5", BIT(5)}, | |
518 | {"CNVI_REQ_STS_6", BIT(6)}, | |
519 | {"ISH_REQ_STS_7", BIT(7)}, | |
520 | {"USB2_SUS_PG_Sys_REQ_STS_10", BIT(10)}, | |
521 | {"PCIe_Clk_REQ_STS_12", BIT(12)}, | |
522 | {"MPHY_Core_DL_REQ_STS_16", BIT(16)}, | |
523 | {"Break-even_En_REQ_STS_17", BIT(17)}, | |
524 | {"Auto-demo_En_REQ_STS_18", BIT(18)}, | |
525 | {"MPHY_SUS_REQ_STS_22", BIT(22)}, | |
526 | {"xDCI_attached_REQ_STS_24", BIT(24)}, | |
527 | {} | |
528 | }; | |
529 | ||
e973f1d3 | 530 | static const struct pmc_bit_map tgl_signal_status_map[] = { |
f632817d GK |
531 | {"LSX_Wake0_En_STS", BIT(0)}, |
532 | {"LSX_Wake0_Pol_STS", BIT(1)}, | |
533 | {"LSX_Wake1_En_STS", BIT(2)}, | |
534 | {"LSX_Wake1_Pol_STS", BIT(3)}, | |
535 | {"LSX_Wake2_En_STS", BIT(4)}, | |
536 | {"LSX_Wake2_Pol_STS", BIT(5)}, | |
537 | {"LSX_Wake3_En_STS", BIT(6)}, | |
538 | {"LSX_Wake3_Pol_STS", BIT(7)}, | |
539 | {"LSX_Wake4_En_STS", BIT(8)}, | |
540 | {"LSX_Wake4_Pol_STS", BIT(9)}, | |
541 | {"LSX_Wake5_En_STS", BIT(10)}, | |
542 | {"LSX_Wake5_Pol_STS", BIT(11)}, | |
543 | {"LSX_Wake6_En_STS", BIT(12)}, | |
544 | {"LSX_Wake6_Pol_STS", BIT(13)}, | |
545 | {"LSX_Wake7_En_STS", BIT(14)}, | |
546 | {"LSX_Wake7_Pol_STS", BIT(15)}, | |
547 | {"Intel_Se_IO_Wake0_En_STS", BIT(16)}, | |
548 | {"Intel_Se_IO_Wake0_Pol_STS", BIT(17)}, | |
549 | {"Intel_Se_IO_Wake1_En_STS", BIT(18)}, | |
550 | {"Intel_Se_IO_Wake1_Pol_STS", BIT(19)}, | |
551 | {"Int_Timer_SS_Wake0_En_STS", BIT(20)}, | |
552 | {"Int_Timer_SS_Wake0_Pol_STS", BIT(21)}, | |
553 | {"Int_Timer_SS_Wake1_En_STS", BIT(22)}, | |
554 | {"Int_Timer_SS_Wake1_Pol_STS", BIT(23)}, | |
555 | {"Int_Timer_SS_Wake2_En_STS", BIT(24)}, | |
556 | {"Int_Timer_SS_Wake2_Pol_STS", BIT(25)}, | |
557 | {"Int_Timer_SS_Wake3_En_STS", BIT(26)}, | |
558 | {"Int_Timer_SS_Wake3_Pol_STS", BIT(27)}, | |
559 | {"Int_Timer_SS_Wake4_En_STS", BIT(28)}, | |
560 | {"Int_Timer_SS_Wake4_Pol_STS", BIT(29)}, | |
561 | {"Int_Timer_SS_Wake5_En_STS", BIT(30)}, | |
562 | {"Int_Timer_SS_Wake5_Pol_STS", BIT(31)}, | |
563 | {} | |
564 | }; | |
565 | ||
566 | static const struct pmc_bit_map *tgl_lpm_maps[] = { | |
e973f1d3 DB |
567 | tgl_clocksource_status_map, |
568 | tgl_power_gating_status_map, | |
569 | tgl_d3_status_map, | |
570 | tgl_vnn_req_status_map, | |
571 | tgl_vnn_misc_status_map, | |
572 | tgl_signal_status_map, | |
f632817d GK |
573 | NULL |
574 | }; | |
575 | ||
49a43794 GK |
576 | static const struct pmc_reg_map tgl_reg_map = { |
577 | .pfear_sts = ext_tgl_pfear_map, | |
578 | .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, | |
025f26de | 579 | .slp_s0_res_counter_step = TGL_PMC_SLP_S0_RES_COUNTER_STEP, |
49a43794 GK |
580 | .ltr_show_sts = cnp_ltr_show_map, |
581 | .msr_sts = msr_map, | |
49a43794 GK |
582 | .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, |
583 | .regmap_length = CNP_PMC_MMIO_REG_LEN, | |
584 | .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, | |
585 | .ppfear_buckets = ICL_PPFEAR_NUM_ENTRIES, | |
586 | .pm_cfg_offset = CNP_PMC_PM_CFG_OFFSET, | |
587 | .pm_read_disable_bit = CNP_PMC_READ_DISABLE_BIT, | |
588 | .ltr_ignore_max = TGL_NUM_IP_IGN_ALLOWED, | |
005125bf | 589 | .lpm_num_maps = TGL_LPM_NUM_MAPS, |
29c2dd88 | 590 | .lpm_res_counter_step_x2 = TGL_PMC_LPM_RES_COUNTER_STEP_X2, |
8074a79f | 591 | .lpm_sts_latch_en_offset = TGL_LPM_STS_LATCH_EN_OFFSET, |
a45096ac | 592 | .lpm_en_offset = TGL_LPM_EN_OFFSET, |
005125bf | 593 | .lpm_priority_offset = TGL_LPM_PRI_OFFSET, |
a45096ac | 594 | .lpm_residency_offset = TGL_LPM_RESIDENCY_OFFSET, |
f632817d GK |
595 | .lpm_sts = tgl_lpm_maps, |
596 | .lpm_status_offset = TGL_LPM_STATUS_OFFSET, | |
7adb1e8a | 597 | .lpm_live_status_offset = TGL_LPM_LIVE_STATUS_OFFSET, |
ee7abc10 | 598 | .etr3_offset = ETR3_OFFSET, |
49a43794 GK |
599 | }; |
600 | ||
42813136 GK |
601 | static void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev) |
602 | { | |
603 | struct pmc_dev *pmcdev = platform_get_drvdata(pdev); | |
604 | const int num_maps = pmcdev->map->lpm_num_maps; | |
605 | u32 lpm_size = LPM_MAX_NUM_MODES * num_maps * 4; | |
606 | union acpi_object *out_obj; | |
607 | struct acpi_device *adev; | |
608 | guid_t s0ix_dsm_guid; | |
609 | u32 *lpm_req_regs, *addr; | |
610 | ||
611 | adev = ACPI_COMPANION(&pdev->dev); | |
612 | if (!adev) | |
613 | return; | |
614 | ||
615 | guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid); | |
616 | ||
617 | out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0, | |
618 | ACPI_GET_LOW_MODE_REGISTERS, NULL); | |
619 | if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { | |
620 | u32 size = out_obj->buffer.length; | |
621 | ||
622 | if (size != lpm_size) { | |
623 | acpi_handle_debug(adev->handle, | |
624 | "_DSM returned unexpected buffer size, have %u, expect %u\n", | |
625 | size, lpm_size); | |
626 | goto free_acpi_obj; | |
627 | } | |
628 | } else { | |
629 | acpi_handle_debug(adev->handle, | |
630 | "_DSM function 0 evaluation failed\n"); | |
631 | goto free_acpi_obj; | |
632 | } | |
633 | ||
634 | addr = (u32 *)out_obj->buffer.pointer; | |
635 | ||
636 | lpm_req_regs = devm_kzalloc(&pdev->dev, lpm_size * sizeof(u32), | |
637 | GFP_KERNEL); | |
638 | if (!lpm_req_regs) | |
639 | goto free_acpi_obj; | |
640 | ||
641 | memcpy(lpm_req_regs, addr, lpm_size); | |
642 | pmcdev->lpm_req_regs = lpm_req_regs; | |
643 | ||
644 | free_acpi_obj: | |
645 | ACPI_FREE(out_obj); | |
646 | } | |
647 | ||
b740d2e9 RB |
648 | static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset) |
649 | { | |
650 | return readl(pmcdev->regbase + reg_offset); | |
651 | } | |
652 | ||
e0e60abc AS |
653 | static inline void pmc_core_reg_write(struct pmc_dev *pmcdev, int reg_offset, |
654 | u32 val) | |
173943b3 RB |
655 | { |
656 | writel(val, pmcdev->regbase + reg_offset); | |
657 | } | |
658 | ||
025f26de | 659 | static inline u64 pmc_core_adjust_slp_s0_step(struct pmc_dev *pmcdev, u32 value) |
b740d2e9 | 660 | { |
025f26de | 661 | return (u64)value * pmcdev->map->slp_s0_res_counter_step; |
b740d2e9 RB |
662 | } |
663 | ||
ee7abc10 TM |
664 | static int set_etr3(struct pmc_dev *pmcdev) |
665 | { | |
666 | const struct pmc_reg_map *map = pmcdev->map; | |
667 | u32 reg; | |
668 | int err; | |
669 | ||
670 | if (!map->etr3_offset) | |
671 | return -EOPNOTSUPP; | |
672 | ||
673 | mutex_lock(&pmcdev->lock); | |
674 | ||
675 | /* check if CF9 is locked */ | |
676 | reg = pmc_core_reg_read(pmcdev, map->etr3_offset); | |
677 | if (reg & ETR3_CF9LOCK) { | |
678 | err = -EACCES; | |
679 | goto out_unlock; | |
680 | } | |
681 | ||
682 | /* write CF9 global reset bit */ | |
683 | reg |= ETR3_CF9GR; | |
684 | pmc_core_reg_write(pmcdev, map->etr3_offset, reg); | |
685 | ||
686 | reg = pmc_core_reg_read(pmcdev, map->etr3_offset); | |
687 | if (!(reg & ETR3_CF9GR)) { | |
688 | err = -EIO; | |
689 | goto out_unlock; | |
690 | } | |
691 | ||
692 | err = 0; | |
693 | ||
694 | out_unlock: | |
695 | mutex_unlock(&pmcdev->lock); | |
696 | return err; | |
697 | } | |
698 | static umode_t etr3_is_visible(struct kobject *kobj, | |
699 | struct attribute *attr, | |
700 | int idx) | |
701 | { | |
702 | struct device *dev = container_of(kobj, struct device, kobj); | |
703 | struct pmc_dev *pmcdev = dev_get_drvdata(dev); | |
704 | const struct pmc_reg_map *map = pmcdev->map; | |
705 | u32 reg; | |
706 | ||
707 | mutex_lock(&pmcdev->lock); | |
708 | reg = pmc_core_reg_read(pmcdev, map->etr3_offset); | |
709 | mutex_unlock(&pmcdev->lock); | |
710 | ||
711 | return reg & ETR3_CF9LOCK ? attr->mode & (SYSFS_PREALLOC | 0444) : attr->mode; | |
712 | } | |
713 | ||
714 | static ssize_t etr3_show(struct device *dev, | |
715 | struct device_attribute *attr, char *buf) | |
716 | { | |
717 | struct pmc_dev *pmcdev = dev_get_drvdata(dev); | |
718 | const struct pmc_reg_map *map = pmcdev->map; | |
719 | u32 reg; | |
720 | ||
721 | if (!map->etr3_offset) | |
722 | return -EOPNOTSUPP; | |
723 | ||
724 | mutex_lock(&pmcdev->lock); | |
725 | ||
726 | reg = pmc_core_reg_read(pmcdev, map->etr3_offset); | |
727 | reg &= ETR3_CF9GR | ETR3_CF9LOCK; | |
728 | ||
729 | mutex_unlock(&pmcdev->lock); | |
730 | ||
731 | return sysfs_emit(buf, "0x%08x", reg); | |
732 | } | |
733 | ||
734 | static ssize_t etr3_store(struct device *dev, | |
735 | struct device_attribute *attr, | |
736 | const char *buf, size_t len) | |
737 | { | |
738 | struct pmc_dev *pmcdev = dev_get_drvdata(dev); | |
739 | int err; | |
740 | u32 reg; | |
741 | ||
742 | err = kstrtouint(buf, 16, ®); | |
743 | if (err) | |
744 | return err; | |
745 | ||
746 | /* allow only CF9 writes */ | |
747 | if (reg != ETR3_CF9GR) | |
748 | return -EINVAL; | |
749 | ||
750 | err = set_etr3(pmcdev); | |
751 | if (err) | |
752 | return err; | |
753 | ||
754 | return len; | |
755 | } | |
756 | static DEVICE_ATTR_RW(etr3); | |
757 | ||
758 | static struct attribute *pmc_attrs[] = { | |
759 | &dev_attr_etr3.attr, | |
760 | NULL | |
761 | }; | |
762 | ||
763 | static const struct attribute_group pmc_attr_group = { | |
764 | .attrs = pmc_attrs, | |
765 | .is_visible = etr3_is_visible, | |
766 | }; | |
767 | ||
768 | static const struct attribute_group *pmc_dev_groups[] = { | |
769 | &pmc_attr_group, | |
770 | NULL | |
771 | }; | |
772 | ||
df2294fb | 773 | static int pmc_core_dev_state_get(void *data, u64 *val) |
b740d2e9 | 774 | { |
df2294fb | 775 | struct pmc_dev *pmcdev = data; |
c977b98b | 776 | const struct pmc_reg_map *map = pmcdev->map; |
df2294fb | 777 | u32 value; |
b740d2e9 | 778 | |
c977b98b | 779 | value = pmc_core_reg_read(pmcdev, map->slp_s0_offset); |
025f26de | 780 | *val = pmc_core_adjust_slp_s0_step(pmcdev, value); |
b740d2e9 RB |
781 | |
782 | return 0; | |
783 | } | |
784 | ||
df2294fb | 785 | DEFINE_DEBUGFS_ATTRIBUTE(pmc_core_dev_state, pmc_core_dev_state_get, NULL, "%llu\n"); |
b740d2e9 | 786 | |
7dc4dc56 | 787 | static int pmc_core_check_read_lock_bit(struct pmc_dev *pmcdev) |
173943b3 | 788 | { |
173943b3 RB |
789 | u32 value; |
790 | ||
c977b98b SP |
791 | value = pmc_core_reg_read(pmcdev, pmcdev->map->pm_cfg_offset); |
792 | return value & BIT(pmcdev->map->pm_read_disable_bit); | |
173943b3 RB |
793 | } |
794 | ||
aae43c2b GK |
795 | static void pmc_core_slps0_display(struct pmc_dev *pmcdev, struct device *dev, |
796 | struct seq_file *s) | |
797 | { | |
798 | const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps; | |
799 | const struct pmc_bit_map *map; | |
800 | int offset = pmcdev->map->slps0_dbg_offset; | |
801 | u32 data; | |
802 | ||
803 | while (*maps) { | |
804 | map = *maps; | |
805 | data = pmc_core_reg_read(pmcdev, offset); | |
806 | offset += 4; | |
807 | while (map->name) { | |
808 | if (dev) | |
46461f87 | 809 | dev_info(dev, "SLP_S0_DBG: %-32s\tState: %s\n", |
aae43c2b GK |
810 | map->name, |
811 | data & map->bit_mask ? "Yes" : "No"); | |
812 | if (s) | |
813 | seq_printf(s, "SLP_S0_DBG: %-32s\tState: %s\n", | |
814 | map->name, | |
815 | data & map->bit_mask ? "Yes" : "No"); | |
816 | ++map; | |
817 | } | |
818 | ++maps; | |
819 | } | |
820 | } | |
821 | ||
267fc714 GK |
822 | static int pmc_core_lpm_get_arr_size(const struct pmc_bit_map **maps) |
823 | { | |
824 | int idx; | |
825 | ||
826 | for (idx = 0; maps[idx]; idx++) | |
827 | ;/* Nothing */ | |
828 | ||
829 | return idx; | |
830 | } | |
831 | ||
aae43c2b GK |
832 | static void pmc_core_lpm_display(struct pmc_dev *pmcdev, struct device *dev, |
833 | struct seq_file *s, u32 offset, | |
834 | const char *str, | |
835 | const struct pmc_bit_map **maps) | |
836 | { | |
267fc714 GK |
837 | int index, idx, len = 32, bit_mask, arr_size; |
838 | u32 *lpm_regs; | |
839 | ||
840 | arr_size = pmc_core_lpm_get_arr_size(maps); | |
841 | lpm_regs = kmalloc_array(arr_size, sizeof(*lpm_regs), GFP_KERNEL); | |
842 | if (!lpm_regs) | |
843 | return; | |
aae43c2b | 844 | |
267fc714 | 845 | for (index = 0; index < arr_size; index++) { |
aae43c2b GK |
846 | lpm_regs[index] = pmc_core_reg_read(pmcdev, offset); |
847 | offset += 4; | |
848 | } | |
849 | ||
267fc714 | 850 | for (idx = 0; idx < arr_size; idx++) { |
aae43c2b | 851 | if (dev) |
46461f87 | 852 | dev_info(dev, "\nLPM_%s_%d:\t0x%x\n", str, idx, |
aae43c2b GK |
853 | lpm_regs[idx]); |
854 | if (s) | |
855 | seq_printf(s, "\nLPM_%s_%d:\t0x%x\n", str, idx, | |
856 | lpm_regs[idx]); | |
857 | for (index = 0; maps[idx][index].name && index < len; index++) { | |
858 | bit_mask = maps[idx][index].bit_mask; | |
859 | if (dev) | |
46461f87 | 860 | dev_info(dev, "%-30s %-30d\n", |
aae43c2b GK |
861 | maps[idx][index].name, |
862 | lpm_regs[idx] & bit_mask ? 1 : 0); | |
863 | if (s) | |
864 | seq_printf(s, "%-30s %-30d\n", | |
865 | maps[idx][index].name, | |
866 | lpm_regs[idx] & bit_mask ? 1 : 0); | |
867 | } | |
868 | } | |
267fc714 GK |
869 | |
870 | kfree(lpm_regs); | |
aae43c2b GK |
871 | } |
872 | ||
4cf2afd6 BD |
873 | static bool slps0_dbg_latch; |
874 | ||
90113f3e AS |
875 | static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset) |
876 | { | |
877 | return readb(pmcdev->regbase + offset); | |
878 | } | |
879 | ||
e3985478 GK |
880 | static void pmc_core_display_map(struct seq_file *s, int index, int idx, int ip, |
881 | u8 pf_reg, const struct pmc_bit_map **pf_map) | |
0bdfaf42 RB |
882 | { |
883 | seq_printf(s, "PCH IP: %-2d - %-32s\tState: %s\n", | |
e3985478 GK |
884 | ip, pf_map[idx][index].name, |
885 | pf_map[idx][index].bit_mask & pf_reg ? "Off" : "On"); | |
0bdfaf42 RB |
886 | } |
887 | ||
3b1f9955 | 888 | static int pmc_core_ppfear_show(struct seq_file *s, void *unused) |
0bdfaf42 RB |
889 | { |
890 | struct pmc_dev *pmcdev = s->private; | |
e3985478 | 891 | const struct pmc_bit_map **maps = pmcdev->map->pfear_sts; |
c977b98b | 892 | u8 pf_regs[PPFEAR_MAX_NUM_ENTRIES]; |
e3985478 | 893 | int index, iter, idx, ip = 0; |
0bdfaf42 | 894 | |
c977b98b | 895 | iter = pmcdev->map->ppfear0_offset; |
0bdfaf42 | 896 | |
c977b98b SP |
897 | for (index = 0; index < pmcdev->map->ppfear_buckets && |
898 | index < PPFEAR_MAX_NUM_ENTRIES; index++, iter++) | |
0bdfaf42 RB |
899 | pf_regs[index] = pmc_core_reg_read_byte(pmcdev, iter); |
900 | ||
e3985478 GK |
901 | for (idx = 0; maps[idx]; idx++) { |
902 | for (index = 0; maps[idx][index].name && | |
903 | index < pmcdev->map->ppfear_buckets * 8; ip++, index++) | |
904 | pmc_core_display_map(s, index, idx, ip, | |
905 | pf_regs[index / 8], maps); | |
906 | } | |
0bdfaf42 RB |
907 | |
908 | return 0; | |
909 | } | |
3b1f9955 | 910 | DEFINE_SHOW_ATTRIBUTE(pmc_core_ppfear); |
0bdfaf42 | 911 | |
173943b3 | 912 | /* This function should return link status, 0 means ready */ |
7dc4dc56 | 913 | static int pmc_core_mtpmc_link_status(struct pmc_dev *pmcdev) |
173943b3 | 914 | { |
173943b3 RB |
915 | u32 value; |
916 | ||
917 | value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_STS_OFFSET); | |
4f24ecff | 918 | return value & BIT(SPT_PMC_MSG_FULL_STS_BIT); |
173943b3 RB |
919 | } |
920 | ||
7dc4dc56 | 921 | static int pmc_core_send_msg(struct pmc_dev *pmcdev, u32 *addr_xram) |
173943b3 | 922 | { |
173943b3 RB |
923 | u32 dest; |
924 | int timeout; | |
925 | ||
926 | for (timeout = NUM_RETRIES; timeout > 0; timeout--) { | |
7dc4dc56 | 927 | if (pmc_core_mtpmc_link_status(pmcdev) == 0) |
173943b3 RB |
928 | break; |
929 | msleep(5); | |
930 | } | |
931 | ||
7dc4dc56 | 932 | if (timeout <= 0 && pmc_core_mtpmc_link_status(pmcdev)) |
173943b3 RB |
933 | return -EBUSY; |
934 | ||
935 | dest = (*addr_xram & MTPMC_MASK) | (1U << 1); | |
936 | pmc_core_reg_write(pmcdev, SPT_PMC_MTPMC_OFFSET, dest); | |
937 | return 0; | |
938 | } | |
939 | ||
3b1f9955 | 940 | static int pmc_core_mphy_pg_show(struct seq_file *s, void *unused) |
173943b3 RB |
941 | { |
942 | struct pmc_dev *pmcdev = s->private; | |
943 | const struct pmc_bit_map *map = pmcdev->map->mphy_sts; | |
944 | u32 mphy_core_reg_low, mphy_core_reg_high; | |
945 | u32 val_low, val_high; | |
946 | int index, err = 0; | |
947 | ||
948 | if (pmcdev->pmc_xram_read_bit) { | |
949 | seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS."); | |
950 | return 0; | |
951 | } | |
952 | ||
953 | mphy_core_reg_low = (SPT_PMC_MPHY_CORE_STS_0 << 16); | |
954 | mphy_core_reg_high = (SPT_PMC_MPHY_CORE_STS_1 << 16); | |
955 | ||
956 | mutex_lock(&pmcdev->lock); | |
957 | ||
7dc4dc56 | 958 | if (pmc_core_send_msg(pmcdev, &mphy_core_reg_low) != 0) { |
173943b3 RB |
959 | err = -EBUSY; |
960 | goto out_unlock; | |
961 | } | |
962 | ||
963 | msleep(10); | |
964 | val_low = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET); | |
965 | ||
7dc4dc56 | 966 | if (pmc_core_send_msg(pmcdev, &mphy_core_reg_high) != 0) { |
173943b3 RB |
967 | err = -EBUSY; |
968 | goto out_unlock; | |
969 | } | |
970 | ||
971 | msleep(10); | |
972 | val_high = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET); | |
973 | ||
aff374df | 974 | for (index = 0; index < 8 && map[index].name; index++) { |
173943b3 RB |
975 | seq_printf(s, "%-32s\tState: %s\n", |
976 | map[index].name, | |
977 | map[index].bit_mask & val_low ? "Not power gated" : | |
978 | "Power gated"); | |
979 | } | |
980 | ||
981 | for (index = 8; map[index].name; index++) { | |
982 | seq_printf(s, "%-32s\tState: %s\n", | |
983 | map[index].name, | |
984 | map[index].bit_mask & val_high ? "Not power gated" : | |
985 | "Power gated"); | |
986 | } | |
987 | ||
988 | out_unlock: | |
989 | mutex_unlock(&pmcdev->lock); | |
990 | return err; | |
991 | } | |
3b1f9955 | 992 | DEFINE_SHOW_ATTRIBUTE(pmc_core_mphy_pg); |
173943b3 | 993 | |
fe748227 RB |
994 | static int pmc_core_pll_show(struct seq_file *s, void *unused) |
995 | { | |
996 | struct pmc_dev *pmcdev = s->private; | |
997 | const struct pmc_bit_map *map = pmcdev->map->pll_sts; | |
998 | u32 mphy_common_reg, val; | |
999 | int index, err = 0; | |
1000 | ||
1001 | if (pmcdev->pmc_xram_read_bit) { | |
1002 | seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS."); | |
1003 | return 0; | |
1004 | } | |
1005 | ||
1006 | mphy_common_reg = (SPT_PMC_MPHY_COM_STS_0 << 16); | |
1007 | mutex_lock(&pmcdev->lock); | |
1008 | ||
7dc4dc56 | 1009 | if (pmc_core_send_msg(pmcdev, &mphy_common_reg) != 0) { |
fe748227 RB |
1010 | err = -EBUSY; |
1011 | goto out_unlock; | |
1012 | } | |
1013 | ||
1014 | /* Observed PMC HW response latency for MTPMC-MFPMC is ~10 ms */ | |
1015 | msleep(10); | |
1016 | val = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET); | |
1017 | ||
1018 | for (index = 0; map[index].name ; index++) { | |
1019 | seq_printf(s, "%-32s\tState: %s\n", | |
1020 | map[index].name, | |
1021 | map[index].bit_mask & val ? "Active" : "Idle"); | |
1022 | } | |
1023 | ||
1024 | out_unlock: | |
1025 | mutex_unlock(&pmcdev->lock); | |
1026 | return err; | |
1027 | } | |
3b1f9955 | 1028 | DEFINE_SHOW_ATTRIBUTE(pmc_core_pll); |
fe748227 | 1029 | |
7dc4dc56 | 1030 | static int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value) |
9c2ee199 | 1031 | { |
c977b98b | 1032 | const struct pmc_reg_map *map = pmcdev->map; |
36974daf DB |
1033 | u32 reg; |
1034 | int err = 0; | |
95924388 AS |
1035 | |
1036 | mutex_lock(&pmcdev->lock); | |
9c2ee199 | 1037 | |
36974daf | 1038 | if (value > map->ltr_ignore_max) { |
9c2ee199 RB |
1039 | err = -EINVAL; |
1040 | goto out_unlock; | |
1041 | } | |
1042 | ||
36974daf DB |
1043 | reg = pmc_core_reg_read(pmcdev, map->ltr_ignore_offset); |
1044 | reg |= BIT(value); | |
1045 | pmc_core_reg_write(pmcdev, map->ltr_ignore_offset, reg); | |
9c2ee199 RB |
1046 | |
1047 | out_unlock: | |
1048 | mutex_unlock(&pmcdev->lock); | |
36974daf DB |
1049 | |
1050 | return err; | |
1051 | } | |
1052 | ||
1053 | static ssize_t pmc_core_ltr_ignore_write(struct file *file, | |
1054 | const char __user *userbuf, | |
1055 | size_t count, loff_t *ppos) | |
1056 | { | |
7dc4dc56 DB |
1057 | struct seq_file *s = file->private_data; |
1058 | struct pmc_dev *pmcdev = s->private; | |
36974daf DB |
1059 | u32 buf_size, value; |
1060 | int err; | |
1061 | ||
1062 | buf_size = min_t(u32, count, 64); | |
1063 | ||
1064 | err = kstrtou32_from_user(userbuf, buf_size, 10, &value); | |
1065 | if (err) | |
1066 | return err; | |
1067 | ||
7dc4dc56 | 1068 | err = pmc_core_send_ltr_ignore(pmcdev, value); |
36974daf | 1069 | |
9c2ee199 RB |
1070 | return err == 0 ? count : err; |
1071 | } | |
1072 | ||
1073 | static int pmc_core_ltr_ignore_show(struct seq_file *s, void *unused) | |
1074 | { | |
1075 | return 0; | |
1076 | } | |
1077 | ||
1078 | static int pmc_core_ltr_ignore_open(struct inode *inode, struct file *file) | |
1079 | { | |
1080 | return single_open(file, pmc_core_ltr_ignore_show, inode->i_private); | |
1081 | } | |
1082 | ||
1083 | static const struct file_operations pmc_core_ltr_ignore_ops = { | |
1084 | .open = pmc_core_ltr_ignore_open, | |
1085 | .read = seq_read, | |
1086 | .write = pmc_core_ltr_ignore_write, | |
1087 | .llseek = seq_lseek, | |
1088 | .release = single_release, | |
1089 | }; | |
1090 | ||
4cf2afd6 BD |
1091 | static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset) |
1092 | { | |
1093 | const struct pmc_reg_map *map = pmcdev->map; | |
1094 | u32 fd; | |
1095 | ||
1096 | mutex_lock(&pmcdev->lock); | |
1097 | ||
1098 | if (!reset && !slps0_dbg_latch) | |
1099 | goto out_unlock; | |
1100 | ||
1101 | fd = pmc_core_reg_read(pmcdev, map->slps0_dbg_offset); | |
1102 | if (reset) | |
1103 | fd &= ~CNP_PMC_LATCH_SLPS0_EVENTS; | |
1104 | else | |
1105 | fd |= CNP_PMC_LATCH_SLPS0_EVENTS; | |
1106 | pmc_core_reg_write(pmcdev, map->slps0_dbg_offset, fd); | |
1107 | ||
3be39553 | 1108 | slps0_dbg_latch = false; |
4cf2afd6 BD |
1109 | |
1110 | out_unlock: | |
1111 | mutex_unlock(&pmcdev->lock); | |
1112 | } | |
1113 | ||
1114 | static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused) | |
1115 | { | |
1116 | struct pmc_dev *pmcdev = s->private; | |
4cf2afd6 BD |
1117 | |
1118 | pmc_core_slps0_dbg_latch(pmcdev, false); | |
4d6a63e0 | 1119 | pmc_core_slps0_display(pmcdev, NULL, s); |
4cf2afd6 | 1120 | pmc_core_slps0_dbg_latch(pmcdev, true); |
4d6a63e0 | 1121 | |
4cf2afd6 BD |
1122 | return 0; |
1123 | } | |
1124 | DEFINE_SHOW_ATTRIBUTE(pmc_core_slps0_dbg); | |
1125 | ||
8122e7cd RB |
1126 | static u32 convert_ltr_scale(u32 val) |
1127 | { | |
1128 | /* | |
1129 | * As per PCIE specification supporting document | |
1130 | * ECN_LatencyTolnReporting_14Aug08.pdf the Latency | |
1131 | * Tolerance Reporting data payload is encoded in a | |
1132 | * 3 bit scale and 10 bit value fields. Values are | |
1133 | * multiplied by the indicated scale to yield an absolute time | |
1134 | * value, expressible in a range from 1 nanosecond to | |
1135 | * 2^25*(2^10-1) = 34,326,183,936 nanoseconds. | |
1136 | * | |
1137 | * scale encoding is as follows: | |
1138 | * | |
1139 | * ---------------------------------------------- | |
1140 | * |scale factor | Multiplier (ns) | | |
1141 | * ---------------------------------------------- | |
1142 | * | 0 | 1 | | |
1143 | * | 1 | 32 | | |
1144 | * | 2 | 1024 | | |
1145 | * | 3 | 32768 | | |
1146 | * | 4 | 1048576 | | |
1147 | * | 5 | 33554432 | | |
1148 | * | 6 | Invalid | | |
1149 | * | 7 | Invalid | | |
1150 | * ---------------------------------------------- | |
1151 | */ | |
1152 | if (val > 5) { | |
1153 | pr_warn("Invalid LTR scale factor.\n"); | |
1154 | return 0; | |
1155 | } | |
1156 | ||
1157 | return 1U << (5 * val); | |
1158 | } | |
1159 | ||
2eb15055 RB |
1160 | static int pmc_core_ltr_show(struct seq_file *s, void *unused) |
1161 | { | |
1162 | struct pmc_dev *pmcdev = s->private; | |
1163 | const struct pmc_bit_map *map = pmcdev->map->ltr_show_sts; | |
8122e7cd RB |
1164 | u64 decoded_snoop_ltr, decoded_non_snoop_ltr; |
1165 | u32 ltr_raw_data, scale, val; | |
1166 | u16 snoop_ltr, nonsnoop_ltr; | |
2eb15055 RB |
1167 | int index; |
1168 | ||
1169 | for (index = 0; map[index].name ; index++) { | |
8122e7cd RB |
1170 | decoded_snoop_ltr = decoded_non_snoop_ltr = 0; |
1171 | ltr_raw_data = pmc_core_reg_read(pmcdev, | |
1172 | map[index].bit_mask); | |
1173 | snoop_ltr = ltr_raw_data & ~MTPMC_MASK; | |
1174 | nonsnoop_ltr = (ltr_raw_data >> 0x10) & ~MTPMC_MASK; | |
1175 | ||
1176 | if (FIELD_GET(LTR_REQ_NONSNOOP, ltr_raw_data)) { | |
1177 | scale = FIELD_GET(LTR_DECODED_SCALE, nonsnoop_ltr); | |
1178 | val = FIELD_GET(LTR_DECODED_VAL, nonsnoop_ltr); | |
1179 | decoded_non_snoop_ltr = val * convert_ltr_scale(scale); | |
1180 | } | |
1181 | ||
1182 | if (FIELD_GET(LTR_REQ_SNOOP, ltr_raw_data)) { | |
1183 | scale = FIELD_GET(LTR_DECODED_SCALE, snoop_ltr); | |
1184 | val = FIELD_GET(LTR_DECODED_VAL, snoop_ltr); | |
1185 | decoded_snoop_ltr = val * convert_ltr_scale(scale); | |
1186 | } | |
1187 | ||
1188 | seq_printf(s, "%-32s\tLTR: RAW: 0x%-16x\tNon-Snoop(ns): %-16llu\tSnoop(ns): %-16llu\n", | |
1189 | map[index].name, ltr_raw_data, | |
1190 | decoded_non_snoop_ltr, | |
1191 | decoded_snoop_ltr); | |
2eb15055 RB |
1192 | } |
1193 | return 0; | |
1194 | } | |
1195 | DEFINE_SHOW_ATTRIBUTE(pmc_core_ltr); | |
1196 | ||
29c2dd88 GK |
1197 | static inline u64 adjust_lpm_residency(struct pmc_dev *pmcdev, u32 offset, |
1198 | const int lpm_adj_x2) | |
1199 | { | |
1200 | u64 lpm_res = pmc_core_reg_read(pmcdev, offset); | |
1201 | ||
1202 | return GET_X2_COUNTER((u64)lpm_adj_x2 * lpm_res); | |
1203 | } | |
1204 | ||
a45096ac GK |
1205 | static int pmc_core_substate_res_show(struct seq_file *s, void *unused) |
1206 | { | |
1207 | struct pmc_dev *pmcdev = s->private; | |
29c2dd88 | 1208 | const int lpm_adj_x2 = pmcdev->map->lpm_res_counter_step_x2; |
a45096ac | 1209 | u32 offset = pmcdev->map->lpm_residency_offset; |
005125bf | 1210 | int i, mode; |
a45096ac | 1211 | |
005125bf GK |
1212 | seq_printf(s, "%-10s %-15s\n", "Substate", "Residency"); |
1213 | ||
1214 | pmc_for_each_mode(i, mode, pmcdev) { | |
29c2dd88 GK |
1215 | seq_printf(s, "%-10s %-15llu\n", pmc_lpm_modes[mode], |
1216 | adjust_lpm_residency(pmcdev, offset + (4 * mode), lpm_adj_x2)); | |
a45096ac GK |
1217 | } |
1218 | ||
1219 | return 0; | |
1220 | } | |
1221 | DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_res); | |
1222 | ||
f632817d GK |
1223 | static int pmc_core_substate_sts_regs_show(struct seq_file *s, void *unused) |
1224 | { | |
1225 | struct pmc_dev *pmcdev = s->private; | |
1226 | const struct pmc_bit_map **maps = pmcdev->map->lpm_sts; | |
1227 | u32 offset = pmcdev->map->lpm_status_offset; | |
1228 | ||
913f984a | 1229 | pmc_core_lpm_display(pmcdev, NULL, s, offset, "STATUS", maps); |
f632817d GK |
1230 | |
1231 | return 0; | |
1232 | } | |
1233 | DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_sts_regs); | |
1234 | ||
7adb1e8a GK |
1235 | static int pmc_core_substate_l_sts_regs_show(struct seq_file *s, void *unused) |
1236 | { | |
1237 | struct pmc_dev *pmcdev = s->private; | |
1238 | const struct pmc_bit_map **maps = pmcdev->map->lpm_sts; | |
1239 | u32 offset = pmcdev->map->lpm_live_status_offset; | |
1240 | ||
1241 | pmc_core_lpm_display(pmcdev, NULL, s, offset, "LIVE_STATUS", maps); | |
1242 | ||
1243 | return 0; | |
1244 | } | |
1245 | DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_l_sts_regs); | |
1246 | ||
952c1553 GK |
1247 | static void pmc_core_substate_req_header_show(struct seq_file *s) |
1248 | { | |
1249 | struct pmc_dev *pmcdev = s->private; | |
1250 | int i, mode; | |
1251 | ||
1252 | seq_printf(s, "%30s |", "Element"); | |
1253 | pmc_for_each_mode(i, mode, pmcdev) | |
1254 | seq_printf(s, " %9s |", pmc_lpm_modes[mode]); | |
1255 | ||
1256 | seq_printf(s, " %9s |\n", "Status"); | |
1257 | } | |
1258 | ||
1259 | static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused) | |
1260 | { | |
1261 | struct pmc_dev *pmcdev = s->private; | |
1262 | const struct pmc_bit_map **maps = pmcdev->map->lpm_sts; | |
1263 | const struct pmc_bit_map *map; | |
1264 | const int num_maps = pmcdev->map->lpm_num_maps; | |
1265 | u32 sts_offset = pmcdev->map->lpm_status_offset; | |
1266 | u32 *lpm_req_regs = pmcdev->lpm_req_regs; | |
1267 | int mp; | |
1268 | ||
1269 | /* Display the header */ | |
1270 | pmc_core_substate_req_header_show(s); | |
1271 | ||
1272 | /* Loop over maps */ | |
1273 | for (mp = 0; mp < num_maps; mp++) { | |
1274 | u32 req_mask = 0; | |
1275 | u32 lpm_status; | |
1276 | int mode, idx, i, len = 32; | |
1277 | ||
1278 | /* | |
1279 | * Capture the requirements and create a mask so that we only | |
1280 | * show an element if it's required for at least one of the | |
1281 | * enabled low power modes | |
1282 | */ | |
1283 | pmc_for_each_mode(idx, mode, pmcdev) | |
1284 | req_mask |= lpm_req_regs[mp + (mode * num_maps)]; | |
1285 | ||
1286 | /* Get the last latched status for this map */ | |
1287 | lpm_status = pmc_core_reg_read(pmcdev, sts_offset + (mp * 4)); | |
1288 | ||
1289 | /* Loop over elements in this map */ | |
1290 | map = maps[mp]; | |
1291 | for (i = 0; map[i].name && i < len; i++) { | |
1292 | u32 bit_mask = map[i].bit_mask; | |
1293 | ||
1294 | if (!(bit_mask & req_mask)) | |
1295 | /* | |
1296 | * Not required for any enabled states | |
1297 | * so don't display | |
1298 | */ | |
1299 | continue; | |
1300 | ||
1301 | /* Display the element name in the first column */ | |
1302 | seq_printf(s, "%30s |", map[i].name); | |
1303 | ||
1304 | /* Loop over the enabled states and display if required */ | |
1305 | pmc_for_each_mode(idx, mode, pmcdev) { | |
1306 | if (lpm_req_regs[mp + (mode * num_maps)] & bit_mask) | |
1307 | seq_printf(s, " %9s |", | |
1308 | "Required"); | |
1309 | else | |
1310 | seq_printf(s, " %9s |", " "); | |
1311 | } | |
1312 | ||
1313 | /* In Status column, show the last captured state of this agent */ | |
1314 | if (lpm_status & bit_mask) | |
1315 | seq_printf(s, " %9s |", "Yes"); | |
1316 | else | |
1317 | seq_printf(s, " %9s |", " "); | |
1318 | ||
1319 | seq_puts(s, "\n"); | |
1320 | } | |
1321 | } | |
1322 | ||
1323 | return 0; | |
1324 | } | |
1325 | DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_req_regs); | |
1326 | ||
8074a79f DB |
1327 | static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused) |
1328 | { | |
1329 | struct pmc_dev *pmcdev = s->private; | |
1330 | bool c10; | |
1331 | u32 reg; | |
1332 | int idx, mode; | |
1333 | ||
1334 | reg = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_sts_latch_en_offset); | |
1335 | if (reg & LPM_STS_LATCH_MODE) { | |
1336 | seq_puts(s, "c10"); | |
1337 | c10 = false; | |
1338 | } else { | |
1339 | seq_puts(s, "[c10]"); | |
1340 | c10 = true; | |
1341 | } | |
1342 | ||
1343 | pmc_for_each_mode(idx, mode, pmcdev) { | |
1344 | if ((BIT(mode) & reg) && !c10) | |
1345 | seq_printf(s, " [%s]", pmc_lpm_modes[mode]); | |
1346 | else | |
1347 | seq_printf(s, " %s", pmc_lpm_modes[mode]); | |
1348 | } | |
1349 | ||
1350 | seq_puts(s, " clear\n"); | |
1351 | ||
1352 | return 0; | |
1353 | } | |
1354 | ||
1355 | static ssize_t pmc_core_lpm_latch_mode_write(struct file *file, | |
1356 | const char __user *userbuf, | |
1357 | size_t count, loff_t *ppos) | |
1358 | { | |
1359 | struct seq_file *s = file->private_data; | |
1360 | struct pmc_dev *pmcdev = s->private; | |
1361 | bool clear = false, c10 = false; | |
1362 | unsigned char buf[8]; | |
1363 | size_t ret; | |
1364 | int idx, m, mode; | |
1365 | u32 reg; | |
1366 | ||
1367 | if (count > sizeof(buf) - 1) | |
1368 | return -EINVAL; | |
1369 | ||
1370 | ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, userbuf, count); | |
1371 | if (ret < 0) | |
1372 | return ret; | |
1373 | ||
1374 | buf[count] = '\0'; | |
1375 | ||
1376 | /* | |
1377 | * Allowed strings are: | |
1378 | * Any enabled substate, e.g. 'S0i2.0' | |
1379 | * 'c10' | |
1380 | * 'clear' | |
1381 | */ | |
1382 | mode = sysfs_match_string(pmc_lpm_modes, buf); | |
1383 | ||
1384 | /* Check string matches enabled mode */ | |
1385 | pmc_for_each_mode(idx, m, pmcdev) | |
1386 | if (mode == m) | |
1387 | break; | |
1388 | ||
1389 | if (mode != m || mode < 0) { | |
1390 | if (sysfs_streq(buf, "clear")) | |
1391 | clear = true; | |
1392 | else if (sysfs_streq(buf, "c10")) | |
1393 | c10 = true; | |
1394 | else | |
1395 | return -EINVAL; | |
1396 | } | |
1397 | ||
1398 | if (clear) { | |
1399 | mutex_lock(&pmcdev->lock); | |
1400 | ||
1401 | reg = pmc_core_reg_read(pmcdev, pmcdev->map->etr3_offset); | |
1402 | reg |= ETR3_CLEAR_LPM_EVENTS; | |
1403 | pmc_core_reg_write(pmcdev, pmcdev->map->etr3_offset, reg); | |
1404 | ||
1405 | mutex_unlock(&pmcdev->lock); | |
1406 | ||
1407 | return count; | |
1408 | } | |
1409 | ||
1410 | if (c10) { | |
1411 | mutex_lock(&pmcdev->lock); | |
1412 | ||
1413 | reg = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_sts_latch_en_offset); | |
1414 | reg &= ~LPM_STS_LATCH_MODE; | |
1415 | pmc_core_reg_write(pmcdev, pmcdev->map->lpm_sts_latch_en_offset, reg); | |
1416 | ||
1417 | mutex_unlock(&pmcdev->lock); | |
1418 | ||
1419 | return count; | |
1420 | } | |
1421 | ||
1422 | /* | |
1423 | * For LPM mode latching we set the latch enable bit and selected mode | |
1424 | * and clear everything else. | |
1425 | */ | |
1426 | reg = LPM_STS_LATCH_MODE | BIT(mode); | |
1427 | mutex_lock(&pmcdev->lock); | |
1428 | pmc_core_reg_write(pmcdev, pmcdev->map->lpm_sts_latch_en_offset, reg); | |
1429 | mutex_unlock(&pmcdev->lock); | |
1430 | ||
1431 | return count; | |
1432 | } | |
1433 | DEFINE_PMC_CORE_ATTR_WRITE(pmc_core_lpm_latch_mode); | |
1434 | ||
8aba056a RB |
1435 | static int pmc_core_pkgc_show(struct seq_file *s, void *unused) |
1436 | { | |
1437 | struct pmc_dev *pmcdev = s->private; | |
1438 | const struct pmc_bit_map *map = pmcdev->map->msr_sts; | |
1439 | u64 pcstate_count; | |
1440 | int index; | |
1441 | ||
1442 | for (index = 0; map[index].name ; index++) { | |
1443 | if (rdmsrl_safe(map[index].bit_mask, &pcstate_count)) | |
1444 | continue; | |
1445 | ||
c09c6071 HP |
1446 | pcstate_count *= 1000; |
1447 | do_div(pcstate_count, tsc_khz); | |
1448 | seq_printf(s, "%-8s : %llu\n", map[index].name, | |
8aba056a RB |
1449 | pcstate_count); |
1450 | } | |
1451 | ||
1452 | return 0; | |
1453 | } | |
1454 | DEFINE_SHOW_ATTRIBUTE(pmc_core_pkgc); | |
1455 | ||
005125bf GK |
1456 | static void pmc_core_get_low_power_modes(struct pmc_dev *pmcdev) |
1457 | { | |
1458 | u8 lpm_priority[LPM_MAX_NUM_MODES]; | |
1459 | u32 lpm_en; | |
1460 | int mode, i, p; | |
1461 | ||
1462 | /* Use LPM Maps to indicate support for substates */ | |
1463 | if (!pmcdev->map->lpm_num_maps) | |
1464 | return; | |
1465 | ||
1466 | lpm_en = pmc_core_reg_read(pmcdev, pmcdev->map->lpm_en_offset); | |
1467 | pmcdev->num_lpm_modes = hweight32(lpm_en); | |
1468 | ||
1469 | /* Each byte contains information for 2 modes (7:4 and 3:0) */ | |
1470 | for (mode = 0; mode < LPM_MAX_NUM_MODES; mode += 2) { | |
1471 | u8 priority = pmc_core_reg_read_byte(pmcdev, | |
1472 | pmcdev->map->lpm_priority_offset + (mode / 2)); | |
1473 | int pri0 = GENMASK(3, 0) & priority; | |
1474 | int pri1 = (GENMASK(7, 4) & priority) >> 4; | |
1475 | ||
1476 | lpm_priority[pri0] = mode; | |
1477 | lpm_priority[pri1] = mode + 1; | |
1478 | } | |
1479 | ||
1480 | /* | |
1481 | * Loop though all modes from lowest to highest priority, | |
1482 | * and capture all enabled modes in order | |
1483 | */ | |
1484 | i = 0; | |
1485 | for (p = LPM_MAX_NUM_MODES - 1; p >= 0; p--) { | |
1486 | int mode = lpm_priority[p]; | |
1487 | ||
1488 | if (!(BIT(mode) & lpm_en)) | |
1489 | continue; | |
1490 | ||
1491 | pmcdev->lpm_en_modes[i++] = mode; | |
1492 | } | |
1493 | } | |
1494 | ||
b740d2e9 RB |
1495 | static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) |
1496 | { | |
1497 | debugfs_remove_recursive(pmcdev->dbgfs_dir); | |
1498 | } | |
1499 | ||
15167554 | 1500 | static void pmc_core_dbgfs_register(struct pmc_dev *pmcdev) |
b740d2e9 | 1501 | { |
750e0f57 | 1502 | struct dentry *dir; |
b740d2e9 RB |
1503 | |
1504 | dir = debugfs_create_dir("pmc_core", NULL); | |
b740d2e9 | 1505 | pmcdev->dbgfs_dir = dir; |
b740d2e9 | 1506 | |
750e0f57 RB |
1507 | debugfs_create_file("slp_s0_residency_usec", 0444, dir, pmcdev, |
1508 | &pmc_core_dev_state); | |
b740d2e9 | 1509 | |
6268c0b2 GK |
1510 | if (pmcdev->map->pfear_sts) |
1511 | debugfs_create_file("pch_ip_power_gating_status", 0444, dir, | |
1512 | pmcdev, &pmc_core_ppfear_fops); | |
173943b3 | 1513 | |
750e0f57 RB |
1514 | debugfs_create_file("ltr_ignore", 0644, dir, pmcdev, |
1515 | &pmc_core_ltr_ignore_ops); | |
9c2ee199 | 1516 | |
cd89e92b | 1517 | debugfs_create_file("ltr_show", 0444, dir, pmcdev, &pmc_core_ltr_fops); |
2eb15055 | 1518 | |
8aba056a RB |
1519 | debugfs_create_file("package_cstate_show", 0444, dir, pmcdev, |
1520 | &pmc_core_pkgc_fops); | |
1521 | ||
750e0f57 RB |
1522 | if (pmcdev->map->pll_sts) |
1523 | debugfs_create_file("pll_status", 0444, dir, pmcdev, | |
3b1f9955 | 1524 | &pmc_core_pll_fops); |
9c2ee199 | 1525 | |
750e0f57 RB |
1526 | if (pmcdev->map->mphy_sts) |
1527 | debugfs_create_file("mphy_core_lanes_power_gating_status", | |
1528 | 0444, dir, pmcdev, | |
3b1f9955 | 1529 | &pmc_core_mphy_pg_fops); |
0bdfaf42 | 1530 | |
4cf2afd6 BD |
1531 | if (pmcdev->map->slps0_dbg_maps) { |
1532 | debugfs_create_file("slp_s0_debug_status", 0444, | |
1533 | dir, pmcdev, | |
1534 | &pmc_core_slps0_dbg_fops); | |
1535 | ||
1536 | debugfs_create_bool("slp_s0_dbg_latch", 0644, | |
1537 | dir, &slps0_dbg_latch); | |
1538 | } | |
a45096ac GK |
1539 | |
1540 | if (pmcdev->map->lpm_en_offset) { | |
1541 | debugfs_create_file("substate_residencies", 0444, | |
1542 | pmcdev->dbgfs_dir, pmcdev, | |
1543 | &pmc_core_substate_res_fops); | |
1544 | } | |
f632817d GK |
1545 | |
1546 | if (pmcdev->map->lpm_status_offset) { | |
1547 | debugfs_create_file("substate_status_registers", 0444, | |
1548 | pmcdev->dbgfs_dir, pmcdev, | |
1549 | &pmc_core_substate_sts_regs_fops); | |
7adb1e8a GK |
1550 | debugfs_create_file("substate_live_status_registers", 0444, |
1551 | pmcdev->dbgfs_dir, pmcdev, | |
1552 | &pmc_core_substate_l_sts_regs_fops); | |
8074a79f DB |
1553 | debugfs_create_file("lpm_latch_mode", 0644, |
1554 | pmcdev->dbgfs_dir, pmcdev, | |
1555 | &pmc_core_lpm_latch_mode_fops); | |
7adb1e8a | 1556 | } |
952c1553 GK |
1557 | |
1558 | if (pmcdev->lpm_req_regs) { | |
1559 | debugfs_create_file("substate_requirements", 0444, | |
1560 | pmcdev->dbgfs_dir, pmcdev, | |
1561 | &pmc_core_substate_req_regs_fops); | |
1562 | } | |
0bdfaf42 | 1563 | } |
b740d2e9 RB |
1564 | |
1565 | static const struct x86_cpu_id intel_pmc_core_ids[] = { | |
a69b3b1d TG |
1566 | X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, &spt_reg_map), |
1567 | X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, &spt_reg_map), | |
1568 | X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, &spt_reg_map), | |
1569 | X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &spt_reg_map), | |
1570 | X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, &cnp_reg_map), | |
1571 | X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &icl_reg_map), | |
1572 | X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI, &icl_reg_map), | |
1573 | X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &cnp_reg_map), | |
1574 | X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &cnp_reg_map), | |
1575 | X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &tgl_reg_map), | |
1576 | X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, &tgl_reg_map), | |
1577 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT, &tgl_reg_map), | |
e87fa339 | 1578 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, &icl_reg_map), |
68cb1a97 | 1579 | X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &tgl_reg_map), |
0636cdc9 | 1580 | X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &tgl_reg_map), |
b740d2e9 RB |
1581 | {} |
1582 | }; | |
1583 | ||
21ae4357 SP |
1584 | MODULE_DEVICE_TABLE(x86cpu, intel_pmc_core_ids); |
1585 | ||
661405bd | 1586 | static const struct pci_device_id pmc_pci_ids[] = { |
476bac56 AS |
1587 | { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID) }, |
1588 | { } | |
661405bd RB |
1589 | }; |
1590 | ||
238f9c11 RB |
1591 | /* |
1592 | * This quirk can be used on those platforms where | |
cbe35819 | 1593 | * the platform BIOS enforces 24Mhz crystal to shutdown |
238f9c11 RB |
1594 | * before PMC can assert SLP_S0#. |
1595 | */ | |
c9f86d6c | 1596 | static bool xtal_ignore; |
9ae11e23 | 1597 | static int quirk_xtal_ignore(const struct dmi_system_id *id) |
238f9c11 | 1598 | { |
c9f86d6c DB |
1599 | xtal_ignore = true; |
1600 | return 0; | |
1601 | } | |
1602 | ||
1603 | static void pmc_core_xtal_ignore(struct pmc_dev *pmcdev) | |
1604 | { | |
238f9c11 RB |
1605 | u32 value; |
1606 | ||
1607 | value = pmc_core_reg_read(pmcdev, pmcdev->map->pm_vric1_offset); | |
1608 | /* 24MHz Crystal Shutdown Qualification Disable */ | |
1609 | value |= SPT_PMC_VRIC1_XTALSDQDIS; | |
1610 | /* Low Voltage Mode Enable */ | |
1611 | value &= ~SPT_PMC_VRIC1_SLPS0LVEN; | |
1612 | pmc_core_reg_write(pmcdev, pmcdev->map->pm_vric1_offset, value); | |
238f9c11 RB |
1613 | } |
1614 | ||
1615 | static const struct dmi_system_id pmc_core_dmi_table[] = { | |
1616 | { | |
1617 | .callback = quirk_xtal_ignore, | |
1618 | .ident = "HP Elite x2 1013 G3", | |
1619 | .matches = { | |
1620 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | |
1621 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Elite x2 1013 G3"), | |
1622 | }, | |
1623 | }, | |
1624 | {} | |
1625 | }; | |
1626 | ||
c9f86d6c DB |
1627 | static void pmc_core_do_dmi_quirks(struct pmc_dev *pmcdev) |
1628 | { | |
1629 | dmi_check_system(pmc_core_dmi_table); | |
1630 | ||
1631 | if (xtal_ignore) | |
1632 | pmc_core_xtal_ignore(pmcdev); | |
1633 | } | |
1634 | ||
6c96a78c | 1635 | static int pmc_core_probe(struct platform_device *pdev) |
b740d2e9 | 1636 | { |
6c96a78c | 1637 | static bool device_initialized; |
7dc4dc56 | 1638 | struct pmc_dev *pmcdev; |
b740d2e9 | 1639 | const struct x86_cpu_id *cpu_id; |
745698c3 | 1640 | u64 slp_s0_addr; |
b740d2e9 | 1641 | |
6c96a78c RJ |
1642 | if (device_initialized) |
1643 | return -ENODEV; | |
1644 | ||
7dc4dc56 DB |
1645 | pmcdev = devm_kzalloc(&pdev->dev, sizeof(*pmcdev), GFP_KERNEL); |
1646 | if (!pmcdev) | |
1647 | return -ENOMEM; | |
1648 | ||
1649 | platform_set_drvdata(pdev, pmcdev); | |
1650 | ||
b740d2e9 | 1651 | cpu_id = x86_match_cpu(intel_pmc_core_ids); |
21ae4357 SP |
1652 | if (!cpu_id) |
1653 | return -ENODEV; | |
1654 | ||
1655 | pmcdev->map = (struct pmc_reg_map *)cpu_id->driver_data; | |
745698c3 | 1656 | |
661405bd | 1657 | /* |
43e82d8a GK |
1658 | * Coffee Lake has CPU ID of Kaby Lake and Cannon Lake PCH. So here |
1659 | * Sunrisepoint PCH regmap can't be used. Use Cannon Lake PCH regmap | |
661405bd RB |
1660 | * in this case. |
1661 | */ | |
e50af833 | 1662 | if (pmcdev->map == &spt_reg_map && !pci_dev_present(pmc_pci_ids)) |
661405bd RB |
1663 | pmcdev->map = &cnp_reg_map; |
1664 | ||
7d505758 | 1665 | if (lpit_read_residency_count_address(&slp_s0_addr)) { |
745698c3 | 1666 | pmcdev->base_addr = PMC_BASE_ADDR_DEFAULT; |
7d505758 VB |
1667 | |
1668 | if (page_is_ram(PHYS_PFN(pmcdev->base_addr))) | |
1669 | return -ENODEV; | |
1670 | } else { | |
745698c3 | 1671 | pmcdev->base_addr = slp_s0_addr - pmcdev->map->slp_s0_offset; |
7d505758 | 1672 | } |
745698c3 | 1673 | |
21ae4357 SP |
1674 | pmcdev->regbase = ioremap(pmcdev->base_addr, |
1675 | pmcdev->map->regmap_length); | |
1676 | if (!pmcdev->regbase) | |
b740d2e9 | 1677 | return -ENOMEM; |
b740d2e9 | 1678 | |
173943b3 | 1679 | mutex_init(&pmcdev->lock); |
42813136 | 1680 | |
7dc4dc56 | 1681 | pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(pmcdev); |
005125bf | 1682 | pmc_core_get_low_power_modes(pmcdev); |
c9f86d6c | 1683 | pmc_core_do_dmi_quirks(pmcdev); |
173943b3 | 1684 | |
42813136 GK |
1685 | if (pmcdev->map == &tgl_reg_map) |
1686 | pmc_core_get_tgl_lpm_reqs(pdev); | |
1687 | ||
36974daf DB |
1688 | /* |
1689 | * On TGL, due to a hardware limitation, the GBE LTR blocks PC10 when | |
1690 | * a cable is attached. Tell the PMC to ignore it. | |
1691 | */ | |
1692 | if (pmcdev->map == &tgl_reg_map) { | |
1693 | dev_dbg(&pdev->dev, "ignoring GBE LTR\n"); | |
7dc4dc56 | 1694 | pmc_core_send_ltr_ignore(pmcdev, 3); |
36974daf DB |
1695 | } |
1696 | ||
15167554 | 1697 | pmc_core_dbgfs_register(pmcdev); |
b740d2e9 | 1698 | |
6c96a78c RJ |
1699 | device_initialized = true; |
1700 | dev_info(&pdev->dev, " initialized\n"); | |
1701 | ||
b740d2e9 RB |
1702 | return 0; |
1703 | } | |
1704 | ||
6c96a78c | 1705 | static int pmc_core_remove(struct platform_device *pdev) |
2854a0aa | 1706 | { |
6c96a78c | 1707 | struct pmc_dev *pmcdev = platform_get_drvdata(pdev); |
b740d2e9 | 1708 | |
21ae4357 | 1709 | pmc_core_dbgfs_unregister(pmcdev); |
6c96a78c | 1710 | platform_set_drvdata(pdev, NULL); |
21ae4357 SP |
1711 | mutex_destroy(&pmcdev->lock); |
1712 | iounmap(pmcdev->regbase); | |
6c96a78c RJ |
1713 | return 0; |
1714 | } | |
1715 | ||
2ac8d46d RJ |
1716 | static bool warn_on_s0ix_failures; |
1717 | module_param(warn_on_s0ix_failures, bool, 0644); | |
1718 | MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix failures"); | |
1719 | ||
01f259f3 | 1720 | static __maybe_unused int pmc_core_suspend(struct device *dev) |
2ac8d46d RJ |
1721 | { |
1722 | struct pmc_dev *pmcdev = dev_get_drvdata(dev); | |
1723 | ||
1724 | pmcdev->check_counters = false; | |
1725 | ||
1726 | /* No warnings on S0ix failures */ | |
1727 | if (!warn_on_s0ix_failures) | |
1728 | return 0; | |
1729 | ||
1730 | /* Check if the syspend will actually use S0ix */ | |
1731 | if (pm_suspend_via_firmware()) | |
1732 | return 0; | |
1733 | ||
1734 | /* Save PC10 residency for checking later */ | |
1735 | if (rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pmcdev->pc10_counter)) | |
1736 | return -EIO; | |
1737 | ||
1738 | /* Save S0ix residency for checking later */ | |
1739 | if (pmc_core_dev_state_get(pmcdev, &pmcdev->s0ix_counter)) | |
1740 | return -EIO; | |
1741 | ||
1742 | pmcdev->check_counters = true; | |
1743 | return 0; | |
1744 | } | |
1745 | ||
1746 | static inline bool pmc_core_is_pc10_failed(struct pmc_dev *pmcdev) | |
1747 | { | |
1748 | u64 pc10_counter; | |
1749 | ||
1750 | if (rdmsrl_safe(MSR_PKG_C10_RESIDENCY, &pc10_counter)) | |
1751 | return false; | |
1752 | ||
1753 | if (pc10_counter == pmcdev->pc10_counter) | |
1754 | return true; | |
1755 | ||
1756 | return false; | |
1757 | } | |
1758 | ||
1759 | static inline bool pmc_core_is_s0ix_failed(struct pmc_dev *pmcdev) | |
1760 | { | |
1761 | u64 s0ix_counter; | |
1762 | ||
1763 | if (pmc_core_dev_state_get(pmcdev, &s0ix_counter)) | |
1764 | return false; | |
1765 | ||
1766 | if (s0ix_counter == pmcdev->s0ix_counter) | |
1767 | return true; | |
1768 | ||
1769 | return false; | |
1770 | } | |
1771 | ||
01f259f3 | 1772 | static __maybe_unused int pmc_core_resume(struct device *dev) |
2ac8d46d RJ |
1773 | { |
1774 | struct pmc_dev *pmcdev = dev_get_drvdata(dev); | |
2e36ac08 GK |
1775 | const struct pmc_bit_map **maps = pmcdev->map->lpm_sts; |
1776 | int offset = pmcdev->map->lpm_status_offset; | |
2ac8d46d RJ |
1777 | |
1778 | if (!pmcdev->check_counters) | |
1779 | return 0; | |
1780 | ||
1781 | if (!pmc_core_is_s0ix_failed(pmcdev)) | |
1782 | return 0; | |
1783 | ||
1784 | if (pmc_core_is_pc10_failed(pmcdev)) { | |
1785 | /* S0ix failed because of PC10 entry failure */ | |
1786 | dev_info(dev, "CPU did not enter PC10!!! (PC10 cnt=0x%llx)\n", | |
1787 | pmcdev->pc10_counter); | |
1788 | return 0; | |
1789 | } | |
1790 | ||
1791 | /* The real interesting case - S0ix failed - lets ask PMC why. */ | |
1792 | dev_warn(dev, "CPU did not enter SLP_S0!!! (S0ix cnt=%llu)\n", | |
1793 | pmcdev->s0ix_counter); | |
4d6a63e0 GK |
1794 | if (pmcdev->map->slps0_dbg_maps) |
1795 | pmc_core_slps0_display(pmcdev, dev, NULL); | |
2e36ac08 GK |
1796 | if (pmcdev->map->lpm_sts) |
1797 | pmc_core_lpm_display(pmcdev, dev, NULL, offset, "STATUS", maps); | |
4d6a63e0 | 1798 | |
2ac8d46d RJ |
1799 | return 0; |
1800 | } | |
1801 | ||
2ac8d46d RJ |
1802 | static const struct dev_pm_ops pmc_core_pm_ops = { |
1803 | SET_LATE_SYSTEM_SLEEP_PM_OPS(pmc_core_suspend, pmc_core_resume) | |
1804 | }; | |
1805 | ||
b02f6a2e RJ |
1806 | static const struct acpi_device_id pmc_core_acpi_ids[] = { |
1807 | {"INT33A1", 0}, /* _HID for Intel Power Engine, _CID PNP0D80*/ | |
1808 | { } | |
1809 | }; | |
1810 | MODULE_DEVICE_TABLE(acpi, pmc_core_acpi_ids); | |
1811 | ||
6c96a78c RJ |
1812 | static struct platform_driver pmc_core_driver = { |
1813 | .driver = { | |
1814 | .name = "intel_pmc_core", | |
b02f6a2e | 1815 | .acpi_match_table = ACPI_PTR(pmc_core_acpi_ids), |
2ac8d46d | 1816 | .pm = &pmc_core_pm_ops, |
ee7abc10 | 1817 | .dev_groups = pmc_dev_groups, |
6c96a78c RJ |
1818 | }, |
1819 | .probe = pmc_core_probe, | |
1820 | .remove = pmc_core_remove, | |
1821 | }; | |
1822 | ||
b02f6a2e | 1823 | module_platform_driver(pmc_core_driver); |
2854a0aa SP |
1824 | |
1825 | MODULE_LICENSE("GPL v2"); | |
1826 | MODULE_DESCRIPTION("Intel PMC Core Driver"); |