From nobody Sun Nov 24 22:51:46 2024 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-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 =3D> system is reset by Software - WDIOF_CARDRESET =3D> system is reset by WDT SoC reset - Others =3D> 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 =20 static bool nowayout =3D WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (defau= lt=3D" __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; +}; =20 struct aspeed_wdt_config { u32 ext_pulse_width_mask; u32 irq_shift; u32 irq_mask; + struct aspeed_wdt_scu scu; }; =20 struct aspeed_wdt { @@ -39,18 +49,39 @@ static const struct aspeed_wdt_config ast2400_config = =3D { .ext_pulse_width_mask =3D 0xff, .irq_shift =3D 0, .irq_mask =3D 0, + .scu =3D { + .compatible =3D "aspeed,ast2400-scu", + .reset_status_reg =3D 0x3c, + .wdt_reset_mask =3D 0x1, + .wdt_sw_reset_mask =3D 0, + .wdt_reset_mask_shift =3D 1, + }, }; =20 static const struct aspeed_wdt_config ast2500_config =3D { .ext_pulse_width_mask =3D 0xfffff, .irq_shift =3D 12, .irq_mask =3D GENMASK(31, 12), + .scu =3D { + .compatible =3D "aspeed,ast2500-scu", + .reset_status_reg =3D 0x3c, + .wdt_reset_mask =3D 0x1, + .wdt_sw_reset_mask =3D 0, + .wdt_reset_mask_shift =3D 2, + }, }; =20 static const struct aspeed_wdt_config ast2600_config =3D { .ext_pulse_width_mask =3D 0xfffff, .irq_shift =3D 0, .irq_mask =3D GENMASK(31, 10), + .scu =3D { + .compatible =3D "aspeed,ast2600-scu", + .reset_status_reg =3D 0x74, + .wdt_reset_mask =3D 0xf, + .wdt_sw_reset_mask =3D 0x8, + .wdt_reset_mask_shift =3D 16, + }, }; =20 static const struct of_device_id aspeed_wdt_of_table[] =3D { @@ -213,6 +244,52 @@ static int aspeed_wdt_restart(struct watchdog_device *= wdd, return 0; } =20 +static int aspeed_wdt_update_bootstatus(struct platform_device *pdev, + struct aspeed_wdt *wdt) +{ + struct resource *res; + struct aspeed_wdt_scu scu =3D wdt->cfg->scu; + struct regmap *scu_base; + u32 reset_mask_width; + u32 reset_mask_shift; + u32 reg_size =3D 0; + u32 idx =3D 0; + u32 status; + int ret; + + res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_size =3D res->end - res->start; + + if (reg_size !=3D 0) + idx =3D ((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 =3D 0; + + scu_base =3D syscon_regmap_lookup_by_compatible(scu.compatible); + if (IS_ERR(scu_base)) + return PTR_ERR(scu_base); + + ret =3D regmap_read(scu_base, scu.reset_status_reg, &status); + if (ret) + return ret; + + reset_mask_width =3D hweight32(scu.wdt_reset_mask); + reset_mask_shift =3D scu.wdt_reset_mask_shift + + reset_mask_width * idx; + + if (status & (scu.wdt_sw_reset_mask << reset_mask_shift)) + wdt->wdd.bootstatus =3D WDIOF_EXTERN1; + else if (status & (scu.wdt_reset_mask << reset_mask_shift)) + wdt->wdd.bootstatus =3D WDIOF_CARDRESET; + else + wdt->wdd.bootstatus =3D 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 *p= dev) writel(duration - 1, wdt->base + WDT_RESET_WIDTH); } =20 + ret =3D aspeed_wdt_update_bootstatus(pdev, wdt); + if (ret) + return ret; + status =3D readl(wdt->base + WDT_TIMEOUT_STATUS); if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) { - wdt->wdd.bootstatus =3D WDIOF_CARDRESET; - if (of_device_is_compatible(np, "aspeed,ast2400-wdt") || of_device_is_compatible(np, "aspeed,ast2500-wdt")) wdt->wdd.groups =3D bswitch_groups; --=20 2.34.1