1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2015 Atmel Corporation, 4 * Nicolas Ferre <nicolas.ferre@atmel.com> 5 * Copyright (c) 2021, Microchip 6 */ 7 8 #include <drivers/atmel_shdwc.h> 9 #include <drivers/sam/at91_ddr.h> 10 #include <drivers/pm/sam/atmel_pm.h> 11 #include <io.h> 12 #include <kernel/dt.h> 13 #include <kernel/thread.h> 14 #include <libfdt.h> 15 #include <stdbool.h> 16 #include <tee_api_defines.h> 17 #include <tee_api_types.h> 18 #include <trace.h> 19 #include <types_ext.h> 20 #include <util.h> 21 22 #include "at91_clk.h" 23 24 #define SHDW_WK_PIN(reg, cfg) ((reg) & \ 25 AT91_SHDW_WKUPIS((cfg)->wkup_pin_input)) 26 #define SHDW_RTCWK(reg, cfg) (((reg) >> ((cfg)->sr_rtcwk_shift)) & 0x1) 27 #define SHDW_RTTWK(reg, cfg) (((reg) >> ((cfg)->sr_rttwk_shift)) & 0x1) 28 #define SHDW_RTCWKEN(cfg) BIT((cfg)->mr_rtcwk_shift) 29 #define SHDW_RTTWKEN(cfg) BIT((cfg)->mr_rttwk_shift) 30 31 #define SLOW_CLK_FREQ 32768ULL 32 #define DBC_PERIOD_US(x) DIV_ROUND_UP((1000000ULL * (x)), SLOW_CLK_FREQ) 33 34 static vaddr_t shdwc_base; 35 static vaddr_t mpddrc_base; 36 37 bool atmel_shdwc_available(void) 38 { 39 return shdwc_base != 0; 40 } 41 42 void __noreturn atmel_shdwc_shutdown(void) 43 { 44 vaddr_t pmc_base = at91_pmc_get_base(); 45 46 /* 47 * Mask exception before entering assembly which does not expect to be 48 * interrupted. 49 */ 50 thread_mask_exceptions(THREAD_EXCP_ALL); 51 52 __atmel_shdwc_shutdown(mpddrc_base, shdwc_base, pmc_base); 53 54 /* We are going to shutdown the CPU so we will never hit this loop */ 55 while (true) 56 ; 57 } 58 59 static const unsigned long long sdwc_dbc_period[] = { 60 0, 3, 32, 512, 4096, 32768, 61 }; 62 63 static uint32_t at91_shdwc_debouncer_value(uint32_t in_period_us) 64 { 65 int i = 0; 66 int max_idx = ARRAY_SIZE(sdwc_dbc_period) - 1; 67 uint64_t period_us = 0; 68 uint64_t max_period_us = DBC_PERIOD_US(sdwc_dbc_period[max_idx]); 69 70 if (in_period_us > max_period_us) { 71 DMSG("debouncer period %"PRIu32" too big, using %"PRIu64" us", 72 in_period_us, max_period_us); 73 return max_idx; 74 } 75 76 for (i = max_idx - 1; i > 0; i--) { 77 period_us = DBC_PERIOD_US(sdwc_dbc_period[i]); 78 if (in_period_us > period_us) 79 break; 80 } 81 82 return i + 1; 83 } 84 85 static uint32_t at91_shdwc_get_wakeup_input(const void *fdt, int np) 86 { 87 const uint32_t *prop = NULL; 88 uint32_t wk_input_mask = 0; 89 uint32_t wuir = 0; 90 uint32_t wk_input = 0; 91 int child = 0; 92 int len = 0; 93 94 fdt_for_each_subnode(child, fdt, np) { 95 prop = fdt_getprop(fdt, child, "reg", &len); 96 if (!prop || len != sizeof(uint32_t)) { 97 DMSG("reg property is missing for node %s", 98 fdt_get_name(fdt, child, NULL)); 99 continue; 100 } 101 wk_input = fdt32_to_cpu(*prop); 102 wk_input_mask = BIT32(wk_input); 103 if (!(wk_input_mask & AT91_SHDW_WKUPEN_MASK)) { 104 DMSG("wake-up input %"PRId32" out of bounds ignore", 105 wk_input); 106 continue; 107 } 108 wuir |= wk_input_mask; 109 110 if (fdt_getprop(fdt, child, "atmel,wakeup-active-high", NULL)) 111 wuir |= AT91_SHDW_WKUPT(wk_input); 112 } 113 114 return wuir; 115 } 116 117 static void at91_shdwc_dt_configure(const void *fdt, int np) 118 { 119 const uint32_t *prop = NULL; 120 uint32_t mode = 0; 121 uint32_t tmp = 0; 122 uint32_t input = 0; 123 int len = 0; 124 125 prop = fdt_getprop(fdt, np, "debounce-delay-us", &len); 126 if (prop && len == sizeof(uint32_t)) { 127 tmp = fdt32_to_cpu(*prop); 128 mode |= AT91_SHDW_WKUPDBC(at91_shdwc_debouncer_value(tmp)); 129 } 130 131 if (fdt_getprop(fdt, np, "atmel,wakeup-rtc-timer", &len)) 132 mode |= AT91_SHDW_RTCWKEN; 133 134 io_write32(shdwc_base + AT91_SHDW_MR, mode); 135 136 input = at91_shdwc_get_wakeup_input(fdt, np); 137 io_write32(shdwc_base + AT91_SHDW_WUIR, input); 138 } 139 140 static TEE_Result atmel_shdwc_probe(const void *fdt, int node, 141 const void *compat_data __unused) 142 { 143 int ddr_node = 0; 144 size_t size = 0; 145 uint32_t ddr = AT91_DDRSDRC_MD_LPDDR2; 146 147 /* 148 * Assembly code relies on the fact that there is only one CPU to avoid 149 * any other one to invalidate TLB/I-Cache. 150 */ 151 COMPILE_TIME_ASSERT(CFG_TEE_CORE_NB_CORE == 1); 152 153 if (dt_map_dev(fdt, node, &shdwc_base, &size) < 0) 154 return TEE_ERROR_GENERIC; 155 156 ddr_node = fdt_node_offset_by_compatible(fdt, -1, 157 "atmel,sama5d3-ddramc"); 158 if (ddr_node < 0) 159 return TEE_ERROR_GENERIC; 160 161 if (dt_map_dev(fdt, ddr_node, &mpddrc_base, &size) < 0) 162 return TEE_ERROR_GENERIC; 163 164 ddr = io_read32(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD; 165 if (ddr != AT91_DDRSDRC_MD_LPDDR2 && ddr != AT91_DDRSDRC_MD_LPDDR3) 166 mpddrc_base = 0; 167 168 at91_shdwc_dt_configure(fdt, node); 169 170 return sama5d2_pm_init(fdt, shdwc_base); 171 } 172 173 static const struct dt_device_match atmel_shdwc_match_table[] = { 174 { .compatible = "atmel,sama5d2-shdwc" }, 175 { } 176 }; 177 178 DEFINE_DT_DRIVER(atmel_shdwc_dt_driver) = { 179 .name = "atmel_shdwc", 180 .type = DT_DRIVER_NOTYPE, 181 .match_table = atmel_shdwc_match_table, 182 .probe = atmel_shdwc_probe, 183 }; 184