From patchwork Fri Oct 7 15:22:00 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pantelis Antoniou X-Patchwork-Id: 9366369 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CA1D16075E for ; Fri, 7 Oct 2016 15:31:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BA109296F7 for ; Fri, 7 Oct 2016 15:31:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AEAD1296FA; Fri, 7 Oct 2016 15:31:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DDB3A296F8 for ; Fri, 7 Oct 2016 15:31:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934042AbcJGPbq (ORCPT ); Fri, 7 Oct 2016 11:31:46 -0400 Received: from mail-wm0-f48.google.com ([74.125.82.48]:36434 "EHLO mail-wm0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756965AbcJGPYW (ORCPT ); Fri, 7 Oct 2016 11:24:22 -0400 Received: by mail-wm0-f48.google.com with SMTP id k125so38868178wma.1 for ; Fri, 07 Oct 2016 08:24:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=konsulko.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=jvPShLTk0ICL1btG4rkxIjV9pVTmWsM+2gYcLyM4MlA=; b=AVxOpQi7T+HGwQdia9l5q+gu8TAe0ZZ7bjBP62zH30SKpmBLPIgMD5ebwDyv1igcWB u0RZHsZAHUOykdKtwQcf+j00ucBBQOFlFzjVbx8Dm4a72vkjUuT2loE3MNKx89eBRpYm JtIrSAhTGzfKKgXNa0TVi7oGgqUAIHrJkTOhA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=jvPShLTk0ICL1btG4rkxIjV9pVTmWsM+2gYcLyM4MlA=; b=a8u534B6qet2OFLlhYnOsEb3S3D2KpaH2P3+Hcibb2YPEq7HLSAGFvBG6wDJLuZcT0 D0faLe3Wt/H+7V8HzXO098x/UgUev0Zl+tT1imQGROgEPxz0fiG/DDNEj5GxYKCdHuPr d0RRA9z8D8jBu2g48z8F5C2a1H6hhvmrjTHOizpSpqAjKKLLJjHoRDC2SMpUMoEVovU3 QnBqQFhumbMaDnydtGNelHF5pax3KOuCGpJzeLLPodqj1f8XkbDROgGv0XT4RyFwknKa hc+CAxkbVKu69xN7nVLecQAKr/bBYWcKJL/T+ovCRsKrr8SKxLhk7Zq9UEPV3NqHMv6k E+yw== X-Gm-Message-State: AA6/9RmUP9ZmKZ0Whm2WV/Kmpudl6At/V7FttCFdnoJyuwy2t0ifddV9R8vxZ09qxTG65A== X-Received: by 10.194.90.206 with SMTP id by14mr17079825wjb.37.1475853860757; Fri, 07 Oct 2016 08:24:20 -0700 (PDT) Received: from localhost.localdomain ([195.97.110.117]) by smtp.gmail.com with ESMTPSA id f2sm3491056wjr.2.2016.10.07.08.24.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 07 Oct 2016 08:24:20 -0700 (PDT) From: Pantelis Antoniou To: Lee Jones Cc: Rob Herring , Mark Rutland , Frank Rowand , David Woodhouse , Brian Norris , Wim Van Sebroeck , Jean Delvare , Georgi Vlaev , Guenter Roeck , JawaharBalaji Thirumalaisamy , Pantelis Antoniou , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-watchdog@vger.kernel.org, linux-hwmon@vger.kernel.org Subject: [PATCH 3/7] watchdog: Add PTX1K I2CS BootFPGA watchdog driver. Date: Fri, 7 Oct 2016 18:22:00 +0300 Message-Id: <1475853724-22557-4-git-send-email-pantelis.antoniou@konsulko.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com> References: <1475853724-22557-1-git-send-email-pantelis.antoniou@konsulko.com> Sender: linux-hwmon-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Georgi Vlaev This driver allows using the I2CS watchdog on PTX1K. The BootFPGA implements a watchdog that allows setting timeout from predefined set of values from 15 msec to 491 sec. Signed-off-by: Georgi Vlaev Signed-off-by: Guenter Roeck Signed-off-by: JawaharBalaji Thirumalaisamy [Ported from Juniper kernel] Signed-off-by: Pantelis Antoniou --- drivers/watchdog/Kconfig | 15 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/jnx_ptx1kbf_wdt.c | 229 +++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 drivers/watchdog/jnx_ptx1kbf_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 2554f47..a3761eb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1033,6 +1033,21 @@ config IT87_WDT To compile this driver as a module, choose M here: the module will be called it87_wdt. +config JNX_PTX1KBF_WDT + tristate "Juniper Networks PTX1000 I2CS BootFPGA Watchdog" + depends on X86 && MFD_JUNIPER_PTX1KBF + ---help--- + This is the driver for the watchdog timer built-in on the Juniper + Networks PTX1000 I2CS/BootFPGA and acessible from the LPC bus. The + BootFPGA watchdog allows several predefined thresholds, so this + driver will select a value close to these static values: 15 ms, + 30 ms, 60 ms, 120 ms, 240 ms, 480 ms, 960 ms, 1920 ms, 3840 ms, + 7680 ms, 15360 ms, 30720 ms, 61440 ms, 122880 ms, 245760 ms and + 516096 ms. + + To compile this driver as a module, choose M here: the + module will be called jnx_ptx1kbf_wdt. + config HP_WATCHDOG tristate "HP ProLiant iLO2+ Hardware Watchdog Timer" depends on X86 && PCI diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 942b795..f9fafdf 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -111,6 +111,7 @@ endif obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o obj-$(CONFIG_IT87_WDT) += it87_wdt.o obj-$(CONFIG_JNX_PTXPMB_WDT) += ptxpmb_wdt.o +obj-$(CONFIG_JNX_PTX1KBF_WDT) += jnx_ptx1kbf_wdt.o obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o obj-$(CONFIG_KEMPLD_WDT) += kempld_wdt.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o diff --git a/drivers/watchdog/jnx_ptx1kbf_wdt.c b/drivers/watchdog/jnx_ptx1kbf_wdt.c new file mode 100644 index 0000000..7d3e0b7 --- /dev/null +++ b/drivers/watchdog/jnx_ptx1kbf_wdt.c @@ -0,0 +1,229 @@ +/* + * Juniper Networks PTX1K RCB I2CS Boot FPGA watchdog driver + * + * Copyright (C) 2014 Juniper Networks. All rights reserved. + * Author: Georgi Vlaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define WDT_MIN_TIMEOUT 1 +#define WDT_MAX_TIMEOUT 491 +#define WDT_DEFAULT_TIMEOUT 60 /* default heartbeat in seconds */ + +#define DRVNAME "jnx-ptx1kbf-wdt" + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); + +#define MSW_NOWAYOUT __MODULE_STRING(WATCHDOG_NOWAYOUT) +MODULE_PARM_DESC(nowayout, + "Cannot be stopped once started (def=" MSW_NOWAYOUT ")"); + +struct ptx1kbf_wdt { + void __iomem *base; + struct watchdog_device wdt_dev; +}; + +/* + * The BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD register defines the watchdog + * timer thresholds in ms: 0x0 = 15 ms, 0x1 = 30 ms, ... 0xD = 122880 ms, + * 0xE = 245760 ms, 0xF = 492520 ms, or value = (2^index * 15) + */ +static int ptx1kbf_index_to_timeout(u8 reg) +{ + return ((1 << (reg & WTT_THRESHOLD_MASK)) * 15) / 1000; +} + +static u8 ptx1kbf_timeout_to_index(unsigned int timeout) +{ + return fls(timeout * 1000 / 15) & WTT_THRESHOLD_MASK; +} + +static int ptx1kbf_wdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int timeout) +{ + struct ptx1kbf_wdt *wdt = watchdog_get_drvdata(wdt_dev); + u8 reg, index; + + if (timeout > WDT_MAX_TIMEOUT) + return -EINVAL; + + index = ptx1kbf_timeout_to_index(timeout); + + reg = ioread8(wdt->base + BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD); + reg &= ~WTT_THRESHOLD_MASK; + reg |= index; + iowrite8(reg, wdt->base + BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD); + + /* Set the actual timeout supported by the watchdog */ + wdt->wdt_dev.timeout = ptx1kbf_index_to_timeout(index); + + return 0; +} + +static int ptx1kbf_wdt_ping(struct watchdog_device *wdt_dev) +{ + return ptx1kbf_wdt_set_timeout(wdt_dev, wdt_dev->timeout); +} + +static int ptx1kbf_wdt_start(struct watchdog_device *wdt_dev) +{ + struct ptx1kbf_wdt *wdt = watchdog_get_drvdata(wdt_dev); + int ret; + u8 reg; + + ret = ptx1kbf_wdt_set_timeout(wdt_dev, wdt_dev->timeout); + if (ret < 0) + return ret; + + reg = ioread8(wdt->base + BOOT_FPGA_BOOT_CONTROL); + reg |= BC_WDT_ENA; + iowrite8(reg, wdt->base + BOOT_FPGA_BOOT_CONTROL); + + return 0; +} + +static int ptx1kbf_wdt_stop(struct watchdog_device *wdt_dev) +{ + struct ptx1kbf_wdt *wdt = watchdog_get_drvdata(wdt_dev); + u8 reg; + + reg = ioread8(wdt->base + BOOT_FPGA_BOOT_CONTROL); + reg &= ~BC_WDT_ENA; + iowrite8(reg, wdt->base + BOOT_FPGA_BOOT_CONTROL); + + return 0; +} + +static struct watchdog_info ptx1kbf_wdt_info = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE, + .identity = "PTX1K BootFPGA Watchdog", + .firmware_version = 0, +}; + +static const struct watchdog_ops ptx1kbf_wdt_ops = { + .owner = THIS_MODULE, + .start = ptx1kbf_wdt_start, + .stop = ptx1kbf_wdt_stop, + .ping = ptx1kbf_wdt_ping, + .set_timeout = ptx1kbf_wdt_set_timeout, +}; + +static int ptx1kbf_wdt_probe(struct platform_device *pdev) +{ + int ret; + struct resource *res; + struct ptx1kbf_wdt *wdt; + u8 reset_reason1, reset_reason2; + unsigned int timeout; + + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + wdt->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(wdt->base)) + return PTR_ERR(wdt->base); + + platform_set_drvdata(pdev, wdt); + wdt->wdt_dev.info = &ptx1kbf_wdt_info; + wdt->wdt_dev.ops = &ptx1kbf_wdt_ops; + wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT; + wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT; + wdt->wdt_dev.timeout = WDT_DEFAULT_TIMEOUT; + wdt->wdt_dev.parent = &pdev->dev; + + reset_reason1 = ioread8(wdt->base + BOOT_FPGA_RESET_REASON1); + reset_reason2 = ioread8(wdt->base + BOOT_FPGA_RESET_REASON2); + if (reset_reason1 & RR1_MSTR) + wdt->wdt_dev.bootstatus |= WDIOF_EXTERN1; + else if (reset_reason1 & RR1_BUTTON) + wdt->wdt_dev.bootstatus |= WDIOF_EXTERN2; + else if (reset_reason1 & RR1_WDOG) + wdt->wdt_dev.bootstatus |= WDIOF_CARDRESET; + else if (reset_reason1 & RR1_POWER_FAIL) + wdt->wdt_dev.bootstatus |= WDIOF_POWERUNDER; + else if (reset_reason1 & RR1_THERM_TRIP) + wdt->wdt_dev.bootstatus |= WDIOF_OVERHEAT; + else if (reset_reason1 & RR2_AUTO_POWER_OFF) + wdt->wdt_dev.bootstatus |= WDIOF_FANFAULT; + + /* Report the FPGA/WDT version */ + ptx1kbf_wdt_info.firmware_version = + ioread8(wdt->base + BOOT_FPGA_VERSION); + + /* + * The PTX1K BIOS configures the timeout when the FPGA watchdog + * is enabled. Index values < 0x07 set thresholds bellow 1s, + * so we can ignore them + */ + timeout = ptx1kbf_index_to_timeout(ioread8(wdt->base + + BOOT_FPGA_WATCHDOG_TIMER_THRESHOLD)); + + watchdog_init_timeout(&wdt->wdt_dev, timeout, &pdev->dev); + watchdog_set_nowayout(&wdt->wdt_dev, nowayout); + watchdog_set_drvdata(&wdt->wdt_dev, wdt); + + /* Stop the watchdog if BIOS has enabled it */ + ptx1kbf_wdt_stop(&wdt->wdt_dev); + + ret = watchdog_register_device(&wdt->wdt_dev); + if (ret) + return ret; + + dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", + wdt->wdt_dev.timeout, nowayout); + + return 0; +} + +static int ptx1kbf_wdt_remove(struct platform_device *pdev) +{ + struct ptx1kbf_wdt *wdt = platform_get_drvdata(pdev); + + watchdog_unregister_device(&wdt->wdt_dev); + + return 0; +} + +static const struct of_device_id ptx1kbf_wdt_of_ids[] = { + { .compatible = "jnx,ptx1kbf-wdt", NULL }, + { } +}; +MODULE_DEVICE_TABLE(of, ptx1kbf_wdt_of_ids); + +static struct platform_driver ptx1kbf_wdt_driver = { + .probe = ptx1kbf_wdt_probe, + .remove = ptx1kbf_wdt_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = ptx1kbf_wdt_of_ids, + }, +}; + +module_platform_driver(ptx1kbf_wdt_driver); + +MODULE_DESCRIPTION("Juniper Networks PTX1K RCB I2CS Boot FPGA watchdog driver"); +MODULE_AUTHOR("Georgi Vlaev "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRVNAME);