1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for the Intel Broxton PMC
5 * (C) Copyright 2014 - 2020 Intel Corporation
7 * This driver is based on Intel SCU IPC driver (intel_scu_ipc.c) by
8 * Sreedhara DS <sreedhara.ds@intel.com>
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.
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>
27 #include <asm/intel_scu_ipc.h>
29 /* Residency with clock rate at 19.2MHz to usecs */
30 #define S0IX_RESIDENCY_IN_USECS(d, s) \
32 u64 result = 10ull * ((d) + (s)); \
33 do_div(result, 192); \
37 /* Resources exported from IFWI */
38 #define PLAT_RESOURCE_IPC_INDEX 0
39 #define PLAT_RESOURCE_IPC_SIZE 0x1000
40 #define PLAT_RESOURCE_GCR_OFFSET 0x1000
41 #define PLAT_RESOURCE_GCR_SIZE 0x1000
42 #define PLAT_RESOURCE_BIOS_DATA_INDEX 1
43 #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2
44 #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3
45 #define PLAT_RESOURCE_ISP_DATA_INDEX 4
46 #define PLAT_RESOURCE_ISP_IFACE_INDEX 5
47 #define PLAT_RESOURCE_GTD_DATA_INDEX 6
48 #define PLAT_RESOURCE_GTD_IFACE_INDEX 7
49 #define PLAT_RESOURCE_ACPI_IO_INDEX 0
52 * BIOS does not create an ACPI device for each PMC function, but
53 * exports multiple resources from one ACPI device (IPC) for multiple
54 * functions. This driver is responsible for creating a child device and
55 * to export resources for those functions.
57 #define SMI_EN_OFFSET 0x0040
59 #define TCO_BASE_OFFSET 0x0060
60 #define TCO_REGS_SIZE 16
61 #define TELEM_SSRAM_SIZE 240
62 #define TELEM_PMC_SSRAM_OFFSET 0x1b00
63 #define TELEM_PUNIT_SSRAM_OFFSET 0x1a00
66 #define PMC_NORTHPEAK_CTRL 0xed
68 static inline bool is_gcr_valid(u32 offset
)
70 return offset
< PLAT_RESOURCE_GCR_SIZE
- 8;
74 * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register
75 * @pmc: PMC device pointer
76 * @offset: offset of GCR register from GCR address base
77 * @data: data pointer for storing the register output
79 * Reads the 64-bit PMC GCR register at given offset.
81 * Return: Negative value on error or 0 on success.
83 int intel_pmc_gcr_read64(struct intel_pmc_dev
*pmc
, u32 offset
, u64
*data
)
85 if (!is_gcr_valid(offset
))
88 spin_lock(&pmc
->gcr_lock
);
89 *data
= readq(pmc
->gcr_mem_base
+ offset
);
90 spin_unlock(&pmc
->gcr_lock
);
94 EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64
);
97 * intel_pmc_gcr_update() - Update PMC GCR register bits
98 * @pmc: PMC device pointer
99 * @offset: offset of GCR register from GCR address base
100 * @mask: bit mask for update operation
103 * Updates the bits of given GCR register as specified by
106 * Return: Negative value on error or 0 on success.
108 int intel_pmc_gcr_update(struct intel_pmc_dev
*pmc
, u32 offset
, u32 mask
, u32 val
)
112 if (!is_gcr_valid(offset
))
115 spin_lock(&pmc
->gcr_lock
);
116 new_val
= readl(pmc
->gcr_mem_base
+ offset
);
118 new_val
= (new_val
& ~mask
) | (val
& mask
);
119 writel(new_val
, pmc
->gcr_mem_base
+ offset
);
121 new_val
= readl(pmc
->gcr_mem_base
+ offset
);
122 spin_unlock(&pmc
->gcr_lock
);
124 /* Check whether the bit update is successful */
125 return (new_val
& mask
) != (val
& mask
) ? -EIO
: 0;
127 EXPORT_SYMBOL_GPL(intel_pmc_gcr_update
);
130 * intel_pmc_s0ix_counter_read() - Read S0ix residency
131 * @pmc: PMC device pointer
132 * @data: Out param that contains current S0ix residency count.
134 * Writes to @data how many usecs the system has been in low-power S0ix
137 * Return: An error code or 0 on success.
139 int intel_pmc_s0ix_counter_read(struct intel_pmc_dev
*pmc
, u64
*data
)
143 spin_lock(&pmc
->gcr_lock
);
144 deep
= readq(pmc
->gcr_mem_base
+ PMC_GCR_TELEM_DEEP_S0IX_REG
);
145 shlw
= readq(pmc
->gcr_mem_base
+ PMC_GCR_TELEM_SHLW_S0IX_REG
);
146 spin_unlock(&pmc
->gcr_lock
);
148 *data
= S0IX_RESIDENCY_IN_USECS(deep
, shlw
);
151 EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read
);
154 * simplecmd_store() - Send a simple IPC command
155 * @dev: Device under the attribute is
156 * @attr: Attribute in question
157 * @buf: Buffer holding data to be stored to the attribute
158 * @count: Number of bytes in @buf
160 * Expects a string with two integers separated with space. These two
161 * values hold command and subcommand that is send to PMC.
163 * Return: Number number of bytes written (@count) or negative errno in
166 static ssize_t
simplecmd_store(struct device
*dev
, struct device_attribute
*attr
,
167 const char *buf
, size_t count
)
169 struct intel_pmc_dev
*pmc
= dev_get_drvdata(dev
);
170 struct intel_scu_ipc_dev
*scu
= pmc
->scu
;
175 ret
= sscanf(buf
, "%d %d", &cmd
, &subcmd
);
177 dev_err(dev
, "Invalid values, expected: cmd subcmd\n");
181 ret
= intel_scu_ipc_dev_simple_command(scu
, cmd
, subcmd
);
187 static DEVICE_ATTR_WO(simplecmd
);
190 * northpeak_store() - Enable or disable Northpeak
191 * @dev: Device under the attribute is
192 * @attr: Attribute in question
193 * @buf: Buffer holding data to be stored to the attribute
194 * @count: Number of bytes in @buf
196 * Expects an unsigned integer. Non-zero enables Northpeak and zero
199 * Return: Number number of bytes written (@count) or negative errno in
202 static ssize_t
northpeak_store(struct device
*dev
, struct device_attribute
*attr
,
203 const char *buf
, size_t count
)
205 struct intel_pmc_dev
*pmc
= dev_get_drvdata(dev
);
206 struct intel_scu_ipc_dev
*scu
= pmc
->scu
;
211 ret
= kstrtoul(buf
, 0, &val
);
215 /* Northpeak is enabled if subcmd == 1 and disabled if it is 0 */
221 ret
= intel_scu_ipc_dev_simple_command(scu
, PMC_NORTHPEAK_CTRL
, subcmd
);
227 static DEVICE_ATTR_WO(northpeak
);
229 static struct attribute
*intel_pmc_attrs
[] = {
230 &dev_attr_northpeak
.attr
,
231 &dev_attr_simplecmd
.attr
,
235 static const struct attribute_group intel_pmc_group
= {
236 .attrs
= intel_pmc_attrs
,
239 static const struct attribute_group
*intel_pmc_groups
[] = {
244 static struct resource punit_res
[6];
246 static struct mfd_cell punit
= {
247 .name
= "intel_punit_ipc",
248 .resources
= punit_res
,
251 static struct itco_wdt_platform_data tco_pdata
= {
252 .name
= "Apollo Lake SoC",
254 .no_reboot_use_pmc
= true,
257 static struct resource tco_res
[2];
259 static const struct mfd_cell tco
= {
261 .ignore_resource_conflicts
= true,
262 .resources
= tco_res
,
263 .num_resources
= ARRAY_SIZE(tco_res
),
264 .platform_data
= &tco_pdata
,
265 .pdata_size
= sizeof(tco_pdata
),
268 static const struct resource telem_res
[] = {
269 DEFINE_RES_MEM(TELEM_PUNIT_SSRAM_OFFSET
, TELEM_SSRAM_SIZE
),
270 DEFINE_RES_MEM(TELEM_PMC_SSRAM_OFFSET
, TELEM_SSRAM_SIZE
),
273 static const struct mfd_cell telem
= {
274 .name
= "intel_telemetry",
275 .resources
= telem_res
,
276 .num_resources
= ARRAY_SIZE(telem_res
),
279 static int intel_pmc_get_tco_resources(struct platform_device
*pdev
)
281 struct resource
*res
;
283 if (acpi_has_watchdog())
286 res
= platform_get_resource(pdev
, IORESOURCE_IO
,
287 PLAT_RESOURCE_ACPI_IO_INDEX
);
289 dev_err(&pdev
->dev
, "Failed to get IO resource\n");
293 tco_res
[0].flags
= IORESOURCE_IO
;
294 tco_res
[0].start
= res
->start
+ TCO_BASE_OFFSET
;
295 tco_res
[0].end
= tco_res
[0].start
+ TCO_REGS_SIZE
- 1;
296 tco_res
[1].flags
= IORESOURCE_IO
;
297 tco_res
[1].start
= res
->start
+ SMI_EN_OFFSET
;
298 tco_res
[1].end
= tco_res
[1].start
+ SMI_EN_SIZE
- 1;
303 static int intel_pmc_get_resources(struct platform_device
*pdev
,
304 struct intel_pmc_dev
*pmc
,
305 struct intel_scu_ipc_data
*scu_data
)
307 struct resource gcr_res
;
308 size_t npunit_res
= 0;
309 struct resource
*res
;
312 scu_data
->irq
= platform_get_irq_optional(pdev
, 0);
314 res
= platform_get_resource(pdev
, IORESOURCE_MEM
,
315 PLAT_RESOURCE_IPC_INDEX
);
317 dev_err(&pdev
->dev
, "Failed to get IPC resource\n");
322 scu_data
->mem
.flags
= res
->flags
;
323 scu_data
->mem
.start
= res
->start
;
324 scu_data
->mem
.end
= res
->start
+ PLAT_RESOURCE_IPC_SIZE
- 1;
327 gcr_res
.flags
= res
->flags
;
328 gcr_res
.start
= res
->start
+ PLAT_RESOURCE_GCR_OFFSET
;
329 gcr_res
.end
= gcr_res
.start
+ PLAT_RESOURCE_GCR_SIZE
- 1;
331 pmc
->gcr_mem_base
= devm_ioremap_resource(&pdev
->dev
, &gcr_res
);
332 if (IS_ERR(pmc
->gcr_mem_base
))
333 return PTR_ERR(pmc
->gcr_mem_base
);
335 /* Only register iTCO watchdog if there is no WDAT ACPI table */
336 ret
= intel_pmc_get_tco_resources(pdev
);
340 /* BIOS data register */
341 res
= platform_get_resource(pdev
, IORESOURCE_MEM
,
342 PLAT_RESOURCE_BIOS_DATA_INDEX
);
344 dev_err(&pdev
->dev
, "Failed to get resource of P-unit BIOS data\n");
347 punit_res
[npunit_res
++] = *res
;
349 /* BIOS interface register */
350 res
= platform_get_resource(pdev
, IORESOURCE_MEM
,
351 PLAT_RESOURCE_BIOS_IFACE_INDEX
);
353 dev_err(&pdev
->dev
, "Failed to get resource of P-unit BIOS interface\n");
356 punit_res
[npunit_res
++] = *res
;
358 /* ISP data register, optional */
359 res
= platform_get_resource(pdev
, IORESOURCE_MEM
,
360 PLAT_RESOURCE_ISP_DATA_INDEX
);
362 punit_res
[npunit_res
++] = *res
;
364 /* ISP interface register, optional */
365 res
= platform_get_resource(pdev
, IORESOURCE_MEM
,
366 PLAT_RESOURCE_ISP_IFACE_INDEX
);
368 punit_res
[npunit_res
++] = *res
;
370 /* GTD data register, optional */
371 res
= platform_get_resource(pdev
, IORESOURCE_MEM
,
372 PLAT_RESOURCE_GTD_DATA_INDEX
);
374 punit_res
[npunit_res
++] = *res
;
376 /* GTD interface register, optional */
377 res
= platform_get_resource(pdev
, IORESOURCE_MEM
,
378 PLAT_RESOURCE_GTD_IFACE_INDEX
);
380 punit_res
[npunit_res
++] = *res
;
382 punit
.num_resources
= npunit_res
;
384 /* Telemetry SSRAM is optional */
385 res
= platform_get_resource(pdev
, IORESOURCE_MEM
,
386 PLAT_RESOURCE_TELEM_SSRAM_INDEX
);
388 pmc
->telem_base
= res
;
393 static int intel_pmc_create_devices(struct intel_pmc_dev
*pmc
)
397 if (!acpi_has_watchdog()) {
398 ret
= devm_mfd_add_devices(pmc
->dev
, PLATFORM_DEVID_AUTO
, &tco
,
404 ret
= devm_mfd_add_devices(pmc
->dev
, PLATFORM_DEVID_AUTO
, &punit
, 1,
409 if (pmc
->telem_base
) {
410 ret
= devm_mfd_add_devices(pmc
->dev
, PLATFORM_DEVID_AUTO
,
411 &telem
, 1, pmc
->telem_base
, 0, NULL
);
417 static const struct acpi_device_id intel_pmc_acpi_ids
[] = {
421 MODULE_DEVICE_TABLE(acpi
, intel_pmc_acpi_ids
);
423 static int intel_pmc_probe(struct platform_device
*pdev
)
425 struct intel_scu_ipc_data scu_data
= {};
426 struct intel_pmc_dev
*pmc
;
429 pmc
= devm_kzalloc(&pdev
->dev
, sizeof(*pmc
), GFP_KERNEL
);
433 pmc
->dev
= &pdev
->dev
;
434 spin_lock_init(&pmc
->gcr_lock
);
436 ret
= intel_pmc_get_resources(pdev
, pmc
, &scu_data
);
438 dev_err(&pdev
->dev
, "Failed to request resources\n");
442 pmc
->scu
= devm_intel_scu_ipc_register(&pdev
->dev
, &scu_data
);
443 if (IS_ERR(pmc
->scu
))
444 return PTR_ERR(pmc
->scu
);
446 platform_set_drvdata(pdev
, pmc
);
448 ret
= intel_pmc_create_devices(pmc
);
450 dev_err(&pdev
->dev
, "Failed to create PMC devices\n");
455 static struct platform_driver intel_pmc_driver
= {
456 .probe
= intel_pmc_probe
,
458 .name
= "intel_pmc_bxt",
459 .acpi_match_table
= intel_pmc_acpi_ids
,
460 .dev_groups
= intel_pmc_groups
,
463 module_platform_driver(intel_pmc_driver
);
465 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
466 MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>");
467 MODULE_DESCRIPTION("Intel Broxton PMC driver");
468 MODULE_LICENSE("GPL v2");