x86: new Intel Atom SoC power management controller driver
PATCH 1/1 x86: new Intel Atom SoC power management controller driver
The Power Management Controller (PMC) controls many of the power management features present in the SoC. This driver provides interface to configure the Power Management Controller (PMC).
This driver exposes PMC device state and sleep state residency via debugfs for observation:
/sys/kernel/debugfs/pmc_atom/dev_state /sys/kernel/debugfs/pmc_atom/sleep_state
This driver also provides a native power off function via PMC PCI IO port.
--- arch/x86/Kconfig | 4 + arch/x86/include/asm/pmc_atom.h | 91 ++++++++++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/pmc_atom.c | 301 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 397 insertions(+) create mode 100644 arch/x86/include/asm/pmc_atom.h create mode 100644 arch/x86/kernel/pmc_atom.c
arch/x86/Kconfig +4 -0
@@ -2420,6 +2420,10 @@ config IOSF_MBI Fabric (IOSF) Sideband MailBox Interface (MBI). For MBI platforms enumerable by PCI. +config PMC_ATOM + def_bool y + depends on PCI + source "net/Kconfig" source "drivers/Kconfig"
(quoted diff) +0 -0
b/arch/x86/include/asm/pmc_atom.h
new file mode 100644
index 0000000..6802d17
arch/x86/include/asm/pmc_atom.h new file +11 -0
@@ -0,0 +1,91 @@ +/* +* Intel Atom SOC Power Management Controller Header File +* Copyright (c) 2014, Intel Corporation. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for
+ * more details.
+ *
+ */
+
+#ifndef PMC_ATOM_H
+#define PMC_ATOM_H
+
+/* ValleyView Power Control Unit PCI Device ID */
+#define PCI_DEVICE_ID_VLV_PMC 0x0F1C
+
+/* PMC Memory mapped IO registers */
+#define PMC_BASE_ADDR_OFFSET 0x44
+#define PMC_BASE_ADDR_MASK 0xFFFFFE00
+#define PMC_MMIO_REG_LEN 0x100
+#define PMC_REG_BIT_WIDTH 32
+
+/* BIOS uses FUNC_DIS to disable specific function */
+#define PMC_FUNC_DIS 0x34
+#define PMC_FUNC_DIS_2 0x38
+/* The timers acumulate time spent in sleep state */
+#define PMC_S0IR_TMR 0x80
+#define PMC_S0I1_TMR 0x84
+#define PMC_S0I2_TMR 0x88
+#define PMC_S0I3_TMR 0x8C
+#define PMC_S0_TMR 0x90
+/* Sleep state counter is in units of of 32us */
+#define PMC_TMR_SHIFT 5
+
+/* These registers reflect D3 status of functions */
+#define PMC_D3_STS_0 0xA0
+
+#define BIT_LPSS1_F0_DMA (1 << 0)
+#define BIT_LPSS1_F1_PWM1 (1 << 1)
+#define BIT_LPSS1_F2_PWM2 (1 << 2)
+#define BIT_LPSS1_F3_HSUART1 (1 << 3)
+#define BIT_LPSS1_F4_HSUART2 (1 << 4)
+#define BIT_LPSS1_F5_SPI (1 << 5)
+#define BIT_LPSS1_F6_XXX (1 << 6)
+#define BIT_LPSS1_F7_XXX (1 << 7)
+#define BIT_SCC_EMMC (1 << 8)
+#define BIT_SCC_SDIO (1 << 9)
+#define BIT_SCC_SDCARD (1 << 10)
+#define BIT_SCC_MIPI (1 << 11)
+#define BIT_HDA (1 << 12)
+#define BIT_LPE (1 << 13)
+#define BIT_OTG (1 << 14)
+#define BIT_USH (1 << 15)
+#define BIT_GBE (1 << 16)
+#define BIT_SATA (1 << 17)
+#define BIT_USB_EHCI (1 << 18)
+#define BIT_SEC (1 << 19)
+#define BIT_PCIE_PORT0 (1 << 20)
+#define BIT_PCIE_PORT1 (1 << 21)
+#define BIT_PCIE_PORT2 (1 << 22)
+#define BIT_PCIE_PORT3 (1 << 23)
+#define BIT_LPSS2_F0_DMA (1 << 24)
+#define BIT_LPSS2_F1_I2C1 (1 << 25)
+#define BIT_LPSS2_F2_I2C2 (1 << 26)
+#define BIT_LPSS2_F3_I2C3 (1 << 27)
+#define BIT_LPSS2_F4_I2C4 (1 << 28)
+#define BIT_LPSS2_F5_I2C5 (1 << 29)
+#define BIT_LPSS2_F6_I2C6 (1 << 30)
+#define BIT_LPSS2_F7_I2C7 (1 << 31)
+
+#define PMC_D3_STS_1 0xA4
+#define BIT_SMB (1 << 0)
+#define BIT_USH_SS_PHY (1 << 1)
+#define BIT_OTG_SS_PHY (1 << 2)
+#define BIT_DFX (1 << 3)
+
+/* PMC I/O Registers */
+#define ACPI_BASE_ADDR_OFFSET 0x40
+#define ACPI_BASE_ADDR_MASK 0xFFFFFE00
+#define ACPI_MMIO_REG_LEN 0x100
+
+#define PM1_CNT 0x4
+#define SLEEP_TYPE_MASK 0xFFFFECFF
+#define SLEEP_TYPE_S5 0x1C00
+#define SLEEP_ENABLE 0x2000
+#endif /* PMC_ATOM_H */
arch/x86/kernel/Makefile +1 -0
@@ -104,6 +104,7 @@ obj-$(CONFIG_EFI) += sysfb_efi.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o +obj-$(CONFIG_PMC_ATOM) += pmc_atom.o ### # 64 bit specific files
arch/x86/kernel/pmc_atom.c new file +11 -0
@@ -0,0 +1,301 @@ +/* +* Intel Atom SOC Power Management Controller Driver +* Copyright (c) 2014, Intel Corporation. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/io.h>
+
+#include <asm/pmc_atom.h>
+
+#define DRIVER_NAME "pmc_atom"
+
+struct pmc_dev {
+ struct pci_dev *pdev;
+ u32 base_addr;
+ void __iomem *regmap;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dbgfs_dir;
+#endif /* CONFIG_DEBUG_FS */
+};
+
+static u32 acpi_base_addr;
+
+struct pmc_dev_map {
+ char *name;
+ u32 bit_mask;
+};
+
+static struct pmc_dev_map dev_map[] = {
+ {"0 - LPSS1_F0_DMA", BIT_LPSS1_F0_DMA},
+ {"1 - LPSS1_F1_PWM1", BIT_LPSS1_F1_PWM1},
+ {"2 - LPSS1_F2_PWM2", BIT_LPSS1_F2_PWM2},
+ {"3 - LPSS1_F3_HSUART1", BIT_LPSS1_F3_HSUART1},
+ {"4 - LPSS1_F4_HSUART2", BIT_LPSS1_F4_HSUART2},
+ {"5 - LPSS1_F5_SPI", BIT_LPSS1_F5_SPI},
+ {"6 - LPSS1_F6_Reserved", BIT_LPSS1_F6_XXX},
+ {"7 - LPSS1_F7_Reserved", BIT_LPSS1_F7_XXX},
+ {"8 - SCC_EMMC", BIT_SCC_EMMC},
+ {"9 - SCC_SDIO", BIT_SCC_SDIO},+ {"10 - SCC_SDCARD", BIT_SCC_SDCARD},
+ {"11 - SCC_MIPI", BIT_SCC_MIPI},
+ {"12 - HDA", BIT_HDA},
+ {"13 - LPE", BIT_LPE},
+ {"14 - OTG", BIT_OTG},
+ {"15 - USH", BIT_USH},
+ {"16 - GBE", BIT_GBE},
+ {"17 - SATA", BIT_SATA},
+ {"18 - USB_EHCI", BIT_USB_EHCI},
+ {"19 - SEC", BIT_SEC},
+ {"20 - PCIE_PORT0", BIT_PCIE_PORT0},
+ {"21 - PCIE_PORT1", BIT_PCIE_PORT1},
+ {"22 - PCIE_PORT2", BIT_PCIE_PORT2},
+ {"23 - PCIE_PORT3", BIT_PCIE_PORT3},
+ {"24 - LPSS2_F0_DMA", BIT_LPSS2_F0_DMA},
+ {"25 - LPSS2_F1_I2C1", BIT_LPSS2_F1_I2C1},
+ {"26 - LPSS2_F2_I2C2", BIT_LPSS2_F2_I2C2},
+ {"27 - LPSS2_F3_I2C3", BIT_LPSS2_F3_I2C3},
+ {"28 - LPSS2_F3_I2C4", BIT_LPSS2_F4_I2C4},
+ {"29 - LPSS2_F5_I2C5", BIT_LPSS2_F5_I2C5},
+ {"30 - LPSS2_F6_I2C6", BIT_LPSS2_F6_I2C6},
+ {"31 - LPSS2_F7_I2C7", BIT_LPSS2_F7_I2C7},
+ {"32 - SMB", BIT_SMB},
+ {"33 - USH_SS_PHY", BIT_OTG_SS_PHY},
+ {"34 - OTG_SS_PHY", BIT_USH_SS_PHY},
+ {"35 - DFX", BIT_DFX},
+};
+
+static inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) +{
+ return readl(pmc->regmap + reg_offset);
+}
+
+static void pmc_power_off(void)
+{
+ u16 pm1_cnt_port;
+ u32 pm1_cnt_value;
+
+ printk(KERN_INFO, "PMC: Preparing to enter system sleep state S5\n");
+
+ pm1_cnt_port = acpi_base_addr + PM1_CNT;
+
+ pm1_cnt_value = inl(pm1_cnt_port);
+ pm1_cnt_value &= SLEEP_TYPE_MASK;
+ pm1_cnt_value |= SLEEP_TYPE_S5;
+ pm1_cnt_value |= SLEEP_ENABLE;
+
+ outl(pm1_cnt_value, pm1_cnt_port);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int pmc_dev_state_show(struct seq_file *s, void *unused) +{
+ struct pmc_dev *pmc = (struct pmc_dev *)s->private;
+ u32 func_dis, func_dis_2, func_dis_index;
+ u32 d3_sts_0, d3_sts_1, d3_sts_index;
+ int dev_num, dev_index, reg_index;
+
+ func_dis = pmc_reg_read(pmc, PMC_FUNC_DIS);
+ func_dis_2 = pmc_reg_read(pmc, PMC_FUNC_DIS_2);
+ d3_sts_0 = pmc_reg_read(pmc, PMC_D3_STS_0);
+ d3_sts_1 = pmc_reg_read(pmc, PMC_D3_STS_1);
+
+ dev_num = sizeof(dev_map) / sizeof(struct pmc_dev_map);
+
+ for (dev_index = 0; dev_index < dev_num; dev_index++) {
+ reg_index = dev_index / PMC_REG_BIT_WIDTH;
+ if (reg_index) {
+ func_dis_index = func_dis_2;
+ d3_sts_index = d3_sts_1;
+ } else {
+ func_dis_index = func_dis;
+ d3_sts_index = d3_sts_0;
+ }
+
+ if (func_dis_index & dev_map[dev_index].bit_mask) {
+ seq_printf(s, "Dev: %-32s\tState: %s [%s]\n",
+ dev_map[dev_index].name, "Disabled",
+ (d3_sts_index & dev_map[dev_index].bit_mask) ?
+ "D3":"D0");
+ } else {
+ seq_printf(s, "Dev: %-32s\tState: %s [%s]\n",
+ dev_map[dev_index].name, "Enabled ",
+ (d3_sts_index & dev_map[dev_index].bit_mask) ?
+ "D3":"D0");
+ }
+ }
+ return 0;
+}
+
+static int pmc_dev_state_open(struct inode *inode, struct file *file) +{
+ return single_open(file, pmc_dev_state_show, inode->i_private);
+}
+
+static const struct file_operations pmc_dev_state_ops = {
+ .open = pmc_dev_state_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int pmc_sleep_tmr_show(struct seq_file *s, void *unused) +{
+ struct pmc_dev *pmc = (struct pmc_dev *)s->private;
+ u64 s0ir_tmr, s0i1_tmr, s0i2_tmr, s0i3_tmr, s0_tmr;
+
+ s0ir_tmr = pmc_reg_read(pmc, PMC_S0IR_TMR) << PMC_TMR_SHIFT;
+ s0i1_tmr = pmc_reg_read(pmc, PMC_S0I1_TMR) << PMC_TMR_SHIFT;
+ s0i2_tmr = pmc_reg_read(pmc, PMC_S0I2_TMR) << PMC_TMR_SHIFT;
+ s0i3_tmr = pmc_reg_read(pmc, PMC_S0I3_TMR) << PMC_TMR_SHIFT;
+ s0_tmr = pmc_reg_read(pmc, PMC_S0_TMR) << PMC_TMR_SHIFT;
+
+ seq_printf(s, "S0IR Residency:\t%lldus\n", s0ir_tmr);
+ seq_printf(s, "S0I1 Residency:\t%lldus\n", s0i1_tmr);
+ seq_printf(s, "S0I2 Residency:\t%lldus\n", s0i2_tmr);
+ seq_printf(s, "S0I3 Residency:\t%lldus\n", s0i3_tmr);
+ seq_printf(s, "S0 Residency:\t%lldus\n", s0_tmr);
+ return 0;
+}
+
+static int pmc_sleep_tmr_open(struct inode *inode, struct file *file) +{
+ return single_open(file, pmc_sleep_tmr_show, inode->i_private);
+}
+
+static const struct file_operations pmc_sleep_tmr_ops = {
+ .open = pmc_sleep_tmr_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void pmc_dbgfs_unregister(struct pmc_dev *pmc)
+{
+ if (!pmc->dbgfs_dir)
+ return;
+
+ debugfs_remove_recursive(pmc->dbgfs_dir);
+ pmc->dbgfs_dir = NULL;
+}
+
+static int pmc_dbgfs_register(struct pmc_dev *pmc)
+{
+ struct dentry *dir, *f;
+
+ dir = debugfs_create_dir("pmc_atom", NULL);
+ if (!dir)
+ return -ENOMEM;
+
+ f = debugfs_create_file("dev_state", S_IFREG | S_IRUGO,
+ dir, pmc, &pmc_dev_state_ops);
+ if (!f) {
+ dev_err(&pmc->pdev->dev, "dev_states register failed\n");
+ goto err;
+ }
+ f = debugfs_create_file("sleep_state", S_IFREG | S_IRUGO,
+ dir, pmc, &pmc_sleep_tmr_ops);
+ if (!f) {
+ dev_err(&pmc->pdev->dev, "sleep_state register failed\n");
+ goto err;
+ }
+ pmc->dbgfs_dir = dir;
+ return 0;
+err:
+ pmc_dbgfs_unregister(pmc);
+ return -ENODEV;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static int pmc_probe(struct pci_dev *pdev,
+ const struct pci_device_id *unused)
+{
+ struct pmc_dev *pmc;
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "error: could not enable device\n");
+ goto err_enable_device;
+ }
+
+ ret = pci_request_regions(pdev, DRIVER_NAME);
+ if (ret) {
+ dev_err(&pdev->dev, "error: could not request PCI region\n");
+ goto err_request_regions;
+ }
+
+ pmc = devm_kzalloc(&pdev->dev, sizeof(struct pmc_dev), GFP_KERNEL);
+ if (!pmc) {
+ dev_err(&pdev->dev, "error: could not allocate memory\n");
+ ret = -ENOMEM;
+ goto err_devm_kzalloc;
+ }
+
+ pmc->pdev = pci_dev_get(pdev);
+
+ pci_read_config_dword(pdev, PMC_BASE_ADDR_OFFSET, &pmc->base_addr);
+ pmc->base_addr &= PMC_BASE_ADDR_MASK;
+
+ pmc->regmap = devm_ioremap_nocache(&pdev->dev,
+ pmc->base_addr, PMC_MMIO_REG_LEN);
+ if (!pmc->regmap) {
+ dev_err(&pdev->dev, "error: ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_devm_ioremap;
+ }
+ pci_set_drvdata(pdev, pmc);
+#ifdef CONFIG_DEBUG_FS
+ pmc_dbgfs_register(pmc);
+#endif /* CONFIG_DEBUG_FS */
+
+ /* Install power off function */
+ pci_read_config_dword(pdev, ACPI_BASE_ADDR_OFFSET, &acpi_base_addr);
+ acpi_base_addr &= ACPI_BASE_ADDR_MASK;
+ if (acpi_base_addr != 0 && pm_power_off == NULL)
+ pm_power_off = pmc_power_off;
+ return 0;
+err_devm_ioremap:
+ pci_dev_put(pdev);
+err_devm_kzalloc:
+ pci_release_regions(pdev);
+err_request_regions:
+ pci_disable_device(pdev);
+err_enable_device:
+ dev_err(&pdev->dev, "error: probe failed\n");
+ return ret;
+}
+
+static const struct pci_device_id pmc_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_VLV_PMC) },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, pmc_pci_ids);
+
+static struct pci_driver pmc_pci_driver = {
+ .name = DRIVER_NAME,
+ .probe = pmc_probe,
+ .id_table = pmc_pci_ids,
+};
+
+module_pci_driver(pmc_pci_driver);
+
+MODULE_AUTHOR("Aubrey Li <[email protected]>"); +MODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface"); +MODULE_LICENSE("GPL v2");
Signature · 1 line
1.7.10.4
Quoted 4 lines · Aubrey
The Power Management Controller (PMC) controls many of the power management features present in the SoC. This driver provides interface to configure the Power Management Controller (PMC).
Quoted 8 lines
This driver exposes PMC device state and sleep state residency via debugfs for observation:
/sys/kernel/debugfs/pmc_atom/dev_state/sys/kernel/debugfs/pmc_atom/sleep_stateThis driver also provides a native power off function via PMC PCI IO port.
What is the reason for putting this in debugfs?
-hpa
Quoted 10 lines · H. Peter Anvin
Quoted 9 lines · Aubrey
The Power Management Controller (PMC) controls many of the power management features present in the SoC. This driver provides interface to configure the Power Management Controller (PMC).
This driver exposes PMC device state and sleep state residency via debugfs for observation:
/sys/kernel/debugfs/pmc_atom/dev_state/sys/kernel/debugfs/pmc_atom/sleep_state
Quoted 5 lines
Quoted 3 lines
This driver also provides a native power off function via PMC PCI IO port.
What is the reason for putting this in debugfs?
S0ix support on Atom SoC needs all of the devices under south complex to be quiesced, as well as the devices under north complex. This interface shows all of the devices states under platform control unit. If the system is not able to enter S0ix, we have a way to diagnose. Or if the system entered S0ix, we have counters to show S0ix entered and its residency.
Thanks,
-Aubrey
Quoted 6 lines
-hpa
Quoted 10 lines · Aubrey
Quoted 2 lines
What is the reason for putting this in debugfs?
S0ix support on Atom SoC needs all of the devices under south complex to be quiesced, as well as the devices under north complex. This interface shows all of the devices states under platform control unit. If the system is not able to enter S0ix, we have a way to diagnose. Or if the system entered S0ix, we have counters to show S0ix entered and its residency.
I guess the real question is: are you sure this is only for debugging, or is this going to be an interface that applications or daemons will actually use (in which case it should live in sysfs).
-hpa
Quoted 12 lines · H. Peter Anvin
Quoted 10 lines · Aubrey
Quoted 2 lines
What is the reason for putting this in debugfs?
S0ix support on Atom SoC needs all of the devices under south complex to be quiesced, as well as the devices under north complex. This interface shows all of the devices states under platform control unit. If the system is not able to enter S0ix, we have a way to diagnose. Or if the system entered S0ix, we have counters to show S0ix entered and its residency.
Quoted 3 lines
I guess the real question is: are you sure this is only for debugging, or is this going to be an interface that applications or daemons will actually use (in which case it should live in sysfs).
These interfaces are uncommitted and don't have consumers now, I'd like to keep them unstable in debugfs.
We can change it if we received a requirement to use them later.
Thanks,
-Aubrey
Quoted 6 lines
-hpa
Quoted 6 lines · Aubrey
These interfaces are uncommitted and don't have consumers now, I'd like to keep them unstable in debugfs.
We can change it if we received a requirement to use them later.
What we absolutely don't want to happen is someone starting to use these unstable interfaces for something other than debugging. If debugfs ever needs to be mounted in a system for full functionality, that is a bug.
-hpa
Quoted 5 lines · H. Peter Anvin
Quoted 4 lines · Aubrey
These interfaces are uncommitted and don't have consumers now, I'd like to keep them unstable in debugfs.
Quoted 7 lines
Quoted 2 lines
We can change it if we received a requirement to use them later.
What we absolutely don't want to happen is someone starting to use these unstable interfaces for something other than debugging. If debugfs ever needs to be mounted in a system for full functionality, that is a bug.
Understood. But we don't have a plan to use it now. Just for observation and diagnosis purpose only.
Are you suggesting we should put them into sysfs now?
Thanks,
-Aubrey
Quoted 5 lines
-hpa
Quoted 10 lines · Aubrey
Quoted 4 lines
What we absolutely don't want to happen is someone starting to use these unstable interfaces for something other than debugging. If debugfs ever needs to be mounted in a system for full functionality, that is a bug.
Understood. But we don't have a plan to use it now. Just for observation and diagnosis purpose only.
Are you suggesting we should put them into sysfs now?
No, I'm just trying to understand if there is a risk.
-hpa
Quoted 9 lines · H. Peter Anvin
Quoted 8 lines · Aubrey
Quoted 4 lines
What we absolutely don't want to happen is someone starting to use these unstable interfaces for something other than debugging. If debugfs ever needs to be mounted in a system for full functionality, that is a bug.
Understood. But we don't have a plan to use it now. Just for observation and diagnosis purpose only.
Quoted 7 lines
Quoted 2 lines
Are you suggesting we should put them into sysfs now?
No, I'm just trying to understand if there is a risk.
-hpa
Joe reminded me that my patch is word wrapped while I was not aware, hope this one work.
Thanks,
-Aubrey
Quoted 1 line
From
6fb474e125ecbab404147d2ca75d6965a4716b53Mon Sep 17 00:00:00 2001
From: Aubrey Li <[email protected]>
Date: Wed, 5 Mar 2014 21:15:56 -0600
Subject: [PATCH] X86 platform: New Intel Atom SOC power management controller
driver
The Power Management Controller (PMC) controls many of the power management features present in the SoC. This driver provides interface to configure the Power Management Controller (PMC).
This driver exposes PMC device state and sleep state residency via debugfs:
/sys/kernel/debugfs/pmc_atom/dev_state /sys/kernel/debugfs/pmc_atom/sleep_state
This driver also provides a native power off function via PMC PCI IO port.
--- arch/x86/Kconfig | 4 + arch/x86/include/asm/pmc_atom.h | 91 ++++++++++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/pmc_atom.c | 301 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 397 insertions(+) create mode 100644 arch/x86/include/asm/pmc_atom.h create mode 100644 arch/x86/kernel/pmc_atom.c
arch/x86/Kconfig +4 -0
@@ -2420,6 +2420,10 @@ config IOSF_MBI Fabric (IOSF) Sideband MailBox Interface (MBI). For MBI platforms enumerable by PCI. +config PMC_ATOM + def_bool y + depends on PCI + source "net/Kconfig" source "drivers/Kconfig"
arch/x86/include/asm/pmc_atom.h new file +91 -0
91 lines not on this page · raw message
arch/x86/kernel/Makefile +1 -0
@@ -104,6 +104,7 @@ obj-$(CONFIG_EFI) += sysfb_efi.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o +obj-$(CONFIG_PMC_ATOM) += pmc_atom.o ### # 64 bit specific files
arch/x86/kernel/pmc_atom.c new file +301 -0
301 lines not on this page · raw message
Signature · 1 line
1.7.10.4
Quoted 1 line · Aubrey
my patch is word wrapped while I was not aware, hope this one work.
trivial notes:
arch/x86/include/asm/pmc_atom.h
Quoted 1 line
arch/x86/include/asm/pmc_atom.h +0
-0
[]
arch/x86/include/asm/pmc_atom.h line 44
Quoted 2 lines
arch/x86/include/asm/pmc_atom.h +2
-0+#define BIT_LPSS1_F0_DMA (1 << 0) +#define BIT_LPSS1_F1_PWM1 (1 << 1)
These could use BIT(foo)
#define BIT_LPSS1_F0_DMA BIT(0)
#define BIT_LPSS1_F1_PWM1 BIT(1)
etc..
arch/x86/include/asm/pmc_atom.h line 80
Quoted 4 lines
arch/x86/include/asm/pmc_atom.h +4
-0+#define BIT_SMB (1 << 0) +#define BIT_USH_SS_PHY (1 << 1) +#define BIT_OTG_SS_PHY (1 << 2) +#define BIT_DFX (1 << 3)
here too.
arch/x86/kernel/pmc_atom.c
Quoted 1 line
arch/x86/kernel/pmc_atom.c +0
-0
[]
arch/x86/kernel/pmc_atom.c line 2
Quoted 3 lines
arch/x86/kernel/pmc_atom.c +2
-0@@ -0,0 +1,301 @@ +/* +* Intel Atom SOC Power Management Controller Driver
[]
arch/x86/kernel/pmc_atom.c line 3
Quoted 1 line
arch/x86/kernel/pmc_atom.c +1
-0+*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
arch/x86/kernel/pmc_atom.c line 5
Quoted 2 lines
arch/x86/kernel/pmc_atom.c +2
-0+static void pmc_power_off (void ) +{
[]
arch/x86/kernel/pmc_atom.c line 93
Quoted 1 line
arch/x86/kernel/pmc_atom.c +1
-0+printk (KERN_INFO ,"PMC: Preparing to enter system sleep state S5\n" );
pr_info("Preparing to enter system sleep state S5\n");arch/x86/kernel/pmc_atom.c line 140
Quoted 11 lines
arch/x86/kernel/pmc_atom.c +11
-0+if (func_dis_index & dev_map[dev_index].bit_mask) { +seq_printf (s,"Dev: %-32s\tState: %s [%s]\n" , + dev_map[dev_index].name,"Disabled" , + (d3_sts_index & dev_map[dev_index].bit_mask) ? +"D3" :"D0" ); + }else { +seq_printf (s,"Dev: %-32s\tState: %s [%s]\n" , + dev_map[dev_index].name,"Enabled " , + (d3_sts_index & dev_map[dev_index].bit_mask) ? +"D3" :"D0" ); + }
Maybe better with a single seq_printf
seq_printf(s, "Dev: %-32s\tState: %s [%s]\n",
dev_map[dev_index].name, dev_map[dev_index].bit_mask & func_dis_index ? "Disabled" : " Enabled ", dev_map[dev_index].bit_mask & d3_sts_index ? "D3" : "D0");
arch/x86/kernel/pmc_atom.c line 245
Quoted 7 lines
arch/x86/kernel/pmc_atom.c +6
-0+static int pmc_probe (struct pci_dev *pdev, +const struct pci_device_id *unused) +{ + pmc =devm_kzalloc (&pdev->dev,sizeof (struct pmc_dev ),GFP_KERNEL ); +if (!pmc) { +dev_err (&pdev->dev,"error: could not allocate memory\n" );
Unnecessary OOM message, kzalloc will dump_stack()
Li, Aubrey
Reviewed-by Joe PerchesQuoted 6 lines · Joe Perches
Quoted 1 line · Aubrey
my patch is word wrapped while I was not aware, hope this one work.
trivial notes:
Thanks for your comments, Joe. Patch refined as below:
-Aubrey
[PATCH] X86 platform: New Intel Atom SOC power management controller driver
The Power Management Controller (PMC) controls many of the power management features present in the SoC. This driver provides interface to configure the Power Management Controller (PMC).
This driver exposes PMC device state and sleep state residency via debugfs:
/sys/kernel/debugfs/pmc_atom/dev_state /sys/kernel/debugfs/pmc_atom/sleep_state
This driver also provides a native power off function via PMC PCI IO port.
--- arch/x86/Kconfig | 4 + arch/x86/include/asm/pmc_atom.h | 91 ++++++++++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/pmc_atom.c | 295 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 391 insertions(+) create mode 100644 arch/x86/include/asm/pmc_atom.h create mode 100644 arch/x86/kernel/pmc_atom.c
arch/x86/Kconfig +4 -0
@@ -2420,6 +2420,10 @@ config IOSF_MBI Fabric (IOSF) Sideband MailBox Interface (MBI). For MBI platforms enumerable by PCI. +config PMC_ATOM + def_bool y + depends on PCI + source "net/Kconfig" source "drivers/Kconfig"
arch/x86/include/asm/pmc_atom.h new file +91 -0
91 lines not on this page · raw message
arch/x86/kernel/Makefile +1 -0
@@ -104,6 +104,7 @@ obj-$(CONFIG_EFI) += sysfb_efi.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o +obj-$(CONFIG_PMC_ATOM) += pmc_atom.o ### # 64 bit specific files
arch/x86/kernel/pmc_atom.c new file +295 -0
295 lines not on this page · raw message
Signature · 1 line
1.7.10.4
Quoted 3 lines · Aubrey
The Power Management Controller (PMC) controls many of the power management features present in the SoC. This driver provides interface to configure the Power Management Controller (PMC).
More trivial notes.
Nothing really that should stop this from being applied.
arch/x86/kernel/pmc_atom.c
Quoted 1 line
arch/x86/kernel/pmc_atom.c +0
-0
I still think that
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
is useful here.
arch/x86/kernel/pmc_atom.c line 17
Quoted 2 lines
arch/x86/kernel/pmc_atom.c +2
-0+#include <linux/module.h> +#include <linux/init.h>
[]
Quoted 1 line
+#define
DRIVER_NAME"pmc_atom"
Maybe
#define DRIVER_NAME KBUILD_MODNAME
too
arch/x86/kernel/pmc_atom.c line 44
Quoted 6 lines
arch/x86/kernel/pmc_atom.c +5
-0+struct pmc_dev_map { +char *name; +u32 bit_mask; +}; +static struct pmc_dev_map dev_map[] = {
static const to reduce data?
struct pmc_dev_map {
const char *name;
u32 bit_mask;
};Quoted 1 line
+static struct
pmc_dev_mapdev_map[] = {
static const struct pmc_dev_map dev_map[] = {
arch/x86/kernel/pmc_atom.c line 46
Quoted 2 lines
arch/x86/kernel/pmc_atom.c +2
-0+ {"0 - LPSS1_F0_DMA", BIT_LPSS1_F0_DMA}, + {"1 - LPSS1_F1_PWM1", BIT_LPSS1_F1_PWM1},
[]
arch/x86/kernel/pmc_atom.c
Quoted 2 lines
arch/x86/kernel/pmc_atom.c +2
-0+static void pmc_power_off (void ) +{
[]
arch/x86/kernel/pmc_atom.c line 93
Quoted 1 line
arch/x86/kernel/pmc_atom.c +1
-0+pr_info ("%s: Preparing to enter system sleep state S5\n" ,DRIVER_NAME );
This is larger code than using pr_fmt
arch/x86/kernel/pmc_atom.c line 107
Quoted 3 lines
arch/x86/kernel/pmc_atom.c +3
-0+#ifdef CONFIG_DEBUG_FS +static int pmc_dev_state_show (struct seq_file *s,void *unused) +{
[]
arch/x86/kernel/pmc_atom.c line 135
Quoted 6 lines
arch/x86/kernel/pmc_atom.c +6
-0+seq_printf (s,"Dev: %-32s\tState: %s [%s]\n" , + dev_map[dev_index].name, + dev_map[dev_index].bit_mask & func_dis_index ? +"Disabled" :"Enabled " , + (d3_sts_index & dev_map[dev_index].bit_mask) ? +"D3" :"D0" );
This reverses the order of the 1st and 2nd trigraph test and to me would be easier to read like:
seq_printf(s, "Dev: %-32s\tState: %s [%s]\n",
dev_map[dev_index].name, dev_map[dev_index].bit_mask & func_dis_index ? "Disabled" : "Enabled ", dev_map[dev_index].bit_mask & d3_sts_index ? "D3" : "D0");
Li, Aubrey
Reviewed-by Joe PerchesQuoted 10 lines · Joe Perches
Quoted 3 lines · Aubrey
The Power Management Controller (PMC) controls many of the power management features present in the SoC. This driver provides interface to configure the Power Management Controller (PMC).
More trivial notes.
Nothing really that should stop this from being applied.
All make sense to me. Welcome your more comments, Joe!
Thanks,
-Aubrey
[PATCH] X86 platform: New Intel Atom SOC power management controller driver
The Power Management Controller (PMC) controls many of the power management features present in the SoC. This driver provides interface to configure the Power Management Controller (PMC).
This driver exposes PMC device state and sleep state residency via debugfs:
/sys/kernel/debugfs/pmc_atom/dev_state /sys/kernel/debugfs/pmc_atom/sleep_state
This driver also provides a native power off function via PMC PCI IO port.
--- arch/x86/Kconfig | 4 + arch/x86/include/asm/pmc_atom.h | 91 ++++++++++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/pmc_atom.c | 297 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 393 insertions(+) create mode 100644 arch/x86/include/asm/pmc_atom.h create mode 100644 arch/x86/kernel/pmc_atom.c
arch/x86/Kconfig +4 -0
@@ -2420,6 +2420,10 @@ config IOSF_MBI Fabric (IOSF) Sideband MailBox Interface (MBI). For MBI platforms enumerable by PCI. +config PMC_ATOM + def_bool y + depends on PCI + source "net/Kconfig" source "drivers/Kconfig"
arch/x86/include/asm/pmc_atom.h new file +91 -0
91 lines not on this page · raw message
arch/x86/kernel/Makefile +1 -0
@@ -104,6 +104,7 @@ obj-$(CONFIG_EFI) += sysfb_efi.o obj-$(CONFIG_PERF_EVENTS) += perf_regs.o obj-$(CONFIG_TRACING) += tracepoint.o obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o +obj-$(CONFIG_PMC_ATOM) += pmc_atom.o ### # 64 bit specific files
arch/x86/kernel/pmc_atom.c new file +297 -0
297 lines not on this page · raw message
Signature · 1 line
1.7.10.4