Commit 6dccf9c5 authored by Len Brown's avatar Len Brown

mrst_pmu: driver for Intel Moorestown Power Management Unit

The Moorestown (MRST) Power Management Unit (PMU) driver
directs the SOC power states in the "Langwell" south complex (SCU).

It hooks pci_platform_pm_ops[] and thus observes all PCI ".set_state"
requests.  For devices in the SC, the pmu driver translates those
PCI requests into the appropriate commands for the SCU.

The PMU driver helps implement S0i3, a deep system idle power idle state.
Entry into S0i3 is via cpuidle, just like regular processor c-states.
S0i3 depends on pre-conditions including uni-processor, graphics off,
and certain IO devices in the SC must be off.  If those pre-conditions
are met, then the PMU allows cpuidle to enter S0i3, otherwise such requests
are demoted, either to Atom C4 or Atom C6.

This driver is based on prototype work by Bruce Flemming,
Illyas Mansoor, Rajeev D. Muralidhar, Vishwesh M. Rudramuni,
Hari Seshadri and Sujith Thomas.  The current driver also
includes contributions from H. Peter Anvin, Arjan van de Ven,
Kristen Accardi, and Yong Wang.

Thanks for additional review feedback from Alan Cox and Randy Dunlap.
Acked-by: default avatarAlan Cox <alan@linux.intel.com>
Acked-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 02f8c6ae
......@@ -3344,6 +3344,12 @@ F: drivers/net/ixgb/
F: drivers/net/ixgbe/
F: drivers/net/ixgbevf/
INTEL MRST PMU DRIVER
M: Len Brown <len.brown@intel.com>
L: linux-pm@lists.linux-foundation.org
S: Supported
F: arch/x86/platform/mrst/pmu.*
INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
L: linux-wireless@vger.kernel.org
S: Orphan
......
obj-$(CONFIG_X86_MRST) += mrst.o
obj-$(CONFIG_X86_MRST) += vrtc.o
obj-$(CONFIG_EARLY_PRINTK_MRST) += early_printk_mrst.o
obj-$(CONFIG_X86_MRST) += pmu.o
This diff is collapsed.
/*
* mrst/pmu.h - private definitions for MRST Power Management Unit mrst/pmu.c
*
* Copyright (c) 2011, 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.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _MRST_PMU_H_
#define _MRST_PMU_H_
#define PCI_DEV_ID_MRST_PMU 0x0810
#define MRST_PMU_DRV_NAME "mrst_pmu"
#define PCI_SUB_CLASS_MASK 0xFF00
#define PCI_VENDOR_CAP_LOG_ID_MASK 0x7F
#define PCI_VENDOR_CAP_LOG_SS_MASK 0x80
#define SUB_SYS_ALL_D0I1 0x01155555
#define S0I3_WAKE_SOURCES 0x00001FFF
#define PM_S0I3_COMMAND \
((0 << 31) | /* Reserved */ \
(0 << 30) | /* Core must be idle */ \
(0xc2 << 22) | /* ACK C6 trigger */ \
(3 << 19) | /* Trigger on DMI message */ \
(3 << 16) | /* Enter S0i3 */ \
(0 << 13) | /* Numeric mode ID (sw) */ \
(3 << 9) | /* Trigger mode */ \
(0 << 8) | /* Do not interrupt */ \
(1 << 0)) /* Set configuration */
#define LSS_DMI 0
#define LSS_SD_HC0 1
#define LSS_SD_HC1 2
#define LSS_NAND 3
#define LSS_IMAGING 4
#define LSS_SECURITY 5
#define LSS_DISPLAY 6
#define LSS_USB_HC 7
#define LSS_USB_OTG 8
#define LSS_AUDIO 9
#define LSS_AUDIO_LPE 9
#define LSS_AUDIO_SSP 9
#define LSS_I2C0 10
#define LSS_I2C1 10
#define LSS_I2C2 10
#define LSS_KBD 10
#define LSS_SPI0 10
#define LSS_SPI1 10
#define LSS_SPI2 10
#define LSS_GPIO 10
#define LSS_SRAM 11 /* used by SCU, do not touch */
#define LSS_SD_HC2 12
/* LSS hardware bits 15,14,13 are hardwired to 0, thus unusable */
#define MRST_NUM_LSS 13
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define SSMSK(mask, lss) ((mask) << ((lss) * 2))
#define D0 0
#define D0i1 1
#define D0i2 2
#define D0i3 3
#define S0I3_SSS_TARGET ( \
SSMSK(D0i1, LSS_DMI) | \
SSMSK(D0i3, LSS_SD_HC0) | \
SSMSK(D0i3, LSS_SD_HC1) | \
SSMSK(D0i3, LSS_NAND) | \
SSMSK(D0i3, LSS_SD_HC2) | \
SSMSK(D0i3, LSS_IMAGING) | \
SSMSK(D0i3, LSS_SECURITY) | \
SSMSK(D0i3, LSS_DISPLAY) | \
SSMSK(D0i3, LSS_USB_HC) | \
SSMSK(D0i3, LSS_USB_OTG) | \
SSMSK(D0i3, LSS_AUDIO) | \
SSMSK(D0i1, LSS_I2C0))
/*
* D0i1 on Langwell is Autonomous Clock Gating (ACG).
* Enable ACG on every LSS except camera and audio
*/
#define D0I1_ACG_SSS_TARGET \
(SUB_SYS_ALL_D0I1 & ~SSMSK(D0i1, LSS_IMAGING) & ~SSMSK(D0i1, LSS_AUDIO))
enum cm_mode {
CM_NOP, /* ignore the config mode value */
CM_IMMEDIATE,
CM_DELAY,
CM_TRIGGER,
CM_INVALID
};
enum sys_state {
SYS_STATE_S0I0,
SYS_STATE_S0I1,
SYS_STATE_S0I2,
SYS_STATE_S0I3,
SYS_STATE_S3,
SYS_STATE_S5
};
#define SET_CFG_CMD 1
enum int_status {
INT_SPURIOUS = 0,
INT_CMD_DONE = 1,
INT_CMD_ERR = 2,
INT_WAKE_RX = 3,
INT_SS_ERROR = 4,
INT_S0IX_MISS = 5,
INT_NO_ACKC6 = 6,
INT_INVALID = 7,
};
/* PMU register interface */
static struct mrst_pmu_reg {
u32 pm_sts; /* 0x00 */
u32 pm_cmd; /* 0x04 */
u32 pm_ics; /* 0x08 */
u32 _resv1; /* 0x0C */
u32 pm_wkc[2]; /* 0x10 */
u32 pm_wks[2]; /* 0x18 */
u32 pm_ssc[4]; /* 0x20 */
u32 pm_sss[4]; /* 0x30 */
u32 pm_wssc[4]; /* 0x40 */
u32 pm_c3c4; /* 0x50 */
u32 pm_c5c6; /* 0x54 */
u32 pm_msi_disable; /* 0x58 */
} *pmu_reg;
static inline u32 pmu_read_sts(void) { return readl(&pmu_reg->pm_sts); }
static inline u32 pmu_read_ics(void) { return readl(&pmu_reg->pm_ics); }
static inline u32 pmu_read_wks(void) { return readl(&pmu_reg->pm_wks[0]); }
static inline u32 pmu_read_sss(void) { return readl(&pmu_reg->pm_sss[0]); }
static inline void pmu_write_cmd(u32 arg) { writel(arg, &pmu_reg->pm_cmd); }
static inline void pmu_write_ics(u32 arg) { writel(arg, &pmu_reg->pm_ics); }
static inline void pmu_write_wkc(u32 arg) { writel(arg, &pmu_reg->pm_wkc[0]); }
static inline void pmu_write_ssc(u32 arg) { writel(arg, &pmu_reg->pm_ssc[0]); }
static inline void pmu_write_wssc(u32 arg)
{ writel(arg, &pmu_reg->pm_wssc[0]); }
static inline void pmu_msi_enable(void) { writel(0, &pmu_reg->pm_msi_disable); }
static inline u32 pmu_msi_is_disabled(void)
{ return readl(&pmu_reg->pm_msi_disable); }
union pmu_pm_ics {
struct {
u32 cause:8;
u32 enable:1;
u32 pending:1;
u32 reserved:22;
} bits;
u32 value;
};
static inline void pmu_irq_enable(void)
{
union pmu_pm_ics pmu_ics;
pmu_ics.value = pmu_read_ics();
pmu_ics.bits.enable = 1;
pmu_write_ics(pmu_ics.value);
}
union pmu_pm_status {
struct {
u32 pmu_rev:8;
u32 pmu_busy:1;
u32 mode_id:4;
u32 Reserved:19;
} pmu_status_parts;
u32 pmu_status_value;
};
static inline int pmu_read_busy_status(void)
{
union pmu_pm_status result;
result.pmu_status_value = pmu_read_sts();
return result.pmu_status_parts.pmu_busy;
}
/* pmu set config parameters */
struct cfg_delay_param_t {
u32 cmd:8;
u32 ioc:1;
u32 cfg_mode:4;
u32 mode_id:3;
u32 sys_state:3;
u32 cfg_delay:8;
u32 rsvd:5;
};
struct cfg_trig_param_t {
u32 cmd:8;
u32 ioc:1;
u32 cfg_mode:4;
u32 mode_id:3;
u32 sys_state:3;
u32 cfg_trig_type:3;
u32 cfg_trig_val:8;
u32 cmbi:1;
u32 rsvd1:1;
};
union pmu_pm_set_cfg_cmd_t {
union {
struct cfg_delay_param_t d_param;
struct cfg_trig_param_t t_param;
} pmu2_params;
u32 pmu_pm_set_cfg_cmd_value;
};
#ifdef FUTURE_PATCH
extern int mrst_s0i3_entry(u32 regval, u32 *regaddr);
#else
static inline int mrst_s0i3_entry(u32 regval, u32 *regaddr) { return -1; }
#endif
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment