diff options
Diffstat (limited to 'drivers/mfd/lpc_ich.c')
| -rw-r--r-- | drivers/mfd/lpc_ich.c | 169 |
1 files changed, 123 insertions, 46 deletions
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 9483bc8472a..7d8482ff586 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -53,11 +53,11 @@ * document number TBD : Wellsburg * document number TBD : Avoton SoC * document number TBD : Coleto Creek + * document number TBD : Wildcat Point-LP */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/errno.h> @@ -71,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 @@ -89,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[] = { @@ -110,7 +113,7 @@ static struct resource wdt_ich_res[] = { { .flags = IORESOURCE_IO, }, - /* GCS */ + /* GCS or PMC */ { .flags = IORESOURCE_MEM, }, @@ -210,7 +213,9 @@ 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 */ }; static struct lpc_ich_info lpc_chipset_info[] = { @@ -301,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", @@ -482,6 +488,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_PPT] = { .name = "Panther Point", .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, }, [LPC_LPT] = { .name = "Lynx Point", @@ -497,12 +504,21 @@ 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", .iTCO_version = 2, }, + [LPC_WPT_LP] = { + .name = "Wildcat Point_LP", + .iTCO_version = 2, + }, }; /* @@ -511,7 +527,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { * pci_driver, because the I/O Controller Hub has also other * functions that probably will be registered by other drivers. */ -static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = { +static const struct pci_device_id lpc_ich_ids[] = { { PCI_VDEVICE(INTEL, 0x2410), LPC_ICH}, { PCI_VDEVICE(INTEL, 0x2420), LPC_ICH0}, { PCI_VDEVICE(INTEL, 0x2440), LPC_ICH2}, @@ -720,7 +736,15 @@ static DEFINE_PCI_DEVICE_TABLE(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}, + { PCI_VDEVICE(INTEL, 0x9cc3), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc5), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc6), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc7), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x9cc9), LPC_WPT_LP}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, lpc_ich_ids); @@ -729,14 +753,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; } } @@ -745,9 +775,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) @@ -755,9 +802,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) @@ -802,7 +860,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"); @@ -828,7 +886,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"); @@ -878,7 +936,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"); @@ -897,14 +955,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)) { @@ -913,9 +977,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]); @@ -939,28 +1011,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 @@ -969,7 +1048,6 @@ static int lpc_ich_probe(struct pci_dev *dev, if (!cell_added) { dev_warn(&dev->dev, "No MFD cells added\n"); lpc_ich_restore_config_space(dev); - pci_set_drvdata(dev, NULL); return -ENODEV; } @@ -980,7 +1058,6 @@ static void lpc_ich_remove(struct pci_dev *dev) { mfd_remove_devices(&dev->dev); lpc_ich_restore_config_space(dev); - pci_set_drvdata(dev, NULL); } static struct pci_driver lpc_ich_driver = { |
