diff options
Diffstat (limited to 'drivers/mfd/lpc_ich.c')
-rw-r--r-- | drivers/mfd/lpc_ich.c | 151 |
1 files changed, 108 insertions, 43 deletions
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index be93fa261ded..3f10ea3f45d1 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -58,7 +58,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/errno.h> @@ -72,9 +71,11 @@ #define ACPIBASE_GPE_END 0x2f #define ACPIBASE_SMI_OFF 0x30 #define ACPIBASE_SMI_END 0x33 +#define ACPIBASE_PMC_OFF 0x08 +#define ACPIBASE_PMC_END 0x0c #define ACPIBASE_TCO_OFF 0x60 #define ACPIBASE_TCO_END 0x7f -#define ACPICTRL 0x44 +#define ACPICTRL_PMCBASE 0x44 #define ACPIBASE_GCS_OFF 0x3410 #define ACPIBASE_GCS_END 0x3414 @@ -90,16 +91,17 @@ #define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i) #define wdt_res(b, i) (&wdt_ich_res[(b) + (i)]) -struct lpc_ich_cfg { - int base; - int ctrl; - int save; -}; - struct lpc_ich_priv { int chipset; - struct lpc_ich_cfg acpi; - struct lpc_ich_cfg gpio; + + int abase; /* ACPI base */ + int actrl_pbase; /* ACPI control or PMC base */ + int gbase; /* GPIO base */ + int gctrl; /* GPIO control */ + + int abase_save; /* Cached ACPI base value */ + int actrl_pbase_save; /* Cached ACPI control or PMC base value */ + int gctrl_save; /* Cached GPIO control value */ }; static struct resource wdt_ich_res[] = { @@ -111,7 +113,7 @@ static struct resource wdt_ich_res[] = { { .flags = IORESOURCE_IO, }, - /* GCS */ + /* GCS or PMC */ { .flags = IORESOURCE_MEM, }, @@ -211,6 +213,7 @@ enum lpc_chipsets { LPC_LPT_LP, /* Lynx Point-LP */ LPC_WBG, /* Wellsburg */ LPC_AVN, /* Avoton SoC */ + LPC_BAYTRAIL, /* Bay Trail SoC */ LPC_COLETO, /* Coleto Creek */ LPC_WPT_LP, /* Wildcat Point-LP */ }; @@ -303,6 +306,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_NM10] = { .name = "NM10", .iTCO_version = 2, + .gpio_version = ICH_V7_GPIO, }, [LPC_ICH8] = { .name = "ICH8 or ICH8R", @@ -499,7 +503,12 @@ static struct lpc_ich_info lpc_chipset_info[] = { }, [LPC_AVN] = { .name = "Avoton SoC", - .iTCO_version = 1, + .iTCO_version = 3, + .gpio_version = AVOTON_GPIO, + }, + [LPC_BAYTRAIL] = { + .name = "Bay Trail SoC", + .iTCO_version = 3, }, [LPC_COLETO] = { .name = "Coleto Creek", @@ -726,6 +735,7 @@ static const struct pci_device_id lpc_ich_ids[] = { { PCI_VDEVICE(INTEL, 0x1f39), LPC_AVN}, { PCI_VDEVICE(INTEL, 0x1f3a), LPC_AVN}, { PCI_VDEVICE(INTEL, 0x1f3b), LPC_AVN}, + { PCI_VDEVICE(INTEL, 0x0f1c), LPC_BAYTRAIL}, { PCI_VDEVICE(INTEL, 0x2390), LPC_COLETO}, { PCI_VDEVICE(INTEL, 0x9cc1), LPC_WPT_LP}, { PCI_VDEVICE(INTEL, 0x9cc2), LPC_WPT_LP}, @@ -742,14 +752,20 @@ static void lpc_ich_restore_config_space(struct pci_dev *dev) { struct lpc_ich_priv *priv = pci_get_drvdata(dev); - if (priv->acpi.save >= 0) { - pci_write_config_byte(dev, priv->acpi.ctrl, priv->acpi.save); - priv->acpi.save = -1; + if (priv->abase_save >= 0) { + pci_write_config_byte(dev, priv->abase, priv->abase_save); + priv->abase_save = -1; + } + + if (priv->actrl_pbase_save >= 0) { + pci_write_config_byte(dev, priv->actrl_pbase, + priv->actrl_pbase_save); + priv->actrl_pbase_save = -1; } - if (priv->gpio.save >= 0) { - pci_write_config_byte(dev, priv->gpio.ctrl, priv->gpio.save); - priv->gpio.save = -1; + if (priv->gctrl_save >= 0) { + pci_write_config_byte(dev, priv->gctrl, priv->gctrl_save); + priv->gctrl_save = -1; } } @@ -758,9 +774,26 @@ static void lpc_ich_enable_acpi_space(struct pci_dev *dev) struct lpc_ich_priv *priv = pci_get_drvdata(dev); u8 reg_save; - pci_read_config_byte(dev, priv->acpi.ctrl, ®_save); - pci_write_config_byte(dev, priv->acpi.ctrl, reg_save | 0x10); - priv->acpi.save = reg_save; + switch (lpc_chipset_info[priv->chipset].iTCO_version) { + case 3: + /* + * Some chipsets (eg Avoton) enable the ACPI space in the + * ACPI BASE register. + */ + pci_read_config_byte(dev, priv->abase, ®_save); + pci_write_config_byte(dev, priv->abase, reg_save | 0x2); + priv->abase_save = reg_save; + break; + default: + /* + * Most chipsets enable the ACPI space in the ACPI control + * register. + */ + pci_read_config_byte(dev, priv->actrl_pbase, ®_save); + pci_write_config_byte(dev, priv->actrl_pbase, reg_save | 0x80); + priv->actrl_pbase_save = reg_save; + break; + } } static void lpc_ich_enable_gpio_space(struct pci_dev *dev) @@ -768,9 +801,20 @@ static void lpc_ich_enable_gpio_space(struct pci_dev *dev) struct lpc_ich_priv *priv = pci_get_drvdata(dev); u8 reg_save; - pci_read_config_byte(dev, priv->gpio.ctrl, ®_save); - pci_write_config_byte(dev, priv->gpio.ctrl, reg_save | 0x10); - priv->gpio.save = reg_save; + pci_read_config_byte(dev, priv->gctrl, ®_save); + pci_write_config_byte(dev, priv->gctrl, reg_save | 0x10); + priv->gctrl_save = reg_save; +} + +static void lpc_ich_enable_pmc_space(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + u8 reg_save; + + pci_read_config_byte(dev, priv->actrl_pbase, ®_save); + pci_write_config_byte(dev, priv->actrl_pbase, reg_save | 0x2); + + priv->actrl_pbase_save = reg_save; } static void lpc_ich_finalize_cell(struct pci_dev *dev, struct mfd_cell *cell) @@ -815,7 +859,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev) struct resource *res; /* Setup power management base register */ - pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg); + pci_read_config_dword(dev, priv->abase, &base_addr_cfg); base_addr = base_addr_cfg & 0x0000ff80; if (!base_addr) { dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n"); @@ -841,7 +885,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev) gpe0_done: /* Setup GPIO base register */ - pci_read_config_dword(dev, priv->gpio.base, &base_addr_cfg); + pci_read_config_dword(dev, priv->gbase, &base_addr_cfg); base_addr = base_addr_cfg & 0x0000ff80; if (!base_addr) { dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n"); @@ -891,7 +935,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev) struct resource *res; /* Setup power management base register */ - pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg); + pci_read_config_dword(dev, priv->abase, &base_addr_cfg); base_addr = base_addr_cfg & 0x0000ff80; if (!base_addr) { dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n"); @@ -910,14 +954,20 @@ static int lpc_ich_init_wdt(struct pci_dev *dev) lpc_ich_enable_acpi_space(dev); /* + * iTCO v2: * Get the Memory-Mapped GCS register. To get access to it * we have to read RCBA from PCI Config space 0xf0 and use * it as base. GCS = RCBA + ICH6_GCS(0x3410). + * + * iTCO v3: + * Get the Power Management Configuration register. To get access + * to it we have to read the PMC BASE from config space and address + * the register at offset 0x8. */ if (lpc_chipset_info[priv->chipset].iTCO_version == 1) { /* Don't register iomem for TCO ver 1 */ lpc_ich_cells[LPC_WDT].num_resources--; - } else { + } else if (lpc_chipset_info[priv->chipset].iTCO_version == 2) { pci_read_config_dword(dev, RCBABASE, &base_addr_cfg); base_addr = base_addr_cfg & 0xffffc000; if (!(base_addr_cfg & 1)) { @@ -926,9 +976,17 @@ static int lpc_ich_init_wdt(struct pci_dev *dev) ret = -ENODEV; goto wdt_done; } - res = wdt_mem_res(ICH_RES_MEM_GCS); + res = wdt_mem_res(ICH_RES_MEM_GCS_PMC); res->start = base_addr + ACPIBASE_GCS_OFF; res->end = base_addr + ACPIBASE_GCS_END; + } else if (lpc_chipset_info[priv->chipset].iTCO_version == 3) { + lpc_ich_enable_pmc_space(dev); + pci_read_config_dword(dev, ACPICTRL_PMCBASE, &base_addr_cfg); + base_addr = base_addr_cfg & 0xfffffe00; + + res = wdt_mem_res(ICH_RES_MEM_GCS_PMC); + res->start = base_addr + ACPIBASE_PMC_OFF; + res->end = base_addr + ACPIBASE_PMC_END; } lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]); @@ -952,28 +1010,35 @@ static int lpc_ich_probe(struct pci_dev *dev, return -ENOMEM; priv->chipset = id->driver_data; - priv->acpi.save = -1; - priv->acpi.base = ACPIBASE; - priv->acpi.ctrl = ACPICTRL; - priv->gpio.save = -1; + priv->actrl_pbase_save = -1; + priv->abase_save = -1; + + priv->abase = ACPIBASE; + priv->actrl_pbase = ACPICTRL_PMCBASE; + + priv->gctrl_save = -1; if (priv->chipset <= LPC_ICH5) { - priv->gpio.base = GPIOBASE_ICH0; - priv->gpio.ctrl = GPIOCTRL_ICH0; + priv->gbase = GPIOBASE_ICH0; + priv->gctrl = GPIOCTRL_ICH0; } else { - priv->gpio.base = GPIOBASE_ICH6; - priv->gpio.ctrl = GPIOCTRL_ICH6; + priv->gbase = GPIOBASE_ICH6; + priv->gctrl = GPIOCTRL_ICH6; } pci_set_drvdata(dev, priv); - ret = lpc_ich_init_wdt(dev); - if (!ret) - cell_added = true; + if (lpc_chipset_info[priv->chipset].iTCO_version) { + ret = lpc_ich_init_wdt(dev); + if (!ret) + cell_added = true; + } - ret = lpc_ich_init_gpio(dev); - if (!ret) - cell_added = true; + if (lpc_chipset_info[priv->chipset].gpio_version) { + ret = lpc_ich_init_gpio(dev); + if (!ret) + cell_added = true; + } /* * We only care if at least one or none of the cells registered |