1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Driver for the Intel Broxton PMC
4 *
5 * (C) Copyright 2014 - 2020 Intel Corporation
6 *
7 * This driver is based on Intel SCU IPC driver (intel_scu_ipc.c) by
8 * Sreedhara DS <sreedhara.ds@intel.com>
9 *
10 * The PMC (Power Management Controller) running on the ARC processor
11 * communicates with another entity running in the IA (Intel Architecture)
12 * core through an IPC (Intel Processor Communications) mechanism which in
13 * turn sends messages between the IA and the PMC.
14 */
15
16 #include <linux/acpi.h>
17 #include <linux/delay.h>
18 #include <linux/errno.h>
19 #include <linux/interrupt.h>
20 #include <linux/io-64-nonatomic-lo-hi.h>
21 #include <linux/mfd/core.h>
22 #include <linux/mfd/intel_pmc_bxt.h>
23 #include <linux/module.h>
24 #include <linux/platform_device.h>
25 #include <linux/platform_data/itco_wdt.h>
26 #include <linux/platform_data/x86/intel_scu_ipc.h>
27
28 /* Residency with clock rate at 19.2MHz to usecs */
29 #define S0IX_RESIDENCY_IN_USECS(d, s) \
30 ({ \
31 u64 result = 10ull * ((d) + (s)); \
32 do_div(result, 192); \
33 result; \
34 })
35
36 /* Resources exported from IFWI */
37 #define PLAT_RESOURCE_IPC_INDEX 0
38 #define PLAT_RESOURCE_IPC_SIZE 0x1000
39 #define PLAT_RESOURCE_GCR_OFFSET 0x1000
40 #define PLAT_RESOURCE_GCR_SIZE 0x1000
41 #define PLAT_RESOURCE_BIOS_DATA_INDEX 1
42 #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2
43 #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3
44 #define PLAT_RESOURCE_ISP_DATA_INDEX 4
45 #define PLAT_RESOURCE_ISP_IFACE_INDEX 5
46 #define PLAT_RESOURCE_GTD_DATA_INDEX 6
47 #define PLAT_RESOURCE_GTD_IFACE_INDEX 7
48 #define PLAT_RESOURCE_ACPI_IO_INDEX 0
49
50 /*
51 * BIOS does not create an ACPI device for each PMC function, but
52 * exports multiple resources from one ACPI device (IPC) for multiple
53 * functions. This driver is responsible for creating a child device and
54 * to export resources for those functions.
55 */
56 #define SMI_EN_OFFSET 0x0040
57 #define SMI_EN_SIZE 4
58 #define TCO_BASE_OFFSET 0x0060
59 #define TCO_REGS_SIZE 16
60 #define TELEM_SSRAM_SIZE 240
61 #define TELEM_PMC_SSRAM_OFFSET 0x1b00
62 #define TELEM_PUNIT_SSRAM_OFFSET 0x1a00
63
64 /* Commands */
65 #define PMC_NORTHPEAK_CTRL 0xed
66
is_gcr_valid(u32 offset)67 static inline bool is_gcr_valid(u32 offset)
68 {
69 return offset < PLAT_RESOURCE_GCR_SIZE - 8;
70 }
71
72 /**
73 * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register
74 * @pmc: PMC device pointer
75 * @offset: offset of GCR register from GCR address base
76 * @data: data pointer for storing the register output
77 *
78 * Reads the 64-bit PMC GCR register at given offset.
79 *
80 * Return: Negative value on error or 0 on success.
81 */
intel_pmc_gcr_read64(struct intel_pmc_dev * pmc,u32 offset,u64 * data)82 int intel_pmc_gcr_read64(struct intel_pmc_dev *pmc, u32 offset, u64 *data)
83 {
84 if (!is_gcr_valid(offset))
85 return -EINVAL;
86
87 spin_lock(&pmc->gcr_lock);
88 *data = readq(pmc->gcr_mem_base + offset);
89 spin_unlock(&pmc->gcr_lock);
90
91 return 0;
92 }
93 EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64);
94
95 /**
96 * intel_pmc_gcr_update() - Update PMC GCR register bits
97 * @pmc: PMC device pointer
98 * @offset: offset of GCR register from GCR address base
99 * @mask: bit mask for update operation
100 * @val: update value
101 *
102 * Updates the bits of given GCR register as specified by
103 * @mask and @val.
104 *
105 * Return: Negative value on error or 0 on success.
106 */
intel_pmc_gcr_update(struct intel_pmc_dev * pmc,u32 offset,u32 mask,u32 val)107 int intel_pmc_gcr_update(struct intel_pmc_dev *pmc, u32 offset, u32 mask, u32 val)
108 {
109 u32 new_val;
110
111 if (!is_gcr_valid(offset))
112 return -EINVAL;
113
114 spin_lock(&pmc->gcr_lock);
115 new_val = readl(pmc->gcr_mem_base + offset);
116
117 new_val = (new_val & ~mask) | (val & mask);
118 writel(new_val, pmc->gcr_mem_base + offset);
119
120 new_val = readl(pmc->gcr_mem_base + offset);
121 spin_unlock(&pmc->gcr_lock);
122
123 /* Check whether the bit update is successful */
124 return (new_val & mask) != (val & mask) ? -EIO : 0;
125 }
126 EXPORT_SYMBOL_GPL(intel_pmc_gcr_update);
127
128 /**
129 * intel_pmc_s0ix_counter_read() - Read S0ix residency
130 * @pmc: PMC device pointer
131 * @data: Out param that contains current S0ix residency count.
132 *
133 * Writes to @data how many usecs the system has been in low-power S0ix
134 * state.
135 *
136 * Return: An error code or 0 on success.
137 */
intel_pmc_s0ix_counter_read(struct intel_pmc_dev * pmc,u64 * data)138 int intel_pmc_s0ix_counter_read(struct intel_pmc_dev *pmc, u64 *data)
139 {
140 u64 deep, shlw;
141
142 spin_lock(&pmc->gcr_lock);
143 deep = readq(pmc->gcr_mem_base + PMC_GCR_TELEM_DEEP_S0IX_REG);
144 shlw = readq(pmc->gcr_mem_base + PMC_GCR_TELEM_SHLW_S0IX_REG);
145 spin_unlock(&pmc->gcr_lock);
146
147 *data = S0IX_RESIDENCY_IN_USECS(deep, shlw);
148 return 0;
149 }
150 EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read);
151
152 /**
153 * simplecmd_store() - Send a simple IPC command
154 * @dev: Device under the attribute is
155 * @attr: Attribute in question
156 * @buf: Buffer holding data to be stored to the attribute
157 * @count: Number of bytes in @buf
158 *
159 * Expects a string with two integers separated with space. These two
160 * values hold command and subcommand that is send to PMC.
161 *
162 * Return: Number number of bytes written (@count) or negative errno in
163 * case of error.
164 */
simplecmd_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)165 static ssize_t simplecmd_store(struct device *dev, struct device_attribute *attr,
166 const char *buf, size_t count)
167 {
168 struct intel_pmc_dev *pmc = dev_get_drvdata(dev);
169 struct intel_scu_ipc_dev *scu = pmc->scu;
170 int subcmd;
171 int cmd;
172 int ret;
173
174 ret = sscanf(buf, "%d %d", &cmd, &subcmd);
175 if (ret != 2) {
176 dev_err(dev, "Invalid values, expected: cmd subcmd\n");
177 return -EINVAL;
178 }
179
180 ret = intel_scu_ipc_dev_simple_command(scu, cmd, subcmd);
181 if (ret)
182 return ret;
183
184 return count;
185 }
186 static DEVICE_ATTR_WO(simplecmd);
187
188 /**
189 * northpeak_store() - Enable or disable Northpeak
190 * @dev: Device under the attribute is
191 * @attr: Attribute in question
192 * @buf: Buffer holding data to be stored to the attribute
193 * @count: Number of bytes in @buf
194 *
195 * Expects an unsigned integer. Non-zero enables Northpeak and zero
196 * disables it.
197 *
198 * Return: Number number of bytes written (@count) or negative errno in
199 * case of error.
200 */
northpeak_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)201 static ssize_t northpeak_store(struct device *dev, struct device_attribute *attr,
202 const char *buf, size_t count)
203 {
204 struct intel_pmc_dev *pmc = dev_get_drvdata(dev);
205 struct intel_scu_ipc_dev *scu = pmc->scu;
206 unsigned long val;
207 int subcmd;
208 int ret;
209
210 ret = kstrtoul(buf, 0, &val);
211 if (ret)
212 return ret;
213
214 /* Northpeak is enabled if subcmd == 1 and disabled if it is 0 */
215 if (val)
216 subcmd = 1;
217 else
218 subcmd = 0;
219
220 ret = intel_scu_ipc_dev_simple_command(scu, PMC_NORTHPEAK_CTRL, subcmd);
221 if (ret)
222 return ret;
223
224 return count;
225 }
226 static DEVICE_ATTR_WO(northpeak);
227
228 static struct attribute *intel_pmc_attrs[] = {
229 &dev_attr_northpeak.attr,
230 &dev_attr_simplecmd.attr,
231 NULL
232 };
233
234 static const struct attribute_group intel_pmc_group = {
235 .attrs = intel_pmc_attrs,
236 };
237
238 static const struct attribute_group *intel_pmc_groups[] = {
239 &intel_pmc_group,
240 NULL
241 };
242
243 static struct resource punit_res[6];
244
245 static struct mfd_cell punit = {
246 .name = "intel_punit_ipc",
247 .resources = punit_res,
248 };
249
250 static struct itco_wdt_platform_data tco_pdata = {
251 .name = "Apollo Lake SoC",
252 .version = 5,
253 .no_reboot_use_pmc = true,
254 };
255
256 static struct resource tco_res[2];
257
258 static const struct mfd_cell tco = {
259 .name = "iTCO_wdt",
260 .ignore_resource_conflicts = true,
261 .resources = tco_res,
262 .num_resources = ARRAY_SIZE(tco_res),
263 .platform_data = &tco_pdata,
264 .pdata_size = sizeof(tco_pdata),
265 };
266
267 static const struct resource telem_res[] = {
268 DEFINE_RES_MEM(TELEM_PUNIT_SSRAM_OFFSET, TELEM_SSRAM_SIZE),
269 DEFINE_RES_MEM(TELEM_PMC_SSRAM_OFFSET, TELEM_SSRAM_SIZE),
270 };
271
272 static const struct mfd_cell telem = {
273 .name = "intel_telemetry",
274 .resources = telem_res,
275 .num_resources = ARRAY_SIZE(telem_res),
276 };
277
intel_pmc_get_tco_resources(struct platform_device * pdev)278 static int intel_pmc_get_tco_resources(struct platform_device *pdev)
279 {
280 struct resource *res;
281
282 if (acpi_has_watchdog())
283 return 0;
284
285 res = platform_get_resource(pdev, IORESOURCE_IO,
286 PLAT_RESOURCE_ACPI_IO_INDEX);
287 if (!res) {
288 dev_err(&pdev->dev, "Failed to get IO resource\n");
289 return -EINVAL;
290 }
291
292 tco_res[0].flags = IORESOURCE_IO;
293 tco_res[0].start = res->start + TCO_BASE_OFFSET;
294 tco_res[0].end = tco_res[0].start + TCO_REGS_SIZE - 1;
295 tco_res[1].flags = IORESOURCE_IO;
296 tco_res[1].start = res->start + SMI_EN_OFFSET;
297 tco_res[1].end = tco_res[1].start + SMI_EN_SIZE - 1;
298
299 return 0;
300 }
301
intel_pmc_get_resources(struct platform_device * pdev,struct intel_pmc_dev * pmc,struct intel_scu_ipc_data * scu_data)302 static int intel_pmc_get_resources(struct platform_device *pdev,
303 struct intel_pmc_dev *pmc,
304 struct intel_scu_ipc_data *scu_data)
305 {
306 struct resource gcr_res;
307 size_t npunit_res = 0;
308 struct resource *res;
309 int ret;
310
311 scu_data->irq = platform_get_irq_optional(pdev, 0);
312
313 res = platform_get_resource(pdev, IORESOURCE_MEM,
314 PLAT_RESOURCE_IPC_INDEX);
315 if (!res) {
316 dev_err(&pdev->dev, "Failed to get IPC resource\n");
317 return -EINVAL;
318 }
319
320 /* IPC registers */
321 scu_data->mem.flags = res->flags;
322 scu_data->mem.start = res->start;
323 scu_data->mem.end = res->start + PLAT_RESOURCE_IPC_SIZE - 1;
324
325 /* GCR registers */
326 gcr_res.flags = res->flags;
327 gcr_res.start = res->start + PLAT_RESOURCE_GCR_OFFSET;
328 gcr_res.end = gcr_res.start + PLAT_RESOURCE_GCR_SIZE - 1;
329
330 pmc->gcr_mem_base = devm_ioremap_resource(&pdev->dev, &gcr_res);
331 if (IS_ERR(pmc->gcr_mem_base))
332 return PTR_ERR(pmc->gcr_mem_base);
333
334 /* Only register iTCO watchdog if there is no WDAT ACPI table */
335 ret = intel_pmc_get_tco_resources(pdev);
336 if (ret)
337 return ret;
338
339 /* BIOS data register */
340 res = platform_get_resource(pdev, IORESOURCE_MEM,
341 PLAT_RESOURCE_BIOS_DATA_INDEX);
342 if (!res) {
343 dev_err(&pdev->dev, "Failed to get resource of P-unit BIOS data\n");
344 return -EINVAL;
345 }
346 punit_res[npunit_res++] = *res;
347
348 /* BIOS interface register */
349 res = platform_get_resource(pdev, IORESOURCE_MEM,
350 PLAT_RESOURCE_BIOS_IFACE_INDEX);
351 if (!res) {
352 dev_err(&pdev->dev, "Failed to get resource of P-unit BIOS interface\n");
353 return -EINVAL;
354 }
355 punit_res[npunit_res++] = *res;
356
357 /* ISP data register, optional */
358 res = platform_get_resource(pdev, IORESOURCE_MEM,
359 PLAT_RESOURCE_ISP_DATA_INDEX);
360 if (res)
361 punit_res[npunit_res++] = *res;
362
363 /* ISP interface register, optional */
364 res = platform_get_resource(pdev, IORESOURCE_MEM,
365 PLAT_RESOURCE_ISP_IFACE_INDEX);
366 if (res)
367 punit_res[npunit_res++] = *res;
368
369 /* GTD data register, optional */
370 res = platform_get_resource(pdev, IORESOURCE_MEM,
371 PLAT_RESOURCE_GTD_DATA_INDEX);
372 if (res)
373 punit_res[npunit_res++] = *res;
374
375 /* GTD interface register, optional */
376 res = platform_get_resource(pdev, IORESOURCE_MEM,
377 PLAT_RESOURCE_GTD_IFACE_INDEX);
378 if (res)
379 punit_res[npunit_res++] = *res;
380
381 punit.num_resources = npunit_res;
382
383 /* Telemetry SSRAM is optional */
384 res = platform_get_resource(pdev, IORESOURCE_MEM,
385 PLAT_RESOURCE_TELEM_SSRAM_INDEX);
386 if (res)
387 pmc->telem_base = res;
388
389 return 0;
390 }
391
intel_pmc_create_devices(struct intel_pmc_dev * pmc)392 static int intel_pmc_create_devices(struct intel_pmc_dev *pmc)
393 {
394 int ret;
395
396 if (!acpi_has_watchdog()) {
397 ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, &tco,
398 1, NULL, 0, NULL);
399 if (ret)
400 return ret;
401 }
402
403 ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, &punit, 1,
404 NULL, 0, NULL);
405 if (ret)
406 return ret;
407
408 if (pmc->telem_base) {
409 ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO,
410 &telem, 1, pmc->telem_base, 0, NULL);
411 }
412
413 return ret;
414 }
415
416 static const struct acpi_device_id intel_pmc_acpi_ids[] = {
417 { "INT34D2" },
418 { }
419 };
420 MODULE_DEVICE_TABLE(acpi, intel_pmc_acpi_ids);
421
intel_pmc_probe(struct platform_device * pdev)422 static int intel_pmc_probe(struct platform_device *pdev)
423 {
424 struct intel_scu_ipc_data scu_data = {};
425 struct intel_pmc_dev *pmc;
426 int ret;
427
428 pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL);
429 if (!pmc)
430 return -ENOMEM;
431
432 pmc->dev = &pdev->dev;
433 spin_lock_init(&pmc->gcr_lock);
434
435 ret = intel_pmc_get_resources(pdev, pmc, &scu_data);
436 if (ret) {
437 dev_err(&pdev->dev, "Failed to request resources\n");
438 return ret;
439 }
440
441 pmc->scu = devm_intel_scu_ipc_register(&pdev->dev, &scu_data);
442 if (IS_ERR(pmc->scu))
443 return PTR_ERR(pmc->scu);
444
445 platform_set_drvdata(pdev, pmc);
446
447 ret = intel_pmc_create_devices(pmc);
448 if (ret)
449 dev_err(&pdev->dev, "Failed to create PMC devices\n");
450
451 return ret;
452 }
453
454 static struct platform_driver intel_pmc_driver = {
455 .probe = intel_pmc_probe,
456 .driver = {
457 .name = "intel_pmc_bxt",
458 .acpi_match_table = intel_pmc_acpi_ids,
459 .dev_groups = intel_pmc_groups,
460 },
461 };
462 module_platform_driver(intel_pmc_driver);
463
464 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
465 MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>");
466 MODULE_DESCRIPTION("Intel Broxton PMC driver");
467 MODULE_LICENSE("GPL v2");
468