]>
Commit | Line | Data |
---|---|---|
156ec473 SS |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * AMD SoC Power Management Controller Driver | |
4 | * | |
5 | * Copyright (c) 2020, Advanced Micro Devices, Inc. | |
6 | * All Rights Reserved. | |
7 | * | |
8 | * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> | |
9 | */ | |
10 | ||
11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
12 | ||
13 | #include <linux/acpi.h> | |
14 | #include <linux/bitfield.h> | |
15 | #include <linux/bits.h> | |
16 | #include <linux/debugfs.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/io.h> | |
19 | #include <linux/iopoll.h> | |
20 | #include <linux/module.h> | |
21 | #include <linux/pci.h> | |
22 | #include <linux/platform_device.h> | |
23 | #include <linux/suspend.h> | |
24 | #include <linux/seq_file.h> | |
25 | #include <linux/uaccess.h> | |
26 | ||
27 | /* SMU communication registers */ | |
28 | #define AMD_PMC_REGISTER_MESSAGE 0x538 | |
29 | #define AMD_PMC_REGISTER_RESPONSE 0x980 | |
30 | #define AMD_PMC_REGISTER_ARGUMENT 0x9BC | |
31 | ||
32 | /* Base address of SMU for mapping physical address to virtual address */ | |
33 | #define AMD_PMC_SMU_INDEX_ADDRESS 0xB8 | |
34 | #define AMD_PMC_SMU_INDEX_DATA 0xBC | |
35 | #define AMD_PMC_MAPPING_SIZE 0x01000 | |
36 | #define AMD_PMC_BASE_ADDR_OFFSET 0x10000 | |
37 | #define AMD_PMC_BASE_ADDR_LO 0x13B102E8 | |
38 | #define AMD_PMC_BASE_ADDR_HI 0x13B102EC | |
39 | #define AMD_PMC_BASE_ADDR_LO_MASK GENMASK(15, 0) | |
40 | #define AMD_PMC_BASE_ADDR_HI_MASK GENMASK(31, 20) | |
41 | ||
42 | /* SMU Response Codes */ | |
43 | #define AMD_PMC_RESULT_OK 0x01 | |
44 | #define AMD_PMC_RESULT_CMD_REJECT_BUSY 0xFC | |
45 | #define AMD_PMC_RESULT_CMD_REJECT_PREREQ 0xFD | |
46 | #define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE | |
47 | #define AMD_PMC_RESULT_FAILED 0xFF | |
48 | ||
b9a4fa69 SS |
49 | /* FCH SSC Registers */ |
50 | #define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30 | |
51 | #define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34 | |
52 | #define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38 | |
53 | #define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C | |
54 | #define FCH_SSC_MAPPING_SIZE 0x800 | |
55 | #define FCH_BASE_PHY_ADDR_LOW 0xFED81100 | |
56 | #define FCH_BASE_PHY_ADDR_HIGH 0x00000000 | |
57 | ||
76620567 SS |
58 | /* SMU Message Definations */ |
59 | #define SMU_MSG_GETSMUVERSION 0x02 | |
60 | #define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 | |
61 | #define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05 | |
62 | #define SMU_MSG_LOG_START 0x06 | |
63 | #define SMU_MSG_LOG_RESET 0x07 | |
64 | #define SMU_MSG_LOG_DUMP_DATA 0x08 | |
65 | #define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 | |
156ec473 SS |
66 | /* List of supported CPU ids */ |
67 | #define AMD_CPU_ID_RV 0x15D0 | |
68 | #define AMD_CPU_ID_RN 0x1630 | |
69 | #define AMD_CPU_ID_PCO AMD_CPU_ID_RV | |
70 | #define AMD_CPU_ID_CZN AMD_CPU_ID_RN | |
71 | ||
156ec473 SS |
72 | #define PMC_MSG_DELAY_MIN_US 100 |
73 | #define RESPONSE_REGISTER_LOOP_MAX 200 | |
74 | ||
76620567 SS |
75 | #define SOC_SUBSYSTEM_IP_MAX 12 |
76 | #define DELAY_MIN_US 2000 | |
77 | #define DELAY_MAX_US 3000 | |
156ec473 SS |
78 | enum amd_pmc_def { |
79 | MSG_TEST = 0x01, | |
80 | MSG_OS_HINT_PCO, | |
81 | MSG_OS_HINT_RN, | |
82 | }; | |
83 | ||
76620567 SS |
84 | struct amd_pmc_bit_map { |
85 | const char *name; | |
86 | u32 bit_mask; | |
87 | }; | |
88 | ||
89 | static const struct amd_pmc_bit_map soc15_ip_blk[] = { | |
90 | {"DISPLAY", BIT(0)}, | |
91 | {"CPU", BIT(1)}, | |
92 | {"GFX", BIT(2)}, | |
93 | {"VDD", BIT(3)}, | |
94 | {"ACP", BIT(4)}, | |
95 | {"VCN", BIT(5)}, | |
96 | {"ISP", BIT(6)}, | |
97 | {"NBIO", BIT(7)}, | |
98 | {"DF", BIT(8)}, | |
99 | {"USB0", BIT(9)}, | |
100 | {"USB1", BIT(10)}, | |
101 | {"LAPIC", BIT(11)}, | |
102 | {} | |
103 | }; | |
104 | ||
156ec473 SS |
105 | struct amd_pmc_dev { |
106 | void __iomem *regbase; | |
76620567 | 107 | void __iomem *smu_virt_addr; |
b9a4fa69 | 108 | void __iomem *fch_virt_addr; |
156ec473 SS |
109 | u32 base_addr; |
110 | u32 cpu_id; | |
76620567 | 111 | u32 active_ips; |
156ec473 | 112 | struct device *dev; |
95e1b60f | 113 | struct mutex lock; /* generic mutex lock */ |
156ec473 SS |
114 | #if IS_ENABLED(CONFIG_DEBUG_FS) |
115 | struct dentry *dbgfs_dir; | |
116 | #endif /* CONFIG_DEBUG_FS */ | |
117 | }; | |
118 | ||
119 | static struct amd_pmc_dev pmc; | |
76620567 | 120 | static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret); |
156ec473 SS |
121 | |
122 | static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset) | |
123 | { | |
124 | return ioread32(dev->regbase + reg_offset); | |
125 | } | |
126 | ||
127 | static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u32 val) | |
128 | { | |
129 | iowrite32(val, dev->regbase + reg_offset); | |
130 | } | |
131 | ||
76620567 SS |
132 | struct smu_metrics { |
133 | u32 table_version; | |
134 | u32 hint_count; | |
135 | u32 s0i3_cyclecount; | |
136 | u32 timein_s0i2; | |
137 | u64 timeentering_s0i3_lastcapture; | |
138 | u64 timeentering_s0i3_totaltime; | |
139 | u64 timeto_resume_to_os_lastcapture; | |
140 | u64 timeto_resume_to_os_totaltime; | |
141 | u64 timein_s0i3_lastcapture; | |
142 | u64 timein_s0i3_totaltime; | |
143 | u64 timein_swdrips_lastcapture; | |
144 | u64 timein_swdrips_totaltime; | |
145 | u64 timecondition_notmet_lastcapture[SOC_SUBSYSTEM_IP_MAX]; | |
146 | u64 timecondition_notmet_totaltime[SOC_SUBSYSTEM_IP_MAX]; | |
147 | } __packed; | |
148 | ||
5b569302 | 149 | #ifdef CONFIG_DEBUG_FS |
156ec473 SS |
150 | static int smu_fw_info_show(struct seq_file *s, void *unused) |
151 | { | |
76620567 SS |
152 | struct amd_pmc_dev *dev = s->private; |
153 | struct smu_metrics table; | |
154 | int idx; | |
155 | ||
156 | if (dev->cpu_id == AMD_CPU_ID_PCO) | |
157 | return -EINVAL; | |
158 | ||
159 | memcpy_fromio(&table, dev->smu_virt_addr, sizeof(struct smu_metrics)); | |
160 | ||
161 | seq_puts(s, "\n=== SMU Statistics ===\n"); | |
162 | seq_printf(s, "Table Version: %d\n", table.table_version); | |
163 | seq_printf(s, "Hint Count: %d\n", table.hint_count); | |
164 | seq_printf(s, "S0i3 Cycle Count: %d\n", table.s0i3_cyclecount); | |
165 | seq_printf(s, "Time (in us) to S0i3: %lld\n", table.timeentering_s0i3_lastcapture); | |
166 | seq_printf(s, "Time (in us) in S0i3: %lld\n", table.timein_s0i3_lastcapture); | |
167 | ||
168 | seq_puts(s, "\n=== Active time (in us) ===\n"); | |
169 | for (idx = 0 ; idx < SOC_SUBSYSTEM_IP_MAX ; idx++) { | |
170 | if (soc15_ip_blk[idx].bit_mask & dev->active_ips) | |
171 | seq_printf(s, "%-8s : %lld\n", soc15_ip_blk[idx].name, | |
172 | table.timecondition_notmet_lastcapture[idx]); | |
173 | } | |
174 | ||
156ec473 SS |
175 | return 0; |
176 | } | |
177 | DEFINE_SHOW_ATTRIBUTE(smu_fw_info); | |
178 | ||
b9a4fa69 SS |
179 | static int s0ix_stats_show(struct seq_file *s, void *unused) |
180 | { | |
181 | struct amd_pmc_dev *dev = s->private; | |
182 | u64 entry_time, exit_time, residency; | |
183 | ||
184 | entry_time = ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_H_OFFSET); | |
185 | entry_time = entry_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_L_OFFSET); | |
186 | ||
187 | exit_time = ioread32(dev->fch_virt_addr + FCH_S0I3_EXIT_TIME_H_OFFSET); | |
188 | exit_time = exit_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_EXIT_TIME_L_OFFSET); | |
189 | ||
190 | /* It's in 48MHz. We need to convert it */ | |
191 | residency = (exit_time - entry_time) / 48; | |
192 | ||
193 | seq_puts(s, "=== S0ix statistics ===\n"); | |
194 | seq_printf(s, "S0ix Entry Time: %lld\n", entry_time); | |
195 | seq_printf(s, "S0ix Exit Time: %lld\n", exit_time); | |
196 | seq_printf(s, "Residency Time: %lld\n", residency); | |
197 | ||
198 | return 0; | |
199 | } | |
200 | DEFINE_SHOW_ATTRIBUTE(s0ix_stats); | |
201 | ||
156ec473 SS |
202 | static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) |
203 | { | |
204 | debugfs_remove_recursive(dev->dbgfs_dir); | |
205 | } | |
206 | ||
207 | static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) | |
208 | { | |
209 | dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL); | |
210 | debugfs_create_file("smu_fw_info", 0644, dev->dbgfs_dir, dev, | |
211 | &smu_fw_info_fops); | |
b9a4fa69 SS |
212 | debugfs_create_file("s0ix_stats", 0644, dev->dbgfs_dir, dev, |
213 | &s0ix_stats_fops); | |
156ec473 SS |
214 | } |
215 | #else | |
216 | static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) | |
217 | { | |
218 | } | |
219 | ||
220 | static inline void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) | |
221 | { | |
222 | } | |
223 | #endif /* CONFIG_DEBUG_FS */ | |
224 | ||
76620567 SS |
225 | static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev) |
226 | { | |
227 | u32 phys_addr_low, phys_addr_hi; | |
228 | u64 smu_phys_addr; | |
229 | ||
230 | if (dev->cpu_id == AMD_CPU_ID_PCO) | |
231 | return -EINVAL; | |
232 | ||
233 | /* Get Active devices list from SMU */ | |
234 | amd_pmc_send_cmd(dev, 0, &dev->active_ips, SMU_MSG_GET_SUP_CONSTRAINTS, 1); | |
235 | ||
236 | /* Get dram address */ | |
237 | amd_pmc_send_cmd(dev, 0, &phys_addr_low, SMU_MSG_LOG_GETDRAM_ADDR_LO, 1); | |
238 | amd_pmc_send_cmd(dev, 0, &phys_addr_hi, SMU_MSG_LOG_GETDRAM_ADDR_HI, 1); | |
239 | smu_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low); | |
240 | ||
241 | dev->smu_virt_addr = devm_ioremap(dev->dev, smu_phys_addr, sizeof(struct smu_metrics)); | |
242 | if (!dev->smu_virt_addr) | |
243 | return -ENOMEM; | |
244 | ||
245 | /* Start the logging */ | |
246 | amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, 0); | |
247 | ||
248 | return 0; | |
249 | } | |
250 | ||
156ec473 SS |
251 | static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) |
252 | { | |
253 | u32 value; | |
254 | ||
255 | value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_RESPONSE); | |
256 | dev_dbg(dev->dev, "AMD_PMC_REGISTER_RESPONSE:%x\n", value); | |
257 | ||
258 | value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_ARGUMENT); | |
259 | dev_dbg(dev->dev, "AMD_PMC_REGISTER_ARGUMENT:%x\n", value); | |
260 | ||
261 | value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_MESSAGE); | |
262 | dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value); | |
263 | } | |
264 | ||
76620567 | 265 | static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret) |
156ec473 SS |
266 | { |
267 | int rc; | |
156ec473 SS |
268 | u32 val; |
269 | ||
95e1b60f | 270 | mutex_lock(&dev->lock); |
156ec473 SS |
271 | /* Wait until we get a valid response */ |
272 | rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE, | |
95e1b60f | 273 | val, val != 0, PMC_MSG_DELAY_MIN_US, |
156ec473 SS |
274 | PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); |
275 | if (rc) { | |
276 | dev_err(dev->dev, "failed to talk to SMU\n"); | |
277 | return rc; | |
278 | } | |
279 | ||
280 | /* Write zero to response register */ | |
281 | amd_pmc_reg_write(dev, AMD_PMC_REGISTER_RESPONSE, 0); | |
282 | ||
283 | /* Write argument into response register */ | |
284 | amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, set); | |
285 | ||
286 | /* Write message ID to message ID register */ | |
156ec473 | 287 | amd_pmc_reg_write(dev, AMD_PMC_REGISTER_MESSAGE, msg); |
76620567 | 288 | |
95e1b60f SS |
289 | /* Wait until we get a valid response */ |
290 | rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE, | |
291 | val, val != 0, PMC_MSG_DELAY_MIN_US, | |
292 | PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX); | |
293 | if (rc) { | |
294 | dev_err(dev->dev, "SMU response timed out\n"); | |
295 | goto out_unlock; | |
296 | } | |
297 | ||
298 | switch (val) { | |
299 | case AMD_PMC_RESULT_OK: | |
76620567 SS |
300 | if (ret) { |
301 | /* PMFW may take longer time to return back the data */ | |
302 | usleep_range(DELAY_MIN_US, 10 * DELAY_MAX_US); | |
303 | *data = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_ARGUMENT); | |
304 | } | |
95e1b60f SS |
305 | break; |
306 | case AMD_PMC_RESULT_CMD_REJECT_BUSY: | |
307 | dev_err(dev->dev, "SMU not ready. err: 0x%x\n", val); | |
308 | rc = -EBUSY; | |
309 | goto out_unlock; | |
310 | case AMD_PMC_RESULT_CMD_UNKNOWN: | |
311 | dev_err(dev->dev, "SMU cmd unknown. err: 0x%x\n", val); | |
312 | rc = -EINVAL; | |
313 | goto out_unlock; | |
314 | case AMD_PMC_RESULT_CMD_REJECT_PREREQ: | |
315 | case AMD_PMC_RESULT_FAILED: | |
316 | default: | |
317 | dev_err(dev->dev, "SMU cmd failed. err: 0x%x\n", val); | |
318 | rc = -EIO; | |
319 | goto out_unlock; | |
320 | } | |
321 | ||
322 | out_unlock: | |
323 | mutex_unlock(&dev->lock); | |
162b937a | 324 | amd_pmc_dump_registers(dev); |
95e1b60f | 325 | return rc; |
156ec473 SS |
326 | } |
327 | ||
76620567 SS |
328 | static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev) |
329 | { | |
330 | switch (dev->cpu_id) { | |
331 | case AMD_CPU_ID_PCO: | |
332 | return MSG_OS_HINT_PCO; | |
333 | case AMD_CPU_ID_RN: | |
334 | return MSG_OS_HINT_RN; | |
335 | } | |
336 | return -EINVAL; | |
337 | } | |
338 | ||
156ec473 SS |
339 | static int __maybe_unused amd_pmc_suspend(struct device *dev) |
340 | { | |
341 | struct amd_pmc_dev *pdev = dev_get_drvdata(dev); | |
342 | int rc; | |
76620567 | 343 | u8 msg; |
156ec473 | 344 | |
76620567 SS |
345 | /* Reset and Start SMU logging - to monitor the s0i3 stats */ |
346 | amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_RESET, 0); | |
347 | amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_START, 0); | |
348 | ||
349 | msg = amd_pmc_get_os_hint(pdev); | |
350 | rc = amd_pmc_send_cmd(pdev, 1, NULL, msg, 0); | |
156ec473 SS |
351 | if (rc) |
352 | dev_err(pdev->dev, "suspend failed\n"); | |
353 | ||
156ec473 SS |
354 | return 0; |
355 | } | |
356 | ||
357 | static int __maybe_unused amd_pmc_resume(struct device *dev) | |
358 | { | |
359 | struct amd_pmc_dev *pdev = dev_get_drvdata(dev); | |
360 | int rc; | |
76620567 | 361 | u8 msg; |
156ec473 | 362 | |
76620567 SS |
363 | /* Let SMU know that we are looking for stats */ |
364 | amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0); | |
365 | ||
366 | msg = amd_pmc_get_os_hint(pdev); | |
367 | rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, 0); | |
156ec473 SS |
368 | if (rc) |
369 | dev_err(pdev->dev, "resume failed\n"); | |
370 | ||
156ec473 SS |
371 | return 0; |
372 | } | |
373 | ||
374 | static const struct dev_pm_ops amd_pmc_pm_ops = { | |
375 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(amd_pmc_suspend, amd_pmc_resume) | |
376 | }; | |
377 | ||
378 | static const struct pci_device_id pmc_pci_ids[] = { | |
379 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) }, | |
380 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) }, | |
381 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) }, | |
382 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) }, | |
383 | { } | |
384 | }; | |
385 | ||
386 | static int amd_pmc_probe(struct platform_device *pdev) | |
387 | { | |
388 | struct amd_pmc_dev *dev = &pmc; | |
389 | struct pci_dev *rdev; | |
76620567 | 390 | u32 base_addr_lo, base_addr_hi; |
b9a4fa69 | 391 | u64 base_addr, fch_phys_addr; |
156ec473 SS |
392 | int err; |
393 | u32 val; | |
394 | ||
395 | dev->dev = &pdev->dev; | |
396 | ||
397 | rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); | |
745ed17a PB |
398 | if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) { |
399 | pci_dev_put(rdev); | |
156ec473 | 400 | return -ENODEV; |
745ed17a | 401 | } |
156ec473 SS |
402 | |
403 | dev->cpu_id = rdev->device; | |
404 | err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_LO); | |
405 | if (err) { | |
406 | dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS); | |
745ed17a | 407 | pci_dev_put(rdev); |
156ec473 SS |
408 | return pcibios_err_to_errno(err); |
409 | } | |
410 | ||
411 | err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val); | |
745ed17a PB |
412 | if (err) { |
413 | pci_dev_put(rdev); | |
156ec473 | 414 | return pcibios_err_to_errno(err); |
745ed17a | 415 | } |
156ec473 SS |
416 | |
417 | base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK; | |
418 | ||
419 | err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_HI); | |
420 | if (err) { | |
421 | dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS); | |
745ed17a | 422 | pci_dev_put(rdev); |
156ec473 SS |
423 | return pcibios_err_to_errno(err); |
424 | } | |
425 | ||
426 | err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val); | |
745ed17a PB |
427 | if (err) { |
428 | pci_dev_put(rdev); | |
156ec473 | 429 | return pcibios_err_to_errno(err); |
745ed17a | 430 | } |
156ec473 SS |
431 | |
432 | base_addr_hi = val & AMD_PMC_BASE_ADDR_LO_MASK; | |
433 | pci_dev_put(rdev); | |
434 | base_addr = ((u64)base_addr_hi << 32 | base_addr_lo); | |
435 | ||
156ec473 SS |
436 | dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMC_BASE_ADDR_OFFSET, |
437 | AMD_PMC_MAPPING_SIZE); | |
438 | if (!dev->regbase) | |
439 | return -ENOMEM; | |
440 | ||
95e1b60f | 441 | mutex_init(&dev->lock); |
76620567 | 442 | |
b9a4fa69 SS |
443 | /* Use FCH registers to get the S0ix stats */ |
444 | base_addr_lo = FCH_BASE_PHY_ADDR_LOW; | |
445 | base_addr_hi = FCH_BASE_PHY_ADDR_HIGH; | |
446 | fch_phys_addr = ((u64)base_addr_hi << 32 | base_addr_lo); | |
447 | dev->fch_virt_addr = devm_ioremap(dev->dev, fch_phys_addr, FCH_SSC_MAPPING_SIZE); | |
448 | if (!dev->fch_virt_addr) | |
449 | return -ENOMEM; | |
450 | ||
76620567 SS |
451 | /* Use SMU to get the s0i3 debug stats */ |
452 | err = amd_pmc_setup_smu_logging(dev); | |
453 | if (err) | |
454 | dev_err(dev->dev, "SMU debugging info not supported on this platform\n"); | |
455 | ||
156ec473 SS |
456 | platform_set_drvdata(pdev, dev); |
457 | amd_pmc_dbgfs_register(dev); | |
458 | return 0; | |
459 | } | |
460 | ||
461 | static int amd_pmc_remove(struct platform_device *pdev) | |
462 | { | |
463 | struct amd_pmc_dev *dev = platform_get_drvdata(pdev); | |
464 | ||
465 | amd_pmc_dbgfs_unregister(dev); | |
95e1b60f | 466 | mutex_destroy(&dev->lock); |
156ec473 SS |
467 | return 0; |
468 | } | |
469 | ||
470 | static const struct acpi_device_id amd_pmc_acpi_ids[] = { | |
471 | {"AMDI0005", 0}, | |
9422584a | 472 | {"AMDI0006", 0}, |
156ec473 SS |
473 | {"AMD0004", 0}, |
474 | { } | |
475 | }; | |
476 | MODULE_DEVICE_TABLE(acpi, amd_pmc_acpi_ids); | |
477 | ||
478 | static struct platform_driver amd_pmc_driver = { | |
479 | .driver = { | |
480 | .name = "amd_pmc", | |
481 | .acpi_match_table = amd_pmc_acpi_ids, | |
482 | .pm = &amd_pmc_pm_ops, | |
483 | }, | |
484 | .probe = amd_pmc_probe, | |
485 | .remove = amd_pmc_remove, | |
486 | }; | |
487 | module_platform_driver(amd_pmc_driver); | |
488 | ||
489 | MODULE_LICENSE("GPL v2"); | |
490 | MODULE_DESCRIPTION("AMD PMC Driver"); |