i2c: cadence: Implement save restore
[linux-2.6-microblaze.git] / drivers / platform / x86 / amd-pmc.c
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
49 /* List of supported CPU ids */
50 #define AMD_CPU_ID_RV                   0x15D0
51 #define AMD_CPU_ID_RN                   0x1630
52 #define AMD_CPU_ID_PCO                  AMD_CPU_ID_RV
53 #define AMD_CPU_ID_CZN                  AMD_CPU_ID_RN
54
55 #define AMD_SMU_FW_VERSION              0x0
56 #define PMC_MSG_DELAY_MIN_US            100
57 #define RESPONSE_REGISTER_LOOP_MAX      200
58
59 enum amd_pmc_def {
60         MSG_TEST = 0x01,
61         MSG_OS_HINT_PCO,
62         MSG_OS_HINT_RN,
63 };
64
65 struct amd_pmc_dev {
66         void __iomem *regbase;
67         void __iomem *smu_base;
68         u32 base_addr;
69         u32 cpu_id;
70         struct device *dev;
71 #if IS_ENABLED(CONFIG_DEBUG_FS)
72         struct dentry *dbgfs_dir;
73 #endif /* CONFIG_DEBUG_FS */
74 };
75
76 static struct amd_pmc_dev pmc;
77
78 static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset)
79 {
80         return ioread32(dev->regbase + reg_offset);
81 }
82
83 static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u32 val)
84 {
85         iowrite32(val, dev->regbase + reg_offset);
86 }
87
88 #ifdef CONFIG_DEBUG_FS
89 static int smu_fw_info_show(struct seq_file *s, void *unused)
90 {
91         struct amd_pmc_dev *dev = s->private;
92         u32 value;
93
94         value = ioread32(dev->smu_base + AMD_SMU_FW_VERSION);
95         seq_printf(s, "SMU FW Info: %x\n", value);
96         return 0;
97 }
98 DEFINE_SHOW_ATTRIBUTE(smu_fw_info);
99
100 static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
101 {
102         debugfs_remove_recursive(dev->dbgfs_dir);
103 }
104
105 static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
106 {
107         dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL);
108         debugfs_create_file("smu_fw_info", 0644, dev->dbgfs_dir, dev,
109                             &smu_fw_info_fops);
110 }
111 #else
112 static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
113 {
114 }
115
116 static inline void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev)
117 {
118 }
119 #endif /* CONFIG_DEBUG_FS */
120
121 static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
122 {
123         u32 value;
124
125         value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_RESPONSE);
126         dev_dbg(dev->dev, "AMD_PMC_REGISTER_RESPONSE:%x\n", value);
127
128         value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_ARGUMENT);
129         dev_dbg(dev->dev, "AMD_PMC_REGISTER_ARGUMENT:%x\n", value);
130
131         value = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_MESSAGE);
132         dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value);
133 }
134
135 static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set)
136 {
137         int rc;
138         u8 msg;
139         u32 val;
140
141         /* Wait until we get a valid response */
142         rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE,
143                                 val, val > 0, PMC_MSG_DELAY_MIN_US,
144                                 PMC_MSG_DELAY_MIN_US * RESPONSE_REGISTER_LOOP_MAX);
145         if (rc) {
146                 dev_err(dev->dev, "failed to talk to SMU\n");
147                 return rc;
148         }
149
150         /* Write zero to response register */
151         amd_pmc_reg_write(dev, AMD_PMC_REGISTER_RESPONSE, 0);
152
153         /* Write argument into response register */
154         amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, set);
155
156         /* Write message ID to message ID register */
157         msg = (dev->cpu_id == AMD_CPU_ID_RN) ? MSG_OS_HINT_RN : MSG_OS_HINT_PCO;
158         amd_pmc_reg_write(dev, AMD_PMC_REGISTER_MESSAGE, msg);
159         return 0;
160 }
161
162 static int __maybe_unused amd_pmc_suspend(struct device *dev)
163 {
164         struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
165         int rc;
166
167         rc = amd_pmc_send_cmd(pdev, 1);
168         if (rc)
169                 dev_err(pdev->dev, "suspend failed\n");
170
171         amd_pmc_dump_registers(pdev);
172         return 0;
173 }
174
175 static int __maybe_unused amd_pmc_resume(struct device *dev)
176 {
177         struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
178         int rc;
179
180         rc = amd_pmc_send_cmd(pdev, 0);
181         if (rc)
182                 dev_err(pdev->dev, "resume failed\n");
183
184         amd_pmc_dump_registers(pdev);
185         return 0;
186 }
187
188 static const struct dev_pm_ops amd_pmc_pm_ops = {
189         SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(amd_pmc_suspend, amd_pmc_resume)
190 };
191
192 static const struct pci_device_id pmc_pci_ids[] = {
193         { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) },
194         { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) },
195         { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) },
196         { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) },
197         { }
198 };
199
200 static int amd_pmc_probe(struct platform_device *pdev)
201 {
202         struct amd_pmc_dev *dev = &pmc;
203         struct pci_dev *rdev;
204         u32 base_addr_lo;
205         u32 base_addr_hi;
206         u64 base_addr;
207         int err;
208         u32 val;
209
210         dev->dev = &pdev->dev;
211
212         rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
213         if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) {
214                 pci_dev_put(rdev);
215                 return -ENODEV;
216         }
217
218         dev->cpu_id = rdev->device;
219         err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_LO);
220         if (err) {
221                 dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS);
222                 pci_dev_put(rdev);
223                 return pcibios_err_to_errno(err);
224         }
225
226         err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val);
227         if (err) {
228                 pci_dev_put(rdev);
229                 return pcibios_err_to_errno(err);
230         }
231
232         base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK;
233
234         err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_HI);
235         if (err) {
236                 dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS);
237                 pci_dev_put(rdev);
238                 return pcibios_err_to_errno(err);
239         }
240
241         err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val);
242         if (err) {
243                 pci_dev_put(rdev);
244                 return pcibios_err_to_errno(err);
245         }
246
247         base_addr_hi = val & AMD_PMC_BASE_ADDR_LO_MASK;
248         pci_dev_put(rdev);
249         base_addr = ((u64)base_addr_hi << 32 | base_addr_lo);
250
251         dev->smu_base = devm_ioremap(dev->dev, base_addr, AMD_PMC_MAPPING_SIZE);
252         if (!dev->smu_base)
253                 return -ENOMEM;
254
255         dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMC_BASE_ADDR_OFFSET,
256                                     AMD_PMC_MAPPING_SIZE);
257         if (!dev->regbase)
258                 return -ENOMEM;
259
260         amd_pmc_dump_registers(dev);
261
262         platform_set_drvdata(pdev, dev);
263         amd_pmc_dbgfs_register(dev);
264         return 0;
265 }
266
267 static int amd_pmc_remove(struct platform_device *pdev)
268 {
269         struct amd_pmc_dev *dev = platform_get_drvdata(pdev);
270
271         amd_pmc_dbgfs_unregister(dev);
272         return 0;
273 }
274
275 static const struct acpi_device_id amd_pmc_acpi_ids[] = {
276         {"AMDI0005", 0},
277         {"AMD0004", 0},
278         { }
279 };
280 MODULE_DEVICE_TABLE(acpi, amd_pmc_acpi_ids);
281
282 static struct platform_driver amd_pmc_driver = {
283         .driver = {
284                 .name = "amd_pmc",
285                 .acpi_match_table = amd_pmc_acpi_ids,
286                 .pm = &amd_pmc_pm_ops,
287         },
288         .probe = amd_pmc_probe,
289         .remove = amd_pmc_remove,
290 };
291 module_platform_driver(amd_pmc_driver);
292
293 MODULE_LICENSE("GPL v2");
294 MODULE_DESCRIPTION("AMD PMC Driver");