From patchwork Fri Nov 1 12:11:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chin-Ting Kuo X-Patchwork-Id: 840547 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BCF1E19CC3D; Fri, 1 Nov 2024 12:12:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730463143; cv=none; b=GVxBy0NS+RZUw7Z1AgRdqajruz4z+h751jXeudpKhDNHfywjjZ7t8JLf3eD9H3MZDxC5Ztqm7/7VF0gI/KDXD4+PFzJdNAPfL7ToZmSKTqhn7GQ642RXJuwH91V2TIOaXzqPzO8ZXlukecZDCk4UCQyprjs8EhlKgMytve9H9qc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730463143; c=relaxed/simple; bh=ZGaDcygt9bL7YlA3SNLWepocttBVFQ51uj+Br8xzAxY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qFdYB7xZv72smQCbhib085fKMWkahUoexeugytqS4Egzyq8V8WVN1fjTHQR9pRE3fh/RnieuzUY/4ZD/SNG6XiW125vpeigcLD0hT8BWKQ81iu6ATueJdGRSaWV/oOlvF8ox1vroe1+3SmT4ubLYnh2WvvDbgWwRIRVrW1xYQRY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.12; Fri, 1 Nov 2024 20:12:01 +0800 Received: from aspeedtech.com (192.168.10.152) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Fri, 1 Nov 2024 20:12:01 +0800 From: Chin-Ting Kuo To: , , , , , , , , CC: , , , , , Subject: [PATCH v4 1/3] watchdog: aspeed: Update bootstatus handling Date: Fri, 1 Nov 2024 20:11:59 +0800 Message-ID: <20241101121201.2464091-2-chin-ting_kuo@aspeedtech.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241101121201.2464091-1-chin-ting_kuo@aspeedtech.com> References: <20241101121201.2464091-1-chin-ting_kuo@aspeedtech.com> Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The boot status in the watchdog device struct is updated during controller probe stage. Application layer can get the boot status through the command, cat /sys/class/watchdog/watchdogX/bootstatus. The boot status mapping rule follows the latest design guide from the OpenBMC shown as below. https://github.com/openbmc/docs/blob/master/designs/bmc-reboot-cause-update.md#proposed-design - WDIOF_EXTERN1 => system is reset by Software - WDIOF_CARDRESET => system is reset by WDT SoC reset - Others => other reset events, e.g., power on reset. On ASPEED platform, the boot status is recorded in the SCU registers. - AST2400: Only a bit represents for any WDT reset. - AST2500: The reset triggered by different WDT controllers can be distinguished by different SCU bits. But, WDIOF_EXTERN1 or WDIOF_CARDRESET still cannot be identified due to HW limitation. - AST2600: Different from AST2500, additional HW bits are added for distinguishing WDIOF_EXTERN1 and WDIOF_CARDRESET. Besides, since alternating boot event is triggered by WDT SoC reset, it is classified as WDIOF_CARDRESET. Signed-off-by: Chin-Ting Kuo --- drivers/watchdog/aspeed_wdt.c | 83 ++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index b4773a6aaf8c..4ad6335ff25b 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -11,21 +11,31 @@ #include #include #include +#include #include #include #include #include +#include #include static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +struct aspeed_wdt_scu { + const char *compatible; + u32 reset_status_reg; + u32 wdt_reset_mask; + u32 wdt_sw_reset_mask; + u32 wdt_reset_mask_shift; +}; struct aspeed_wdt_config { u32 ext_pulse_width_mask; u32 irq_shift; u32 irq_mask; + struct aspeed_wdt_scu scu; }; struct aspeed_wdt { @@ -39,18 +49,39 @@ static const struct aspeed_wdt_config ast2400_config = { .ext_pulse_width_mask = 0xff, .irq_shift = 0, .irq_mask = 0, + .scu = { + .compatible = "aspeed,ast2400-scu", + .reset_status_reg = 0x3c, + .wdt_reset_mask = 0x1, + .wdt_sw_reset_mask = 0, + .wdt_reset_mask_shift = 1, + }, }; static const struct aspeed_wdt_config ast2500_config = { .ext_pulse_width_mask = 0xfffff, .irq_shift = 12, .irq_mask = GENMASK(31, 12), + .scu = { + .compatible = "aspeed,ast2500-scu", + .reset_status_reg = 0x3c, + .wdt_reset_mask = 0x1, + .wdt_sw_reset_mask = 0, + .wdt_reset_mask_shift = 2, + }, }; static const struct aspeed_wdt_config ast2600_config = { .ext_pulse_width_mask = 0xfffff, .irq_shift = 0, .irq_mask = GENMASK(31, 10), + .scu = { + .compatible = "aspeed,ast2600-scu", + .reset_status_reg = 0x74, + .wdt_reset_mask = 0xf, + .wdt_sw_reset_mask = 0x8, + .wdt_reset_mask_shift = 16, + }, }; static const struct of_device_id aspeed_wdt_of_table[] = { @@ -213,6 +244,52 @@ static int aspeed_wdt_restart(struct watchdog_device *wdd, return 0; } +static int aspeed_wdt_update_bootstatus(struct platform_device *pdev, + struct aspeed_wdt *wdt) +{ + struct resource *res; + struct aspeed_wdt_scu scu = wdt->cfg->scu; + struct regmap *scu_base; + u32 reset_mask_width; + u32 reset_mask_shift; + u32 reg_size = 0; + u32 idx = 0; + u32 status; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_size = res->end - res->start; + + if (reg_size != 0) + idx = ((intptr_t)wdt->base & 0x00000fff) / reg_size; + + /* On ast2400, only a bit is used to represent WDT reset */ + if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2400-wdt")) + idx = 0; + + scu_base = syscon_regmap_lookup_by_compatible(scu.compatible); + if (IS_ERR(scu_base)) + return PTR_ERR(scu_base); + + ret = regmap_read(scu_base, scu.reset_status_reg, &status); + if (ret) + return ret; + + reset_mask_width = hweight32(scu.wdt_reset_mask); + reset_mask_shift = scu.wdt_reset_mask_shift + + reset_mask_width * idx; + + if (status & (scu.wdt_sw_reset_mask << reset_mask_shift)) + wdt->wdd.bootstatus = WDIOF_EXTERN1; + else if (status & (scu.wdt_reset_mask << reset_mask_shift)) + wdt->wdd.bootstatus = WDIOF_CARDRESET; + else + wdt->wdd.bootstatus = 0; + + return regmap_write(scu_base, scu.reset_status_reg, + scu.wdt_reset_mask << reset_mask_shift); +} + /* access_cs0 shows if cs0 is accessible, hence the reverted bit */ static ssize_t access_cs0_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -458,10 +535,12 @@ static int aspeed_wdt_probe(struct platform_device *pdev) writel(duration - 1, wdt->base + WDT_RESET_WIDTH); } + ret = aspeed_wdt_update_bootstatus(pdev, wdt); + if (ret) + return ret; + status = readl(wdt->base + WDT_TIMEOUT_STATUS); if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) { - wdt->wdd.bootstatus = WDIOF_CARDRESET; - if (of_device_is_compatible(np, "aspeed,ast2400-wdt") || of_device_is_compatible(np, "aspeed,ast2500-wdt")) wdt->wdd.groups = bswitch_groups; From patchwork Fri Nov 1 12:12:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chin-Ting Kuo X-Patchwork-Id: 840260 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 60D9319CC27; Fri, 1 Nov 2024 12:12:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730463152; cv=none; b=q0K3fttd5YyXgwpC7o0taUXiM2jnSn1S0RMy5rErhXzt3PGdyrtZ8Za1nfRtZyk0BrLsuHzM7WwKF3rokYXLoJSfk9ZVyZr0eN8DhAKWd8ZomTFzG9hrk5K4GpainmKRfi1AWjzKstmi4vp7Nk2lkURDesvRMwH5i2wLERu06Vg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730463152; c=relaxed/simple; bh=yHQyeN3lOKaQ+MpV6agfbg9M3ApVYZeNCKQ7cxllyj4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Vy+ULr8W/cORRlhg/vOn11YI7gmYkYg6hSUQaYaGJmvV0Qwdx7EW6AWroPq+i5E8R2cb5e9Sdmo8UmrX3T37uKpTf9bw7tdspCiZEfYTCKeWr7Pr8VbGIQ65RQXDyYNandDB767w+hBs9TeToF6qugStaB4EP9x/zLADhCY0KIQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.12; Fri, 1 Nov 2024 20:12:02 +0800 Received: from aspeedtech.com (192.168.10.152) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Fri, 1 Nov 2024 20:12:02 +0800 From: Chin-Ting Kuo To: , , , , , , , , CC: , , , , , Subject: [PATCH v4 2/3] watchdog: aspeed: Change aspeed_wdt_config struct name to aspeed_wdt_data Date: Fri, 1 Nov 2024 20:12:00 +0800 Message-ID: <20241101121201.2464091-3-chin-ting_kuo@aspeedtech.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241101121201.2464091-1-chin-ting_kuo@aspeedtech.com> References: <20241101121201.2464091-1-chin-ting_kuo@aspeedtech.com> Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 aspeed_wdt_config struct is used to store some HW configuration information. Changing its naming to a more generic one, aspeed_wdt_data, in order to contain more platform specific inforamtion or SW callback functions. Signed-off-by: Chin-Ting Kuo --- drivers/watchdog/aspeed_wdt.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index 4ad6335ff25b..63b5ff9e2751 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -31,7 +31,7 @@ struct aspeed_wdt_scu { u32 wdt_reset_mask_shift; }; -struct aspeed_wdt_config { +struct aspeed_wdt_data { u32 ext_pulse_width_mask; u32 irq_shift; u32 irq_mask; @@ -42,10 +42,10 @@ struct aspeed_wdt { struct watchdog_device wdd; void __iomem *base; u32 ctrl; - const struct aspeed_wdt_config *cfg; + const struct aspeed_wdt_data *data; }; -static const struct aspeed_wdt_config ast2400_config = { +static const struct aspeed_wdt_data ast2400_data = { .ext_pulse_width_mask = 0xff, .irq_shift = 0, .irq_mask = 0, @@ -58,7 +58,7 @@ static const struct aspeed_wdt_config ast2400_config = { }, }; -static const struct aspeed_wdt_config ast2500_config = { +static const struct aspeed_wdt_data ast2500_data = { .ext_pulse_width_mask = 0xfffff, .irq_shift = 12, .irq_mask = GENMASK(31, 12), @@ -71,7 +71,7 @@ static const struct aspeed_wdt_config ast2500_config = { }, }; -static const struct aspeed_wdt_config ast2600_config = { +static const struct aspeed_wdt_data ast2600_data = { .ext_pulse_width_mask = 0xfffff, .irq_shift = 0, .irq_mask = GENMASK(31, 10), @@ -85,9 +85,9 @@ static const struct aspeed_wdt_config ast2600_config = { }; static const struct of_device_id aspeed_wdt_of_table[] = { - { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_config }, - { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_config }, - { .compatible = "aspeed,ast2600-wdt", .data = &ast2600_config }, + { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_data }, + { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_data }, + { .compatible = "aspeed,ast2600-wdt", .data = &ast2600_data }, { }, }; MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); @@ -216,8 +216,8 @@ static int aspeed_wdt_set_pretimeout(struct watchdog_device *wdd, { struct aspeed_wdt *wdt = to_aspeed_wdt(wdd); u32 actual = pretimeout * WDT_RATE_1MHZ; - u32 s = wdt->cfg->irq_shift; - u32 m = wdt->cfg->irq_mask; + u32 s = wdt->data->irq_shift; + u32 m = wdt->data->irq_mask; wdd->pretimeout = pretimeout; wdt->ctrl &= ~m; @@ -248,7 +248,7 @@ static int aspeed_wdt_update_bootstatus(struct platform_device *pdev, struct aspeed_wdt *wdt) { struct resource *res; - struct aspeed_wdt_scu scu = wdt->cfg->scu; + struct aspeed_wdt_scu scu = wdt->data->scu; struct regmap *scu_base; u32 reset_mask_width; u32 reset_mask_shift; @@ -401,7 +401,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) ofdid = of_match_node(aspeed_wdt_of_table, np); if (!ofdid) return -EINVAL; - wdt->cfg = ofdid->data; + wdt->data = ofdid->data; wdt->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(wdt->base)) @@ -409,7 +409,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) wdt->wdd.info = &aspeed_wdt_info; - if (wdt->cfg->irq_mask) { + if (wdt->data->irq_mask) { int irq = platform_get_irq_optional(pdev, 0); if (irq > 0) { @@ -485,7 +485,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) size_t nrstmask = of_device_is_compatible(np, "aspeed,ast2600-wdt") ? 2 : 1; u32 reg = readl(wdt->base + WDT_RESET_WIDTH); - reg &= wdt->cfg->ext_pulse_width_mask; + reg &= wdt->data->ext_pulse_width_mask; if (of_property_read_bool(np, "aspeed,ext-active-high")) reg |= WDT_ACTIVE_HIGH_MAGIC; else @@ -493,7 +493,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) writel(reg, wdt->base + WDT_RESET_WIDTH); - reg &= wdt->cfg->ext_pulse_width_mask; + reg &= wdt->data->ext_pulse_width_mask; if (of_property_read_bool(np, "aspeed,ext-push-pull")) reg |= WDT_PUSH_PULL_MAGIC; else @@ -510,7 +510,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev) } if (!of_property_read_u32(np, "aspeed,ext-pulse-duration", &duration)) { - u32 max_duration = wdt->cfg->ext_pulse_width_mask + 1; + u32 max_duration = wdt->data->ext_pulse_width_mask + 1; if (duration == 0 || duration > max_duration) { dev_err(dev, "Invalid pulse duration: %uus\n", From patchwork Fri Nov 1 12:12:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chin-Ting Kuo X-Patchwork-Id: 840546 Received: from TWMBX01.aspeed.com (mail.aspeedtech.com [211.20.114.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE27019D8B7; Fri, 1 Nov 2024 12:12:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.20.114.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730463155; cv=none; b=kpKNCAiDzBz+Sx4Ts5gcFqedAg9Iep7mE/xAP2yb4DvmfxoAc0Y25MrP7YPfqJCbneXOQ5aU9+beoAWmwV+bGeVNt/8VPu0Cc7fc9QFLXkBfV4qyx8QQTKropKGr/p71FQqEv50gdL88SMr3tAm2yJ6WjGdncad1usDlvzx2IVg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1730463155; c=relaxed/simple; bh=zi8NB7cF1zN02ZyOGMwY6cDJEjjoHK+KkCYbzXVAWeo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CIkJotgbw8tZnyeKsQM9RmNINHOqtGfD8IxVVdScteOyC6X5oWe4FVW+7Iyed6JnrX/u/f1RQD5BLIKin+VqLpQtaecO19zC/zMaIqErY6r1wTM8a1LNbxTDAmoi1/QuoQpIKjU47exqKxY/oRqrc5zUJKv20J5kmSYEAHbAjWI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com; spf=pass smtp.mailfrom=aspeedtech.com; arc=none smtp.client-ip=211.20.114.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=aspeedtech.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=aspeedtech.com Received: from TWMBX01.aspeed.com (192.168.0.62) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1258.12; Fri, 1 Nov 2024 20:12:02 +0800 Received: from aspeedtech.com (192.168.10.152) by TWMBX01.aspeed.com (192.168.0.62) with Microsoft SMTP Server id 15.2.1258.12 via Frontend Transport; Fri, 1 Nov 2024 20:12:02 +0800 From: Chin-Ting Kuo To: , , , , , , , , CC: , , , , , Subject: [PATCH v4 3/3] watchdog: aspeed: Update restart implementations Date: Fri, 1 Nov 2024 20:12:01 +0800 Message-ID: <20241101121201.2464091-4-chin-ting_kuo@aspeedtech.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241101121201.2464091-1-chin-ting_kuo@aspeedtech.com> References: <20241101121201.2464091-1-chin-ting_kuo@aspeedtech.com> Precedence: bulk X-Mailing-List: linux-watchdog@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Restart callback function is created to distinguish the restart mechanisms between AST2400/AST2500 and AST2600. On AST2400 and AST2500 platforms, system can only be reset by enabling WDT and waiting for WDT timeout. Since AST2600, SW can trigger the reset event consciously and directly by just cinfiguring some HW registers without waiting for WDT timeout. This mechanism is named "SW restart" and is implemented by HW. The WDT counter is not enabled when SW restart is adopted. Signed-off-by: Chin-Ting Kuo --- drivers/watchdog/aspeed_wdt.c | 59 +++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index 63b5ff9e2751..28a16a0c442d 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -23,6 +23,14 @@ static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +struct aspeed_wdt { + struct watchdog_device wdd; + void __iomem *base; + u32 ctrl; + const struct aspeed_wdt_data *data; +}; + struct aspeed_wdt_scu { const char *compatible; u32 reset_status_reg; @@ -36,14 +44,11 @@ struct aspeed_wdt_data { u32 irq_shift; u32 irq_mask; struct aspeed_wdt_scu scu; + int (*restart)(struct aspeed_wdt *wdt); }; -struct aspeed_wdt { - struct watchdog_device wdd; - void __iomem *base; - u32 ctrl; - const struct aspeed_wdt_data *data; -}; +static int aspeed_ast2400_wdt_restart(struct aspeed_wdt *wdt); +static int aspeed_ast2600_wdt_restart(struct aspeed_wdt *wdt); static const struct aspeed_wdt_data ast2400_data = { .ext_pulse_width_mask = 0xff, @@ -56,6 +61,7 @@ static const struct aspeed_wdt_data ast2400_data = { .wdt_sw_reset_mask = 0, .wdt_reset_mask_shift = 1, }, + .restart = aspeed_ast2400_wdt_restart, }; static const struct aspeed_wdt_data ast2500_data = { @@ -69,6 +75,7 @@ static const struct aspeed_wdt_data ast2500_data = { .wdt_sw_reset_mask = 0, .wdt_reset_mask_shift = 2, }, + .restart = aspeed_ast2400_wdt_restart, }; static const struct aspeed_wdt_data ast2600_data = { @@ -82,6 +89,7 @@ static const struct aspeed_wdt_data ast2600_data = { .wdt_sw_reset_mask = 0x8, .wdt_reset_mask_shift = 16, }, + .restart = aspeed_ast2600_wdt_restart, }; static const struct of_device_id aspeed_wdt_of_table[] = { @@ -112,6 +120,11 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); #define WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION BIT(0) #define WDT_RESET_MASK1 0x1c #define WDT_RESET_MASK2 0x20 +#define WDT_SW_RESET_CTRL 0x24 +#define WDT_SW_RESET_COUNT_CLEAR 0xDEADDEAD +#define WDT_SW_RESET_ENABLE 0xAEEDF123 +#define WDT_SW_RESET_MASK1 0x28 +#define WDT_SW_RESET_MASK2 0x2c /* * WDT_RESET_WIDTH controls the characteristics of the external pulse (if @@ -231,11 +244,8 @@ static int aspeed_wdt_set_pretimeout(struct watchdog_device *wdd, return 0; } -static int aspeed_wdt_restart(struct watchdog_device *wdd, - unsigned long action, void *data) +static int aspeed_ast2400_wdt_restart(struct aspeed_wdt *wdt) { - struct aspeed_wdt *wdt = to_aspeed_wdt(wdd); - wdt->ctrl &= ~WDT_CTRL_BOOT_SECONDARY; aspeed_wdt_enable(wdt, 128 * WDT_RATE_1MHZ / 1000); @@ -244,6 +254,35 @@ static int aspeed_wdt_restart(struct watchdog_device *wdd, return 0; } +static int aspeed_ast2600_wdt_restart(struct aspeed_wdt *wdt) +{ + u32 reg; + u32 ctrl = WDT_CTRL_RESET_MODE_SOC | + WDT_CTRL_RESET_SYSTEM; + + reg = readl(wdt->base + WDT_RESET_MASK1); + writel(reg, wdt->base + WDT_SW_RESET_MASK1); + reg = readl(wdt->base + WDT_RESET_MASK2); + writel(reg, wdt->base + WDT_SW_RESET_MASK2); + + writel(ctrl, wdt->base + WDT_CTRL); + writel(WDT_SW_RESET_COUNT_CLEAR, wdt->base + WDT_SW_RESET_CTRL); + writel(WDT_SW_RESET_ENABLE, wdt->base + WDT_SW_RESET_CTRL); + + /* system must be reset immediately */ + mdelay(1000); + + return 0; +} + +static int aspeed_wdt_restart(struct watchdog_device *wdd, + unsigned long action, void *data) +{ + struct aspeed_wdt *wdt = to_aspeed_wdt(wdd); + + return wdt->data->restart(wdt); +} + static int aspeed_wdt_update_bootstatus(struct platform_device *pdev, struct aspeed_wdt *wdt) {