1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <errno.h> 9*91f16700Schasinglulu #include <string.h> 10*91f16700Schasinglulu 11*91f16700Schasinglulu #include <libfdt.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <platform_def.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include <arch_helpers.h> 16*91f16700Schasinglulu #include <common/debug.h> 17*91f16700Schasinglulu #include <drivers/arm/gicv2.h> 18*91f16700Schasinglulu #include <drivers/clk.h> 19*91f16700Schasinglulu #include <drivers/delay_timer.h> 20*91f16700Schasinglulu #include <drivers/st/stm32_iwdg.h> 21*91f16700Schasinglulu #include <drivers/st/stm32mp_clkfunc.h> 22*91f16700Schasinglulu #include <lib/mmio.h> 23*91f16700Schasinglulu #include <lib/utils.h> 24*91f16700Schasinglulu #include <plat/common/platform.h> 25*91f16700Schasinglulu 26*91f16700Schasinglulu /* IWDG registers offsets */ 27*91f16700Schasinglulu #define IWDG_KR_OFFSET 0x00U 28*91f16700Schasinglulu 29*91f16700Schasinglulu /* Registers values */ 30*91f16700Schasinglulu #define IWDG_KR_RELOAD_KEY 0xAAAA 31*91f16700Schasinglulu 32*91f16700Schasinglulu struct stm32_iwdg_instance { 33*91f16700Schasinglulu uintptr_t base; 34*91f16700Schasinglulu unsigned long clock; 35*91f16700Schasinglulu uint8_t flags; 36*91f16700Schasinglulu int num_irq; 37*91f16700Schasinglulu }; 38*91f16700Schasinglulu 39*91f16700Schasinglulu static struct stm32_iwdg_instance stm32_iwdg[IWDG_MAX_INSTANCE]; 40*91f16700Schasinglulu 41*91f16700Schasinglulu static int stm32_iwdg_get_dt_node(struct dt_node_info *info, int offset) 42*91f16700Schasinglulu { 43*91f16700Schasinglulu int node; 44*91f16700Schasinglulu 45*91f16700Schasinglulu node = dt_get_node(info, offset, DT_IWDG_COMPAT); 46*91f16700Schasinglulu if (node < 0) { 47*91f16700Schasinglulu if (offset == -1) { 48*91f16700Schasinglulu VERBOSE("%s: No IDWG found\n", __func__); 49*91f16700Schasinglulu } 50*91f16700Schasinglulu return -FDT_ERR_NOTFOUND; 51*91f16700Schasinglulu } 52*91f16700Schasinglulu 53*91f16700Schasinglulu return node; 54*91f16700Schasinglulu } 55*91f16700Schasinglulu 56*91f16700Schasinglulu void stm32_iwdg_refresh(void) 57*91f16700Schasinglulu { 58*91f16700Schasinglulu uint8_t i; 59*91f16700Schasinglulu 60*91f16700Schasinglulu for (i = 0U; i < IWDG_MAX_INSTANCE; i++) { 61*91f16700Schasinglulu struct stm32_iwdg_instance *iwdg = &stm32_iwdg[i]; 62*91f16700Schasinglulu 63*91f16700Schasinglulu /* 0x00000000 is not a valid address for IWDG peripherals */ 64*91f16700Schasinglulu if (iwdg->base != 0U) { 65*91f16700Schasinglulu clk_enable(iwdg->clock); 66*91f16700Schasinglulu 67*91f16700Schasinglulu mmio_write_32(iwdg->base + IWDG_KR_OFFSET, 68*91f16700Schasinglulu IWDG_KR_RELOAD_KEY); 69*91f16700Schasinglulu 70*91f16700Schasinglulu clk_disable(iwdg->clock); 71*91f16700Schasinglulu } 72*91f16700Schasinglulu } 73*91f16700Schasinglulu } 74*91f16700Schasinglulu 75*91f16700Schasinglulu int stm32_iwdg_init(void) 76*91f16700Schasinglulu { 77*91f16700Schasinglulu int node = -1; 78*91f16700Schasinglulu struct dt_node_info dt_info; 79*91f16700Schasinglulu void *fdt; 80*91f16700Schasinglulu uint32_t __unused count = 0; 81*91f16700Schasinglulu 82*91f16700Schasinglulu if (fdt_get_address(&fdt) == 0) { 83*91f16700Schasinglulu panic(); 84*91f16700Schasinglulu } 85*91f16700Schasinglulu 86*91f16700Schasinglulu for (node = stm32_iwdg_get_dt_node(&dt_info, node); 87*91f16700Schasinglulu node != -FDT_ERR_NOTFOUND; 88*91f16700Schasinglulu node = stm32_iwdg_get_dt_node(&dt_info, node)) { 89*91f16700Schasinglulu struct stm32_iwdg_instance *iwdg; 90*91f16700Schasinglulu uint32_t hw_init; 91*91f16700Schasinglulu uint32_t idx; 92*91f16700Schasinglulu 93*91f16700Schasinglulu count++; 94*91f16700Schasinglulu 95*91f16700Schasinglulu idx = stm32_iwdg_get_instance(dt_info.base); 96*91f16700Schasinglulu iwdg = &stm32_iwdg[idx]; 97*91f16700Schasinglulu iwdg->base = dt_info.base; 98*91f16700Schasinglulu iwdg->clock = (unsigned long)dt_info.clock; 99*91f16700Schasinglulu 100*91f16700Schasinglulu /* DT can specify low power cases */ 101*91f16700Schasinglulu if (fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL) == 102*91f16700Schasinglulu NULL) { 103*91f16700Schasinglulu iwdg->flags |= IWDG_DISABLE_ON_STOP; 104*91f16700Schasinglulu } 105*91f16700Schasinglulu 106*91f16700Schasinglulu if (fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL) == 107*91f16700Schasinglulu NULL) { 108*91f16700Schasinglulu iwdg->flags |= IWDG_DISABLE_ON_STANDBY; 109*91f16700Schasinglulu } 110*91f16700Schasinglulu 111*91f16700Schasinglulu /* Explicit list of supported bit flags */ 112*91f16700Schasinglulu hw_init = stm32_iwdg_get_otp_config(idx); 113*91f16700Schasinglulu 114*91f16700Schasinglulu if ((hw_init & IWDG_HW_ENABLED) != 0) { 115*91f16700Schasinglulu if (dt_info.status == DT_DISABLED) { 116*91f16700Schasinglulu ERROR("OTP enabled but iwdg%u DT-disabled\n", 117*91f16700Schasinglulu idx + 1U); 118*91f16700Schasinglulu panic(); 119*91f16700Schasinglulu } 120*91f16700Schasinglulu iwdg->flags |= IWDG_HW_ENABLED; 121*91f16700Schasinglulu } 122*91f16700Schasinglulu 123*91f16700Schasinglulu if (dt_info.status == DT_DISABLED) { 124*91f16700Schasinglulu zeromem((void *)iwdg, 125*91f16700Schasinglulu sizeof(struct stm32_iwdg_instance)); 126*91f16700Schasinglulu continue; 127*91f16700Schasinglulu } 128*91f16700Schasinglulu 129*91f16700Schasinglulu if ((hw_init & IWDG_DISABLE_ON_STOP) != 0) { 130*91f16700Schasinglulu iwdg->flags |= IWDG_DISABLE_ON_STOP; 131*91f16700Schasinglulu } 132*91f16700Schasinglulu 133*91f16700Schasinglulu if ((hw_init & IWDG_DISABLE_ON_STANDBY) != 0) { 134*91f16700Schasinglulu iwdg->flags |= IWDG_DISABLE_ON_STANDBY; 135*91f16700Schasinglulu } 136*91f16700Schasinglulu 137*91f16700Schasinglulu VERBOSE("IWDG%u found, %ssecure\n", idx + 1U, 138*91f16700Schasinglulu ((dt_info.status & DT_NON_SECURE) != 0) ? 139*91f16700Schasinglulu "non-" : ""); 140*91f16700Schasinglulu 141*91f16700Schasinglulu if ((dt_info.status & DT_NON_SECURE) != 0) { 142*91f16700Schasinglulu stm32mp_register_non_secure_periph_iomem(iwdg->base); 143*91f16700Schasinglulu } else { 144*91f16700Schasinglulu stm32mp_register_secure_periph_iomem(iwdg->base); 145*91f16700Schasinglulu } 146*91f16700Schasinglulu 147*91f16700Schasinglulu #if defined(IMAGE_BL2) 148*91f16700Schasinglulu if (stm32_iwdg_shadow_update(idx, iwdg->flags) != BSEC_OK) { 149*91f16700Schasinglulu return -1; 150*91f16700Schasinglulu } 151*91f16700Schasinglulu #endif 152*91f16700Schasinglulu } 153*91f16700Schasinglulu 154*91f16700Schasinglulu VERBOSE("%u IWDG instance%s found\n", count, (count > 1U) ? "s" : ""); 155*91f16700Schasinglulu 156*91f16700Schasinglulu return 0; 157*91f16700Schasinglulu } 158