From 60ca74ac3c89a476b38d4f41c3bea3745779587e Mon Sep 17 00:00:00 2001 From: Lionel VITTE Date: Mon, 5 Oct 2020 13:19:46 +0200 Subject: [PATCH 11/22] ARM-stm32mp1-r2-rc8-RESET-RTC-WATCHDOG --- .../devicetree/bindings/rtc/st,stm32-rtc.txt | 10 +- drivers/reset/reset-stm32mp1.c | 83 +++++--- drivers/rtc/Kconfig | 1 + drivers/rtc/rtc-stm32.c | 180 +++++++++++++++--- drivers/watchdog/stm32_iwdg.c | 6 +- include/dt-bindings/reset/stm32mp1-resets.h | 15 ++ include/dt-bindings/rtc/rtc-stm32.h | 13 ++ 7 files changed, 246 insertions(+), 62 deletions(-) create mode 100644 include/dt-bindings/rtc/rtc-stm32.h diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt index 130ca5b982538..bab0df81af2cc 100644 --- a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt @@ -21,9 +21,14 @@ Required properties: domain (RTC registers) write protection. It is required on stm32(f4/f7/h7). -Optional properties (to override default rtc_ck parent clock on stm32(f4/f7/h7): +Optional properties: +* to override default rtc_ck parent clock on stm32(f4/f7/h7): - assigned-clocks: reference to the rtc_ck clock entry. - assigned-clock-parents: phandle of the new parent clock of rtc_ck. +* to select and enable RTC Low Speed Clock Output on stm32mp1: +- st,lsco: defines the RTC output on which RTC Low-Speed Clock is Output. The + valid output values are defined in . +- pinctrl state named "default" may be defined to reserve pin for RTC output. Example: @@ -58,4 +63,7 @@ Example: clock-names = "pclk", "rtc_ck"; interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_NONE>, <&exti 19 1>; + st,lsco = ; + pinctrl-0 = <&rtc_out2_rmp_pins_a>; + pinctrl-names = "default"; }; diff --git a/drivers/reset/reset-stm32mp1.c b/drivers/reset/reset-stm32mp1.c index b221a28041fa0..daf0e26b27a8d 100644 --- a/drivers/reset/reset-stm32mp1.c +++ b/drivers/reset/reset-stm32mp1.c @@ -4,14 +4,21 @@ * Author: Gabriel Fernandez for STMicroelectronics. */ +#include +#include #include #include #include +#include #include +#include #include #include +#include -#define CLR_OFFSET 0x4 +#define STM32MP1_RESET_ID_MASK GENMASK(15, 0) + +#define CLR_OFFSET 0x4 struct stm32_reset_data { struct reset_controller_dev rcdev; @@ -79,37 +86,57 @@ static const struct of_device_id stm32_reset_dt_ids[] = { { /* sentinel */ }, }; -static int stm32_reset_probe(struct platform_device *pdev) +static void __init stm32mp1_reset_init(struct device_node *np) { - struct device *dev = &pdev->dev; - struct stm32_reset_data *data; - void __iomem *membase; - struct resource *res; - - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + void __iomem *base; + const struct of_device_id *match; + struct stm32_reset_data *data = NULL; + int ret; + + base = of_iomap(np, 0); + if (!base) { + pr_err("%pOFn: unable to map resource", np); + of_node_put(np); + return; + } + + match = of_match_node(stm32_reset_dt_ids, np); + if (!match) { + pr_err("%s: match data not found\n", __func__); + goto err; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - membase = devm_ioremap_resource(dev, res); - if (IS_ERR(membase)) - return PTR_ERR(membase); + goto err; - data->membase = membase; + data->membase = base; data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; data->rcdev.ops = &stm32_reset_ops; - data->rcdev.of_node = dev->of_node; - - return devm_reset_controller_register(dev, &data->rcdev); + data->rcdev.of_node = np; + data->rcdev.nr_resets = STM32MP1_RESET_ID_MASK; + + ret = reset_controller_register(&data->rcdev); + if (!ret) + return; + +err: + pr_err("stm32mp1 reset failed to initialize\n"); + if (data) + kfree(data); + if (base) + iounmap(base); + of_node_put(np); } -static struct platform_driver stm32_reset_driver = { - .probe = stm32_reset_probe, - .driver = { - .name = "stm32mp1-reset", - .of_match_table = stm32_reset_dt_ids, - }, -}; - -builtin_platform_driver(stm32_reset_driver); +/* + * RCC reset and clock drivers bind to the same RCC node. + * Register RCC reset driver at init through clock of table, + * clock driver for RCC will register at probe time. + */ +static void __init stm32mp1_reset_of_init_drv(struct device_node *np) +{ + of_node_clear_flag(np, OF_POPULATED); + stm32mp1_reset_init(np); +} +OF_DECLARE_1(clk, stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_reset_of_init_drv); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index c5b9804140860..d590b420525ce 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1862,6 +1862,7 @@ config RTC_DRV_R7301 config RTC_DRV_STM32 tristate "STM32 RTC" select REGMAP_MMIO + depends on COMMON_CLK depends on ARCH_STM32 || COMPILE_TEST help If you say yes here you get support for the STM32 On-Chip diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c index 2999e33a7e376..3cf51497681a4 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -6,6 +6,8 @@ #include #include +#include +#include #include #include #include @@ -15,6 +17,8 @@ #include #include +#include + #define DRIVER_NAME "stm32_rtc" /* STM32_RTC_TR bit fields */ @@ -39,6 +43,12 @@ #define STM32_RTC_CR_FMT BIT(6) #define STM32_RTC_CR_ALRAE BIT(8) #define STM32_RTC_CR_ALRAIE BIT(12) +#define STM32_RTC_CR_COSEL BIT(19) +#define STM32_RTC_CR_OSEL_SHIFT 21 +#define STM32_RTC_CR_OSEL GENMASK(22, 21) +#define STM32_RTC_CR_COE BIT(23) +#define STM32_RTC_CR_TAMPOE BIT(26) +#define STM32_RTC_CR_OUT2EN BIT(31) /* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */ #define STM32_RTC_ISR_ALRAWF BIT(0) @@ -75,6 +85,11 @@ /* STM32_RTC_SR/_SCR bit fields */ #define STM32_RTC_SR_ALRA BIT(0) +/* STM32_RTC_CFGR bit fields */ +#define STM32_RTC_CFGR_OUT2_RMP BIT(0) +#define STM32_RTC_CFGR_LSCOEN_OUT1 1 +#define STM32_RTC_CFGR_LSCOEN_OUT2_RMP 2 + /* STM32_RTC_VERR bit fields */ #define STM32_RTC_VERR_MINREV_SHIFT 0 #define STM32_RTC_VERR_MINREV GENMASK(3, 0) @@ -101,6 +116,7 @@ struct stm32_rtc_registers { u16 wpr; u16 sr; u16 scr; + u16 cfgr; u16 verr; }; @@ -114,7 +130,8 @@ struct stm32_rtc_data { void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); bool has_pclk; bool need_dbp; - bool has_wakeirq; + bool has_lsco; + bool need_accuracy; }; struct stm32_rtc { @@ -127,9 +144,87 @@ struct stm32_rtc { struct clk *rtc_ck; const struct stm32_rtc_data *data; int irq_alarm; - int wakeirq_alarm; + int lsco; + struct clk *clk_lsco; }; +/* + * ------------------------------------------------------------------------- + * | TAMPOE | OSEL[1:0] | COE | OUT2EN | RTC_OUT1 | RTC_OUT2 | + * | | | | | | or RTC_OUT2_RMP | + * |-------------------------------------------------------------------------| + * | 0 | 00 | 0 | 0 or 1 | - | - | + * |--------|-----------|-----|--------|------------------|------------------| + * | 0 | 00 | 1 | 0 | CALIB | - | + * |--------|-----------|-----|--------|------------------|------------------| + * | 0 or 1 | !=00 | 0 | 0 | TAMPALRM | - | + * |--------|-----------|-----|--------|------------------|------------------| + * | 0 | 00 | 1 | 1 | - | CALIB | + * |--------|-----------|-----|--------|------------------|------------------| + * | 0 or 1 | !=00 | 0 | 1 | - | TAMPALRM | + * |--------|-----------|-----|--------|------------------|------------------| + * | 0 or 1 | !=00 | 1 | 1 | TAMPALRM | CALIB | + * ------------------------------------------------------------------------- + */ +static int stm32_rtc_clk_lsco_check_availability(struct stm32_rtc *rtc) +{ + struct stm32_rtc_registers regs = rtc->data->regs; + unsigned int cr = readl_relaxed(rtc->base + regs.cr); + unsigned int cfgr = readl_relaxed(rtc->base + regs.cfgr); + unsigned int calib = STM32_RTC_CR_COE; + unsigned int tampalrm = STM32_RTC_CR_TAMPOE | STM32_RTC_CR_OSEL; + + switch (rtc->lsco) { + case RTC_OUT1: + if ((!(cr & STM32_RTC_CR_OUT2EN) && + ((cr & calib) || cr & tampalrm)) || + ((cr & calib) && (cr & tampalrm))) + return -EBUSY; + break; + case RTC_OUT2_RMP: + if ((cr & STM32_RTC_CR_OUT2EN) && + (cfgr & STM32_RTC_CFGR_OUT2_RMP) && + ((cr & calib) || (cr & tampalrm))) + return -EBUSY; + break; + default: + return -EINVAL; + } + + if (clk_get_rate(rtc->rtc_ck) != 32768) + return -ERANGE; + + return 0; +} + +static int stm32_rtc_clk_lsco_register(struct platform_device *pdev) +{ + struct stm32_rtc *rtc = platform_get_drvdata(pdev); + struct stm32_rtc_registers regs = rtc->data->regs; + u8 lscoen; + int ret; + + ret = stm32_rtc_clk_lsco_check_availability(rtc); + if (ret) + return ret; + + lscoen = (rtc->lsco == RTC_OUT1) ? STM32_RTC_CFGR_LSCOEN_OUT1 : + STM32_RTC_CFGR_LSCOEN_OUT2_RMP; + + rtc->clk_lsco = clk_register_gate(&pdev->dev, "rtc_lsco", + __clk_get_name(rtc->rtc_ck), + CLK_IGNORE_UNUSED | CLK_IS_CRITICAL, + rtc->base + regs.cfgr, lscoen, + 0, NULL); + if (IS_ERR(rtc->clk_lsco)) + return PTR_ERR(rtc->clk_lsco); + + of_clk_add_provider(pdev->dev.of_node, + of_clk_src_simple_get, rtc->clk_lsco); + + return 0; +} + static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) { const struct stm32_rtc_registers *regs = &rtc->data->regs; @@ -547,7 +642,8 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32_rtc_data = { .has_pclk = false, .need_dbp = true, - .has_wakeirq = false, + .has_lsco = false, + .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, @@ -558,6 +654,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { .wpr = 0x24, .sr = 0x0C, /* set to ISR offset to ease alarm management */ .scr = UNDEF_REG, + .cfgr = UNDEF_REG, .verr = UNDEF_REG, }, .events = { @@ -569,7 +666,8 @@ static const struct stm32_rtc_data stm32_rtc_data = { static const struct stm32_rtc_data stm32h7_rtc_data = { .has_pclk = true, .need_dbp = true, - .has_wakeirq = false, + .has_lsco = false, + .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, @@ -580,6 +678,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { .wpr = 0x24, .sr = 0x0C, /* set to ISR offset to ease alarm management */ .scr = UNDEF_REG, + .cfgr = UNDEF_REG, .verr = UNDEF_REG, }, .events = { @@ -600,7 +699,8 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32mp1_data = { .has_pclk = true, .need_dbp = false, - .has_wakeirq = true, + .has_lsco = true, + .need_accuracy = true, .regs = { .tr = 0x00, .dr = 0x04, @@ -611,6 +711,7 @@ static const struct stm32_rtc_data stm32mp1_data = { .wpr = 0x24, .sr = 0x50, .scr = 0x5C, + .cfgr = 0x60, .verr = 0x3F4, }, .events = { @@ -641,11 +742,20 @@ static int stm32_rtc_init(struct platform_device *pdev, pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; - for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { - pred_s = (rate / (pred_a + 1)) - 1; + if (rtc->data->need_accuracy) { + for (pred_a = 0; pred_a <= pred_a_max; pred_a++) { + pred_s = (rate / (pred_a + 1)) - 1; + + if (((pred_s + 1) * (pred_a + 1)) == rate) + break; + } + } else { + for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { + pred_s = (rate / (pred_a + 1)) - 1; - if (((pred_s + 1) * (pred_a + 1)) == rate) - break; + if (((pred_s + 1) * (pred_a + 1)) == rate) + break; + } } /* @@ -738,13 +848,15 @@ static int stm32_rtc_probe(struct platform_device *pdev) } else { rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(rtc->pclk)) { - dev_err(&pdev->dev, "no pclk clock"); + if (PTR_ERR(rtc->pclk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "no pclk clock"); return PTR_ERR(rtc->pclk); } rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck"); } if (IS_ERR(rtc->rtc_ck)) { - dev_err(&pdev->dev, "no rtc_ck clock"); + if (PTR_ERR(rtc->pclk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "no rtc_ck clock"); return PTR_ERR(rtc->rtc_ck); } @@ -781,19 +893,12 @@ static int stm32_rtc_probe(struct platform_device *pdev) } ret = device_init_wakeup(&pdev->dev, true); - if (rtc->data->has_wakeirq) { - rtc->wakeirq_alarm = platform_get_irq(pdev, 1); - if (rtc->wakeirq_alarm > 0) { - ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, - rtc->wakeirq_alarm); - } else { - ret = rtc->wakeirq_alarm; - if (rtc->wakeirq_alarm == -EPROBE_DEFER) - goto err; - } - } if (ret) - dev_warn(&pdev->dev, "alarm can't wake up the system: %d", ret); + goto err; + + ret = dev_pm_set_wake_irq(&pdev->dev, rtc->irq_alarm); + if (ret) + goto err; platform_set_drvdata(pdev, rtc); @@ -816,6 +921,21 @@ static int stm32_rtc_probe(struct platform_device *pdev) goto err; } + if (rtc->data->has_lsco) { + ret = of_property_read_s32(pdev->dev.of_node, + "st,lsco", &rtc->lsco); + if (!ret) { + ret = stm32_rtc_clk_lsco_register(pdev); + if (ret) + dev_warn(&pdev->dev, + "LSCO clock registration failed: %d\n", + ret); + } else { + rtc->lsco = ret; + dev_dbg(&pdev->dev, "No LSCO clock: %d\n", ret); + } + } + /* * If INITS flag is reset (calendar year field set to 0x00), calendar * must be initialized @@ -852,6 +972,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) const struct stm32_rtc_registers *regs = &rtc->data->regs; unsigned int cr; + if (!IS_ERR_OR_NULL(rtc->clk_lsco)) + clk_unregister_gate(rtc->clk_lsco); + /* Disable interrupts */ stm32_rtc_wpr_unlock(rtc); cr = readl_relaxed(rtc->base + regs->cr); @@ -881,9 +1004,6 @@ static int stm32_rtc_suspend(struct device *dev) if (rtc->data->has_pclk) clk_disable_unprepare(rtc->pclk); - if (device_may_wakeup(dev)) - return enable_irq_wake(rtc->irq_alarm); - return 0; } @@ -902,15 +1022,13 @@ static int stm32_rtc_resume(struct device *dev) if (ret < 0) return ret; - if (device_may_wakeup(dev)) - return disable_irq_wake(rtc->irq_alarm); - return ret; } #endif -static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops, - stm32_rtc_suspend, stm32_rtc_resume); +static const struct dev_pm_ops stm32_rtc_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_rtc_suspend, stm32_rtc_resume) +}; static struct platform_driver stm32_rtc_driver = { .probe = stm32_rtc_probe, diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index 25188d6bbe152..1b71c205cee0e 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -163,7 +163,8 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, wdt->clk_lsi = devm_clk_get(dev, "lsi"); if (IS_ERR(wdt->clk_lsi)) { - dev_err(dev, "Unable to get lsi clock\n"); + if (PTR_ERR(wdt->clk_lsi) != -EPROBE_DEFER) + dev_err(dev, "Unable to get lsi clock\n"); return PTR_ERR(wdt->clk_lsi); } @@ -171,7 +172,8 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, if (wdt->data->has_pclk) { wdt->clk_pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(wdt->clk_pclk)) { - dev_err(dev, "Unable to get pclk clock\n"); + if (PTR_ERR(wdt->clk_pclk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get pclk clock\n"); return PTR_ERR(wdt->clk_pclk); } diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h index f0c3aaef67a0a..f3a0ed3178356 100644 --- a/include/dt-bindings/reset/stm32mp1-resets.h +++ b/include/dt-bindings/reset/stm32mp1-resets.h @@ -7,6 +7,7 @@ #ifndef _DT_BINDINGS_STM32MP1_RESET_H_ #define _DT_BINDINGS_STM32MP1_RESET_H_ +#define MCU_HOLD_BOOT_R 2144 #define LTDC_R 3072 #define DSI_R 3076 #define DDRPERFM_R 3080 @@ -105,4 +106,18 @@ #define GPIOJ_R 19785 #define GPIOK_R 19786 +/* SCMI reset domain identifiers */ +#define RST_SCMI0_SPI6 0 +#define RST_SCMI0_I2C4 1 +#define RST_SCMI0_I2C6 2 +#define RST_SCMI0_USART1 3 +#define RST_SCMI0_STGEN 4 +#define RST_SCMI0_GPIOZ 5 +#define RST_SCMI0_CRYP1 6 +#define RST_SCMI0_HASH1 7 +#define RST_SCMI0_RNG1 8 +#define RST_SCMI0_MDMA 9 +#define RST_SCMI0_MCU 10 +#define RST_SCMI0_MCU_HOLD_BOOT 11 + #endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h new file mode 100644 index 0000000000000..4373c4dea5879 --- /dev/null +++ b/include/dt-bindings/rtc/rtc-stm32.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header provides constants for STM32_RTC bindings. + */ + +#ifndef _DT_BINDINGS_RTC_RTC_STM32_H +#define _DT_BINDINGS_RTC_RTC_STM32_H + +#define RTC_OUT1 0 +#define RTC_OUT2 1 +#define RTC_OUT2_RMP 2 + +#endif -- 2.17.1