watchdog: at91sam9_wdt: Add SAM9X60 support

SAM9X60 has a slightly different watchdog implementation:
- Timer value moved into a new register WLR
- Some MR register fields have their position changed

This patch add SAM9X60 support, also adds a compatible
for SAMA5D4 which is the same as existing SAM9260.

Signed-off-by: Zixun LI <admin@hifiphile.com>
Reviewed-by: Stefan Roese <sr@denx.de>
This commit is contained in:
Zixun LI 2025-04-28 11:16:26 +02:00 committed by Eugen Hristev
parent c8bf2d686d
commit ac46b48d30
2 changed files with 48 additions and 10 deletions

View File

@ -19,9 +19,16 @@
#else
enum {
AT91_WDT_MODE_SAM9260 = 0,
AT91_WDT_MODE_SAM9X60 = 1
};
struct at91_wdt_priv {
void __iomem *regs;
u32 mr;
u32 wddis;
u8 mode;
};
#endif
@ -33,14 +40,22 @@ struct at91_wdt_priv {
/* Watchdog Mode Register*/
#define AT91_WDT_MR 0x04
#define AT91_WDT_MR_WDV(x) (x & 0xfff)
#define AT91_WDT_MR_WDV(x) ((x) & 0xfff)
#define AT91_SAM9X60_MR_PERIODRST 0x00000010
#define AT91_WDT_MR_WDFIEN 0x00001000
#define AT91_SAM9X60_MR_WDDIS 0x00001000
#define AT91_WDT_MR_WDRSTEN 0x00002000
#define AT91_WDT_MR_WDRPROC 0x00004000
#define AT91_WDT_MR_WDDIS 0x00008000
#define AT91_WDT_MR_WDD(x) ((x & 0xfff) << 16)
#define AT91_WDT_MR_WDD(x) (((x) & 0xfff) << 16)
#define AT91_WDT_MR_WDDBGHLT 0x10000000
#define AT91_SAM9X60_MR_WDIDLEHLT 0x10000000
#define AT91_WDT_MR_WDIDLEHLT 0x20000000
#define AT91_SAM9X60_MR_WDDBGHLT 0x20000000
/* Watchdog Window Level Register */
#define AT91_SAM9X60_WLR 0x0c
#define AT91_SAM9X60_WLR_COUNTER(x) ((x) & 0xfff)
/* Hardware timeout in seconds */
#define WDT_MAX_TIMEOUT 16

View File

@ -49,7 +49,7 @@ static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
ticks = WDT_SEC2TICKS(timeout);
/* Check if disabled */
if (readl(wdt->regs + AT91_WDT_MR) & AT91_WDT_MR_WDDIS) {
if (readl(wdt->regs + AT91_WDT_MR) & wdt->wddis) {
printf("sorry, watchdog is disabled\n");
return -1;
}
@ -60,11 +60,21 @@ static int at91_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
* Since WDV is a 12-bit counter, the maximum period is
* 4096 / 256 = 16 seconds.
*/
wdt->mr = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff) /* restart at any time */
| AT91_WDT_MR_WDV(ticks); /* timer value */
writel(wdt->mr, wdt->regs + AT91_WDT_MR);
if (wdt->mode == AT91_WDT_MODE_SAM9260) {
wdt->mr = AT91_WDT_MR_WDRSTEN /* causes watchdog reset */
| AT91_WDT_MR_WDDBGHLT /* disabled in debug mode */
| AT91_WDT_MR_WDD(0xfff) /* restart at any time */
| AT91_WDT_MR_WDV(ticks); /* timer value */
writel(wdt->mr, wdt->regs + AT91_WDT_MR);
} else if (wdt->mode == AT91_WDT_MODE_SAM9X60) {
writel(AT91_SAM9X60_WLR_COUNTER(ticks), /* timer value */
wdt->regs + AT91_SAM9X60_WLR);
wdt->mr = AT91_SAM9X60_MR_PERIODRST /* causes watchdog reset */
| AT91_SAM9X60_MR_WDDBGHLT; /* disabled in debug mode */
writel(wdt->mr, wdt->regs + AT91_WDT_MR);
}
return 0;
}
@ -74,7 +84,7 @@ static int at91_wdt_stop(struct udevice *dev)
struct at91_wdt_priv *wdt = dev_get_priv(dev);
/* Disable Watchdog Timer */
wdt->mr |= AT91_WDT_MR_WDDIS;
wdt->mr |= wdt->wddis;
writel(wdt->mr, wdt->regs + AT91_WDT_MR);
return 0;
@ -96,7 +106,14 @@ static const struct wdt_ops at91_wdt_ops = {
};
static const struct udevice_id at91_wdt_ids[] = {
{ .compatible = "atmel,at91sam9260-wdt" },
{ .compatible = "atmel,at91sam9260-wdt",
.data = AT91_WDT_MODE_SAM9260 },
{ .compatible = "atmel,sama5d4-wdt",
.data = AT91_WDT_MODE_SAM9260 },
{ .compatible = "microchip,sam9x60-wdt",
.data = AT91_WDT_MODE_SAM9X60 },
{ .compatible = "microchip,sama7g5-wdt",
.data = AT91_WDT_MODE_SAM9X60 },
{}
};
@ -108,6 +125,12 @@ static int at91_wdt_probe(struct udevice *dev)
if (!wdt->regs)
return -EINVAL;
wdt->mode = dev_get_driver_data(dev);
if (wdt->mode == AT91_WDT_MODE_SAM9260)
wdt->wddis = AT91_WDT_MR_WDDIS;
else if (wdt->mode == AT91_WDT_MODE_SAM9X60)
wdt->wddis = AT91_SAM9X60_MR_WDDIS;
debug("%s: Probing wdt%u\n", __func__, dev_seq(dev));
return 0;