@@ -215,6 +215,66 @@ static u32 sp5100_tco_read_pm_reg32(u8 index)
return val;
}
+static int __sp5100_tco_prepare_base(struct sp5100_tco *tco,
+ u32 mmio_addr,
+ const char *dev_name)
+{
+ struct device *dev = tco->wdd.parent;
+ int ret = 0;
+
+ if (!mmio_addr)
+ return -ENOMEM;
+
+ if (!devm_request_mem_region(dev, mmio_addr,
+ SP5100_WDT_MEM_MAP_SIZE,
+ dev_name)) {
+ dev_dbg(dev, "MMIO address 0x%08x already in use\n",
+ mmio_addr);
+ return -EBUSY;
+ }
+
+ tco->tcobase = devm_ioremap(dev, mmio_addr,
+ SP5100_WDT_MEM_MAP_SIZE);
+ if (!tco->tcobase) {
+ dev_dbg(dev, "MMIO address 0x%08x failed mapping.\n",
+ mmio_addr);
+ devm_release_mem_region(dev, mmio_addr,
+ SP5100_WDT_MEM_MAP_SIZE);
+ return -ENOMEM;
+ }
+
+ dev_info(dev, "Using 0x%08x for watchdog MMIO address\n",
+ mmio_addr);
+
+ return ret;
+}
+
+static int sp5100_tco_prepare_base(struct sp5100_tco *tco,
+ u32 mmio_addr,
+ u32 alt_mmio_addr,
+ const char *dev_name)
+{
+ struct device *dev = tco->wdd.parent;
+ int ret = 0;
+
+ dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n",
+ mmio_addr);
+
+ /* Check MMIO address conflict */
+ ret = __sp5100_tco_prepare_base(tco, mmio_addr, dev_name);
+
+ /* Check alternate MMIO address conflict */
+ if (ret)
+ ret = __sp5100_tco_prepare_base(tco, alt_mmio_addr,
+ dev_name);
+
+ if (ret)
+ dev_err(dev, "Failed to reserve-map MMIO (%X) and alternate MMIO (%X) regions. ret=%X",
+ mmio_addr, alt_mmio_addr, ret);
+
+ return ret;
+}
+
static int sp5100_tco_timer_init(struct sp5100_tco *tco)
{
struct watchdog_device *wdd = &tco->wdd;
@@ -259,6 +319,7 @@ static int sp5100_tco_setupdevice(struct device *dev,
struct sp5100_tco *tco = watchdog_get_drvdata(wdd);
const char *dev_name;
u32 mmio_addr = 0, val;
+ u32 alt_mmio_addr = 0;
int ret;
/* Request the IO ports used by this driver */
@@ -277,11 +338,35 @@ static int sp5100_tco_setupdevice(struct device *dev,
dev_name = SP5100_DEVNAME;
mmio_addr = sp5100_tco_read_pm_reg32(SP5100_PM_WATCHDOG_BASE) &
0xfffffff8;
+
+ /*
+ * Secondly, Find the watchdog timer MMIO address
+ * from SBResource_MMIO register.
+ */
+ /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
+ pci_read_config_dword(sp5100_tco_pci,
+ SP5100_SB_RESOURCE_MMIO_BASE,
+ &alt_mmio_addr);
+ if (alt_mmio_addr & ((SB800_ACPI_MMIO_DECODE_EN |
+ SB800_ACPI_MMIO_SEL) !=
+ SB800_ACPI_MMIO_DECODE_EN)) {
+ alt_mmio_addr &= ~0xFFF;
+ alt_mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
+ }
break;
case sb800:
dev_name = SB800_DEVNAME;
mmio_addr = sp5100_tco_read_pm_reg32(SB800_PM_WATCHDOG_BASE) &
0xfffffff8;
+ /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
+ alt_mmio_addr =
+ sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
+ if (!(alt_mmio_addr & (((SB800_ACPI_MMIO_DECODE_EN |
+ SB800_ACPI_MMIO_SEL)) !=
+ SB800_ACPI_MMIO_DECODE_EN))) {
+ alt_mmio_addr &= ~0xFFF;
+ alt_mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
+ }
break;
case efch:
dev_name = SB800_DEVNAME;
@@ -300,84 +385,22 @@ static int sp5100_tco_setupdevice(struct device *dev,
val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
if (val & EFCH_PM_DECODEEN_WDT_TMREN)
mmio_addr = EFCH_PM_WDT_ADDR;
- break;
- default:
- return -ENODEV;
- }
- /* Check MMIO address conflict */
- if (!mmio_addr ||
- !devm_request_mem_region(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE,
- dev_name)) {
- if (mmio_addr)
- dev_dbg(dev, "MMIO address 0x%08x already in use\n",
- mmio_addr);
- switch (tco->tco_reg_layout) {
- case sp5100:
- /*
- * Secondly, Find the watchdog timer MMIO address
- * from SBResource_MMIO register.
- */
- /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
- pci_read_config_dword(sp5100_tco_pci,
- SP5100_SB_RESOURCE_MMIO_BASE,
- &mmio_addr);
- if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN |
- SB800_ACPI_MMIO_SEL)) !=
- SB800_ACPI_MMIO_DECODE_EN) {
- ret = -ENODEV;
- goto unreg_region;
- }
- mmio_addr &= ~0xFFF;
- mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
- break;
- case sb800:
- /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
- mmio_addr =
- sp5100_tco_read_pm_reg32(SB800_PM_ACPI_MMIO_EN);
- if ((mmio_addr & (SB800_ACPI_MMIO_DECODE_EN |
- SB800_ACPI_MMIO_SEL)) !=
- SB800_ACPI_MMIO_DECODE_EN) {
- ret = -ENODEV;
- goto unreg_region;
- }
- mmio_addr &= ~0xFFF;
- mmio_addr += SB800_PM_WDT_MMIO_OFFSET;
- break;
- case efch:
- val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL);
- if (!(val & EFCH_PM_ISACONTROL_MMIOEN)) {
- ret = -ENODEV;
- goto unreg_region;
- }
- mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
- EFCH_PM_ACPI_MMIO_WDT_OFFSET;
- break;
- }
- dev_dbg(dev, "Got 0x%08x from SBResource_MMIO register\n",
- mmio_addr);
- if (!devm_request_mem_region(dev, mmio_addr,
- SP5100_WDT_MEM_MAP_SIZE,
- dev_name)) {
- dev_dbg(dev, "MMIO address 0x%08x already in use\n",
- mmio_addr);
- ret = -EBUSY;
- goto unreg_region;
+ val = sp5100_tco_read_pm_reg8(EFCH_PM_ISACONTROL);
+ if (val & EFCH_PM_ISACONTROL_MMIOEN) {
+ alt_mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
+ EFCH_PM_ACPI_MMIO_WDT_OFFSET;
}
- }
- tco->tcobase = devm_ioremap(dev, mmio_addr, SP5100_WDT_MEM_MAP_SIZE);
- if (!tco->tcobase) {
- dev_err(dev, "failed to get tcobase address\n");
- ret = -ENOMEM;
- goto unreg_region;
+ break;
+ default:
+ return -ENODEV;
}
- dev_info(dev, "Using 0x%08x for watchdog MMIO address\n", mmio_addr);
-
- ret = sp5100_tco_timer_init(tco);
+ ret = sp5100_tco_prepare_base(tco, mmio_addr, alt_mmio_addr, dev_name);
+ if (!ret)
+ ret = sp5100_tco_timer_init(tco);
-unreg_region:
release_region(SP5100_IO_PM_INDEX_REG, SP5100_PM_IOPORTS_SIZE);
return ret;
}