Commit 887c8ec7 authored by Aaron Sierra's avatar Aaron Sierra Committed by Samuel Ortiz

watchdog: Convert iTCO_wdt driver to mfd model

This patch converts the iTCO_wdt driver to use the multi-function device
driver model. It uses resources discovered by the lpc_ich driver, so that
it no longer does its own PCI scanning.
Signed-off-by: default avatarAaron Sierra <asierra@xes-inc.com>
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 16c5c023
......@@ -785,7 +785,8 @@ config LPC_ICH
help
The LPC bridge function of the Intel ICH provides support for
many functional units. This driver provides needed support for
other drivers to control these functions, currently GPIO.
other drivers to control these functions, currently GPIO and
watchdog.
config MFD_RDC321X
tristate "Support for RDC-R321x southbridge"
......
......@@ -65,14 +65,42 @@
#define ACPIBASE 0x40
#define ACPIBASE_GPE_OFF 0x28
#define ACPIBASE_GPE_END 0x2f
#define ACPIBASE_SMI_OFF 0x30
#define ACPIBASE_SMI_END 0x33
#define ACPIBASE_TCO_OFF 0x60
#define ACPIBASE_TCO_END 0x7f
#define ACPICTRL 0x44
#define ACPIBASE_GCS_OFF 0x3410
#define ACPIBASE_GCS_END 0x3414
#define GPIOBASE 0x48
#define GPIOCTRL 0x4C
#define RCBABASE 0xf0
#define wdt_io_res(i) wdt_res(0, i)
#define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i)
#define wdt_res(b, i) (&wdt_ich_res[(b) + (i)])
static int lpc_ich_acpi_save = -1;
static int lpc_ich_gpio_save = -1;
static struct resource wdt_ich_res[] = {
/* ACPI - TCO */
{
.flags = IORESOURCE_IO,
},
/* ACPI - SMI */
{
.flags = IORESOURCE_IO,
},
/* GCS */
{
.flags = IORESOURCE_MEM,
},
};
static struct resource gpio_ich_res[] = {
/* GPIO */
{
......@@ -85,10 +113,17 @@ static struct resource gpio_ich_res[] = {
};
enum lpc_cells {
LPC_GPIO = 0,
LPC_WDT = 0,
LPC_GPIO,
};
static struct mfd_cell lpc_ich_cells[] = {
[LPC_WDT] = {
.name = "iTCO_wdt",
.num_resources = ARRAY_SIZE(wdt_ich_res),
.resources = wdt_ich_res,
.ignore_resource_conflicts = true,
},
[LPC_GPIO] = {
.name = "gpio_ich",
.num_resources = ARRAY_SIZE(gpio_ich_res),
......@@ -162,218 +197,276 @@ enum lpc_chipsets {
struct lpc_ich_info lpc_chipset_info[] __devinitdata = {
[LPC_ICH] = {
.name = "ICH",
.iTCO_version = 1,
},
[LPC_ICH0] = {
.name = "ICH0",
.iTCO_version = 1,
},
[LPC_ICH2] = {
.name = "ICH2",
.iTCO_version = 1,
},
[LPC_ICH2M] = {
.name = "ICH2-M",
.iTCO_version = 1,
},
[LPC_ICH3] = {
.name = "ICH3-S",
.iTCO_version = 1,
},
[LPC_ICH3M] = {
.name = "ICH3-M",
.iTCO_version = 1,
},
[LPC_ICH4] = {
.name = "ICH4",
.iTCO_version = 1,
},
[LPC_ICH4M] = {
.name = "ICH4-M",
.iTCO_version = 1,
},
[LPC_CICH] = {
.name = "C-ICH",
.iTCO_version = 1,
},
[LPC_ICH5] = {
.name = "ICH5 or ICH5R",
.iTCO_version = 1,
},
[LPC_6300ESB] = {
.name = "6300ESB",
.iTCO_version = 1,
},
[LPC_ICH6] = {
.name = "ICH6 or ICH6R",
.iTCO_version = 2,
.gpio_version = ICH_V6_GPIO,
},
[LPC_ICH6M] = {
.name = "ICH6-M",
.iTCO_version = 2,
.gpio_version = ICH_V6_GPIO,
},
[LPC_ICH6W] = {
.name = "ICH6W or ICH6RW",
.iTCO_version = 2,
.gpio_version = ICH_V6_GPIO,
},
[LPC_631XESB] = {
.name = "631xESB/632xESB",
.iTCO_version = 2,
.gpio_version = ICH_V6_GPIO,
},
[LPC_ICH7] = {
.name = "ICH7 or ICH7R",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH7DH] = {
.name = "ICH7DH",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH7M] = {
.name = "ICH7-M or ICH7-U",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH7MDH] = {
.name = "ICH7-M DH",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_NM10] = {
.name = "NM10",
.iTCO_version = 2,
},
[LPC_ICH8] = {
.name = "ICH8 or ICH8R",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH8DH] = {
.name = "ICH8DH",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH8DO] = {
.name = "ICH8DO",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH8M] = {
.name = "ICH8M",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH8ME] = {
.name = "ICH8M-E",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH9] = {
.name = "ICH9",
.iTCO_version = 2,
.gpio_version = ICH_V9_GPIO,
},
[LPC_ICH9R] = {
.name = "ICH9R",
.iTCO_version = 2,
.gpio_version = ICH_V9_GPIO,
},
[LPC_ICH9DH] = {
.name = "ICH9DH",
.iTCO_version = 2,
.gpio_version = ICH_V9_GPIO,
},
[LPC_ICH9DO] = {
.name = "ICH9DO",
.iTCO_version = 2,
.gpio_version = ICH_V9_GPIO,
},
[LPC_ICH9M] = {
.name = "ICH9M",
.iTCO_version = 2,
.gpio_version = ICH_V9_GPIO,
},
[LPC_ICH9ME] = {
.name = "ICH9M-E",
.iTCO_version = 2,
.gpio_version = ICH_V9_GPIO,
},
[LPC_ICH10] = {
.name = "ICH10",
.iTCO_version = 2,
.gpio_version = ICH_V10CONS_GPIO,
},
[LPC_ICH10R] = {
.name = "ICH10R",
.iTCO_version = 2,
.gpio_version = ICH_V10CONS_GPIO,
},
[LPC_ICH10D] = {
.name = "ICH10D",
.iTCO_version = 2,
.gpio_version = ICH_V10CORP_GPIO,
},
[LPC_ICH10DO] = {
.name = "ICH10DO",
.iTCO_version = 2,
.gpio_version = ICH_V10CORP_GPIO,
},
[LPC_PCH] = {
.name = "PCH Desktop Full Featured",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_PCHM] = {
.name = "PCH Mobile Full Featured",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_P55] = {
.name = "P55",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_PM55] = {
.name = "PM55",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_H55] = {
.name = "H55",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_QM57] = {
.name = "QM57",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_H57] = {
.name = "H57",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_HM55] = {
.name = "HM55",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_Q57] = {
.name = "Q57",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_HM57] = {
.name = "HM57",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_PCHMSFF] = {
.name = "PCH Mobile SFF Full Featured",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_QS57] = {
.name = "QS57",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_3400] = {
.name = "3400",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_3420] = {
.name = "3420",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_3450] = {
.name = "3450",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_EP80579] = {
.name = "EP80579",
.iTCO_version = 2,
},
[LPC_CPT] = {
.name = "Cougar Point",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_CPTD] = {
.name = "Cougar Point Desktop",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_CPTM] = {
.name = "Cougar Point Mobile",
.iTCO_version = 2,
.gpio_version = ICH_V5_GPIO,
},
[LPC_PBG] = {
.name = "Patsburg",
.iTCO_version = 2,
},
[LPC_DH89XXCC] = {
.name = "DH89xxCC",
.iTCO_version = 2,
},
[LPC_PPT] = {
.name = "Panther Point",
.iTCO_version = 2,
},
[LPC_LPT] = {
.name = "Lynx Point",
.iTCO_version = 2,
},
};
......@@ -666,12 +759,88 @@ static int __devinit lpc_ich_init_gpio(struct pci_dev *dev,
return ret;
}
static int __devinit lpc_ich_init_wdt(struct pci_dev *dev,
const struct pci_device_id *id)
{
u32 base_addr_cfg;
u32 base_addr;
int ret;
bool acpi_conflict = false;
struct resource *res;
/* Setup power management base register */
pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_err(&dev->dev, "I/O space for ACPI uninitialized\n");
ret = -ENODEV;
goto wdt_done;
}
res = wdt_io_res(ICH_RES_IO_TCO);
res->start = base_addr + ACPIBASE_TCO_OFF;
res->end = base_addr + ACPIBASE_TCO_END;
ret = acpi_check_resource_conflict(res);
if (ret) {
acpi_conflict = true;
goto wdt_done;
}
res = wdt_io_res(ICH_RES_IO_SMI);
res->start = base_addr + ACPIBASE_SMI_OFF;
res->end = base_addr + ACPIBASE_SMI_END;
ret = acpi_check_resource_conflict(res);
if (ret) {
acpi_conflict = true;
goto wdt_done;
}
lpc_ich_enable_acpi_space(dev);
/*
* 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).
*/
if (lpc_chipset_info[id->driver_data].iTCO_version == 2) {
pci_read_config_dword(dev, RCBABASE, &base_addr_cfg);
base_addr = base_addr_cfg & 0xffffc000;
if (!(base_addr_cfg & 1)) {
pr_err("RCBA is disabled by hardware/BIOS, "
"device disabled\n");
ret = -ENODEV;
goto wdt_done;
}
res = wdt_mem_res(ICH_RES_MEM_GCS);
res->start = base_addr + ACPIBASE_GCS_OFF;
res->end = base_addr + ACPIBASE_GCS_END;
ret = acpi_check_resource_conflict(res);
if (ret) {
acpi_conflict = true;
goto wdt_done;
}
}
lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id);
ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT],
1, NULL, 0);
wdt_done:
if (acpi_conflict)
pr_warn("Resource conflict(s) found affecting %s\n",
lpc_ich_cells[LPC_WDT].name);
return ret;
}
static int __devinit lpc_ich_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
int ret;
bool cell_added = false;
ret = lpc_ich_init_wdt(dev, id);
if (!ret)
cell_added = true;
ret = lpc_ich_init_gpio(dev, id);
if (!ret)
cell_added = true;
......
......@@ -563,6 +563,7 @@ config INTEL_SCU_WATCHDOG
config ITCO_WDT
tristate "Intel TCO Timer/Watchdog"
depends on (X86 || IA64) && PCI
select LPC_ICH
---help---
Hardware driver for the intel TCO timer based watchdog devices.
These drivers are included in the Intel 82801 I/O Controller
......
/* iTCO Vendor Specific Support hooks */
#ifdef CONFIG_ITCO_VENDOR_SUPPORT
extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
extern void iTCO_vendor_pre_stop(unsigned long);
extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
extern void iTCO_vendor_pre_start(struct resource *, unsigned int);
extern void iTCO_vendor_pre_stop(struct resource *);
extern void iTCO_vendor_pre_keepalive(struct resource *, unsigned int);
extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
extern int iTCO_vendor_check_noreboot_on(void);
#else
......
......@@ -35,11 +35,6 @@
#include "iTCO_vendor.h"
/* iTCO defines */
#define SMI_EN (acpibase + 0x30) /* SMI Control and Enable Register */
#define TCOBASE (acpibase + 0x60) /* TCO base address */
#define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */
/* List of vendor support modes */
/* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
#define SUPERMICRO_OLD_BOARD 1
......@@ -82,24 +77,24 @@ MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default="
* 20.6 seconds.
*/
static void supermicro_old_pre_start(unsigned long acpibase)
static void supermicro_old_pre_start(struct resource *smires)
{
unsigned long val32;
/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
val32 = inl(SMI_EN);
val32 = inl(smires->start);
val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
outl(val32, SMI_EN); /* Needed to activate watchdog */
outl(val32, smires->start); /* Needed to activate watchdog */
}
static void supermicro_old_pre_stop(unsigned long acpibase)
static void supermicro_old_pre_stop(struct resource *smires)
{
unsigned long val32;
/* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
val32 = inl(SMI_EN);
val32 = inl(smires->start);
val32 |= 0x00002000; /* Turn on SMI clearing watchdog */
outl(val32, SMI_EN); /* Needed to deactivate watchdog */
outl(val32, smires->start); /* Needed to deactivate watchdog */
}
/*
......@@ -270,66 +265,66 @@ static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
* Don't use this fix if you don't need to!!!
*/
static void broken_bios_start(unsigned long acpibase)
static void broken_bios_start(struct resource *smires)
{
unsigned long val32;
val32 = inl(SMI_EN);
val32 = inl(smires->start);
/* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI#
Bit 0: GBL_SMI_EN -> 0 = No SMI# will be generated by ICH. */
val32 &= 0xffffdffe;
outl(val32, SMI_EN);
outl(val32, smires->start);
}
static void broken_bios_stop(unsigned long acpibase)
static void broken_bios_stop(struct resource *smires)
{
unsigned long val32;
val32 = inl(SMI_EN);
val32 = inl(smires->start);
/* Bit 13: TCO_EN -> 1 = Enables TCO logic generating an SMI#
Bit 0: GBL_SMI_EN -> 1 = Turn global SMI on again. */
val32 |= 0x00002001;
outl(val32, SMI_EN);
outl(val32, smires->start);
}
/*
* Generic Support Functions
*/
void iTCO_vendor_pre_start(unsigned long acpibase,
void iTCO_vendor_pre_start(struct resource *smires,
unsigned int heartbeat)
{
switch (vendorsupport) {
case SUPERMICRO_OLD_BOARD:
supermicro_old_pre_start(acpibase);
supermicro_old_pre_start(smires);
break;
case SUPERMICRO_NEW_BOARD:
supermicro_new_pre_start(heartbeat);
break;
case BROKEN_BIOS:
broken_bios_start(acpibase);
broken_bios_start(smires);
break;
}
}
EXPORT_SYMBOL(iTCO_vendor_pre_start);
void iTCO_vendor_pre_stop(unsigned long acpibase)
void iTCO_vendor_pre_stop(struct resource *smires)
{
switch (vendorsupport) {
case SUPERMICRO_OLD_BOARD:
supermicro_old_pre_stop(acpibase);
supermicro_old_pre_stop(smires);
break;
case SUPERMICRO_NEW_BOARD:
supermicro_new_pre_stop();
break;
case BROKEN_BIOS:
broken_bios_stop(acpibase);
broken_bios_stop(smires);
break;
}
}
EXPORT_SYMBOL(iTCO_vendor_pre_stop);
void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat)
void iTCO_vendor_pre_keepalive(struct resource *smires, unsigned int heartbeat)
{
if (vendorsupport == SUPERMICRO_NEW_BOARD)
supermicro_new_pre_set_heartbeat(heartbeat);
......
This diff is collapsed.
......@@ -20,6 +20,12 @@
#ifndef LPC_ICH_H
#define LPC_ICH_H
/* Watchdog resources */
#define ICH_RES_IO_TCO 0
#define ICH_RES_IO_SMI 1
#define ICH_RES_MEM_OFF 2
#define ICH_RES_MEM_GCS 0
/* GPIO resources */
#define ICH_RES_GPIO 0
#define ICH_RES_GPE0 1
......@@ -35,6 +41,7 @@
struct lpc_ich_info {
char name[32];
unsigned int iTCO_version;
unsigned int gpio_version;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment