Skip to content

Commit 0578fff

Browse files
ktbowman-amdWim Van Sebroeck
authored andcommitted
Watchdog: sp5100_tco: Add initialization using EFCH MMIO
cd6h/cd7h port I/O can be disabled on recent AMD hardware. Read accesses to disabled cd6h/cd7h port I/O will return F's and written data is dropped. It is recommended to replace the cd6h/cd7h port I/O with MMIO. Co-developed-by: Robert Richter <rrichter@amd.com> Signed-off-by: Robert Richter <rrichter@amd.com> Signed-off-by: Terry Bowman <terry.bowman@amd.com> Tested-by: Jean Delvare <jdelvare@suse.de> Reviewed-by: Jean Delvare <jdelvare@suse.de> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Link: https://lore.kernel.org/r/20220202153525.1693378-4-terry.bowman@amd.com Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
1 parent 1f182ac commit 0578fff

File tree

2 files changed

+104
-1
lines changed

2 files changed

+104
-1
lines changed

drivers/watchdog/sp5100_tco.c

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
/* internal variables */
5050

5151
enum tco_reg_layout {
52-
sp5100, sb800, efch
52+
sp5100, sb800, efch, efch_mmio
5353
};
5454

5555
struct sp5100_tco {
@@ -209,6 +209,8 @@ static void tco_timer_enable(struct sp5100_tco *tco)
209209
~EFCH_PM_WATCHDOG_DISABLE,
210210
EFCH_PM_DECODEEN_SECOND_RES);
211211
break;
212+
default:
213+
break;
212214
}
213215
}
214216

@@ -307,6 +309,99 @@ static int sp5100_tco_timer_init(struct sp5100_tco *tco)
307309
return 0;
308310
}
309311

312+
static u8 efch_read_pm_reg8(void __iomem *addr, u8 index)
313+
{
314+
return readb(addr + index);
315+
}
316+
317+
static void efch_update_pm_reg8(void __iomem *addr, u8 index, u8 reset, u8 set)
318+
{
319+
u8 val;
320+
321+
val = readb(addr + index);
322+
val &= reset;
323+
val |= set;
324+
writeb(val, addr + index);
325+
}
326+
327+
static void tco_timer_enable_mmio(void __iomem *addr)
328+
{
329+
efch_update_pm_reg8(addr, EFCH_PM_DECODEEN3,
330+
~EFCH_PM_WATCHDOG_DISABLE,
331+
EFCH_PM_DECODEEN_SECOND_RES);
332+
}
333+
334+
static int sp5100_tco_setupdevice_mmio(struct device *dev,
335+
struct watchdog_device *wdd)
336+
{
337+
struct sp5100_tco *tco = watchdog_get_drvdata(wdd);
338+
const char *dev_name = SB800_DEVNAME;
339+
u32 mmio_addr = 0, alt_mmio_addr = 0;
340+
struct resource *res;
341+
void __iomem *addr;
342+
int ret;
343+
u32 val;
344+
345+
res = request_mem_region_muxed(EFCH_PM_ACPI_MMIO_PM_ADDR,
346+
EFCH_PM_ACPI_MMIO_PM_SIZE,
347+
"sp5100_tco");
348+
349+
if (!res) {
350+
dev_err(dev,
351+
"Memory region 0x%08x already in use\n",
352+
EFCH_PM_ACPI_MMIO_PM_ADDR);
353+
return -EBUSY;
354+
}
355+
356+
addr = ioremap(EFCH_PM_ACPI_MMIO_PM_ADDR, EFCH_PM_ACPI_MMIO_PM_SIZE);
357+
if (!addr) {
358+
dev_err(dev, "Address mapping failed\n");
359+
ret = -ENOMEM;
360+
goto out;
361+
}
362+
363+
/*
364+
* EFCH_PM_DECODEEN_WDT_TMREN is dual purpose. This bitfield
365+
* enables sp5100_tco register MMIO space decoding. The bitfield
366+
* also starts the timer operation. Enable if not already enabled.
367+
*/
368+
val = efch_read_pm_reg8(addr, EFCH_PM_DECODEEN);
369+
if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
370+
efch_update_pm_reg8(addr, EFCH_PM_DECODEEN, 0xff,
371+
EFCH_PM_DECODEEN_WDT_TMREN);
372+
}
373+
374+
/* Error if the timer could not be enabled */
375+
val = efch_read_pm_reg8(addr, EFCH_PM_DECODEEN);
376+
if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
377+
dev_err(dev, "Failed to enable the timer\n");
378+
ret = -EFAULT;
379+
goto out;
380+
}
381+
382+
mmio_addr = EFCH_PM_WDT_ADDR;
383+
384+
/* Determine alternate MMIO base address */
385+
val = efch_read_pm_reg8(addr, EFCH_PM_ISACONTROL);
386+
if (val & EFCH_PM_ISACONTROL_MMIOEN)
387+
alt_mmio_addr = EFCH_PM_ACPI_MMIO_ADDR +
388+
EFCH_PM_ACPI_MMIO_WDT_OFFSET;
389+
390+
ret = sp5100_tco_prepare_base(tco, mmio_addr, alt_mmio_addr, dev_name);
391+
if (!ret) {
392+
tco_timer_enable_mmio(addr);
393+
ret = sp5100_tco_timer_init(tco);
394+
}
395+
396+
out:
397+
if (addr)
398+
iounmap(addr);
399+
400+
release_resource(res);
401+
402+
return ret;
403+
}
404+
310405
static int sp5100_tco_setupdevice(struct device *dev,
311406
struct watchdog_device *wdd)
312407
{
@@ -316,6 +411,9 @@ static int sp5100_tco_setupdevice(struct device *dev,
316411
u32 alt_mmio_addr = 0;
317412
int ret;
318413

414+
if (tco->tco_reg_layout == efch_mmio)
415+
return sp5100_tco_setupdevice_mmio(dev, wdd);
416+
319417
/* Request the IO ports used by this driver */
320418
if (!request_muxed_region(SP5100_IO_PM_INDEX_REG,
321419
SP5100_PM_IOPORTS_SIZE, "sp5100_tco")) {

drivers/watchdog/sp5100_tco.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,9 @@
8383
#define EFCH_PM_ISACONTROL_MMIOEN BIT(1)
8484

8585
#define EFCH_PM_ACPI_MMIO_ADDR 0xfed80000
86+
#define EFCH_PM_ACPI_MMIO_PM_OFFSET 0x00000300
8687
#define EFCH_PM_ACPI_MMIO_WDT_OFFSET 0x00000b00
88+
89+
#define EFCH_PM_ACPI_MMIO_PM_ADDR (EFCH_PM_ACPI_MMIO_ADDR + \
90+
EFCH_PM_ACPI_MMIO_PM_OFFSET)
91+
#define EFCH_PM_ACPI_MMIO_PM_SIZE 8

0 commit comments

Comments
 (0)