From patchwork Mon Mar 18 10:58:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vadim Pasternak X-Patchwork-Id: 10857377 X-Patchwork-Delegate: andy.shevchenko@gmail.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F3DEE922 for ; Mon, 18 Mar 2019 10:58:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DA4DE2934D for ; Mon, 18 Mar 2019 10:58:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CED702934E; Mon, 18 Mar 2019 10:58:35 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY 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 EE18029350 for ; Mon, 18 Mar 2019 10:58:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726692AbfCRK6e (ORCPT ); Mon, 18 Mar 2019 06:58:34 -0400 Received: from mail-il-dmz.mellanox.com ([193.47.165.129]:35570 "EHLO mellanox.co.il" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726695AbfCRK6e (ORCPT ); Mon, 18 Mar 2019 06:58:34 -0400 Received: from Internal Mail-Server by MTLPINE1 (envelope-from vadimp@mellanox.com) with ESMTPS (AES256-SHA encrypted); 18 Mar 2019 12:58:27 +0200 Received: from r-build-lowlevel.mtr.labs.mlnx. (r-build-lowlevel.mtr.labs.mlnx [10.209.0.190]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id x2IAwPZr022996; Mon, 18 Mar 2019 12:58:27 +0200 From: Vadim Pasternak To: dvhart@infradead.org, andy.shevchenko@gmail.com Cc: platform-driver-x86@vger.kernel.org, michealsh@mellanox.com, Vadim Pasternak Subject: [PATCH v1 platform-next 2/2] platform/x86: mlx-platform: Add mlx-wdt platform driver activation Date: Mon, 18 Mar 2019 10:58:23 +0000 Message-Id: <20190318105823.2821-3-vadimp@mellanox.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20190318105823.2821-1-vadimp@mellanox.com> References: <20190318105823.2821-1-vadimp@mellanox.com> Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add mlx-wdt platform driver activation. Watchdog driver uses the same regmap infrastructure as others Mellanox platform drivers. Specific registers description for watchdog platform data configuration are added to mlx-platform. There are the registers for watchdog timer manipulation, and action setting on watchdog timer expiration. The watchdog action function could be configured to perform one of the following: system reset, setting PWM to full speed or counter increment. Two types of watchdog devices are supported main and auxiliary. These devices are co-exist and each of them could be configured to handle the specific action. Signed-off-by: Michael Shych Signed-off-by: Vadim Pasternak --- drivers/platform/x86/mlx-platform.c | 225 +++++++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 3f129a28ee43..0f60b7887928 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -56,6 +56,16 @@ #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a +#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 +#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8 +#define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9 +#define MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET 0xcb +#define MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET 0xcd +#define MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET 0xce +#define MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET 0xcf +#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1 +#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2 +#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3 #define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 #define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 #define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 @@ -129,6 +139,18 @@ #define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 #define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 +/* Masks and default values for watchdogs */ +#define MLXPLAT_CPLD_WD1_CLEAR_MASK GENMASK(7, 1) +#define MLXPLAT_CPLD_WD2_CLEAR_MASK (GENMASK(7, 0) & ~BIT(1)) + +#define MLXPLAT_CPLD_WD_TYPE1_TO_MASK GENMASK(7, 4) +#define MLXPLAT_CPLD_WD_TYPE2_TO_MASK 0 +#define MLXPLAT_CPLD_WD_RESET_ACT_MASK GENMASK(7, 1) +#define MLXPLAT_CPLD_WD_FAN_ACT_MASK (GENMASK(7, 0) & ~BIT(4)) +#define MLXPLAT_CPLD_WD_COUNT_ACT_MASK (GENMASK(7, 0) & ~BIT(7)) +#define MLXPLAT_CPLD_WD_DFLT_TIMEOUT 30 +#define MLXPLAT_CPLD_WD_MAX_DEVS 2 + /* mlxplat_priv - platform private data * @pdev_i2c - i2c controller platform device * @pdev_mux - array of mux platform devices @@ -136,6 +158,7 @@ * @pdev_led - led platform devices * @pdev_io_regs - register access platform devices * @pdev_fan - FAN platform devices + * @pdev_wd - array of watchdog platform devices */ struct mlxplat_priv { struct platform_device *pdev_i2c; @@ -144,6 +167,7 @@ struct mlxplat_priv { struct platform_device *pdev_led; struct platform_device *pdev_io_regs; struct platform_device *pdev_fan; + struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; }; /* Regions for LPC I2C controller and LPC base register space */ @@ -1351,6 +1375,148 @@ static struct mlxreg_core_platform_data mlxplat_default_fan_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), }; +/* Watchdog type1: hardware implementation version1 + * (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140 systems). + */ +static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type1[] = { + { + .label = "action", + .reg = MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, + .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, + .bit = 0, + }, + { + .label = "timeout", + .reg = MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET, + .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK, + .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, + }, + { + .label = "ping", + .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET, + .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK, + .bit = 0, + }, + { + .label = "reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .bit = 6, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type1[] = { + { + .label = "action", + .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, + .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, + .bit = 4, + }, + { + .label = "timeout", + .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET, + .mask = MLXPLAT_CPLD_WD_TYPE1_TO_MASK, + .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, + }, + { + .label = "ping", + .reg = MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET, + .mask = MLXPLAT_CPLD_WD1_CLEAR_MASK, + .bit = 1, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type1[] = { + { + .data = mlxplat_mlxcpld_wd_main_regs_type1, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type1), + .version = MLX_WDT_TYPE1, + .identity = "mlx-wdt-main", + }, + { + .data = mlxplat_mlxcpld_wd_aux_regs_type1, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type1), + .version = MLX_WDT_TYPE1, + .identity = "mlx-wdt-aux", + }, +}; + +/* Watchdog type2: hardware implementation version 2 + * (all systems except (MSN2700, MSN2410, MSN2740, MSN2100 and MSN2140). + */ +static struct mlxreg_core_data mlxplat_mlxcpld_wd_main_regs_type2[] = { + { + .label = "action", + .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, + .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, + .bit = 0, + }, + { + .label = "timeout", + .reg = MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET, + .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, + .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, + }, + { + .label = "timeleft", + .reg = MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET, + .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, + }, + { + .label = "ping", + .reg = MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, + .mask = MLXPLAT_CPLD_WD_RESET_ACT_MASK, + .bit = 0, + }, + { + .label = "reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .bit = 6, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_wd_aux_regs_type2[] = { + { + .label = "action", + .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, + .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, + .bit = 4, + }, + { + .label = "timeout", + .reg = MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET, + .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, + .health_cntr = MLXPLAT_CPLD_WD_DFLT_TIMEOUT, + }, + { + .label = "timeleft", + .reg = MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET, + .mask = MLXPLAT_CPLD_WD_TYPE2_TO_MASK, + }, + { + .label = "ping", + .reg = MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, + .mask = MLXPLAT_CPLD_WD_FAN_ACT_MASK, + .bit = 4, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_mlxcpld_wd_set_type2[] = { + { + .data = mlxplat_mlxcpld_wd_main_regs_type2, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_main_regs_type2), + .version = MLX_WDT_TYPE2, + .identity = "mlx-wdt-main", + }, + { + .data = mlxplat_mlxcpld_wd_aux_regs_type2, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_wd_aux_regs_type2), + .version = MLX_WDT_TYPE2, + .identity = "mlx-wdt-aux", + }, +}; + static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -1373,6 +1539,14 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: return true; @@ -1416,6 +1590,16 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: @@ -1473,6 +1657,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: @@ -1500,6 +1688,7 @@ static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 }, { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 }, { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET, 0x00 }, }; struct mlxplat_mlxcpld_regmap_context { @@ -1549,6 +1738,8 @@ static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; static struct mlxreg_core_platform_data *mlxplat_led; static struct mlxreg_core_platform_data *mlxplat_regs_io; static struct mlxreg_core_platform_data *mlxplat_fan; +static struct mlxreg_core_platform_data + *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) { @@ -1564,6 +1755,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_default_led_data; mlxplat_regs_io = &mlxplat_default_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; return 1; }; @@ -1582,6 +1774,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_msn21xx_led_data; mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; return 1; }; @@ -1600,6 +1793,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_default_led_data; mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; return 1; }; @@ -1618,6 +1812,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_msn21xx_led_data; mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; return 1; }; @@ -1637,6 +1832,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) mlxplat_led = &mlxplat_default_ng_led_data; mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; mlxplat_fan = &mlxplat_default_fan_data; + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; return 1; }; @@ -1919,15 +2116,35 @@ static int __init mlxplat_init(void) } } + /* Add WD drivers. */ + for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { + if (mlxplat_wd_data[j]) { + mlxplat_wd_data[j]->regmap = mlxplat_hotplug->regmap; + priv->pdev_wd[j] = platform_device_register_resndata + (&mlxplat_dev->dev, + "mlx-wdt", j, NULL, 0, + mlxplat_wd_data[j], + sizeof(*mlxplat_wd_data[j])); + if (IS_ERR(priv->pdev_wd[j])) { + err = PTR_ERR(priv->pdev_wd[j]); + goto fail_platform_wd_register; + } + } + } + /* Sync registers with hardware. */ regcache_mark_dirty(mlxplat_hotplug->regmap); err = regcache_sync(mlxplat_hotplug->regmap); if (err) - goto fail_platform_fan_register; + goto fail_platform_wd_register; return 0; -fail_platform_fan_register: +fail_platform_wd_register: + while (--j >= 0) { + if (priv->pdev_wd[j]) + platform_device_unregister(priv->pdev_wd[j]); + } if (mlxplat_fan) platform_device_unregister(priv->pdev_fan); fail_platform_io_regs_register: @@ -1953,6 +2170,10 @@ static void __exit mlxplat_exit(void) struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); int i; + for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) { + if (mlxplat_wd_data[i]) + platform_device_unregister(priv->pdev_wd[i]); + } if (priv->pdev_fan) platform_device_unregister(priv->pdev_fan); if (priv->pdev_io_regs)