+++ /dev/null
-/*
- * mrst.c: Intel Moorestown platform specific setup code
- *
- * (C) Copyright 2008 Intel Corporation
- * Author: Jacob Pan (jacob.jun.pan@intel.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- */
-
-#define pr_fmt(fmt) "mrst: " fmt
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/scatterlist.h>
-#include <linux/sfi.h>
-#include <linux/intel_pmic_gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/i2c.h>
-#include <linux/i2c/pca953x.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
-
-#include <asm/setup.h>
-#include <asm/mpspec_def.h>
-#include <asm/hw_irq.h>
-#include <asm/apic.h>
-#include <asm/io_apic.h>
-#include <asm/mrst.h>
-#include <asm/mrst-vrtc.h>
-#include <asm/io.h>
-#include <asm/i8259.h>
-#include <asm/intel_scu_ipc.h>
-#include <asm/apb_timer.h>
-#include <asm/reboot.h>
-
-/*
- * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
- * cmdline option x86_mrst_timer can be used to override the configuration
- * to prefer one or the other.
- * at runtime, there are basically three timer configurations:
- * 1. per cpu apbt clock only
- * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
- * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
- *
- * by default (without cmdline option), platform code first detects cpu type
- * to see if we are on lincroft or penwell, then set up both lapic or apbt
- * clocks accordingly.
- * i.e. by default, medfield uses configuration #2, moorestown uses #1.
- * config #3 is supported but not recommended on medfield.
- *
- * rating and feature summary:
- * lapic (with C3STOP) --------- 100
- * apbt (always-on) ------------ 110
- * lapic (always-on,ARAT) ------ 150
- */
-
-__cpuinitdata enum mrst_timer_options mrst_timer_options;
-
-static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM];
-static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM];
-enum mrst_cpu_type __mrst_cpu_chip;
-EXPORT_SYMBOL_GPL(__mrst_cpu_chip);
-
-int sfi_mtimer_num;
-
-struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX];
-EXPORT_SYMBOL_GPL(sfi_mrtc_array);
-int sfi_mrtc_num;
-
-static void mrst_power_off(void)
-{
- if (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT)
- intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 1);
-}
-
-static void mrst_reboot(void)
-{
- if (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT)
- intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 0);
- else
- intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0);
-}
-
-/* parse all the mtimer info to a static mtimer array */
-static int __init sfi_parse_mtmr(struct sfi_table_header *table)
-{
- struct sfi_table_simple *sb;
- struct sfi_timer_table_entry *pentry;
- struct mpc_intsrc mp_irq;
- int totallen;
-
- sb = (struct sfi_table_simple *)table;
- if (!sfi_mtimer_num) {
- sfi_mtimer_num = SFI_GET_NUM_ENTRIES(sb,
- struct sfi_timer_table_entry);
- pentry = (struct sfi_timer_table_entry *) sb->pentry;
- totallen = sfi_mtimer_num * sizeof(*pentry);
- memcpy(sfi_mtimer_array, pentry, totallen);
- }
-
- pr_debug("SFI MTIMER info (num = %d):\n", sfi_mtimer_num);
- pentry = sfi_mtimer_array;
- for (totallen = 0; totallen < sfi_mtimer_num; totallen++, pentry++) {
- pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz,"
- " irq = %d\n", totallen, (u32)pentry->phys_addr,
- pentry->freq_hz, pentry->irq);
- if (!pentry->irq)
- continue;
- mp_irq.type = MP_INTSRC;
- mp_irq.irqtype = mp_INT;
-/* triggering mode edge bit 2-3, active high polarity bit 0-1 */
- mp_irq.irqflag = 5;
- mp_irq.srcbus = MP_BUS_ISA;
- mp_irq.srcbusirq = pentry->irq; /* IRQ */
- mp_irq.dstapic = MP_APIC_ALL;
- mp_irq.dstirq = pentry->irq;
- mp_save_irq(&mp_irq);
- }
-
- return 0;
-}
-
-struct sfi_timer_table_entry *sfi_get_mtmr(int hint)
-{
- int i;
- if (hint < sfi_mtimer_num) {
- if (!sfi_mtimer_usage[hint]) {
- pr_debug("hint taken for timer %d irq %d\n",\
- hint, sfi_mtimer_array[hint].irq);
- sfi_mtimer_usage[hint] = 1;
- return &sfi_mtimer_array[hint];
- }
- }
- /* take the first timer available */
- for (i = 0; i < sfi_mtimer_num;) {
- if (!sfi_mtimer_usage[i]) {
- sfi_mtimer_usage[i] = 1;
- return &sfi_mtimer_array[i];
- }
- i++;
- }
- return NULL;
-}
-
-void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr)
-{
- int i;
- for (i = 0; i < sfi_mtimer_num;) {
- if (mtmr->irq == sfi_mtimer_array[i].irq) {
- sfi_mtimer_usage[i] = 0;
- return;
- }
- i++;
- }
-}
-
-/* parse all the mrtc info to a global mrtc array */
-int __init sfi_parse_mrtc(struct sfi_table_header *table)
-{
- struct sfi_table_simple *sb;
- struct sfi_rtc_table_entry *pentry;
- struct mpc_intsrc mp_irq;
-
- int totallen;
-
- sb = (struct sfi_table_simple *)table;
- if (!sfi_mrtc_num) {
- sfi_mrtc_num = SFI_GET_NUM_ENTRIES(sb,
- struct sfi_rtc_table_entry);
- pentry = (struct sfi_rtc_table_entry *)sb->pentry;
- totallen = sfi_mrtc_num * sizeof(*pentry);
- memcpy(sfi_mrtc_array, pentry, totallen);
- }
-
- pr_debug("SFI RTC info (num = %d):\n", sfi_mrtc_num);
- pentry = sfi_mrtc_array;
- for (totallen = 0; totallen < sfi_mrtc_num; totallen++, pentry++) {
- pr_debug("RTC[%d]: paddr = 0x%08x, irq = %d\n",
- totallen, (u32)pentry->phys_addr, pentry->irq);
- mp_irq.type = MP_INTSRC;
- mp_irq.irqtype = mp_INT;
- mp_irq.irqflag = 0xf; /* level trigger and active low */
- mp_irq.srcbus = MP_BUS_ISA;
- mp_irq.srcbusirq = pentry->irq; /* IRQ */
- mp_irq.dstapic = MP_APIC_ALL;
- mp_irq.dstirq = pentry->irq;
- mp_save_irq(&mp_irq);
- }
- return 0;
-}
-
-static unsigned long __init mrst_calibrate_tsc(void)
-{
- unsigned long flags, fast_calibrate;
- if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
- u32 lo, hi, ratio, fsb;
-
- rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
- pr_debug("IA32 perf status is 0x%x, 0x%0x\n", lo, hi);
- ratio = (hi >> 8) & 0x1f;
- pr_debug("ratio is %d\n", ratio);
- if (!ratio) {
- pr_err("read a zero ratio, should be incorrect!\n");
- pr_err("force tsc ratio to 16 ...\n");
- ratio = 16;
- }
- rdmsr(MSR_FSB_FREQ, lo, hi);
- if ((lo & 0x7) == 0x7)
- fsb = PENWELL_FSB_FREQ_83SKU;
- else
- fsb = PENWELL_FSB_FREQ_100SKU;
- fast_calibrate = ratio * fsb;
- pr_debug("read penwell tsc %lu khz\n", fast_calibrate);
- lapic_timer_frequency = fsb * 1000 / HZ;
- /* mark tsc clocksource as reliable */
- set_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC_RELIABLE);
- } else {
- local_irq_save(flags);
- fast_calibrate = apbt_quick_calibrate();
- local_irq_restore(flags);
- }
-
- if (fast_calibrate)
- return fast_calibrate;
-
- return 0;
-}
-
-static void __init mrst_time_init(void)
-{
- sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
- switch (mrst_timer_options) {
- case MRST_TIMER_APBT_ONLY:
- break;
- case MRST_TIMER_LAPIC_APBT:
- x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
- x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
- break;
- default:
- if (!boot_cpu_has(X86_FEATURE_ARAT))
- break;
- x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
- x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
- return;
- }
- /* we need at least one APB timer */
- pre_init_apic_IRQ0();
- apbt_time_init();
-}
-
-static void __cpuinit mrst_arch_setup(void)
-{
- if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
- __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
- else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26)
- __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
- else {
- pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n",
- boot_cpu_data.x86, boot_cpu_data.x86_model);
- __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
- }
- pr_debug("Moorestown CPU %s identified\n",
- (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ?
- "Lincroft" : "Penwell");
-}
-
-/* MID systems don't have i8042 controller */
-static int mrst_i8042_detect(void)
-{
- return 0;
-}
-
-/*
- * Moorestown specific x86_init function overrides and early setup
- * calls.
- */
-void __init x86_mrst_early_setup(void)
-{
- x86_init.resources.probe_roms = x86_init_noop;
- x86_init.resources.reserve_resources = x86_init_noop;
-
- x86_init.timers.timer_init = mrst_time_init;
- x86_init.timers.setup_percpu_clockev = x86_init_noop;
-
- x86_init.irqs.pre_vector_init = x86_init_noop;
-
- x86_init.oem.arch_setup = mrst_arch_setup;
-
- x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
-
- x86_platform.calibrate_tsc = mrst_calibrate_tsc;
- x86_platform.i8042_detect = mrst_i8042_detect;
- x86_init.timers.wallclock_init = mrst_rtc_init;
- x86_init.pci.init = pci_mrst_init;
- x86_init.pci.fixup_irqs = x86_init_noop;
-
- legacy_pic = &null_legacy_pic;
-
- /* Moorestown specific power_off/restart method */
- pm_power_off = mrst_power_off;
- machine_ops.emergency_restart = mrst_reboot;
-
- /* Avoid searching for BIOS MP tables */
- x86_init.mpparse.find_smp_config = x86_init_noop;
- x86_init.mpparse.get_smp_config = x86_init_uint_noop;
- set_bit(MP_BUS_ISA, mp_bus_not_pci);
-}
-
-/*
- * if user does not want to use per CPU apb timer, just give it a lower rating
- * than local apic timer and skip the late per cpu timer init.
- */
-static inline int __init setup_x86_mrst_timer(char *arg)
-{
- if (!arg)
- return -EINVAL;
-
- if (strcmp("apbt_only", arg) == 0)
- mrst_timer_options = MRST_TIMER_APBT_ONLY;
- else if (strcmp("lapic_and_apbt", arg) == 0)
- mrst_timer_options = MRST_TIMER_LAPIC_APBT;
- else {
- pr_warning("X86 MRST timer option %s not recognised"
- " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
- arg);
- return -EINVAL;
- }
- return 0;
-}
-__setup("x86_mrst_timer=", setup_x86_mrst_timer);
-
-/*
- * Parsing GPIO table first, since the DEVS table will need this table
- * to map the pin name to the actual pin.
- */
-static struct sfi_gpio_table_entry *gpio_table;
-static int gpio_num_entry;
-
-static int __init sfi_parse_gpio(struct sfi_table_header *table)
-{
- struct sfi_table_simple *sb;
- struct sfi_gpio_table_entry *pentry;
- int num, i;
-
- if (gpio_table)
- return 0;
- sb = (struct sfi_table_simple *)table;
- num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry);
- pentry = (struct sfi_gpio_table_entry *)sb->pentry;
-
- gpio_table = (struct sfi_gpio_table_entry *)
- kmalloc(num * sizeof(*pentry), GFP_KERNEL);
- if (!gpio_table)
- return -1;
- memcpy(gpio_table, pentry, num * sizeof(*pentry));
- gpio_num_entry = num;
-
- pr_debug("GPIO pin info:\n");
- for (i = 0; i < num; i++, pentry++)
- pr_debug("info[%2d]: controller = %16.16s, pin_name = %16.16s,"
- " pin = %d\n", i,
- pentry->controller_name,
- pentry->pin_name,
- pentry->pin_no);
- return 0;
-}
-
-static int get_gpio_by_name(const char *name)
-{
- struct sfi_gpio_table_entry *pentry = gpio_table;
- int i;
-
- if (!pentry)
- return -1;
- for (i = 0; i < gpio_num_entry; i++, pentry++) {
- if (!strncmp(name, pentry->pin_name, SFI_NAME_LEN))
- return pentry->pin_no;
- }
- return -1;
-}
-
-/*
- * Here defines the array of devices platform data that IAFW would export
- * through SFI "DEVS" table, we use name and type to match the device and
- * its platform data.
- */
-struct devs_id {
- char name[SFI_NAME_LEN + 1];
- u8 type;
- u8 delay;
- void *(*get_platform_data)(void *info);
-};
-
-/* the offset for the mapping of global gpio pin to irq */
-#define MRST_IRQ_OFFSET 0x100
-
-static void __init *pmic_gpio_platform_data(void *info)
-{
- static struct intel_pmic_gpio_platform_data pmic_gpio_pdata;
- int gpio_base = get_gpio_by_name("pmic_gpio_base");
-
- if (gpio_base == -1)
- gpio_base = 64;
- pmic_gpio_pdata.gpio_base = gpio_base;
- pmic_gpio_pdata.irq_base = gpio_base + MRST_IRQ_OFFSET;
- pmic_gpio_pdata.gpiointr = 0xffffeff8;
-
- return &pmic_gpio_pdata;
-}
-
-static void __init *max3111_platform_data(void *info)
-{
- struct spi_board_info *spi_info = info;
- int intr = get_gpio_by_name("max3111_int");
-
- spi_info->mode = SPI_MODE_0;
- if (intr == -1)
- return NULL;
- spi_info->irq = intr + MRST_IRQ_OFFSET;
- return NULL;
-}
-
-/* we have multiple max7315 on the board ... */
-#define MAX7315_NUM 2
-static void __init *max7315_platform_data(void *info)
-{
- static struct pca953x_platform_data max7315_pdata[MAX7315_NUM];
- static int nr;
- struct pca953x_platform_data *max7315 = &max7315_pdata[nr];
- struct i2c_board_info *i2c_info = info;
- int gpio_base, intr;
- char base_pin_name[SFI_NAME_LEN + 1];
- char intr_pin_name[SFI_NAME_LEN + 1];
-
- if (nr == MAX7315_NUM) {
- pr_err("too many max7315s, we only support %d\n",
- MAX7315_NUM);
- return NULL;
- }
- /* we have several max7315 on the board, we only need load several
- * instances of the same pca953x driver to cover them
- */
- strcpy(i2c_info->type, "max7315");
- if (nr++) {
- sprintf(base_pin_name, "max7315_%d_base", nr);
- sprintf(intr_pin_name, "max7315_%d_int", nr);
- } else {
- strcpy(base_pin_name, "max7315_base");
- strcpy(intr_pin_name, "max7315_int");
- }
-
- gpio_base = get_gpio_by_name(base_pin_name);
- intr = get_gpio_by_name(intr_pin_name);
-
- if (gpio_base == -1)
- return NULL;
- max7315->gpio_base = gpio_base;
- if (intr != -1) {
- i2c_info->irq = intr + MRST_IRQ_OFFSET;
- max7315->irq_base = gpio_base + MRST_IRQ_OFFSET;
- } else {
- i2c_info->irq = -1;
- max7315->irq_base = -1;
- }
- return max7315;
-}
-
-static void *tca6416_platform_data(void *info)
-{
- static struct pca953x_platform_data tca6416;
- struct i2c_board_info *i2c_info = info;
- int gpio_base, intr;
- char base_pin_name[SFI_NAME_LEN + 1];
- char intr_pin_name[SFI_NAME_LEN + 1];
-
- strcpy(i2c_info->type, "tca6416");
- strcpy(base_pin_name, "tca6416_base");
- strcpy(intr_pin_name, "tca6416_int");
-
- gpio_base = get_gpio_by_name(base_pin_name);
- intr = get_gpio_by_name(intr_pin_name);
-
- if (gpio_base == -1)
- return NULL;
- tca6416.gpio_base = gpio_base;
- if (intr != -1) {
- i2c_info->irq = intr + MRST_IRQ_OFFSET;
- tca6416.irq_base = gpio_base + MRST_IRQ_OFFSET;
- } else {
- i2c_info->irq = -1;
- tca6416.irq_base = -1;
- }
- return &tca6416;
-}
-
-static void *mpu3050_platform_data(void *info)
-{
- struct i2c_board_info *i2c_info = info;
- int intr = get_gpio_by_name("mpu3050_int");
-
- if (intr == -1)
- return NULL;
-
- i2c_info->irq = intr + MRST_IRQ_OFFSET;
- return NULL;
-}
-
-static void *ektf2136_spi_platform_data(void *info)
-{
- static int dummy;
- struct spi_board_info *spi_info = info;
- int intr = get_gpio_by_name("ts_int");
-
- if (intr == -1)
- return NULL;
- spi_info->irq = intr + MRST_IRQ_OFFSET;
-
- /* we return a dummy pdata */
- return &dummy;
-}
-
-static void __init *emc1403_platform_data(void *info)
-{
- static short intr2nd_pdata;
- struct i2c_board_info *i2c_info = info;
- int intr = get_gpio_by_name("thermal_int");
- int intr2nd = get_gpio_by_name("thermal_alert");
-
- if (intr == -1 || intr2nd == -1)
- return NULL;
-
- i2c_info->irq = intr + MRST_IRQ_OFFSET;
- intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET;
-
- return &intr2nd_pdata;
-}
-
-static void __init *lis331dl_platform_data(void *info)
-{
- static short intr2nd_pdata;
- struct i2c_board_info *i2c_info = info;
- int intr = get_gpio_by_name("accel_int");
- int intr2nd = get_gpio_by_name("accel_2");
-
- if (intr == -1 || intr2nd == -1)
- return NULL;
-
- i2c_info->irq = intr + MRST_IRQ_OFFSET;
- intr2nd_pdata = intr2nd + MRST_IRQ_OFFSET;
-
- return &intr2nd_pdata;
-}
-
-static void __init *no_platform_data(void *info)
-{
- return NULL;
-}
-
-static const struct devs_id __initconst device_ids[] = {
- {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data},
- {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data},
- {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data},
- {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data},
- {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data},
- {"tca6416", SFI_DEV_TYPE_I2C, 1, &tca6416_platform_data},
- {"emc1403", SFI_DEV_TYPE_I2C, 1, &emc1403_platform_data},
- {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data},
- {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data},
- {"msic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data},
- {"mpu3050", SFI_DEV_TYPE_I2C, 1, &mpu3050_platform_data},
- {"ektf2136_spi", SFI_DEV_TYPE_SPI, 0, &ektf2136_spi_platform_data},
- {},
-};
-
-#define MAX_IPCDEVS 24
-static struct platform_device *ipc_devs[MAX_IPCDEVS];
-static int ipc_next_dev;
-
-#define MAX_SCU_SPI 24
-static struct spi_board_info *spi_devs[MAX_SCU_SPI];
-static int spi_next_dev;
-
-#define MAX_SCU_I2C 24
-static struct i2c_board_info *i2c_devs[MAX_SCU_I2C];
-static int i2c_bus[MAX_SCU_I2C];
-static int i2c_next_dev;
-
-static void __init intel_scu_device_register(struct platform_device *pdev)
-{
- if(ipc_next_dev == MAX_IPCDEVS)
- pr_err("too many SCU IPC devices");
- else
- ipc_devs[ipc_next_dev++] = pdev;
-}
-
-static void __init intel_scu_spi_device_register(struct spi_board_info *sdev)
-{
- struct spi_board_info *new_dev;
-
- if (spi_next_dev == MAX_SCU_SPI) {
- pr_err("too many SCU SPI devices");
- return;
- }
-
- new_dev = kzalloc(sizeof(*sdev), GFP_KERNEL);
- if (!new_dev) {
- pr_err("failed to alloc mem for delayed spi dev %s\n",
- sdev->modalias);
- return;
- }
- memcpy(new_dev, sdev, sizeof(*sdev));
-
- spi_devs[spi_next_dev++] = new_dev;
-}
-
-static void __init intel_scu_i2c_device_register(int bus,
- struct i2c_board_info *idev)
-{
- struct i2c_board_info *new_dev;
-
- if (i2c_next_dev == MAX_SCU_I2C) {
- pr_err("too many SCU I2C devices");
- return;
- }
-
- new_dev = kzalloc(sizeof(*idev), GFP_KERNEL);
- if (!new_dev) {
- pr_err("failed to alloc mem for delayed i2c dev %s\n",
- idev->type);
- return;
- }
- memcpy(new_dev, idev, sizeof(*idev));
-
- i2c_bus[i2c_next_dev] = bus;
- i2c_devs[i2c_next_dev++] = new_dev;
-}
-
-BLOCKING_NOTIFIER_HEAD(intel_scu_notifier);
-EXPORT_SYMBOL_GPL(intel_scu_notifier);
-
-/* Called by IPC driver */
-void intel_scu_devices_create(void)
-{
- int i;
-
- for (i = 0; i < ipc_next_dev; i++)
- platform_device_add(ipc_devs[i]);
-
- for (i = 0; i < spi_next_dev; i++)
- spi_register_board_info(spi_devs[i], 1);
-
- for (i = 0; i < i2c_next_dev; i++) {
- struct i2c_adapter *adapter;
- struct i2c_client *client;
-
- adapter = i2c_get_adapter(i2c_bus[i]);
- if (adapter) {
- client = i2c_new_device(adapter, i2c_devs[i]);
- if (!client)
- pr_err("can't create i2c device %s\n",
- i2c_devs[i]->type);
- } else
- i2c_register_board_info(i2c_bus[i], i2c_devs[i], 1);
- }
- intel_scu_notifier_post(SCU_AVAILABLE, 0L);
-}
-EXPORT_SYMBOL_GPL(intel_scu_devices_create);
-
-/* Called by IPC driver */
-void intel_scu_devices_destroy(void)
-{
- int i;
-
- intel_scu_notifier_post(SCU_DOWN, 0L);
-
- for (i = 0; i < ipc_next_dev; i++)
- platform_device_del(ipc_devs[i]);
-}
-EXPORT_SYMBOL_GPL(intel_scu_devices_destroy);
-
-static void __init install_irq_resource(struct platform_device *pdev, int irq)
-{
- /* Single threaded */
- static struct resource __initdata res = {
- .name = "IRQ",
- .flags = IORESOURCE_IRQ,
- };
- res.start = irq;
- platform_device_add_resources(pdev, &res, 1);
-}
-
-static void __init sfi_handle_ipc_dev(struct platform_device *pdev)
-{
- const struct devs_id *dev = device_ids;
- void *pdata = NULL;
-
- while (dev->name[0]) {
- if (dev->type == SFI_DEV_TYPE_IPC &&
- !strncmp(dev->name, pdev->name, SFI_NAME_LEN)) {
- pdata = dev->get_platform_data(pdev);
- break;
- }
- dev++;
- }
- pdev->dev.platform_data = pdata;
- intel_scu_device_register(pdev);
-}
-
-static void __init sfi_handle_spi_dev(struct spi_board_info *spi_info)
-{
- const struct devs_id *dev = device_ids;
- void *pdata = NULL;
-
- while (dev->name[0]) {
- if (dev->type == SFI_DEV_TYPE_SPI &&
- !strncmp(dev->name, spi_info->modalias, SFI_NAME_LEN)) {
- pdata = dev->get_platform_data(spi_info);
- break;
- }
- dev++;
- }
- spi_info->platform_data = pdata;
- if (dev->delay)
- intel_scu_spi_device_register(spi_info);
- else
- spi_register_board_info(spi_info, 1);
-}
-
-static void __init sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info)
-{
- const struct devs_id *dev = device_ids;
- void *pdata = NULL;
-
- while (dev->name[0]) {
- if (dev->type == SFI_DEV_TYPE_I2C &&
- !strncmp(dev->name, i2c_info->type, SFI_NAME_LEN)) {
- pdata = dev->get_platform_data(i2c_info);
- break;
- }
- dev++;
- }
- i2c_info->platform_data = pdata;
-
- if (dev->delay)
- intel_scu_i2c_device_register(bus, i2c_info);
- else
- i2c_register_board_info(bus, i2c_info, 1);
- }
-
-
-static int __init sfi_parse_devs(struct sfi_table_header *table)
-{
- struct sfi_table_simple *sb;
- struct sfi_device_table_entry *pentry;
- struct spi_board_info spi_info;
- struct i2c_board_info i2c_info;
- struct platform_device *pdev;
- int num, i, bus;
- int ioapic;
- struct io_apic_irq_attr irq_attr;
-
- sb = (struct sfi_table_simple *)table;
- num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry);
- pentry = (struct sfi_device_table_entry *)sb->pentry;
-
- for (i = 0; i < num; i++, pentry++) {
- if (pentry->irq != (u8)0xff) { /* native RTE case */
- /* these SPI2 devices are not exposed to system as PCI
- * devices, but they have separate RTE entry in IOAPIC
- * so we have to enable them one by one here
- */
- ioapic = mp_find_ioapic(pentry->irq);
- irq_attr.ioapic = ioapic;
- irq_attr.ioapic_pin = pentry->irq;
- irq_attr.trigger = 1;
- irq_attr.polarity = 1;
- io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr);
- }
- switch (pentry->type) {
- case SFI_DEV_TYPE_IPC:
- /* ID as IRQ is a hack that will go away */
- pdev = platform_device_alloc(pentry->name, pentry->irq);
- if (pdev == NULL) {
- pr_err("out of memory for SFI platform device '%s'.\n",
- pentry->name);
- continue;
- }
- install_irq_resource(pdev, pentry->irq);
- pr_debug("info[%2d]: IPC bus, name = %16.16s, "
- "irq = 0x%2x\n", i, pentry->name, pentry->irq);
- sfi_handle_ipc_dev(pdev);
- break;
- case SFI_DEV_TYPE_SPI:
- memset(&spi_info, 0, sizeof(spi_info));
- strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN);
- spi_info.irq = pentry->irq;
- spi_info.bus_num = pentry->host_num;
- spi_info.chip_select = pentry->addr;
- spi_info.max_speed_hz = pentry->max_freq;
- pr_debug("info[%2d]: SPI bus = %d, name = %16.16s, "
- "irq = 0x%2x, max_freq = %d, cs = %d\n", i,
- spi_info.bus_num,
- spi_info.modalias,
- spi_info.irq,
- spi_info.max_speed_hz,
- spi_info.chip_select);
- sfi_handle_spi_dev(&spi_info);
- break;
- case SFI_DEV_TYPE_I2C:
- memset(&i2c_info, 0, sizeof(i2c_info));
- bus = pentry->host_num;
- strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN);
- i2c_info.irq = pentry->irq;
- i2c_info.addr = pentry->addr;
- pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, "
- "irq = 0x%2x, addr = 0x%x\n", i, bus,
- i2c_info.type,
- i2c_info.irq,
- i2c_info.addr);
- sfi_handle_i2c_dev(bus, &i2c_info);
- break;
- case SFI_DEV_TYPE_UART:
- case SFI_DEV_TYPE_HSI:
- default:
- ;
- }
- }
- return 0;
-}
-
-static int __init mrst_platform_init(void)
-{
- sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio);
- sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs);
- return 0;
-}
-arch_initcall(mrst_platform_init);
-
-/*
- * we will search these buttons in SFI GPIO table (by name)
- * and register them dynamically. Please add all possible
- * buttons here, we will shrink them if no GPIO found.
- */
-static struct gpio_keys_button gpio_button[] = {
- {KEY_POWER, -1, 1, "power_btn", EV_KEY, 0, 3000},
- {KEY_PROG1, -1, 1, "prog_btn1", EV_KEY, 0, 20},
- {KEY_PROG2, -1, 1, "prog_btn2", EV_KEY, 0, 20},
- {SW_LID, -1, 1, "lid_switch", EV_SW, 0, 20},
- {KEY_VOLUMEUP, -1, 1, "vol_up", EV_KEY, 0, 20},
- {KEY_VOLUMEDOWN, -1, 1, "vol_down", EV_KEY, 0, 20},
- {KEY_CAMERA, -1, 1, "camera_full", EV_KEY, 0, 20},
- {KEY_CAMERA_FOCUS, -1, 1, "camera_half", EV_KEY, 0, 20},
- {SW_KEYPAD_SLIDE, -1, 1, "MagSw1", EV_SW, 0, 20},
- {SW_KEYPAD_SLIDE, -1, 1, "MagSw2", EV_SW, 0, 20},
-};
-
-static struct gpio_keys_platform_data mrst_gpio_keys = {
- .buttons = gpio_button,
- .rep = 1,
- .nbuttons = -1, /* will fill it after search */
-};
-
-static struct platform_device pb_device = {
- .name = "gpio-keys",
- .id = -1,
- .dev = {
- .platform_data = &mrst_gpio_keys,
- },
-};
-
-/*
- * Shrink the non-existent buttons, register the gpio button
- * device if there is some
- */
-static int __init pb_keys_init(void)
-{
- struct gpio_keys_button *gb = gpio_button;
- int i, num, good = 0;
-
- num = sizeof(gpio_button) / sizeof(struct gpio_keys_button);
- for (i = 0; i < num; i++) {
- gb[i].gpio = get_gpio_by_name(gb[i].desc);
- if (gb[i].gpio == -1)
- continue;
-
- if (i != good)
- gb[good] = gb[i];
- good++;
- }
-
- if (good) {
- mrst_gpio_keys.nbuttons = good;
- return platform_device_register(&pb_device);
- }
- return 0;
-}
-late_initcall(pb_keys_init);
+++ /dev/null
-/*
- * mid_pmu.c - This driver provides interface to configure the 2 pmu's
- * Copyright (c) 2010, 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.
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/pci.h>
-#include <linux/semaphore.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/jhash.h>
-#include <linux/intel_mid_pm.h>
-#include <linux/suspend.h>
-#include <linux/wakelock.h>
-
-#include "pmu.h"
-
-/* These are the set of LSS's that are checked
- * to be D0i3 before entering S0i1/3
- */
-static u8 s0ix_lss[] = {
- PMU_SDIO0_LSS_00,
- PMU_EMMC0_LSS_01,
-
-#ifdef CONFIG_HSI_ARASAN
- PMU_HSI_LSS_03,
-#endif
-
-#ifdef CONFIG_DX_SEP
- PMU_SECURITY_LSS_04,
-#endif
-
-#ifdef CONFIG_USB_PENWELL_OTG
- PMU_USB_OTG_LSS_06,
-#endif
-
-#ifdef TELEPHONY_ENABLE_S0IX
- PMU_AUDIO_ENGINE_LSS_08,
- PMU_AUDIO_DMA_LSS_09,
- PMU_AUDIO_SSP0_LSS_51,
- PMU_AUDIO_SSP1_LSS_52,
- PMU_SPI3_LSS_36,
-#endif
-
-#ifdef DWSPI_ENABLE_S0IX
- PMU_SPI1_LSS_18,
-#endif
-
-#ifdef WLAN_ENABLE_S0IX
- PMU_SDIO1_LSS_30,
-#endif
-
-#ifdef I2C_ENABLE_S0IX
- PMU_I2C0_LSS_20,
- PMU_I2C1_LSS_21,
- PMU_I2C2_LSS_27,
- PMU_I2C3_LSS_33,
- PMU_I2C4_LSS_34,
- PMU_I2C5_LSS_35,
-#endif
-
- PMU_UART2_LSS_41,
-
-};
-static u32 TARGET_CFG[4];
-static u32 s0ix_target[4];
-
-/* These are the set of LSS's that are checked
- * to be D0i3 before entering LPMP3 mode.
- */
-static u8 lpmp3_lss[] = {
- PMU_SDIO0_LSS_00,
- PMU_EMMC0_LSS_01,
-
-#ifdef CONFIG_HSI_ARASAN
- PMU_HSI_LSS_03,
-#endif
-
-#ifdef CONFIG_DX_SEP
- PMU_SECURITY_LSS_04,
-#endif
-
-#ifdef CONFIG_USB_PENWELL_OTG
- PMU_USB_OTG_LSS_06,
-#endif
-
-#ifdef TELEPHONY_ENABLE_S0IX
- PMU_SPI3_LSS_36,
-#endif
-
-#ifdef DWSPI_ENABLE_S0IX
- PMU_SPI1_LSS_18,
-#endif
-
-#ifdef WLAN_ENABLE_S0IX
- PMU_SDIO1_LSS_30,
-#endif
-
-#ifdef I2C_ENABLE_S0IX
- PMU_I2C0_LSS_20,
- PMU_I2C1_LSS_21,
- PMU_I2C2_LSS_27,
- PMU_I2C3_LSS_33,
- PMU_I2C4_LSS_34,
- PMU_I2C5_LSS_35,
-#endif
-
- PMU_UART2_LSS_41,
-
-};
-static u32 LPMP3_CFG[4];
-static u32 lpmp3_target[4];
-
-/* These are the LSS that need to be kept
- * always ON D0i0, you can add any LSS id
- * that you need to keep always on here.
- */
-static u8 lss_to_ignore[] = {
- PMU_USB_HSIC_LSS_07,
- PMU_SRAM_LSS_10,
- PMU_SRAM_LSS_11,
- PMU_SRAM_LSS_12,
- PMU_SRAM_LSS_13,
- PMU_PTI_DAFCA_LSS_15,
- PMU_SC_DMA_LSS_16,
- PMU_SPIO_LSS_17,
- PMU_MAIN_FABRIC_LSS_22,
- PMU_SEC_FABRIC_LSS_23,
- PMU_SC_FABRIC_LSS_24,
- PMU_SCU_ROM_LSS_26,
- PMU_SSC_LSS_28,
- PMU_SECURITY_LSS_29,
- PMU_SCU_RAM0_LSS_31,
- PMU_SCU_RAM1_LSS_32,
- PMU_GPIO1_LSS_37,
- PMU_PWR_BUTTON_LSS_38,
- PMU_GPIO0_LSS_39,
- PMU_ADC_LSS_42,
- PMU_CHARGER_LSS_43,
- PMU_SEC_TAPC_LSS_44,
- PMU_RTC_LSS_45,
- PMU_GPI_LSS_46,
- PMU_HDMI_VREG_LSS_47,
- PMU_IOSF_OCP_BRG_LSS_53,
- PMU_SVID_LSS_55,
- PMU_SOC_FUSE_LSS_56,
- PMU_RSVD3_LSS_57,
- PMU_RSVD4_LSS_58,
- PMU_RSVD5_LSS_59,
- PMU_RSVD6_LSS_60,
- PMU_RSVD7_LSS_61,
- PMU_RSVD8_LSS_62,
- PMU_RSVD9_LSS_63
-};
-static u32 IGNORE_CFG[4];
-
-/* These are the LSS that need
- * to be configured in SSS registers
- * before issuing S0i1 command
- */
-static u8 s0i1_sss_lss[] = {
- PMU_SDIO0_LSS_00,
- PMU_EMMC0_LSS_01,
- PMU_AONT_LSS_02,
- PMU_HSI_LSS_03,
- PMU_SECURITY_LSS_04,
- PMU_EMMC1_LSS_05,
- PMU_USB_OTG_LSS_06,
- PMU_USB_HSIC_LSS_07,
- PMU_AUDIO_ENGINE_LSS_08,
- PMU_AUDIO_DMA_LSS_09,
- PMU_SRAM_LSS_12,
- PMU_SRAM_LSS_13,
- PMU_SDIO2_LSS_14,
- PMU_SPI1_LSS_18,
- PMU_SPI2_LSS_19,
- PMU_I2C0_LSS_20,
- PMU_I2C1_LSS_21,
- PMU_AUDIO_RAM_LSS_25,
- PMU_I2C2_LSS_27,
- PMU_SDIO1_LSS_30,
- PMU_I2C3_LSS_33,
- PMU_I2C4_LSS_34,
- PMU_I2C5_LSS_35,
- PMU_SPI3_LSS_36,
- PMU_GPIO1_LSS_37,
- PMU_PWR_BUTTON_LSS_38,
- PMU_KEYBRD_LSS_40,
- PMU_UART2_LSS_41,
- PMU_AUDIO_SSP2_LSS_48,
- PMU_AUDIO_SLIM1_LSS_49,
- PMU_RESET_LSS_50,
- PMU_AUDIO_SSP0_LSS_51,
- PMU_AUDIO_SSP1_LSS_52,
- PMU_GP_DMA_LSS_54
-};
-static u32 s0i1_sss[4];
-
-/* These are the LSS that need
- * to be configured in SSS registers
- * before issuing S0i3 command
- */
-static u8 s0i3_sss_lss[] = {
- PMU_SDIO0_LSS_00,
- PMU_EMMC0_LSS_01,
- PMU_AONT_LSS_02,
- PMU_HSI_LSS_03,
- PMU_SECURITY_LSS_04,
- PMU_EMMC1_LSS_05,
- PMU_USB_OTG_LSS_06,
- PMU_USB_HSIC_LSS_07,
- PMU_AUDIO_ENGINE_LSS_08,
- PMU_AUDIO_DMA_LSS_09,
- PMU_SRAM_LSS_12,
- PMU_SRAM_LSS_13,
- PMU_SDIO2_LSS_14,
- PMU_SPI1_LSS_18,
- PMU_SPI2_LSS_19,
- PMU_I2C0_LSS_20,
- PMU_I2C1_LSS_21,
- PMU_AUDIO_RAM_LSS_25,
- PMU_I2C2_LSS_27,
- PMU_SDIO1_LSS_30,
- PMU_I2C3_LSS_33,
- PMU_I2C4_LSS_34,
- PMU_I2C5_LSS_35,
- PMU_SPI3_LSS_36,
- PMU_GPIO1_LSS_37,
- PMU_PWR_BUTTON_LSS_38,
- PMU_KEYBRD_LSS_40,
- PMU_UART2_LSS_41,
- PMU_AUDIO_SSP2_LSS_48,
- PMU_AUDIO_SLIM1_LSS_49,
- PMU_RESET_LSS_50,
- PMU_AUDIO_SSP0_LSS_51,
- PMU_AUDIO_SSP1_LSS_52,
- PMU_GP_DMA_LSS_54
-};
-static u32 s0i3_sss[4];
-static u32 s3_sss[4];
-
-/* These are the LSS that need
- * to be configured in SSSarch/x86/kernel/mid_pmu.c registers
- * before issuing LPMP3 command
- */
-static u8 lpmp3_sss_lss[] = {
- PMU_SDIO0_LSS_00,
- PMU_EMMC0_LSS_01,
- PMU_AONT_LSS_02,
- PMU_HSI_LSS_03,
- PMU_SECURITY_LSS_04,
- PMU_EMMC1_LSS_05,
- PMU_USB_OTG_LSS_06,
- PMU_USB_HSIC_LSS_07,
- PMU_SDIO2_LSS_14,
- PMU_SPI1_LSS_18,
- PMU_SPI2_LSS_19,
- PMU_I2C0_LSS_20,
- PMU_I2C1_LSS_21,
- PMU_I2C2_LSS_27,
- PMU_SDIO1_LSS_30,
- PMU_I2C3_LSS_33,
- PMU_I2C4_LSS_34,
- PMU_I2C5_LSS_35,
- PMU_SPI3_LSS_36,
- PMU_GPIO1_LSS_37,
- PMU_PWR_BUTTON_LSS_38,
- PMU_KEYBRD_LSS_40,
- PMU_UART2_LSS_41,
- PMU_AUDIO_SLIM1_LSS_49,
- PMU_RESET_LSS_50,
- PMU_AUDIO_SSP0_LSS_51,
- PMU_AUDIO_SSP1_LSS_52,
- PMU_GP_DMA_LSS_54
-};
-static u32 lpmp3_sss[4];
-
-/* These are the LSS that need to be ignored
- * as wake sources when in S3
- */
-static u8 ignore_lss_in_wkc[] = {
- PMU_AONT_LSS_02,
- PMU_ADC_LSS_42
-};
-static u32 IGNORE_WKC_S3_CFG[2];
-
-static struct pci_dev_index pci_dev_hash[MID_PCI_INDEX_HASH_SIZE];
-
-
-static int dev_init_state;
-static struct intel_mid_base_addr base_addr;
-static struct mrst_pmu_reg __iomem *pmu_reg;
-
-#ifdef CONFIG_HAS_WAKELOCK
-static struct wake_lock pmu_wake_lock;
-#endif
-
-static u32 apm_base;
-static u32 ospm_base;
-static spinlock_t nc_ready_lock;
-
-/*
- * Locking strategy::
- *
- * Two semaphores are used to lock the global variables used in
- * the code. The entry points in pmu driver are pmu_pci_set_power_state()
- * and PMU interrupt handler contexts, so here is the flow of how
- * the semaphores are used.
- *
- * In D0ix command case::
- * set_power_state process context:
- * set_power_state()->acquire_scu_ready_sem()->issue_interactive_cmd->
- * wait_for_interactive_complete_sem->release scu_ready sem
- *
- * PMU Interrupt context:
- * pmu_interrupt_handler()->release interactive_complete_sem->return
- *
- * In Idle handler case::
- * Idle context:
- * idle_handler()->try_acquire_scu_ready_sem->if acquired->
- * issue s0ix command->return
- *
- * PMU Interrupt context:
- * pmu_Interrupt_handler()->release scu_ready_sem->return
- *
- */
-static struct semaphore scu_ready_sem =
- __SEMAPHORE_INITIALIZER(scu_ready_sem, 1);
-static struct semaphore set_mode_complete_sem =
- __SEMAPHORE_INITIALIZER(set_mode_complete_sem, 0);
-
-static int scu_comms_okay = 1;
-
-#ifdef ENABLE_SCU_WATCHDOG
-/* scu semaphore watchdog timer */
-static void scu_watchdog_func(unsigned long arg)
-{
- struct semaphore* sem = (struct semaphore *) arg;
-
- WARN(1, "SCU watchdog triggered, dead lock occured,"
- "diabling SCU comms.\n");
- scu_comms_okay = 0;
-
- /* unblock the blocking thread */
- up(sem);
-}
-#endif
-
-/*
- * Acquire the said semaphore and activating a watchdog timer
- * that triggers after timeout, if we are able to acquire then
- * delete the timer.
- */
-static void down_scu_timed(struct semaphore *sem)
-{
-#ifdef ENABLE_SCU_WATCHDOG
- struct timer_list *scu_watchdog_timer =
- kmalloc(sizeof(struct timer_list), GFP_KERNEL);
-
- if (!scu_watchdog_timer) {
- WARN(1, "Malloc failed.\n");
- return;
- }
-
- init_timer(scu_watchdog_timer);
- scu_watchdog_timer->function = scu_watchdog_func;
- scu_watchdog_timer->data = (unsigned long) sem;
-
- /*10secs timeout*/
- scu_watchdog_timer->expires =
- jiffies + msecs_to_jiffies(10 * 1000);
- add_timer(scu_watchdog_timer);
-#endif
-
- down(sem);
-
-#ifdef ENABLE_SCU_WATCHDOG
- del_timer_sync(scu_watchdog_timer);
- kfree(scu_watchdog_timer);
-#endif
-}
-
-/* Device information for all the PCI devices present on SC */
-static struct pci_dev_info intel_mid_pci_devices[MAX_DEVICES];
-static int num_wakes[MAX_DEVICES];
-static int cmd_error_int;
-static u64 pmu_init_time;
-static u8 pmu_in_s3;
-static struct mid_pmu_stats {
- u64 err_count[3];
- u64 count;
- u64 time;
- u64 last_entry;
- u64 last_try;
- u64 first_entry;
-} pmu_stats[SYS_STATE_S5];
-static enum sys_state pmu_current_state;
-
-static void pmu_stat_start(enum sys_state type)
-{
- pmu_current_state = type;
- pmu_stats[type].last_try = cpu_clock(smp_processor_id());
-}
-
-static void pmu_stat_end(void)
-{
- enum sys_state type = pmu_current_state;
-
- if (type > SYS_STATE_S0I0) {
- pmu_stats[type].last_entry =
- pmu_stats[type].last_try;
-
- /*if it is the first entry save the time*/
- if (!pmu_stats[type].count)
- pmu_stats[type].first_entry =
- pmu_stats[type].last_entry;
-
- pmu_stats[type].time +=
- cpu_clock(smp_processor_id())
- - pmu_stats[type].last_entry;
-
- pmu_stats[type].count++;
- }
-
- pmu_current_state = SYS_STATE_S0I0;
-}
-
-static void pmu_stat_clear(void)
-{
- pmu_current_state = SYS_STATE_S0I0;
-}
-
-static void pmu_stat_error(u8 err_type)
-{
- enum sys_state type = pmu_current_state;
- u8 err_index;
-
- if (type > SYS_STATE_S0I0) {
- switch (err_type) {
- case SUBSYS_POW_ERR_INT:
- trace_printk("S0ix_POW_ERR_INT\n");
- err_index = 0;
- break;
- case S0ix_MISS_INT:
- trace_printk("S0ix_MISS_INT\n");
- err_index = 1;
- break;
- case NO_ACKC6_INT:
- trace_printk("S0ix_ACKC6_INT\n");
- err_index = 2;
- break;
- default:
- err_index = 3;
- break;
- }
-
- if (err_index < 3)
- pmu_stats[type].err_count[err_index]++;
- }
-}
-
-static void pmu_stat_seq_printf(struct seq_file *s, int type, char *typestr)
-{
- unsigned long long t;
- unsigned long nanosec_rem, remainder;
- unsigned long time, init_2_now_time;
-
- seq_printf(s, "%s\t%5llu\t%10llu\t%9llu\t%9llu\t", typestr,
- pmu_stats[type].count,
- pmu_stats[type].err_count[0],
- pmu_stats[type].err_count[1],
- pmu_stats[type].err_count[2]);
-
- t = pmu_stats[type].time;
- nanosec_rem = do_div(t, 1000000000);
-
- /* convert time in secs */
- time = (unsigned long)t;
-
- seq_printf(s, "%5lu.%06lu\t",
- (unsigned long) t, nanosec_rem / 1000);
-
- t = pmu_stats[type].last_entry;
- nanosec_rem = do_div(t, 1000000000);
- seq_printf(s, "%5lu.%06lu\t",
- (unsigned long) t, nanosec_rem / 1000);
-
- t = pmu_stats[type].first_entry;
- nanosec_rem = do_div(t, 1000000000);
- seq_printf(s, "%5lu.%06lu\t",
- (unsigned long) t, nanosec_rem / 1000);
-
- t = cpu_clock(raw_smp_processor_id());
- t -= pmu_init_time;
- nanosec_rem = do_div(t, 1000000000);
-
- init_2_now_time = (unsigned long) t;
-
- /* for calculating percentage residency */
- time = time * 100;
- t = (u64) time;
- remainder = do_div(t, init_2_now_time);
- time = (unsigned long) t;
-
- /* for getting 3 digit precision after
- * decimal dot */
- remainder *= 1000;
- t = (u64) remainder;
- remainder = do_div(t, init_2_now_time);
- seq_printf(s, "%5lu.%03lu\n", time, (unsigned long) t);
-}
-
-/*Experimentally enabling S0i3 as extended C-States*/
-static char s0ix[5] = "s0i3";
-static int extended_cstate_mode = MID_S0I3_STATE;
-static int set_extended_cstate_mode(const char *val, struct kernel_param *kp)
-{
- char valcp[5];
- strncpy(valcp, val, 5);
- valcp[4] = '\0';
-
-#ifdef CONFIG_HAS_WAKELOCK
- /* will also disable s0ix */
- if (strcmp(valcp, "s3s3") == 0)
- wake_unlock(&pmu_wake_lock);
-#endif
-
- /* Acquire the scu_ready_sem */
- down_scu_timed(&scu_ready_sem);
-
- if (strcmp(valcp, "s0i3") == 0)
- extended_cstate_mode = MID_S0I3_STATE;
- else if (strcmp(valcp, "s0i1") == 0)
- extended_cstate_mode = MID_S0I1_STATE;
- else if (strcmp(valcp, "s0ix") == 0)
- extended_cstate_mode = MID_S0IX_STATE;
- else {
- extended_cstate_mode = -1;
- strncpy(valcp, "none", 5);
- }
- strncpy(s0ix, valcp, 5);
-
- up(&scu_ready_sem);
-
- return 0;
-}
-
-/* Maps pci power states to SCU D0ix mask */
-static int pci_2_mfld_state(pci_power_t pci_state)
-{
- int mfld_state = D0I0_MASK;
-
- switch (pci_state) {
- case PCI_D0:
- mfld_state = D0I0_MASK;
- break;
-
- case PCI_D1:
- mfld_state = D0I1_MASK;
- break;
-
- case PCI_D2:
- mfld_state = D0I2_MASK;
- break;
-
- case PCI_D3cold:
- case PCI_D3hot:
- mfld_state = D0I3_MASK;
- break;
-
- default:
- WARN(1, "%s: wrong pci_state received.\n", __func__);
- break;
- }
-
- return mfld_state;
-}
-
-static int get_extended_cstate_mode(char *buffer, struct kernel_param *kp)
-{
- strcpy(buffer, s0ix);
- return 4;
-}
-
-module_param_call(s0ix, set_extended_cstate_mode,
- get_extended_cstate_mode, NULL, 0644);
-MODULE_PARM_DESC(s0ix,
- "setup extended c state s0ix mode [s0i3|s0i1|s0ix|none]");
-
-/* the device object */
-static struct pci_dev *pmu_dev;
-
-/*virtual memory address for PMU base returned by ioremap_nocache().*/
-static struct mid_pmu_dev intel_mid_pmu_base;
-
-#ifdef CONFIG_VIDEO_ATOMISP
-static int camera_off;
-#else
-static int camera_off = 1;
-#endif
-
-#ifdef GFX_ENABLE
-static int display_off;
-#else
-/* If Gfx is disabled
- * assume s0ix is not blocked
- * from gfx side
- */
-static int display_off = 1;
-#endif
-
-static int s0i1_possible;
-static int lpmp3_possible;
-static int s0i3_possible;
-static int c6_demoted;
-static int interactive_cmd_sent;
-static int s0ix_entered;
-static u32 pmu1_max_devs, pmu2_max_devs, ss_per_reg;
-
-static int _pmu_issue_command(struct pmu_ss_states *pm_ssc, int mode, int ioc,
- int pmu_num);
-static void pmu_read_sss(struct pmu_ss_states *pm_ssc);
-static int _pmu2_wait_not_busy(void);
-
-/* PCI Device Id structure */
-static DEFINE_PCI_DEVICE_TABLE(mid_pm_ids) = {
- {PCI_VDEVICE(INTEL, MID_PMU_MRST_DRV_DEV_ID), 0},
- {PCI_VDEVICE(INTEL, MID_PMU_MFLD_DRV_DEV_ID), 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(pci, mid_pm_ids);
-
-int get_target_platform_state(void)
-{
- if (likely(scu_comms_okay &&
- (extended_cstate_mode != -1) && display_off\
- && camera_off))
- return extended_cstate_mode;
-
- return 0;
-}
-EXPORT_SYMBOL(get_target_platform_state);
-
-static int _pmu_read_status(int pmu_num, int type)
-{
- u32 temp;
- union pmu_pm_status result;
-
- temp = readl(&pmu_reg->pm_sts);
-
- /* extract the busy bit */
- result.pmu_status_value = temp;
-
- if (type == PMU_BUSY_STATUS)
- return result.pmu_status_parts.pmu_busy;
- else if (type == PMU_MODE_ID)
- return result.pmu_status_parts.mode_id;
-
- return 0;
-}
-
-static int _pmu2_wait_not_busy(void)
-{
- int pmu_busy_retry = 500000;
-
- /* wait 500ms that the latest pmu command finished */
- while (--pmu_busy_retry) {
- if (_pmu_read_status(PMU_NUM_2, PMU_BUSY_STATUS) == 0)
- return 0;
-
- udelay(1);
- }
-
- WARN(1, "pmu2 busy!");
-
- return -EBUSY;
-}
-
-static void pmu_write_subsys_config(struct pmu_ss_states *pm_ssc)
-{
- /* South complex in Penwell has multiple registers for
- * PM_SSC, etc.
- */
- writel(pm_ssc->pmu2_states[0], &pmu_reg->pm_ssc[0]);
-
- if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
- writel(pm_ssc->pmu2_states[1], &pmu_reg->pm_ssc[1]);
- writel(pm_ssc->pmu2_states[2], &pmu_reg->pm_ssc[2]);
- writel(pm_ssc->pmu2_states[3], &pmu_reg->pm_ssc[3]);
- }
-}
-
-/**
- * pmu_set_cfg_mode_params - platform specific configuration mode parameters
- */
-static int pmu_set_cfg_mode_params(struct cfg_mode_params
- *cfg_mode_parms, union pmu_pm_set_cfg_cmd_t *command, int pmu_num)
-{
- struct cfg_trig_param_t cmd;
-
- /* parameter check */
- if (cfg_mode_parms->cfg_mode >= CM_INVALID) {
- pr_alert("invalid config mode\n");
- return PMU_FAILED;
- }
-
- if (cfg_mode_parms->cfg_cmbi > 1) {
- pr_alert("invalid cfg_cmbi bit\n");
- return PMU_FAILED;
- }
-
- if (cfg_mode_parms->cfg_trigger >= INVALID_TRIG) {
- pr_alert("invalid cfg_trigger mode\n");
- return PMU_FAILED;
- }
-
- if (command == NULL) {
- pr_alert("invalid pointer\n");
- return PMU_FAILED;
- }
-
- if (pmu_num == PMU_NUM_1) {
- command->pmu1_params.cfg_mode = cfg_mode_parms->cfg_mode;
- command->pmu1_params.cfg_delay = cfg_mode_parms->cfg_delay;
- command->pmu1_params.cfg_trigger = cfg_mode_parms->cfg_trigger;
- } else if (pmu_num == PMU_NUM_2) {
- command->pmu2_params.d_param.cfg_mode =
- cfg_mode_parms->cfg_mode;
-
- /* Based on the cfg_mode set these parameters */
- switch (cfg_mode_parms->cfg_mode) {
- case CM_NOP:
- case CM_IMMEDIATE:
- command->pmu2_params.d_param.cfg_delay = 0;
- command->pmu2_params.d_param.rsvd = 0;
- break;
- case CM_DELAY:
- command->pmu2_params.d_param.cfg_delay =
- cfg_mode_parms->cfg_delay;
- command->pmu2_params.d_param.rsvd = 0;
- break;
- case CM_TRIGGER:
- /* Based on the trigger type construct the cfg_trigger
- * parameters
- */
- cmd = command->pmu2_params.t_param;
- switch (cfg_mode_parms->cfg_trigger) {
- case NO_TRIG:
- cmd.cfg_trig_type = cfg_mode_parms->cfg_trigger;
- cmd.cmbi = cfg_mode_parms->cfg_cmbi;
- cmd.rsvd1 = 0;
- cmd.cfg_trig_val = cfg_mode_parms->cfg_trig_val;
- break;
- case LPM_EVENT_TRIG:
- cmd.cfg_trig_type = cfg_mode_parms->cfg_trigger;
- cmd.cmbi = cfg_mode_parms->cfg_cmbi;
- cmd.rsvd1 = 0;
- if (cfg_mode_parms->cfg_trig_val != PME_ID_LPE
- && cfg_mode_parms->cfg_trig_val !=
- PME_ID_USB) {
- pr_alert("pme_Id"
- "not supported in this release\n");
- return PMU_FAILED;
- }
- cmd.cfg_trig_val = cfg_mode_parms->cfg_trig_val;
- break;
- case EXT_GPIO_INPUT_TRIG:
- cmd.cfg_trig_type = cfg_mode_parms->cfg_trigger;
- cmd.cmbi = cfg_mode_parms->cfg_cmbi;
- cmd.rsvd1 = 0;
- cmd.cfg_trig_val = cfg_mode_parms->cfg_trig_val;
- break;
- case C_STATE_TRANS_TRIG:
- cmd.cfg_trig_type = cfg_mode_parms->cfg_trigger;
- cmd.cmbi = cfg_mode_parms->cfg_cmbi;
- cmd.rsvd1 = 0;
- cmd.cfg_trig_val = cfg_mode_parms->cfg_trig_val;
- break;
- default:
- pr_alert("invalid state\n");
- return PMU_FAILED;
- break;
- };
- command->pmu2_params.t_param = cmd;
- break;
- default:
- WARN_ON(1);
- return PMU_FAILED;
- };
- }
- return 0;
-}
-
-/**
- * pmu_send_set_config_command - Platform specific function to send
- * configuration commands to Firmware
- */
-static int pmu_send_set_config_command(union pmu_pm_set_cfg_cmd_t
- *command, u8 ioc, enum sys_state state, int pmu_num)
-{
- /* parameter check */
- if ((ioc != 1) && (ioc != 0)) {
- pr_alert("invalid ioc bit\n");
- return PMU_FAILED;
- }
-
- /* construct the command to send SET_CFG to particular PMU */
- if (pmu_num == PMU_NUM_1) {
- command->pmu1_params.cmd = SET_CFG_CMD;
- command->pmu1_params.ioc = ioc;
- command->pmu1_params.mode_id = MODE_ID_MAGIC_NUM;
- command->pmu1_params.rsvd = 0;
- } else if (pmu_num == PMU_NUM_2) {
- command->pmu2_params.d_param.cmd =
- SET_CFG_CMD;
- command->pmu2_params.d_param.ioc = ioc;
- command->pmu2_params.d_param.mode_id =
- MODE_ID_MAGIC_NUM;
-
- /* set the sys state */
- switch (state) {
- case SYS_STATE_S0I0:
- case SYS_STATE_S0I1:
- case SYS_STATE_S0I3:
- command->pmu2_params.
- d_param.sys_state = state;
- break;
- default:
- pr_alert("invalid state\n");
- return PMU_FAILED;
- break;
- }
- }
-
- /* write the value of PM_CMD into particular PMU */
- dev_dbg(&pmu_dev->dev, "command being written %x\n", \
- command->pmu_pm_set_cfg_cmd_value);
-
- writel(command->pmu_pm_set_cfg_cmd_value, &pmu_reg->pm_cmd);
-
- return 0;
-}
-
-/* return the last wake source id, and make statistics about wake sources */
-static int pmu_get_wake_source(void)
-{
- u32 wake0, wake1;
- int i;
- int source = INVALID_WAKE_SRC;
-
- wake0 = readl(&pmu_reg->pm_wks[0]);
- wake1 = readl(&pmu_reg->pm_wks[1]);
-
- while (wake0) {
- i = fls(wake0) - 1;
- source = i + pmu1_max_devs;
- num_wakes[source]++;
- trace_printk("wake_from_lss%d\n", source - pmu1_max_devs);
- wake0 &= ~(1<<i);
- }
-
- while (wake1) {
- i = fls(wake1) - 1;
- source = i + 32 + pmu1_max_devs;
- trace_printk("wake_from_lss%d\n", source - pmu1_max_devs);
- num_wakes[source]++;
- wake1 &= ~(1<<i);
- }
-
- return source;
-}
-
-static int pmu_is_interrupt_pending(int pmu_num)
-{
- u32 temp;
- union pmu_pm_ics result;
-
- /* read the pm interrupt status register */
- temp = readl(&pmu_reg->pm_ics);
- result.pmu_pm_ics_value = temp;
-
- /* return the pm interrupt status int pending bit info */
- return result.pmu_pm_ics_parts.int_pend;
-}
-
-static inline void pmu_clear_interrupt_pending(int pmu_num)
-{
- u32 temp;
-
- /* read the pm interrupt status register */
- temp = readl(&pmu_reg->pm_ics);
-
- /* write into the PM_ICS register */
- writel(temp, &pmu_reg->pm_ics);
-}
-
-static inline void pmu_enable_interrupt_from_pmu(int pmu_num)
-{
- u32 temp;
- union pmu_pm_ics result;
-
- /* read the pm interrupt status register */
- temp = readl(&pmu_reg->pm_ics);
- result = (union pmu_pm_ics)temp;
-
- result.pmu_pm_ics_parts.int_enable = 1;
-
- /* enable the interrupts */
- writel(result.pmu_pm_ics_value, &pmu_reg->pm_ics);
-}
-
-static inline int pmu_read_interrupt_status(int pmu_num)
-{
- u32 temp;
- union pmu_pm_ics result;
-
- /* read the pm interrupt status register */
- temp = readl(&pmu_reg->pm_ics);
-
- result.pmu_pm_ics_value = temp;
-
- if (result.pmu_pm_ics_parts.int_status == 0)
- return PMU_FAILED;
-
- /* return the pm interrupt status int pending bit info */
- return result.pmu_pm_ics_parts.int_status;
-}
-
-/**
- * This is a helper function used to program pm registers
- * in SCU. We configure the wakeable devices & the
- * wake sub system states on exit from S0ix state
- */
-static inline int _mfld_s0ix_enter(u32 s0ix_value)
-{
- struct pmu_ss_states cur_pmsss;
-
- /* If display status is 0 retry on next c6 */
- if (unlikely((display_off == 0) || (camera_off == 0))) {
- up(&scu_ready_sem);
- goto ret;
- }
-
- /* If PMU is busy, we'll retry on next C6 */
- if (unlikely(_pmu_read_status(PMU_NUM_2, PMU_BUSY_STATUS))) {
- up(&scu_ready_sem);
- goto ret;
- }
-
- /* setup the wake capable devices */
- writel(intel_mid_pmu_base.ss_config->wake_state.wake_enable[0],
- &pmu_reg->pm_wkc[0]);
- writel(intel_mid_pmu_base.ss_config->wake_state.wake_enable[1],
- &pmu_reg->pm_wkc[1]);
-
- /* Re-program the sub systems state on wakeup as the current SSS*/
- pmu_read_sss(&cur_pmsss);
-
- writel(cur_pmsss.pmu2_states[0], &pmu_reg->pm_wssc[0]);
- writel(cur_pmsss.pmu2_states[1], &pmu_reg->pm_wssc[1]);
- writel(cur_pmsss.pmu2_states[2], &pmu_reg->pm_wssc[2]);
- writel(cur_pmsss.pmu2_states[3], &pmu_reg->pm_wssc[3]);
-
- switch (s0ix_value) {
- case S0I1_VALUE:
- wrmsr(MSR_C6OFFLOAD_CTL_REG,
- MSR_C6OFFLOAD_CLEAR_LOW, MSR_C6OFFLOAD_CLEAR_HIGH);
- writel(s0i1_sss[0], &pmu_reg->pm_ssc[0]);
- writel(s0i1_sss[1], &pmu_reg->pm_ssc[1]);
- writel(s0i1_sss[2], &pmu_reg->pm_ssc[2]);
- writel(s0i1_sss[3], &pmu_reg->pm_ssc[3]);
- pmu_stat_start(SYS_STATE_S0I1);
- break;
-
- case LPMP3_VALUE:
- wrmsr(MSR_C6OFFLOAD_CTL_REG,
- MSR_C6OFFLOAD_CLEAR_LOW, MSR_C6OFFLOAD_CLEAR_HIGH);
- writel(lpmp3_sss[0], &pmu_reg->pm_ssc[0]);
- writel(lpmp3_sss[1], &pmu_reg->pm_ssc[1]);
- writel(lpmp3_sss[2], &pmu_reg->pm_ssc[2]);
- writel(lpmp3_sss[3], &pmu_reg->pm_ssc[3]);
- pmu_stat_start(SYS_STATE_S0I2);
- break;
-
- case S0I3_VALUE:
- writel(s0i3_sss[0], &pmu_reg->pm_ssc[0]);
- writel(s0i3_sss[1], &pmu_reg->pm_ssc[1]);
- writel(s0i3_sss[2], &pmu_reg->pm_ssc[2]);
- writel(s0i3_sss[3], &pmu_reg->pm_ssc[3]);
- pmu_stat_start(SYS_STATE_S0I3);
- break;
- }
-
- /* issue a command to SCU */
- writel(s0ix_value, &pmu_reg->pm_cmd);
- return 1;
-
-ret:
- return 0;
-}
-
-int mfld_s0i1_enter(void)
-{
- /* check if we can acquire scu_ready_sem
- * if we are not able to then do a c6 */
- if (down_trylock(&scu_ready_sem))
- goto ret;
-
- if (!s0i1_possible && !lpmp3_possible) {
- up(&scu_ready_sem);
- goto ret;
- }
-
- s0ix_entered =
- _mfld_s0ix_enter(s0i1_possible ? S0I1_VALUE : LPMP3_VALUE);
-
-ret:
- return s0ix_entered;
-}
-EXPORT_SYMBOL(mfld_s0i1_enter);
-
-int mfld_s0i3_enter(void)
-{
- u32 ssw_val = 0;
- int num_retry = 15000;
- int status = 0;
-
- /* skip S0i3 if SCU is not okay */
- if (unlikely(!scu_comms_okay))
- goto ret;
-
- /* check if we can acquire scu_ready_sem
- * if we are not able to then do a c6 */
- if (down_trylock(&scu_ready_sem))
- goto ret;
-
- if (!s0i3_possible) {
- up(&scu_ready_sem);
- goto ret;
- }
-
- s0ix_entered = _mfld_s0ix_enter(S0I3_VALUE);
-
- /* If s0i3 command is issued
- * then wait for c6 sram offload
- * to complete */
- if (s0ix_entered) {
- do {
- ssw_val = readl(base_addr.offload_reg);
-
- if ((ssw_val & C6OFFLOAD_BIT_MASK) == C6OFFLOAD_BIT)
- break;
-
- } while (num_retry--);
-
- /* enable c6Offload only if write access bit is set
- * if not then we will demote c6 to a c4 */
- if (likely((ssw_val & C6OFFLOAD_BIT_MASK) == C6OFFLOAD_BIT)) {
- wrmsr(MSR_C6OFFLOAD_CTL_REG,
- MSR_C6OFFLOAD_SET_LOW, MSR_C6OFFLOAD_SET_HIGH);
- status = 1;
- } else {
- pmu_stat_clear();
- WARN(1, "mid_pmu: error cpu offload bit not set.\n");
- }
- }
-
-ret:
- return status;
-}
-EXPORT_SYMBOL(mfld_s0i3_enter);
-
-/**
- * pmu_sc_irq - pmu driver interrupt handler
- * Context: interrupt context
- *
- * PMU interrupt handler based on the status of the interrupt
- * will send net link event to PM Framework.
- * - During inactivity interrupt it sends the information of inactivity
- * counter that caused the interrupt as net link event.
- * - During wake interrupt it sends the information of source of wake
- * sub system that caused the wake interrupt as net link event.
- */
-static irqreturn_t pmu_sc_irq(int irq, void *ignored)
-{
- u8 status = IRQ_NONE;
-
- /* check if interrup pending bit is set, if not ignore interrupt */
- if (unlikely(!pmu_is_interrupt_pending(PMU_NUM_2)))
- goto ret_no_clear;
-
- /* read the interrupt status */
- status = pmu_read_interrupt_status(PMU_NUM_2);
- if (unlikely(status == PMU_FAILED))
- dev_dbg(&pmu_dev->dev, "Invalid interrupt source\n");
-
- switch (status) {
- case INVALID_INT:
- status = IRQ_NONE;
- goto ret_no_clear;
-
- case CMD_COMPLETE_INT:
- break;
-
- case CMD_ERROR_INT:
- cmd_error_int++;
- break;
-
- case SUBSYS_POW_ERR_INT:
- case NO_ACKC6_INT:
- case S0ix_MISS_INT:
- pmu_stat_error(status);
- break;
-
- case WAKE_RECEIVED_INT:
- (void)pmu_get_wake_source();
- break;
- }
-
- if (status == WAKE_RECEIVED_INT)
- pmu_stat_end();
- else
- pmu_stat_clear();
-
- wrmsr(MSR_C6OFFLOAD_CTL_REG,
- MSR_C6OFFLOAD_CLEAR_LOW, MSR_C6OFFLOAD_CLEAR_HIGH);
-
- /* clear the interrupt pending bit */
- pmu_clear_interrupt_pending(PMU_NUM_2);
-
- /*
- * In case of interactive command
- * let the waiting set_power_state()
- * release scu_ready_sem
- */
- if (interactive_cmd_sent) {
- interactive_cmd_sent = 0;
-
- /* unblock set_power_state() */
- up(&set_mode_complete_sem);
- } else {
- s0ix_entered = 0;
-
- /* S0ix case release it */
- up(&scu_ready_sem);
- }
-
- status = IRQ_HANDLED;
-ret_no_clear:
- return status;
-}
-
-void pmu_enable_forward_msi(void)
-{
- writel(0, &pmu_reg->pm_msic);
-}
-EXPORT_SYMBOL(pmu_enable_forward_msi);
-
-unsigned long pmu_get_cstate(unsigned long eax)
-{
- unsigned long state = eax;
-
- /* If we get C6 in between s0ix, it should
- * be demoted to C4 */
- if ((s0ix_entered) && (eax == C6_HINT)) {
- state = C4_HINT;
- c6_demoted++;
- } else if ((eax == C7_HINT) || (eax == C8_HINT)) {
- /* for S0ix choose C6 */
- state = C6_HINT;
- }
-
- return state;
-}
-EXPORT_SYMBOL(pmu_get_cstate);
-
-static inline u32 find_index_in_hash(struct pci_dev *pdev, int *found)
-{
- u32 h_index;
- int i;
-
- /* assuming pdev is not null */
- WARN_ON(pdev == NULL);
-
- h_index = jhash_1word(((pdev->vendor<<16)|pdev->device),
- MID_PCI_INDEX_HASH_INITVALUE) & MID_PCI_INDEX_HASH_MASK;
-
- /* assume not found */
- *found = 0;
-
- for (i = 0; i < MID_PCI_INDEX_HASH_SIZE; i++) {
- if (likely(pci_dev_hash[h_index].pdev == pdev)) {
- *found = 1;
- break;
- }
-
- /* assume no deletions, hence there shouldn't be any
- * gaps ie., NULL's */
- if (unlikely(pci_dev_hash[h_index].pdev == NULL)) {
- /* found NULL, that means we wont have
- * it in hash */
- break;
- }
-
- h_index = (h_index+1)%MID_PCI_INDEX_HASH_SIZE;
- }
-
- /* Assume hash table wont be full */
- WARN_ON(i == MID_PCI_INDEX_HASH_SIZE);
-
- return h_index;
-}
-
-static int get_pci_to_pmu_index(struct pci_dev *pdev)
-{
- int pm, type;
- unsigned int base_class;
- unsigned int sub_class;
- u8 ss;
- int index = PMU_FAILED;
- u32 h_index;
- int found;
-
- h_index = find_index_in_hash(pdev, &found);
-
- if (found)
- return (int)pci_dev_hash[h_index].index;
-
- /* if not found, h_index would be where
- * we can insert this */
-
- base_class = pdev->class >> 16;
- sub_class = (pdev->class & SUB_CLASS_MASK) >> 8;
- pm = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
-
- /* read the logical sub system id & cap if present */
- pci_read_config_byte(pdev, pm + 4, &ss);
-
- /*FIXME:: pci_table is wrong and put bad ss for HSU0 and HSU1 */
- if (pdev->device == 0x81c || pdev->device == 0x81b)
- ss = (LOG_SS_MASK | PMU_UART2_LSS_41);
-
- /*FIXME:: HSI does not have an LSS listed in pci_table */
- if (pdev->device == 0x833) {
- dev_warn(&pdev->dev, "HSI pci pm config = 0x%x\n", ss);
- ss = (LOG_SS_MASK | PMU_HSI_LSS_03);
- }
-
- type = ss & LOG_SS_MASK;
- ss = ss & LOG_ID_MASK;
-
- /*FIXME:: remove this once IFWI fixes Audio DMA LSS to 9 */
- if (ss == PMU_SC_DMA_LSS_16)
- ss = PMU_AUDIO_DMA_LSS_09;
-
- if ((base_class == PCI_BASE_CLASS_DISPLAY) && !sub_class)
- index = 1;
- else if ((__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) &&
- (base_class == PCI_BASE_CLASS_MULTIMEDIA) &&
- (sub_class == ISP_SUB_CLASS))
- index = MFLD_ISP_POS;
- else if (type)
- index = pmu1_max_devs + ss;
-
- if (index != PMU_FAILED) {
- /* insert into hash table */
- pci_dev_hash[h_index].pdev = pdev;
-
- /* assume index never exceeds 0xff */
- WARN_ON(index > 0xFF);
-
- pci_dev_hash[h_index].index = (u8)index;
-
- if (index < pmu1_max_devs) {
- intel_mid_pci_devices[index].ss_idx = 0;
- intel_mid_pci_devices[index].ss_pos = index;
- intel_mid_pci_devices[index].pmu_num = PMU_NUM_1;
- } else if (index >= pmu1_max_devs &&
- index < (pmu1_max_devs + pmu2_max_devs)) {
- intel_mid_pci_devices[index].ss_idx = ss / ss_per_reg;
- intel_mid_pci_devices[index].ss_pos = ss % ss_per_reg;
- intel_mid_pci_devices[index].pmu_num = PMU_NUM_2;
- } else {
- index = PMU_FAILED;
- }
-
- WARN_ON(index == PMU_FAILED);
- }
-
- return index;
-}
-
-static void mid_pci_find_info(struct pci_dev *pdev)
-{
- int index, pm;
- unsigned int base_class;
- unsigned int sub_class;
- u8 ss, cap;
- int i;
- base_class = pdev->class >> 16;
- sub_class = (pdev->class & SUB_CLASS_MASK) >> 8;
-
- pm = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
-
- /* read the logical sub system id & cap if present */
- pci_read_config_byte(pdev, pm + 4, &ss);
- pci_read_config_byte(pdev, pm + 5, &cap);
-
- /* get the index for the copying of ss info */
- index = get_pci_to_pmu_index(pdev);
-
- if (index == PMU_FAILED)
- return;
-
- /* initialize gfx subsystem info */
- if ((base_class == PCI_BASE_CLASS_DISPLAY) && !sub_class) {
- intel_mid_pci_devices[index].log_id = index;
- intel_mid_pci_devices[index].cap = PM_SUPPORT;
- } else if ((base_class == PCI_BASE_CLASS_MULTIMEDIA) &&
- (sub_class == ISP_SUB_CLASS)) {
- if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
- intel_mid_pci_devices[index].log_id = index;
- intel_mid_pci_devices[index].cap = PM_SUPPORT;
- } else if (ss && cap) {
- intel_mid_pci_devices[index].log_id = ss & LOG_ID_MASK;
- intel_mid_pci_devices[index].cap = cap;
- }
- } else if (ss && cap) {
- intel_mid_pci_devices[index].log_id = ss & LOG_ID_MASK;
- intel_mid_pci_devices[index].cap = cap;
- }
-
- for (i = 0; i < PMU_MAX_LSS_SHARE &&
- intel_mid_pci_devices[index].dev_driver[i]; i++) {
- /* do nothing */
- }
-
- WARN_ON(i >= PMU_MAX_LSS_SHARE);
-
- if (i < PMU_MAX_LSS_SHARE) {
- intel_mid_pci_devices[index].dev_driver[i] = pdev;
- intel_mid_pci_devices[index].dev_power_state[i] = PCI_D0;
- }
-}
-
-static void pmu_enumerate(void)
-{
- struct pci_dev *pdev = NULL;
- unsigned int base_class;
-
- while ((pdev = pci_get_device(PCI_ID_ANY, PCI_ID_ANY, pdev)) != NULL) {
-
- /* find the base class info */
- base_class = pdev->class >> 16;
-
- if (base_class == PCI_BASE_CLASS_BRIDGE)
- continue;
-
- mid_pci_find_info(pdev);
- }
-}
-
-static void pmu_read_sss(struct pmu_ss_states *pm_ssc)
-{
- pm_ssc->pmu2_states[0] = readl(&pmu_reg->pm_sss[0]);
-
- if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
- pm_ssc->pmu2_states[1] = readl(&pmu_reg->pm_sss[1]);
- pm_ssc->pmu2_states[2] = readl(&pmu_reg->pm_sss[2]);
- pm_ssc->pmu2_states[3] = readl(&pmu_reg->pm_sss[3]);
- } else {
- pm_ssc->pmu2_states[1] = 0;
- pm_ssc->pmu2_states[2] = 0;
- pm_ssc->pmu2_states[3] = 0;
- }
-}
-
-static bool check_s0ix_possible(struct pmu_ss_states *pmsss)
-{
- if (((pmsss->pmu2_states[0] & TARGET_CFG[0]) ==
- s0ix_target[0]) &&
- ((pmsss->pmu2_states[1] & TARGET_CFG[1]) ==
- s0ix_target[1]) &&
- ((pmsss->pmu2_states[2] & TARGET_CFG[2]) ==
- s0ix_target[2]) &&
- ((pmsss->pmu2_states[3] & TARGET_CFG[3]) ==
- s0ix_target[3]))
- return true;
-
- return false;
-}
-
-static bool check_lpmp3_possible(struct pmu_ss_states *pmsss)
-{
- if (((pmsss->pmu2_states[0] & LPMP3_CFG[0]) ==
- lpmp3_target[0]) &&
- ((pmsss->pmu2_states[1] & LPMP3_CFG[1]) ==
- lpmp3_target[1]) &&
- ((pmsss->pmu2_states[2] & LPMP3_CFG[2]) ==
- lpmp3_target[2]) &&
- ((pmsss->pmu2_states[3] & LPMP3_CFG[3]) ==
- lpmp3_target[3]))
- return true;
-
- return false;
-}
-
-static void pmu_set_s0ix_possible(int state)
-{
- /* assume S0ix not possible */
- s0i1_possible = lpmp3_possible = s0i3_possible = 0;
-
- if (state != PCI_D0) {
- struct pmu_ss_states cur_pmsss;
-
- pmu_read_sss(&cur_pmsss);
-
- if (likely(check_s0ix_possible(&cur_pmsss)))
- s0i1_possible = s0i3_possible = 1;
- else if (check_lpmp3_possible(&cur_pmsss))
- lpmp3_possible = 1;
- }
-
-#ifdef CONFIG_HAS_WAKELOCK
-#ifdef S0I3_POSSIBLE_WAKELOCK
- if (s0i3_possible && wake_lock_active(&pmu_wake_lock))
- wake_unlock(&pmu_wake_lock);
- if (!s0i3_possible && !wake_lock_active(&pmu_wake_lock))
- wake_lock(&pmu_wake_lock);
-#endif
-#endif
-}
-/*
- * For all devices in this lss, we check what is the weakest power state
- *
- * Thus we dont power down if another device needs more power
- */
-
-static pci_power_t pmu_pci_get_weakest_state_for_lss(int lss_index,
- struct pci_dev *pdev, pci_power_t state)
-{
- int i;
- pci_power_t weakest = state;
-
- for (i = 0; i < PMU_MAX_LSS_SHARE; i++) {
- if (intel_mid_pci_devices[lss_index].dev_driver[i] == pdev)
- intel_mid_pci_devices[lss_index].dev_power_state[i] =
- state;
-
- if (intel_mid_pci_devices[lss_index].dev_driver[i] &&
- (intel_mid_pci_devices[lss_index].dev_power_state[i]
- < weakest)) {
- dev_warn(&pdev->dev, "%s:%s prevented me to suspend...\n",
- dev_name(&intel_mid_pci_devices[lss_index].dev_driver[i]->dev),
- dev_driver_string(&intel_mid_pci_devices[lss_index].dev_driver[i]->dev));
-
- weakest = intel_mid_pci_devices[lss_index].
- dev_power_state[i];
- }
- }
- return weakest;
-}
-
-static int pmu_pci_to_indexes(struct pci_dev *pdev, int *index,
- int *pmu_num, int *ss_idx, int *ss_pos)
-{
- int i;
-
- i = get_pci_to_pmu_index(pdev);
- if (i == PMU_FAILED)
- return PMU_FAILED;
-
- *index = i;
- *ss_pos = intel_mid_pci_devices[i].ss_pos;
- *ss_idx = intel_mid_pci_devices[i].ss_idx;
- *pmu_num = intel_mid_pci_devices[i].pmu_num;
-
- return PMU_SUCCESS;
-}
-
-static int wait_for_nc_pmcmd_complete(int verify_mask, int state_type
- , int reg_type)
-{
- int pwr_sts;
- int count = 0;
- u32 addr;
-
- switch (reg_type) {
- case APM_REG_TYPE:
- addr = apm_base + APM_STS;
- break;
- case OSPM_REG_TYPE:
- addr = ospm_base + OSPM_PM_SSS;
- break;
- default:
- return -EINVAL;
- }
-
- while (true) {
- pwr_sts = inl(addr);
- if (state_type == OSPM_ISLAND_DOWN) {
- if ((pwr_sts & verify_mask) == verify_mask)
- break;
- else
- udelay(10);
- } else if (state_type == OSPM_ISLAND_UP) {
- if (pwr_sts == verify_mask)
- break;
- else
- udelay(10);
- }
- count++;
- if (WARN_ONCE(count > 500000, "Timed out waiting for P-Unit"))
- return -EBUSY;
- }
- return 0;
-}
-
-/**
- * pmu_nc_set_power_state - Callback function is used by all the devices
- * in north complex for a platform specific device power on/shutdown.
- * Following assumptions are made by this function
- *
- * Every new request starts from scratch with no assumptions
- * on previous/pending request to Punit.
- * Caller is responsible to retry if request fails.
- * Avoids multiple requests to Punit if target state is
- * already in the expected state.
- * spin_locks guarantee serialized access to these registers
- * and avoid concurrent access from 2d/3d, VED, VEC, ISP & IPH.
- *
- */
-int pmu_nc_set_power_state(int islands, int state_type, int reg_type)
-{
- u32 pwr_cnt = 0;
- u32 pwr_mask = 0;
- unsigned long flags;
- int i, lss, mask;
- int ret = 0;
-
- spin_lock_irqsave(&nc_ready_lock, flags);
-
- switch (reg_type) {
- case APM_REG_TYPE:
- pwr_cnt = inl(apm_base + APM_STS);
- break;
- case OSPM_REG_TYPE:
- pwr_cnt = inl(ospm_base + OSPM_PM_SSS);
- break;
- default:
- ret = -EINVAL;
- goto unlock;
- }
-
- pwr_mask = pwr_cnt;
- for (i = 0; i < OSPM_MAX_POWER_ISLANDS; i++) {
- lss = islands & (0x1 << i);
- if (lss) {
- mask = 0x3 << (2 * i);
- if (state_type == OSPM_ISLAND_DOWN)
- pwr_mask |= mask;
- else if (state_type == OSPM_ISLAND_UP)
- pwr_mask &= ~mask;
- }
- }
-
- if (pwr_mask != pwr_cnt) {
- switch (reg_type) {
- case APM_REG_TYPE:
- outl(pwr_mask, apm_base + APM_CMD);
- break;
- case OSPM_REG_TYPE:
- outl(pwr_mask, (ospm_base + OSPM_PM_SSC));
- break;
- }
-
- ret =
- wait_for_nc_pmcmd_complete(pwr_mask, state_type, reg_type);
- }
-
-unlock:
- spin_unlock_irqrestore(&nc_ready_lock, flags);
- return ret;
-}
-EXPORT_SYMBOL(pmu_nc_set_power_state);
-
-/**
- * pmu_pci_set_power_state - Callback function is used by all the PCI devices
- * for a platform specific device power on/shutdown.
- *
- */
-int __ref pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t state)
-{
- int i;
- u32 pm_cmd_val;
- u32 new_value;
- int sub_sys_pos, sub_sys_index;
- int pmu_num;
- struct pmu_ss_states cur_pmssc;
- int status = 0;
-
- /* while booting just ignore this callback from devices */
- /* If SCU is not okay, nothing to do */
- if (unlikely((dev_init_state == 0) || !scu_comms_okay))
- return status;
-
- /* Try to acquire the scu_ready_sem, if not
- * get blocked, until pmu_sc_irq() releases */
- down_scu_timed(&scu_ready_sem);
- interactive_cmd_sent = 1;
-
- status =
- pmu_pci_to_indexes(pdev, &i, &pmu_num, &sub_sys_index, &sub_sys_pos);
-
- if (status)
- goto unlock;
-
- state = pmu_pci_get_weakest_state_for_lss(i, pdev, state);
-
- /* store the display status */
- if (i == GFX_LSS_INDEX)
- display_off = (int)(state != PCI_D0);
-
- /*Update the Camera status per ISP Driver Suspended/Resumed */
- if (i == MFLD_ISP_POS)
- camera_off = (int)(state != PCI_D0);
-
- if (pmu_num == PMU_NUM_2) {
-
- /* initialize the current pmssc states */
- memset(&cur_pmssc, 0, sizeof(cur_pmssc));
-
- status = _pmu2_wait_not_busy();
-
- if (status)
- goto unlock;
-
- pmu_read_sss(&cur_pmssc);
-
- /* Add old s3_sss values, so we get complete list */
- if (unlikely(pmu_in_s3)) {
- cur_pmssc.pmu2_states[0] |= s3_sss[0];
- cur_pmssc.pmu2_states[1] |= s3_sss[1];
- cur_pmssc.pmu2_states[2] |= s3_sss[2];
- cur_pmssc.pmu2_states[3] |= s3_sss[3];
- }
-
- /* Read the pm_cmd val & update the value */
- pm_cmd_val =
- (D0I3_MASK << (sub_sys_pos * BITS_PER_LSS));
-
- /* First clear the LSS bits */
- new_value = cur_pmssc.pmu2_states[sub_sys_index] &
- (~pm_cmd_val);
-
- if (state != PCI_D0) {
- pm_cmd_val =
- (pci_2_mfld_state(state) <<
- (sub_sys_pos * BITS_PER_LSS));
-
- new_value |= pm_cmd_val;
- }
-
- /* nothing to do, so dont do it... */
- if (new_value == cur_pmssc.pmu2_states[sub_sys_index])
- goto unlock;
-
- cur_pmssc.pmu2_states[sub_sys_index] = new_value;
-
- /* set the lss positions that need
- * to be ignored to D0i0 */
- for (i = 0; i < 4; i++)
- cur_pmssc.pmu2_states[i] &= IGNORE_CFG[i];
-
- /* no need to issue command if s3 is in progress */
- if (likely(!pmu_in_s3)) {
- /* Issue the pmu command to PMU 2
- * flag is needed to distinguish between
- * S0ix vs interactive command in pmu_sc_irq()
- */
- status =
- _pmu_issue_command(&cur_pmssc, SET_MODE,
- 1, PMU_NUM_2);
-
- if (unlikely(status != PMU_SUCCESS)) {
- dev_dbg(&pmu_dev->dev,
- "Failed to Issue a PM command to PMU2\n");
- goto unlock;
- }
-
- /*
- * Wait for interactive command to complete.
- * If we dont wait, there is a possibility that
- * the driver may access the device before its
- * powered on in SCU.
- *
- */
- down_scu_timed(&set_mode_complete_sem);
-
- pmu_set_s0ix_possible(state);
- } else {
- /*
- * while s3 is in-progress we only
- * store these values and use those
- * to configure wakeup after s3
- */
- s3_sss[0] = cur_pmssc.pmu2_states[0];
- s3_sss[1] = cur_pmssc.pmu2_states[1];
- s3_sss[2] = cur_pmssc.pmu2_states[2];
- s3_sss[3] = cur_pmssc.pmu2_states[3];
- }
- }
-
-unlock:
- interactive_cmd_sent = 0;
- up(&scu_ready_sem);
- return status;
-}
-
-static int _pmu_issue_command(struct pmu_ss_states *pm_ssc, int mode, int ioc,
- int pmu_num)
-{
- union pmu_pm_set_cfg_cmd_t command;
- int sys_state = SYS_STATE_S0I0;
- struct cfg_mode_params cfg_mode_param;
- int status;
- u32 tmp;
-
- /* pmu_issue_command for PMU1 is an NOP */
- if (pmu_num == PMU_NUM_1)
- return 0;
-
- if (_pmu_read_status(PMU_NUM_2, PMU_BUSY_STATUS)) {
- dev_dbg(&pmu_dev->dev, "PMU2 is busy, Operation not"
- "permitted\n");
- return PMU_FAILED;
- }
-
-
- /* enable interrupts in PMU2 so that interrupts are
- * propagated when ioc bit for a particular set
- * command is set
- */
- /* Enable the hardware interrupt */
- tmp = readl(&pmu_reg->pm_ics);
- tmp |= 0x100;/* Enable interrupts */
- writel(tmp, &pmu_reg->pm_ics);
-
- switch (mode) {
- case SET_MODE:
- cfg_mode_param.cfg_mode = CM_IMMEDIATE;
- cfg_mode_param.cfg_trigger = NO_TRIG;
- cfg_mode_param.cfg_delay = 0;
- cfg_mode_param.cfg_trig_val = 0;
- cfg_mode_param.cfg_cmbi = 0;
- sys_state = SYS_STATE_S0I0;
- break;
- case SET_AOAC_S0i1:
- cfg_mode_param.cfg_mode = CM_TRIGGER;
- cfg_mode_param.cfg_trigger = C_STATE_TRANS_TRIG;
- cfg_mode_param.cfg_trig_val = ACK_C6_DMI_MSG;
- cfg_mode_param.cfg_delay = 0;
- cfg_mode_param.cfg_cmbi = 0;
- sys_state = SYS_STATE_S0I1;
- break;
- case SET_AOAC_S0i2:
- cfg_mode_param.cfg_mode = CM_TRIGGER;
- cfg_mode_param.cfg_trigger = C_STATE_TRANS_TRIG;
- cfg_mode_param.cfg_trig_val = ACK_C6_DMI_MSG;
- cfg_mode_param.cfg_delay = 0;
- cfg_mode_param.cfg_cmbi = 0;
- sys_state = SYS_STATE_S0I2;
- break;
- case SET_AOAC_S0i3:
- cfg_mode_param.cfg_mode = CM_TRIGGER;
- cfg_mode_param.cfg_trigger = C_STATE_TRANS_TRIG;
- cfg_mode_param.cfg_trig_val = ACK_C6_DMI_MSG;
- cfg_mode_param.cfg_delay = 0;
- cfg_mode_param.cfg_cmbi = 0;
- sys_state = SYS_STATE_S0I3;
- break;
- case SET_LPAUDIO:
- cfg_mode_param.cfg_mode = CM_TRIGGER;
- cfg_mode_param.cfg_trigger = LPM_EVENT_TRIG;
- cfg_mode_param.cfg_trig_val = PME_ID_USB;
- cfg_mode_param.cfg_delay = 0;
- cfg_mode_param.cfg_cmbi = 1;
- sys_state = SYS_STATE_S0I3;
- break;
- default:
- WARN_ON(1);
- status = PMU_FAILED;
- goto ret;
- }
-
- /* Configure the sub systems for pmu2 */
- pmu_write_subsys_config(pm_ssc);
-
- /* Configre the parameters required for config mode */
- status =
- pmu_set_cfg_mode_params(&cfg_mode_param, &command, PMU_NUM_2);
- if (status != PMU_SUCCESS)
- goto ret;
-
- /* Send the set config command for pmu1 its configured
- * for mode CM_IMMEDIATE & hence with No Trigger
- */
- status =
- pmu_send_set_config_command(&command, ioc, sys_state, PMU_NUM_2);
-
-ret:
- return status;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int pmu_devices_state_show(struct seq_file *s, void *unused)
-{
- struct pci_dev *pdev = NULL;
- int index, i, pmu_num, ss_idx, ss_pos;
- unsigned int base_class;
- u32 mask, val, needed;
- struct pmu_ss_states cur_pmsss;
- char *dstates[] = {"D0", "D0i1", "D0i2", "D0i3"};
-
- /* Acquire the scu_ready_sem */
- down_scu_timed(&scu_ready_sem);
-
- if (_pmu2_wait_not_busy())
- goto unlock;
-
- pmu_read_sss(&cur_pmsss);
-
- seq_printf(s, "TARGET_CFG: ");
- for (i = 0; i < 4; i++)
- seq_printf(s, "%08X ", TARGET_CFG[i]);
-
- seq_printf(s, "\n");
- seq_printf(s, "SSS: ");
-
- for (i = 0; i < 4; i++)
- seq_printf(s, "%08lX ", cur_pmsss.pmu2_states[i]);
-
- if (!display_off)
- seq_printf(s, "display not suspended: blocking s0ix\n");
- else if (!camera_off)
- seq_printf(s, "camera not suspended: blocking s0ix\n");
- else if (s0i3_possible)
- seq_printf(s, "can enter s0i1 or s0i3\n");
- else if (lpmp3_possible)
- seq_printf(s, "can enter lpmp3\n");
- else
- seq_printf(s, "blocking s0ix\n");
-
- seq_printf(s, "cmd_error_int count: %d\n", cmd_error_int);
- seq_printf(s, "c6_demotion count: %d\n", c6_demoted);
-
- seq_printf(s,
- "\tcount\tsybsys_pow\ts0ix_miss\tno_ack_c6\ttime (secs)\tlast_entry");
- seq_printf(s, "\tfirst_entry\tresidency(%%)\n");
-
- pmu_stat_seq_printf(s, SYS_STATE_S0I1, "s0i1");
- pmu_stat_seq_printf(s, SYS_STATE_S0I2, "lpmp3");
- pmu_stat_seq_printf(s, SYS_STATE_S0I3, "s0i3");
- pmu_stat_seq_printf(s, SYS_STATE_S3, "s3");
-
- while ((pdev = pci_get_device(PCI_ID_ANY, PCI_ID_ANY, pdev)) != NULL) {
-
- /* find the base class info */
- base_class = pdev->class >> 16;
-
- if (base_class == PCI_BASE_CLASS_BRIDGE)
- continue;
-
- if (pmu_pci_to_indexes(pdev, &index, &pmu_num, &ss_idx,
- &ss_pos))
- continue;
-
- if (pmu_num == PMU_NUM_1)
- continue;
-
- mask = (D0I3_MASK << (ss_pos * BITS_PER_LSS));
- val = (cur_pmsss.pmu2_states[ss_idx] & mask) >>
- (ss_pos * BITS_PER_LSS);
- needed = ((TARGET_CFG[ss_idx] & mask) != 0);
-
- seq_printf(s, "pci %04x %04X %s %20s: lss:%02d reg:%d"
- "mask:%08X wk:% 8d %s %s\n",
- pdev->vendor, pdev->device, dev_name(&pdev->dev),
- dev_driver_string(&pdev->dev),
- index-pmu1_max_devs, ss_idx, mask, num_wakes[index],
- dstates[val&3],
- (needed && !val) ? "blocking s0ix" : "");
-
- }
-
-unlock:
- up(&scu_ready_sem);
- return 0;
-}
-
-static int devices_state_open(struct inode *inode, struct file *file)
-{
- return single_open(file, pmu_devices_state_show, NULL);
-}
-
-static ssize_t devices_state_write(struct file *file,
- const char __user *userbuf, size_t count, loff_t *ppos)
-{
- char buf[32];
- int buf_size = min(count, sizeof(buf)-1);
-
- if (copy_from_user(buf, userbuf, buf_size))
- return -EFAULT;
-
- /* Acquire the scu_ready_sem */
- down_scu_timed(&scu_ready_sem);
-
- buf[buf_size] = 0;
-
- if (((strlen("clear")+1) == buf_size) &&
- !strncmp(buf, "clear", strlen("clear"))) {
- memset(pmu_stats, 0,
- (sizeof(struct mid_pmu_stats)*SYS_STATE_S5));
- memset(num_wakes, 0, sizeof(int)*MAX_DEVICES);
- cmd_error_int = c6_demoted = 0;
- pmu_current_state = SYS_STATE_S0I0;
- pmu_init_time =
- cpu_clock(raw_smp_processor_id());
- }
-
- up(&scu_ready_sem);
-
- return buf_size;
-}
-
-static const struct file_operations devices_state_operations = {
- .open = devices_state_open,
- .read = seq_read,
- .write = devices_state_write,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static struct lss_definition {
- char *lss_name;
- char *block;
- char *subsystem;
-} medfield_lsses[] = {
- {"Lss00", "Storage", "SDIO0 (HC2)"},
- {"Lss01", "Storage", "eMMC0 (HC0a)"},
- {"NA", "Storage", "ND_CTL (Note 5)"},
- {"Lss03", "H S I", "H S I DMA"},
- {"Lss04", "Security", "RNG"},
- {"Lss05", "Storage", "eMMC1 (HC0b)"},
- {"Lss06", "USB", "USB OTG (ULPI)"},
- {"NA", "USB", "USB HSIC (Host) (Note 5)"},
- {"Lss08", "Audio", ""},
- {"Lss09", "Audio", ""},
- {"Lss10", "SRAM", " SRAM CTL+SRAM_16KB"},
- {"Lss11", "SRAM", " SRAM CTL+SRAM_16KB"},
- {"Lss12", "SRAM", "SRAM BANK (16KB+3x32KBKB)"},
- {"Lss13", "SRAM", "SRAM BANK(4x32KB)"},
- {"Lss14", "SDIO COMMS", "SDIO2 (HC1b)"},
- {"Lss15", "PTI, DAFCA", " DFX Blocks"},
- {"Lss16", "SC", " DMA"},
- {"NA", "SC", "SPI0/MSIC"},
- {"Lss18", "GP", "SPI1"},
- {"Lss19", "GP", " SPI2"},
- {"Lss20", "GP", " I2C0"},
- {"Lss21", "GP", " I2C1"},
- {"NA", "Fabrics", " Main Fabric"},
- {"NA", "Fabrics", " Secondary Fabric"},
- {"NA", "SC", "SC Fabric"},
- {"Lss25", "Audio", " I-RAM BANK1 (32 + 256KB)"},
- {"NA", "SCU", " ROM BANK1 (18KB+18KB+18KB)"},
- {"Lss27", "GP", "I2C2"},
- {"NA", "SSC", "SSC (serial bus controller to FLIS)"},
- {"Lss29", "Security", "Chaabi AON Registers"},
- {"Lss30", "SDIO COMMS", "SDIO1 (HC1a)"},
- {"NA", "SCU", "I-RAM BANK0 (32KB)"},
- {"NA", "SCU", "I-RAM BANK1 (32KB)"},
- {"Lss33", "GP", "I2C3 (HDMI)"},
- {"Lss34", "GP", "I2C4"},
- {"Lss35", "GP", "I2C5"},
- {"Lss36", "GP", "SSP (SPI3)"},
- {"Lss37", "GP", "GPIO1"},
- {"NA", "GP", "GP Fabric"},
- {"Lss39", "SC", "GPIO0"},
- {"Lss40", "SC", "KBD"},
- {"Lss41", "SC", "UART2:0"},
- {"NA", "NA", "NA"},
- {"NA", "NA", "NA"},
- {"Lss44", "Security", " Security TAPC"},
- {"NA", "MISC", "AON Timers"},
- {"NA", "PLL", "LFHPLL and Spread Spectrum"},
- {"NA", "PLL", "USB PLL"},
- {"Lss48", "Audio", " SSP2 (I2S2)"},
- {"NA", "Audio", "SLIMBUS CTL 1 (note 5)"},
- {"NA", "Audio", "SLIMBUS CTL 2 (note 5)"},
- {"Lss51", "Audio", "SSP0"},
- {"Lss52", "Audio", "SSP1"},
- {"NA", "Bridge", "IOSF to OCP Bridge"},
- {"Lss54", "GP", "DMA"},
- {"NA", "SC", "SVID (Serial Voltage ID)"},
- {"NA", "SOC Fuse", "SoC Fuse Block (note 3)"},
- {"NA", "NA", "NA"},
-};
-
-static int medfield_lsses_num =
- sizeof(medfield_lsses)/sizeof(medfield_lsses[0]);
-
-static char *lss_device_status[4] = { "D0i0", "D0i1", "D0i2", "D0i3" };
-
-static int show_pmu_lss_status(struct seq_file *s, void *unused)
-{
- int sss_reg_index;
- int offset;
- int lss;
- unsigned long status;
- unsigned long sub_status;
- unsigned long lss_status[4];
- struct lss_definition *entry;
-
- /* Acquire the scu_ready_sem */
- down_scu_timed(&scu_ready_sem);
-
- lss_status[0] = readl(&pmu_reg->pm_sss[0]);
- lss_status[1] = readl(&pmu_reg->pm_sss[1]);
- lss_status[2] = readl(&pmu_reg->pm_sss[2]);
- lss_status[3] = readl(&pmu_reg->pm_sss[3]);
- lss = 0;
- seq_printf(s, "%5s\t%12s %35s %4s\n",
- "lss", "block", "subsystem", "state");
- seq_printf(s, "==========================================================\n");
- for (sss_reg_index = 0; sss_reg_index < 4; sss_reg_index++) {
- status = lss_status[sss_reg_index];
- for (offset = 0; offset < sizeof(unsigned long) * 8 / 2;
- offset++) {
- sub_status = status & 3;
- if (lss >= medfield_lsses_num)
- entry = &medfield_lsses[medfield_lsses_num - 1];
- else
- entry = &medfield_lsses[lss];
- seq_printf(s, "%5s\t%12s %35s %4s\n",
- entry->lss_name, entry->block,
- entry->subsystem,
- lss_device_status[sub_status]);
- status >>= 2;
- lss++;
- }
- }
-
- up(&scu_ready_sem);
-
- return 0;
-}
-
-static int pmu_sss_state_open(struct inode *inode, struct file *file)
-{
- return single_open(file, show_pmu_lss_status, NULL);
-}
-
-static const struct file_operations pmu_sss_state_operations = {
- .open = pmu_sss_state_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-#endif /* DEBUG_FS */
-
-/* Reads the status of each driver and updates the LSS values.
- * To be called with scu_ready_sem mutex held, and pmu_config
- * initialized with '0's
- */
-static void update_all_lss_states(struct pmu_ss_states *pmu_config)
-{
- int i;
- u32 PCIALLDEV_CFG[4] = {0, 0, 0, 0};
-
- for (i = 0; i < MAX_DEVICES; i++) {
- int pmu_num =
- intel_mid_pci_devices[i].pmu_num;
- struct pci_dev *pdev =
- intel_mid_pci_devices[i].dev_driver[0];
-
- if ((pmu_num == PMU_NUM_2) && pdev) {
- int ss_idx, ss_pos;
- pci_power_t state;
-
- ss_idx = intel_mid_pci_devices[i].ss_idx;
- ss_pos = intel_mid_pci_devices[i].ss_pos;
-
- /* By default its set to '0' hence
- * no need to update PCI_D0 state
- */
- state = pmu_pci_get_weakest_state_for_lss
- (i, pdev, pdev->current_state);
-
- pmu_config->pmu2_states[ss_idx] |=
- (pci_2_mfld_state(state) << (ss_pos * BITS_PER_LSS));
-
- PCIALLDEV_CFG[ss_idx] |=
- (D0I3_MASK << (ss_pos * BITS_PER_LSS));
- }
- }
-
- /* We shutdown devices that are in the target config, and that are
- not in the pci table, some devices are indeed not advertised in pci
- table for certain firmwares. This is the case for HSI firmwares,
- SPI3 device is not advertised, and would then prevent s0i3. */
- for (i = 0; i < 4; i++)
- pmu_config->pmu2_states[i] |=
- TARGET_CFG[i] & (~PCIALLDEV_CFG[i]);
-}
-
-static pci_power_t _pmu_choose_state(int device_lss)
-{
- pci_power_t state;
-
- switch (device_lss) {
- case PMU_SECURITY_LSS_04:
- state = PCI_D2;
- break;
-
- case PMU_USB_OTG_LSS_06:
- case PMU_USB_HSIC_LSS_07:
- case PMU_UART2_LSS_41:
- state = PCI_D1;
- break;
-
- default:
- state = PCI_D3hot;
- break;
- }
-
- return state;
-}
-
-static int pmu_init(void)
-{
- int i, status;
- struct pmu_ss_states pmu_config;
- pci_power_t state;
- struct pmu_suspend_config *ss_config;
-
- dev_dbg(&pmu_dev->dev, "PMU Driver loaded\n");
- spin_lock_init(&nc_ready_lock);
-
- /* initialise s0ix lss list */
- for (i = 0; i < (sizeof(s0ix_lss)/sizeof(u8)); i++) {
- TARGET_CFG[s0ix_lss[i]/ss_per_reg] |=
- (D0I3_MASK << (s0ix_lss[i]%ss_per_reg * BITS_PER_LSS));
-
- state = _pmu_choose_state(s0ix_lss[i]);
- s0ix_target[s0ix_lss[i]/ss_per_reg] |=
- (pci_2_mfld_state(state)
- << (s0ix_lss[i]%ss_per_reg * BITS_PER_LSS));
- }
-
- /* initialise lpmp3 lss list */
- for (i = 0; i < (sizeof(lpmp3_lss)/sizeof(u8)); i++) {
- LPMP3_CFG[lpmp3_lss[i]/ss_per_reg] |=
- (D0I3_MASK << (lpmp3_lss[i]%ss_per_reg * BITS_PER_LSS));
-
- state = _pmu_choose_state(lpmp3_lss[i]);
- lpmp3_target[lpmp3_lss[i]/ss_per_reg] |=
- (pci_2_mfld_state(state)
- << (lpmp3_lss[i]%ss_per_reg * BITS_PER_LSS));
- }
-
- /* initialise ignore lss list */
- for (i = 0; i < (sizeof(lss_to_ignore)/sizeof(u8)); i++)
- IGNORE_CFG[lss_to_ignore[i]/ss_per_reg] |=
- (D0I3_MASK << (lss_to_ignore[i]%ss_per_reg * BITS_PER_LSS));
-
- /* All ignored lss should be in D0i0 */
- for (i = 0; i < 4; i++)
- IGNORE_CFG[i] = ~IGNORE_CFG[i];
-
- /* initialise ignore wkc lss list */
- for (i = 0; i < (sizeof(ignore_lss_in_wkc)/sizeof(u8)); i++)
- IGNORE_WKC_S3_CFG[ignore_lss_in_wkc[i]/32] |=
- (1 << (ignore_lss_in_wkc[i]%32));
-
- /* All ignored lss should be in non wakable state */
- for (i = 0; i < 2; i++)
- IGNORE_WKC_S3_CFG[i] = ~IGNORE_WKC_S3_CFG[i];
-
- /* initialise s0i1 sss list */
- for (i = 0; i < (sizeof(s0i1_sss_lss)/sizeof(u8)); i++) {
- state = _pmu_choose_state(s0i1_sss_lss[i]);
- s0i1_sss[s0i1_sss_lss[i]/ss_per_reg] |= (pci_2_mfld_state(state)
- << (s0i1_sss_lss[i]%ss_per_reg * BITS_PER_LSS));
- }
-
- /* initialise s0i3 sss list */
- for (i = 0; i < (sizeof(s0i3_sss_lss)/sizeof(u8)); i++) {
- state = _pmu_choose_state(s0i3_sss_lss[i]);
- s0i3_sss[s0i3_sss_lss[i]/ss_per_reg] |= (pci_2_mfld_state(state)
- << (s0i3_sss_lss[i]%ss_per_reg * BITS_PER_LSS));
- }
-
- /* initialise lpmp3 sss list */
- for (i = 0; i < (sizeof(lpmp3_sss_lss)/sizeof(u8)); i++) {
- state = _pmu_choose_state(lpmp3_sss_lss[i]);
- lpmp3_sss[lpmp3_sss_lss[i]/ss_per_reg] |=
- (pci_2_mfld_state(state) <<
- (lpmp3_sss_lss[i]%ss_per_reg * BITS_PER_LSS));
- }
-
- /* enumerate the PCI configuration space */
- pmu_enumerate();
-
-#ifdef CONFIG_DEBUG_FS
- /* /sys/kernel/debug/mid_pmu_states */
- (void) debugfs_create_file("mid_pmu_states", S_IFREG | S_IRUGO,
- NULL, NULL, &devices_state_operations);
-
- /* /sys/kernel/debug/pmu_sss_states */
- (void) debugfs_create_file("pmu_sss_states", S_IFREG | S_IRUGO,
- NULL, NULL, &pmu_sss_state_operations);
-#endif
-
- /* initialize the state variables here */
- intel_mid_pmu_base.disable_cpu1 = false;
-
- intel_mid_pmu_base.ss_config =
- kzalloc(sizeof(struct pmu_suspend_config), GFP_KERNEL);
-
- if (intel_mid_pmu_base.ss_config == NULL) {
- dev_dbg(&pmu_dev->dev, "Allocation of memory"
- "for ss_config has failed\n");
- status = PMU_FAILED;
- goto out_err1;
- }
-
- memset(&pmu_config, 0, sizeof(pmu_config));
-
- intel_mid_pmu_base.ss_config->ss_state = pmu_config;
-
- /* initialize for the autonomous S0i3 */
- ss_config = intel_mid_pmu_base.ss_config;
-
- /* setup the wake capable devices */
- intel_mid_pmu_base.ss_config->wake_state.wake_enable[0] =
- WAKE_ENABLE_0;
- intel_mid_pmu_base.ss_config->wake_state.wake_enable[1] =
- WAKE_ENABLE_1;
-
- /* Acquire the scu_ready_sem */
- down_scu_timed(&scu_ready_sem);
-
- /* Now we have initialized the driver
- * Allow drivers to get blocked in
- * pmu_pci_set_power_state(), until we finish
- * first interactive command.
- */
- dev_init_state = 1;
-
- /* get the current status of each of the driver
- * and update it in SCU
- */
- update_all_lss_states(&pmu_config);
-
- /* send a interactive command to fw */
- interactive_cmd_sent = 1;
- status = _pmu_issue_command(&pmu_config, SET_MODE, 1, PMU_NUM_2);
- if (status != PMU_SUCCESS) {
- interactive_cmd_sent = 0;
- dev_dbg(&pmu_dev->dev,\
- "Failure from pmu mode change to interactive."
- " = %d\n", status);
- status = PMU_FAILED;
- up(&scu_ready_sem);
- goto out_err1;
- }
-
- /*
- * Wait for interactive command to complete.
- * If we dont wait, there is a possibility that
- * the driver may access the device before its
- * powered on in SCU.
- *
- */
- down_scu_timed(&set_mode_complete_sem);
-
- /* In cases were gfx is not enabled
- * this will enable s0ix immediately
- */
- pmu_set_s0ix_possible(PCI_D3hot);
-
- up(&scu_ready_sem);
-
-out_err1:
- return status;
-}
-
-/**
- * mid_pmu_probe - This is the function where most of the PMU driver
- * initialization happens.
- */
-static int __devinit mid_pmu_probe(struct pci_dev *dev,
- const struct pci_device_id *pci_id)
-{
- int ret;
- struct mrst_pmu_reg __iomem *pmu;
-
-#ifdef CONFIG_HAS_WAKELOCK
- wake_lock_init(&pmu_wake_lock, WAKE_LOCK_SUSPEND, "mid_pmu");
-#endif
-
- /* Init the device */
- ret = pci_enable_device(dev);
- if (ret) {
- pr_err("Mid PM device cant be enabled\n");
- goto out_err0;
- }
-
- /* store the dev */
- pmu_dev = dev;
-
- ret = pci_request_regions(dev, PMU_DRV_NAME);
- if (ret < 0) {
- pr_err("pci request region has failed\n");
- goto out_err1;
- }
-
- if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
- pmu1_max_devs = PMU1_MAX_PENWELL_DEVS;
- pmu2_max_devs = PMU2_MAX_PENWELL_DEVS;
- ss_per_reg = 16;
- } else {
- pmu1_max_devs = PMU1_MAX_MRST_DEVS;
- pmu2_max_devs = PMU2_MAX_MRST_DEVS;
- ss_per_reg = 8;
- }
-
- /* Map the NC PM registers */
- apm_base = MDFLD_MSG_READ32(OSPM_PUNIT_PORT, OSPM_APMBA) & 0xffff;
- ospm_base = MDFLD_MSG_READ32(OSPM_PUNIT_PORT, OSPM_OSPMBA) & 0xffff;
-
- /* Map the memory of pmu1 PMU reg base */
- pmu = pci_iomap(dev, 0, 0);
- if (pmu == NULL) {
- dev_dbg(&pmu_dev->dev, "Unable to map the PMU2 address"
- "space\n");
- ret = PMU_FAILED;
- goto out_err2;
- }
-
- pmu_reg = pmu;
-
- if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
- /* Map the memory of offload_reg */
- base_addr.offload_reg = ioremap_nocache(0xffd01ffc, 4);
- if (base_addr.offload_reg == NULL) {
- dev_dbg(&pmu_dev->dev,
- "Unable to map the offload_reg address space\n");
- ret = PMU_FAILED;
- goto out_err3;
- }
- }
-
- if (request_irq(dev->irq, pmu_sc_irq, IRQF_NO_SUSPEND, PMU_DRV_NAME,
- NULL)) {
- dev_dbg(&pmu_dev->dev, "Registering isr has failed\n");
- ret = PMU_FAILED;
- goto out_err3;
- }
-
- /* call pmu init() for initialization of pmu interface */
- ret = pmu_init();
- if (ret != PMU_SUCCESS) {
- dev_dbg(&pmu_dev->dev, "PMU initialization has failed\n");
- goto out_err4;
- }
-
- pmu_init_time =
- cpu_clock(raw_smp_processor_id());
-
- return 0;
-
-out_err4:
- free_irq(dev->irq, &pmu_sc_irq);
-out_err3:
- pci_iounmap(dev, base_addr.pmu2_base);
- base_addr.pmu2_base = NULL;
-out_err2:
- base_addr.pmu1_base = NULL;
-out_err1:
- pci_release_region(dev, 0);
- pci_disable_device(dev);
-out_err0:
-#ifdef CONFIG_HAS_WAKELOCK
- wake_unlock(&pmu_wake_lock);
-#endif
- return ret;
-}
-
-static void __devexit mid_pmu_remove(struct pci_dev *dev)
-{
- dev_dbg(&pmu_dev->dev, "Mid PM mid_pmu_remove called\n");
-
- /* Freeing up the irq */
- free_irq(dev->irq, &pmu_sc_irq);
-
- /* Freeing up memory allocated for PMU1 & PMU2 */
- if (__mrst_cpu_chip == MRST_CPU_CHIP_PENWELL) {
- iounmap(base_addr.offload_reg);
- base_addr.offload_reg = NULL;
- }
- pci_iounmap(dev, pmu_reg);
- base_addr.pmu1_base = NULL;
- base_addr.pmu2_base = NULL;
-
- /* disable the current PCI device */
- pci_release_region(dev, 0);
- pci_disable_device(dev);
-}
-
-static struct pci_driver driver = {
- .name = PMU_DRV_NAME,
- .id_table = mid_pm_ids,
- .probe = mid_pmu_probe,
- .remove = __devexit_p(mid_pmu_remove),
-};
-
-/* return platform specific deepest states that the device can enter */
-pci_power_t pmu_pci_choose_state(struct pci_dev *pdev)
-{
- int i;
- int sub_sys_pos, sub_sys_index;
- int status;
- int device_lss;
- int pmu_num;
-
- pci_power_t state = PCI_D3hot;
-
- if (dev_init_state) {
- status =
- pmu_pci_to_indexes(pdev, &i, &pmu_num,
- &sub_sys_index, &sub_sys_pos);
-
- if ((status == PMU_SUCCESS) &&
- (pmu_num == PMU_NUM_2)) {
-
- device_lss = (sub_sys_index * ss_per_reg) + sub_sys_pos;
-
- state = _pmu_choose_state(device_lss);
- }
- }
-
- return state;
-}
-EXPORT_SYMBOL(pmu_pci_choose_state);
-
-bool pmu_pci_power_manageable(struct pci_dev *dev)
-{
- return true;
-}
-EXPORT_SYMBOL(pmu_pci_power_manageable);
-
-/* At this point of time we expect all devices to be
- * wake capable will be modified in future
- */
-bool pmu_pci_can_wakeup(struct pci_dev *dev)
-{
- return true;
-}
-EXPORT_SYMBOL(pmu_pci_can_wakeup);
-
-int pmu_pci_sleep_wake(struct pci_dev *dev, bool enable)
-{
- return 0;
-}
-EXPORT_SYMBOL(pmu_pci_sleep_wake);
-
-static int mfld_s3_enter(void)
-{
- u32 ssw_val = 0;
- int num_retry = 15000;
- int status = 0;
-
- /* check if we can acquire scu_ready_sem
- * if we are not able to then do a c6 */
- if (down_trylock(&scu_ready_sem)) {
- status = -EINVAL;
- goto ret;
- }
-
- /* If PMU is busy, we'll retry on next C6 */
- if (unlikely(_pmu_read_status(PMU_NUM_2, PMU_BUSY_STATUS))) {
- up(&scu_ready_sem);
- status = -EINVAL;
- goto ret;
- }
-
- /* setup the wake capable devices */
- writel(IGNORE_WKC_S3_CFG[0], &pmu_reg->pm_wkc[0]);
- writel(IGNORE_WKC_S3_CFG[1], &pmu_reg->pm_wkc[1]);
-
- /* Re-program the sub systems state on wakeup as the current SSS*/
- writel(s3_sss[0], &pmu_reg->pm_wssc[0]);
- writel(s3_sss[1], &pmu_reg->pm_wssc[1]);
- writel(s3_sss[2], &pmu_reg->pm_wssc[2]);
- writel(s3_sss[3], &pmu_reg->pm_wssc[3]);
-
- /* program pm ssc registers */
- writel(s0i3_sss[0], &pmu_reg->pm_ssc[0]);
- writel(s0i3_sss[1], &pmu_reg->pm_ssc[1]);
- writel(s0i3_sss[2], &pmu_reg->pm_ssc[2]);
- writel(s0i3_sss[3], &pmu_reg->pm_ssc[3]);
-
- /* issue a command to SCU */
- writel(S0I3_VALUE, &pmu_reg->pm_cmd);
-
- /* If s0i3 command is issued
- * then wait for c6 sram offload
- * to complete */
- do {
- ssw_val = readl(base_addr.offload_reg);
-
- if ((ssw_val & C6OFFLOAD_BIT_MASK) == C6OFFLOAD_BIT)
- break;
-
- } while (num_retry--);
-
- if (unlikely((ssw_val & C6OFFLOAD_BIT_MASK) != C6OFFLOAD_BIT)) {
- status = -EINVAL;
- pmu_stat_clear();
- WARN(1, "mid_pmu: error cpu offload bit not set.\n");
- } else {
- unsigned long ecx = 1; /* break on interrupt flag */
- unsigned long eax = C6_HINT;
- u32 temp = 0;
- pmu_stat_start(SYS_STATE_S3);
-
- /* issue c6 offload */
- wrmsr(MSR_C6OFFLOAD_CTL_REG,
- MSR_C6OFFLOAD_SET_LOW, MSR_C6OFFLOAD_SET_HIGH);
-
- __monitor((void *) &temp, 0, 0);
- smp_mb();
-
- s0ix_entered = 1;
- __mwait(eax, ecx);
- pmu_enable_forward_msi();
- }
-
-ret:
- return status;
-}
-
-static int mid_valid(suspend_state_t state)
-{
- switch (state) {
- case PM_SUSPEND_ON:
- case PM_SUSPEND_MEM:
- return 1;
- default:
- return 0;
- }
-}
-
-static int mid_prepare(void)
-{
- memset(s3_sss, 0, sizeof(s3_sss));
- pmu_in_s3 = 1;
- return 0;
-}
-
-static int mid_prepare_late(void)
-{
- return 0;
-}
-
-static int mid_suspend(suspend_state_t state)
-{
- int ret;
-
- if (state != PM_SUSPEND_MEM)
- ret = -EINVAL;
-
- trace_printk("s3_entry\n");
- ret = mfld_s3_enter();
- trace_printk("s3_exit %d\n", ret);
- if (ret != 0)
- dev_dbg(&pmu_dev->dev, "Failed to enter S3 status: %d\n", ret);
-
- return ret;
-}
-
-static void mid_wake(void)
-{
- pmu_in_s3 = 0;
-}
-
-static void mid_finish(void)
-{
- pmu_in_s3 = 0;
-}
-
-static void mid_end(void)
-{
-#ifdef CONFIG_HAS_WAKELOCK
- /* Prime the wakelock system to re-suspend after giving other
- * threads a chance to wake up and acquire wake lock
- * this avoids to put wake lock in other things like pwrbutton
- */
- long timeout = HZ;
- wake_lock_timeout(&pmu_wake_lock, timeout);
-#endif
-}
-
-static struct platform_suspend_ops mid_suspend_ops = {
- .valid = mid_valid,
- .prepare = mid_prepare,
- .prepare_late = mid_prepare_late,
- .enter = mid_suspend,
- .wake = mid_wake,
- .finish = mid_finish,
- .end = mid_end,
-};
-
-/**
- * mid_pci_register_init - register the PMU driver as PCI device
- */
-static int __init mid_pci_register_init(void)
-{
- int ret;
-
- /* registering PCI device */
- ret = pci_register_driver(&driver);
- suspend_set_ops(&mid_suspend_ops);
-
- return ret;
-}
-device_initcall(mid_pci_register_init);
-
-static void __exit mid_pci_cleanup(void)
-{
- suspend_set_ops(NULL);
- /* registering PCI device */
- pci_unregister_driver(&driver);
-}
-module_exit(mid_pci_cleanup);
+++ /dev/null
-/*
- * mid_pmu.h
- * Copyright (c) 2010, 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 _MID_PMU_H_
-#define _MID_PMU_H_
-
-#include <linux/intel_mid_pm.h>
-
-#define PCI_ID_ANY (~0)
-
-/* P Unit Memory Map */
-
-/* PMU1 Register */
-#define PMU1_PMU_BASE_ADDR 0x940
-#define PMU2_PMU_BASE_ADDR 0xFF11D000
-
-/* PMU register memory map */
-
-/* PMU1/PMU2 PM Status Reg */
-#define PMU_PM_STS_REG 0x00
-/* PMU1/PMU2 PM Command Reg */
-#define PMU_PM_CMD_REG 0x04
-/* PMU1/PMU2 PM Interrupt Control and Status Reg */
-#define PMU_PM_ICS_REG 0x08
-/* PMU1/PMU2 PM subsystem configuration register */
-#define PMU_PM_SSC_REG0 0x20
-#define PMU_PM_SSC_REG1 0x24
-#define PMU_PM_SSC_REG2 0x28
-#define PMU_PM_SSC_REG3 0x2C
-/* PMU1/PMU2 PM Subsystem status Reg */
-#define PMU_PM_SSS_REG0 0x30
-#define PMU_PM_SSS_REG1 0x34
-#define PMU_PM_SSS_REG2 0x38
-#define PMU_PM_SSS_REG3 0x3C
-/* PMU2 PM Wake Control */
-#define PMU_PM_WKC_REG0 0x10
-#define PMU_PM_WKC_REG1 0x14
-/* PMU2 PM Wake Status Reg */
-#define PMU_PM_WKS_REG0 0x18
-#define PMU_PM_WKS_REG1 0x1C
-/* PMU2 PM Wake Status Reg */
-#define PMU_PM_WSSC_REG0 0x40
-#define PMU_PM_WSSC_REG1 0x44
-#define PMU_PM_WSSC_REG2 0x48
-#define PMU_PM_WSSC_REG3 0x4C
-/* PMU2 PM Subsystem status Reg */
-#define PMU_PM_C3C4_REG 0x50
-/* PMU2 PM Subsystem status Reg */
-#define PMU_PM_C5C6_REG 0x54
-/* PMU2 PM Subsystem status Reg */
-#define PMU_PM_MSIC_REG 0x58
-
-#define ACK_C6_DMI_MSG 0xC2
-#define MODE_ID_MAGIC_NUM 1
-#define PMU1_END_ADDRESS 0x34
-#define PMU2_END_ADDRESS 0x3B8
-
-#define PMU2_SS_CFG_MASK 0x00FFFFFF
-#define PMU2_WAKE_CFG_MASK 0x00000FFF
-#define WAKE_CTRL_DEFAULT 0x1C2
-
-/* PM table definitions */
-#define PM_TABLE_BASE 0x1D000
-#define PM_TABLE_PMU1_OFFSET 0x0
-#define PM_TABLE_PMU2_OFFSET 0x0
-#define PM_TABLE_PMU2_LOG_TO_PHY_MAP 0x0
-#define PM_TABLE_MAX 0xF0
-#define PM_TABLE_THRESH_MASK 0xFFFF
-
-/* Inactivity register definitions */
-#define PMU_INA_INT_STS_REG 0x220
-#define PMU_INA_THRESH_BASE 0x240
-#define PMU_INA_CTR_BASE 0x340
-#define PMU_INA_STS_REG 0x210
-#define PMU_INA_INVALID_SRC 0xFF
-#define PMU_INA_CTR_MAX 32
-#define SINGLE_BIT_MASK 0x1
-
-/* External timers register definitions */
-#define PMU2_EXT_TIMERS_BASE 0xff11B800
-#define PMU2_EXT_TIMERS_BASE_MAX 0xB0
-#define PMU2_EXT_TIMERS_MAX 8
-#define PMU2_EXT_TIMERS_0_OFFSET 0x14
-#define PMU2_EXT_TIMERS_LOAD_COUNT_REG 0x0
-#define PMU2_EXT_TIMERS_CUR_VAL_REG 0x4
-#define PMU2_EXT_TIMERS_CTRL_REG 0x8
-#define PMU2_EXT_TIMERS_EOI_REG 0xC
-#define PMU2_EXT_TIMERS_INT_STATUS_REG 0x10
-#define PMU2_EXT_TIMERS_GLB_INT_STATUS_REG 0xa0
-#define PMU2_EXT_TIMERS_GLB_EOI_REG 0xa4
-#define PMU2_EXT_TIMERS_RAW_INT_STATUS_REG 0xa8
-#define PMU2_EXT_TIMERS_COMP_VER 0xac
-#define TIMER_COUNT_ALL_ONES 0xFFFFFFFF
-#define TIMER_IS_MASKED 0x4
-#define TIMER_IS_NOT_MASKED 0x3
-#define TIMER_FREE_RUNNING_MODE 0x5
-#define TIMER_USER_DEFINED_MODE 0x2
-#define TIMER_EN_VAL 0x1
-
-/* Definitions used for Enumeration */
-#define SFI_PCI_CFG_START 0x80000000
-#define SFI_PCI_CFG_SIZE 256
-#define PMU1_DEV_MASK 0x3FFF
-#define PMU2_DEV_MASK 0x3FFFFFFF
-#define PM_SUPPORT 0x21
-#define LOG_ID_MASK 0x7F
-#define SUB_CLASS_MASK 0xFF00
-
-/* Definitions for Message Bus Interface */
-#define MSG_CMD_REG 0xD0
-#define MSG_DATA_REG 0xD4
-
-/* Definition for C6 Offload MSR Address */
-#define MSR_C6OFFLOAD_CTL_REG 0x120
-
-#define MSR_C6OFFLOAD_SET_LOW 1
-#define MSR_C6OFFLOAD_SET_HIGH 0
-
-#define MSR_C6OFFLOAD_CLEAR_LOW 0
-#define MSR_C6OFFLOAD_CLEAR_HIGH 0
-
-#define C6OFFLOAD_BIT_MASK 0x2
-#define C6OFFLOAD_BIT 0x2
-
-/* Need to be changed after PMU driver is added as PCI device */
-#define MID_PMU_MRST_DRV_DEV_ID 0x0810
-#define MID_PMU_MFLD_DRV_DEV_ID 0x0828
-
-#define PMU_DRV_NAME "intel_pmu_driver"
-
-#define MID_PCI_INDEX_HASH_BITS 7 /*size 128*/
-#define MID_PCI_INDEX_HASH_SIZE (1<<MID_PCI_INDEX_HASH_BITS)
-#define MID_PCI_INDEX_HASH_MASK (MID_PCI_INDEX_HASH_SIZE-1)
-
-/* some random number for initvalue */
-#define MID_PCI_INDEX_HASH_INITVALUE 0x27041975
-
-#define S0I1_VALUE 0X30992601
-#define LPMP3_VALUE 0X40492601
-#define S0I3_VALUE 0X309B2601
-
-#define WAKE_ENABLE_0 0xffffffff
-#define WAKE_ENABLE_1 0xffffffff
-#define INVALID_WAKE_SRC 0xFFFF
-
-#ifdef CONFIG_DRM_INTEL_MID
-#define GFX_ENABLE
-#endif
-
-#define TELEPHONY_ENABLE_S0IX
-#define WLAN_ENABLE_S0IX
-#define I2C_ENABLE_S0IX
-#define DWSPI_ENABLE_S0IX
-
-#define LOG_SS_MASK 0x80
-#define MFLD_ISP_POS 7
-#define ISP_SUB_CLASS 0x80
-
-#define D0I0_MASK 0
-#define D0I1_MASK 1
-#define D0I2_MASK 2
-#define D0I3_MASK 3
-
-#define BITS_PER_LSS 2
-
-#define GFX_LSS_INDEX 1
-
-#define PMU_SDIO0_LSS_00 0
-#define PMU_EMMC0_LSS_01 1
-#define PMU_AONT_LSS_02 2
-#define PMU_HSI_LSS_03 3
-#define PMU_SECURITY_LSS_04 4
-#define PMU_EMMC1_LSS_05 5
-#define PMU_USB_OTG_LSS_06 6
-#define PMU_USB_HSIC_LSS_07 7
-#define PMU_AUDIO_ENGINE_LSS_08 8
-#define PMU_AUDIO_DMA_LSS_09 9
-#define PMU_SRAM_LSS_10 10
-#define PMU_SRAM_LSS_11 11
-#define PMU_SRAM_LSS_12 12
-#define PMU_SRAM_LSS_13 13
-#define PMU_SDIO2_LSS_14 14
-#define PMU_PTI_DAFCA_LSS_15 15
-#define PMU_SC_DMA_LSS_16 16
-#define PMU_SPIO_LSS_17 17
-#define PMU_SPI1_LSS_18 18
-#define PMU_SPI2_LSS_19 19
-#define PMU_I2C0_LSS_20 20
-#define PMU_I2C1_LSS_21 21
-#define PMU_MAIN_FABRIC_LSS_22 22
-#define PMU_SEC_FABRIC_LSS_23 23
-#define PMU_SC_FABRIC_LSS_24 24
-#define PMU_AUDIO_RAM_LSS_25 25
-#define PMU_SCU_ROM_LSS_26 26
-#define PMU_I2C2_LSS_27 27
-#define PMU_SSC_LSS_28 28
-#define PMU_SECURITY_LSS_29 29
-#define PMU_SDIO1_LSS_30 30
-#define PMU_SCU_RAM0_LSS_31 31
-#define PMU_SCU_RAM1_LSS_32 32
-#define PMU_I2C3_LSS_33 33
-#define PMU_I2C4_LSS_34 34
-#define PMU_I2C5_LSS_35 35
-#define PMU_SPI3_LSS_36 36
-#define PMU_GPIO1_LSS_37 37
-#define PMU_PWR_BUTTON_LSS_38 38
-#define PMU_GPIO0_LSS_39 39
-#define PMU_KEYBRD_LSS_40 40
-#define PMU_UART2_LSS_41 41
-#define PMU_ADC_LSS_42 42
-#define PMU_CHARGER_LSS_43 43
-#define PMU_SEC_TAPC_LSS_44 44
-#define PMU_RTC_LSS_45 45
-#define PMU_GPI_LSS_46 46
-#define PMU_HDMI_VREG_LSS_47 47
-#define PMU_AUDIO_SSP2_LSS_48 48
-#define PMU_AUDIO_SLIM1_LSS_49 49
-#define PMU_RESET_LSS_50 50
-#define PMU_AUDIO_SSP0_LSS_51 51
-#define PMU_AUDIO_SSP1_LSS_52 52
-#define PMU_IOSF_OCP_BRG_LSS_53 53
-#define PMU_GP_DMA_LSS_54 54
-#define PMU_SVID_LSS_55 55
-#define PMU_SOC_FUSE_LSS_56 56
-#define PMU_RSVD3_LSS_57 57
-#define PMU_RSVD4_LSS_58 58
-#define PMU_RSVD5_LSS_59 59
-#define PMU_RSVD6_LSS_60 60
-#define PMU_RSVD7_LSS_61 61
-#define PMU_RSVD8_LSS_62 62
-#define PMU_RSVD9_LSS_63 63
-
-#define PMU_BASE_ADDR(pmu_num) ((pmu_num == 0) ? \
- (u32) base_addr.pmu1_base :\
- (u32) base_addr.pmu2_base);
-
-/* North Complex Power management */
-#define OSPM_PUNIT_PORT 0x04
-#define OSPM_OSPMBA 0x78
-#define OSPM_PM_SSC 0x20
-#define OSPM_PM_SSS 0x30
-
-#define OSPM_APMBA 0x7a
-#define APM_CMD 0x0
-#define APM_STS 0x04
-
-
-enum cm_trigger {
- NO_TRIG, /* No trigger is required */
- LPM_EVENT_TRIG, /* trigger on a LPM event */
- EXT_GPIO_INPUT_TRIG, /* trigger on a GPIO input */
- C_STATE_TRANS_TRIG, /* trigger on a C state transition */
- DMI_MSG_TRIG, /* trigger on a C state transition */
- INVALID_TRIG
-};
-
-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
-};
-
-enum pme_id {
- PME_ID_LPE = 1, /* pme id for LPE */
- PME_ID_USB = 2 /* pme id for USB */
-};
-
-enum pm_cmd {
- SET_CFG_CMD = 1
-};
-
-enum int_status {
- INVALID_INT = 0,
- CMD_COMPLETE_INT = 1,
- CMD_ERROR_INT = 2,
- WAKE_RECEIVED_INT = 3,
- SUBSYS_POW_ERR_INT = 4,
- S0ix_MISS_INT = 5,
- NO_ACKC6_INT = 6,
- INVALID_SRC_INT
-};
-
-enum pmu_regs {
- PM_STATUS = 0,
- PM_CMD = 1,
- PM_INT_STATUS = 2,
- PM_WAKE_CFG = 3,
- PM_WAKE_STATUS = 4,
- PM_SUB_SYS_CFG = 5,
- PM_SUB_SYS_STATUS = 6,
- PM_WAKE_SUB_SYS_CFG = 7,
- PM_C3C4_CTR = 8,
- PM_C5C6_CTR = 9,
- PM_MSIC = 10,
- PM_INVALID
-};
-
-struct mid_pmu_dev {
- u32 pmu1_sub_systems;
- u32 pmu2_sub_systems;
- u32 pmu_wake_cfg;
- u32 pmu_wake_ss_states;
- int pmu2_states;
- int s0ix_retry_enb;
- int retry_exit;
- u32 pmode;
- bool disable_cpu1;
- struct pmu_suspend_config *ss_config;
-};
-
-struct pci_dev_index {
- struct pci_dev *pdev;
- u8 index;
-};
-
-/* PMU register interface */
-struct mrst_pmu_reg {
- u32 pm_sts; /* 0x00 */
- u32 pm_cmd; /* 0x04 */
- u32 pm_ics; /* 0x08 */
- u32 _resv1;
- 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_msic; /* 0x58 */
-};
-
-/* PMU registers for pmu ( PMU2 / PMU1) PMU2 --> LNG PMU1 --> LNC */
-union pmu_pm_ss_cfg {
- struct {
- u32 ss_0:2; /* cDmi / L1 power domain */
- u32 ss_1:2; /* SD HC0 / Display */
- u32 ss_2:2; /* SD HC1 / GFX */
- u32 ss_3:2; /* Nand / Ved */
- u32 ss_4:2; /* ISP Imaging / Vec */
- u32 ss_5:2; /* Security / Mipi */
- u32 ss_6:2; /* Display / LVDS */
- u32 ss_7:2; /* USB Host */
- u32 ss_8:2; /* USB OTG */
- u32 ss_9:2; /* Audio */
- u32 ss_10:2; /* Gpio */
- u32 ss_11:2; /* Shared SRAM */
- u32 ss_12:2; /* rsvd */
- u32 ss_13:2; /* rsvd */
- u32 ss_14:2; /* rsvd */
- u32 ss_15:2; /* rsvd */
- } pmu_pm_ss_cfg_parts;
- u32 pmu_pm_ss_cfg_value;
-};
-
-union pmu_pm_ss_status {
- struct {
- u32 ss_0:2; /* cDmi / L1 power domain */
- u32 ss_1:2; /* SD HC0 / Display */
- u32 ss_2:2; /* SD HC1 / GFX */
- u32 ss_3:2; /* Nand / Ved */
- u32 ss_4:2; /* ISP Imaging / Vec */
- u32 ss_5:2; /* Security / Mipi */
- u32 ss_6:2; /* Display / LVDS */
- u32 ss_7:2; /* USB Host */
- u32 ss_8:2; /* USB OTG */
- u32 ss_9:2; /* Audio */
- u32 ss_10:2; /* Gpio */
- u32 ss_11:2; /* Shared SRAM */
- u32 ss_12:2; /* rsvd */
- u32 ss_13:2; /* rsvd */
- u32 ss_14:2; /* rsvd */
- u32 ss_15:2; /* rsvd */
- } pmu_pm_ss_status_parts;
- u32 pmu_pm_ss_status_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;
-};
-
-union pmu_pm_cmd {
- struct {
- u32 cmd:8;
- u32 ioc:1;
- u32 pmu_cmd_param:23;
- } pmu_pm_cmd_parts;
- u32 pmu_pm_cmd_value;
-};
-
-struct cfg_mode_params {
- u32 cfg_mode;
- u32 cfg_trigger;
- u32 cfg_trig_val;
- u32 cfg_delay;
- u32 cfg_cmbi;
-};
-
-/* pmu 1 pm set config parameters */
-struct pmu1_pm_set_cfg_cmd_parts {
- u32 cmd:8;
- u32 ioc:1;
- u32 cfg_mode:4;
- u32 cfg_delay:4;
- u32 cfg_trigger:4;
- u32 mode_id:4;
- u32 rsvd:7;
-};
-
-/* pmu 2 pm 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 {
- struct pmu1_pm_set_cfg_cmd_parts pmu1_params;
- union {
- struct cfg_delay_param_t d_param;
- struct cfg_trig_param_t t_param;
- } pmu2_params;
- u32 pmu_pm_set_cfg_cmd_value;
-};
-
-union pmu_pm_ics {
- struct {
- u32 int_status:8;
- u32 int_enable:1;
- u32 int_pend:1;
- u32 reserved:22;
- } pmu_pm_ics_parts;
- u32 pmu_pm_ics_value;
-};
-
-struct pmu_ospm_reg {
- union pmu_pm_status *pm_status;
- union pmu_pm_cmd *pm_cmd;
- union pmu_pm_ics *pm_ics;
- u32 pm_wkc;
- u32 rsvd1;
- u32 pm_wks;
- u32 rsvd2;
- union pmu_pm_ss_cfg *pm_ss_cfg;
- u32 rsvd3[3];
- union pmu_pm_ss_status *pm_ss_status;
- u32 rsvd4[3];
- u32 pm_wssc;
- u32 rsvd5[3];
- u32 pm_c3c4_ctr;
- u32 pm_c5c6_ctr;
- u32 pm_msic;
-};
-
-struct intel_mid_base_addr {
- u32 *pmu1_base;
- void __iomem *pmu2_base;
- u32 *pm_table_base;
- u32 __iomem *offload_reg;
-};
-
-/*APIs to get the APM base address */
-static inline u32 MDFLD_MSG_READ32(uint port, uint offset)
-{
- int mcr = (0x10<<24) | (port << 16) | (offset << 8);
- uint32_t ret_val = 0;
- struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
- pci_write_config_dword(pci_root, 0xD0, mcr);
- pci_read_config_dword(pci_root, 0xD4, &ret_val);
- pci_dev_put(pci_root);
- return ret_val;
-}
-static inline void MDFLD_MSG_WRITE32(uint port, uint offset, u32 value)
-{
- int mcr = (0x11<<24) | (port << 16) | (offset << 8) | 0xF0;
- struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
- pci_write_config_dword(pci_root, 0xD4, value);
- pci_write_config_dword(pci_root, 0xD0, mcr);
- pci_dev_put(pci_root);
-}
-
-/* API used to change the platform mode */
-extern int pmu_pci_set_power_state(struct pci_dev *pdev, pci_power_t state);
-extern pci_power_t pmu_pci_choose_state(struct pci_dev *pdev);
-extern bool pmu_pci_power_manageable(struct pci_dev *pdev);
-extern bool pmu_pci_can_wakeup(struct pci_dev *pdev);
-extern int pmu_pci_sleep_wake(struct pci_dev *pdev, bool enable);
-#endif