11fe98f82SClément Léger // SPDX-License-Identifier: BSD-2-Clause 21fe98f82SClément Léger /* 31fe98f82SClément Léger * Copyright 2022 Microchip 41fe98f82SClément Léger * 51fe98f82SClément Léger * Driver for AT91 PIOBU 61fe98f82SClément Léger */ 71fe98f82SClément Léger 81fe98f82SClément Léger #include <assert.h> 91fe98f82SClément Léger #include <drivers/atmel_rtc.h> 106dcd18c8SClément Léger #include <drivers/gpio.h> 111fe98f82SClément Léger #include <dt-bindings/gpio/atmel,piobu.h> 121fe98f82SClément Léger #include <io.h> 131fe98f82SClément Léger #include <kernel/boot.h> 141fe98f82SClément Léger #include <kernel/dt.h> 159e3c57c8SEtienne Carriere #include <kernel/dt_driver.h> 161fe98f82SClément Léger #include <kernel/pm.h> 171fe98f82SClément Léger #include <libfdt.h> 181fe98f82SClément Léger #include <mm/core_memprot.h> 191fe98f82SClément Léger 201fe98f82SClément Léger #define SECUMOD_MAX_PINS 8 211fe98f82SClément Léger #define SECUMOD_PIN_MASK (BIT(SECUMOD_MAX_PINS) - 1) 221fe98f82SClément Léger #define SECUMOD_PIN_SHIFT 16 231fe98f82SClément Léger #define SECUMOD_PIN_VAL(pin) BIT(SECUMOD_PIN_SHIFT + (pin)) 241fe98f82SClément Léger 251fe98f82SClément Léger #define DT_GPIO_CELLS 2 261fe98f82SClément Léger 271fe98f82SClément Léger #define SECUMOD_CR 0x0 281fe98f82SClément Léger #define SECUMOD_CR_KEY_SHIFT 16 291fe98f82SClément Léger #define SECUMOD_CR_KEY SHIFT_U32(0x89CA, SECUMOD_CR_KEY_SHIFT) 301fe98f82SClément Léger #define SECUMOD_CR_BACKUP BIT(0) 311fe98f82SClément Léger #define SECUMOD_CR_NORMAL BIT(1) 321fe98f82SClément Léger 331fe98f82SClément Léger #define SECUMOD_SR 0x8 341fe98f82SClément Léger #define SECUMOD_SR_JTAG BIT(3) 351fe98f82SClément Léger #define SECUMOD_SR_TST_PIN BIT(2) 361fe98f82SClément Léger 371fe98f82SClément Léger #define SECUMOD_SCR 0x10 381fe98f82SClément Léger 391fe98f82SClément Léger #define SECUMOD_PIOBU(x) (0x18 + (x) * 0x4) 401fe98f82SClément Léger #define SECUMOD_PIOBU_AFV_MASK GENMASK_32(3, 0) 411fe98f82SClément Léger #define SECUMOD_PIOBU_RFV_SHIFT 4 421fe98f82SClément Léger #define SECUMOD_PIOBU_OUTPUT BIT(8) 431fe98f82SClément Léger #define SECUMOD_PIOBU_SOD BIT(9) 441fe98f82SClément Léger #define SECUMOD_PIOBU_PDS BIT(10) 451fe98f82SClément Léger #define SECUMOD_PIOBU_PULLUP_SHIFT 12 461fe98f82SClément Léger #define SECUMOD_PIOBU_SWITCH_SHIFT 15 471fe98f82SClément Léger 481fe98f82SClément Léger #define SECUMOD_JTAGCR 0x68 491fe98f82SClément Léger #define SECUMOD_JTAGCR_FNTRST 0x1 501fe98f82SClément Léger 511fe98f82SClément Léger #define SECUMOD_BMPR 0x7C 521fe98f82SClément Léger #define SECUMOD_NMPR 0x80 531fe98f82SClément Léger #define SECUMOD_NIEPR 0x84 541fe98f82SClément Léger #define SECUMOD_NIDPR 0x88 551fe98f82SClément Léger #define SECUMOD_NIMPR 0x8C 561fe98f82SClément Léger #define SECUMOD_WKPR 0x90 571fe98f82SClément Léger 581fe98f82SClément Léger static vaddr_t secumod_base; 591fe98f82SClément Léger static uint32_t gpio_protected; 601fe98f82SClément Léger static struct gpio_chip secumod_chip; 611fe98f82SClément Léger 621fe98f82SClément Léger /* 631fe98f82SClément Léger * Get value from GPIO controller 641fe98f82SClément Léger * chip: pointer to GPIO controller chip instance 651fe98f82SClément Léger * gpio_pin: pin from which value needs to be read 661fe98f82SClément Léger * Return target GPIO pin level. 671fe98f82SClément Léger */ 688bc270b1SClément Léger static enum gpio_level secumod_gpio_get_value(struct gpio_chip *chip __unused, 691fe98f82SClément Léger unsigned int gpio_pin) 701fe98f82SClément Léger { 711fe98f82SClément Léger vaddr_t piobu_addr = 0; 721fe98f82SClément Léger uint32_t piobu = 0; 731fe98f82SClément Léger 741fe98f82SClément Léger assert(gpio_pin < SECUMOD_MAX_PINS && 751fe98f82SClément Léger !(gpio_protected & BIT32(gpio_pin))); 761fe98f82SClément Léger 771fe98f82SClément Léger piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin); 781fe98f82SClément Léger piobu = io_read32(piobu_addr); 791fe98f82SClément Léger 801fe98f82SClément Léger if (piobu & SECUMOD_PIOBU_PDS) 811fe98f82SClément Léger return GPIO_LEVEL_HIGH; 821fe98f82SClément Léger else 831fe98f82SClément Léger return GPIO_LEVEL_LOW; 841fe98f82SClément Léger } 851fe98f82SClément Léger 861fe98f82SClément Léger /* 871fe98f82SClément Léger * Set value for GPIO controller 881fe98f82SClément Léger * chip: pointer to GPIO controller chip instance 891fe98f82SClément Léger * gpio_pin: pin to which value needs to be written 901fe98f82SClément Léger * value: Level state for the target pin 911fe98f82SClément Léger */ 928bc270b1SClément Léger static void secumod_gpio_set_value(struct gpio_chip *chip __unused, 931fe98f82SClément Léger unsigned int gpio_pin, enum gpio_level value) 941fe98f82SClément Léger { 951fe98f82SClément Léger vaddr_t piobu_addr = 0; 961fe98f82SClément Léger 971fe98f82SClément Léger assert(gpio_pin < SECUMOD_MAX_PINS && 981fe98f82SClément Léger !(gpio_protected & BIT32(gpio_pin))); 991fe98f82SClément Léger 1001fe98f82SClément Léger piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin); 1011fe98f82SClément Léger 1021fe98f82SClément Léger if (value == GPIO_LEVEL_HIGH) 1031fe98f82SClément Léger io_setbits32(piobu_addr, SECUMOD_PIOBU_SOD); 1041fe98f82SClément Léger else 1051fe98f82SClément Léger io_clrbits32(piobu_addr, SECUMOD_PIOBU_SOD); 1061fe98f82SClément Léger } 1071fe98f82SClément Léger 1081fe98f82SClément Léger /* 1091fe98f82SClément Léger * Get direction from GPIO controller 1101fe98f82SClément Léger * chip: pointer to GPIO controller chip instance 1111fe98f82SClément Léger * gpio_pin: pin from which direction needs to be read 1121fe98f82SClément Léger */ 1138bc270b1SClément Léger static enum gpio_dir secumod_gpio_get_direction(struct gpio_chip *chip __unused, 1141fe98f82SClément Léger unsigned int gpio_pin) 1151fe98f82SClément Léger { 1161fe98f82SClément Léger vaddr_t piobu_addr = 0; 1171fe98f82SClément Léger uint32_t piobu = 0; 1181fe98f82SClément Léger 1191fe98f82SClément Léger assert(gpio_pin < SECUMOD_MAX_PINS && 1201fe98f82SClément Léger !(gpio_protected & BIT32(gpio_pin))); 1211fe98f82SClément Léger 1221fe98f82SClément Léger piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin); 1231fe98f82SClément Léger piobu = io_read32(piobu_addr); 1241fe98f82SClément Léger 1251fe98f82SClément Léger if (piobu & SECUMOD_PIOBU_OUTPUT) 1261fe98f82SClément Léger return GPIO_DIR_OUT; 1271fe98f82SClément Léger else 1281fe98f82SClément Léger return GPIO_DIR_IN; 1291fe98f82SClément Léger } 1301fe98f82SClément Léger 1311fe98f82SClément Léger /* 1321fe98f82SClément Léger * Set direction for GPIO controller 1331fe98f82SClément Léger * chip: pointer to GPIO controller chip instance 1341fe98f82SClément Léger * gpio_pin: pin on which direction needs to be set 1351fe98f82SClément Léger * direction: direction which needs to be set on pin 1361fe98f82SClément Léger */ 1378bc270b1SClément Léger static void secumod_gpio_set_direction(struct gpio_chip *chip __unused, 1388bc270b1SClément Léger unsigned int gpio_pin, 1398bc270b1SClément Léger enum gpio_dir direction) 1401fe98f82SClément Léger { 1411fe98f82SClément Léger vaddr_t piobu_addr = 0; 1421fe98f82SClément Léger 1431fe98f82SClément Léger assert(gpio_pin < SECUMOD_MAX_PINS && 1441fe98f82SClément Léger !(gpio_protected & BIT32(gpio_pin))); 1451fe98f82SClément Léger 1461fe98f82SClément Léger piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin); 1471fe98f82SClément Léger 1481fe98f82SClément Léger if (direction == GPIO_DIR_OUT) 1491fe98f82SClément Léger io_setbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT); 1501fe98f82SClément Léger else 1511fe98f82SClément Léger io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT); 1521fe98f82SClément Léger } 1531fe98f82SClément Léger 1541fe98f82SClément Léger /* 1551fe98f82SClément Léger * Get interrupt from GPIO controller 1561fe98f82SClément Léger * chip: pointer to GPIO controller chip instance 1571fe98f82SClément Léger * gpio_pin: pin from which interrupt value needs to be read 1581fe98f82SClément Léger */ 1598bc270b1SClément Léger static enum gpio_interrupt 1608bc270b1SClément Léger secumod_gpio_get_interrupt(struct gpio_chip *chip __unused, 1611fe98f82SClément Léger unsigned int gpio_pin) 1621fe98f82SClément Léger { 1631fe98f82SClément Léger vaddr_t nimpr_addr = secumod_base + SECUMOD_NIMPR; 1641fe98f82SClément Léger uint32_t data = 0; 1651fe98f82SClément Léger 1661fe98f82SClément Léger assert(gpio_pin < SECUMOD_MAX_PINS && 1671fe98f82SClément Léger !(gpio_protected & BIT32(gpio_pin))); 1681fe98f82SClément Léger 1691fe98f82SClément Léger data = io_read32(nimpr_addr); 1701fe98f82SClément Léger 1711fe98f82SClément Léger if (data & SECUMOD_PIN_VAL(gpio_pin)) 1721fe98f82SClément Léger return GPIO_INTERRUPT_ENABLE; 1731fe98f82SClément Léger else 1741fe98f82SClément Léger return GPIO_INTERRUPT_DISABLE; 1751fe98f82SClément Léger } 1761fe98f82SClément Léger 1771fe98f82SClément Léger /* 1781fe98f82SClément Léger * Set interrupt event for GPIO controller 1791fe98f82SClément Léger * chip: pointer to GPIO controller chip instance 1801fe98f82SClément Léger * gpio_pin: pin on which interrupt value needs to be set 1811fe98f82SClément Léger * interrupt: interrupt value which needs to be set on pin 1821fe98f82SClément Léger */ 1838bc270b1SClément Léger static void secumod_gpio_set_interrupt(struct gpio_chip *chip __unused, 1841fe98f82SClément Léger unsigned int gpio_pin, 1851fe98f82SClément Léger enum gpio_interrupt interrupt) 1861fe98f82SClément Léger { 1871fe98f82SClément Léger vaddr_t niepr_addr = secumod_base + SECUMOD_NIEPR; 1881fe98f82SClément Léger 1891fe98f82SClément Léger assert(gpio_pin < SECUMOD_MAX_PINS && 1901fe98f82SClément Léger !(gpio_protected & BIT32(gpio_pin))); 1911fe98f82SClément Léger 1921fe98f82SClément Léger if (interrupt == GPIO_INTERRUPT_ENABLE) 1931fe98f82SClément Léger io_setbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin)); 1941fe98f82SClément Léger else 1951fe98f82SClément Léger io_clrbits32(niepr_addr, SECUMOD_PIN_VAL(gpio_pin)); 1961fe98f82SClément Léger } 1971fe98f82SClément Léger 1981fe98f82SClément Léger static const struct gpio_ops atmel_piobu_ops = { 1998bc270b1SClément Léger .get_direction = secumod_gpio_get_direction, 2008bc270b1SClément Léger .set_direction = secumod_gpio_set_direction, 2018bc270b1SClément Léger .get_value = secumod_gpio_get_value, 2028bc270b1SClément Léger .set_value = secumod_gpio_set_value, 2038bc270b1SClément Léger .get_interrupt = secumod_gpio_get_interrupt, 2048bc270b1SClément Léger .set_interrupt = secumod_gpio_set_interrupt, 2051fe98f82SClément Léger }; 2061fe98f82SClément Léger 207*b786cc03SClément Léger static struct gpio *secumod_dt_get(struct dt_driver_phandle_args *a, void *data, 208*b786cc03SClément Léger TEE_Result *res) 209*b786cc03SClément Léger { 210*b786cc03SClément Léger struct gpio *gpio = NULL; 211*b786cc03SClément Léger struct gpio_chip *chip = data; 212*b786cc03SClément Léger 213*b786cc03SClément Léger gpio = gpio_dt_alloc_pin(a, res); 214*b786cc03SClément Léger if (*res) 215*b786cc03SClément Léger return NULL; 216*b786cc03SClément Léger 217*b786cc03SClément Léger if (gpio_protected & BIT32(gpio->pin)) { 218*b786cc03SClément Léger free(gpio); 219*b786cc03SClément Léger return NULL; 220*b786cc03SClément Léger } 221*b786cc03SClément Léger 222*b786cc03SClément Léger gpio->chip = chip; 223*b786cc03SClément Léger 224*b786cc03SClément Léger return gpio; 225*b786cc03SClément Léger } 226*b786cc03SClément Léger 2271fe98f82SClément Léger static enum itr_return secumod_it_handler(struct itr_handler *handler __unused) 2281fe98f82SClément Léger { 2291fe98f82SClément Léger int i = 0; 2301fe98f82SClément Léger struct optee_rtc_time tm = { }; 2311fe98f82SClément Léger TEE_Result res = TEE_ERROR_GENERIC; 2321fe98f82SClément Léger uint32_t sr = io_read32(secumod_base + SECUMOD_SR); 2331fe98f82SClément Léger 2341fe98f82SClément Léger for (i = 0; i < SECUMOD_MAX_PINS; i++) { 2351fe98f82SClément Léger if (sr & SECUMOD_PIN_VAL(i)) 2361fe98f82SClément Léger EMSG("Detected tampering on pin %d", i); 2371fe98f82SClément Léger } 2381fe98f82SClément Léger 2391fe98f82SClément Léger if (sr & SECUMOD_SR_JTAG) 2401fe98f82SClément Léger EMSG("JTAG tampering attempt"); 2411fe98f82SClément Léger 2421fe98f82SClément Léger if (sr & SECUMOD_SR_TST_PIN) 2431fe98f82SClément Léger EMSG("Test pin tampering attempt"); 2441fe98f82SClément Léger 2451fe98f82SClément Léger res = atmel_rtc_get_tamper_timestamp(&tm); 2461fe98f82SClément Léger if (!res) { 2471fe98f82SClément Léger EMSG("Date of tampering: %02"PRIu32"/%02"PRIu32"/%02"PRIu32"", 2481fe98f82SClément Léger tm.tm_mday, tm.tm_mon, tm.tm_year); 2491fe98f82SClément Léger EMSG("Time of tampering: %02"PRIu32":%02"PRIu32":%02"PRIu32"", 2501fe98f82SClément Léger tm.tm_hour, tm.tm_min, tm.tm_sec); 2511fe98f82SClément Léger } 2521fe98f82SClément Léger 2531fe98f82SClément Léger io_write32(secumod_base + SECUMOD_SCR, 2541fe98f82SClément Léger SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT); 2551fe98f82SClément Léger 2561fe98f82SClément Léger panic("Tampering detected, system halted"); 2571fe98f82SClément Léger 2581fe98f82SClément Léger return ITRR_HANDLED; 2591fe98f82SClément Léger } 2601fe98f82SClément Léger 2611fe98f82SClément Léger static struct itr_handler secumod_itr_handler = { 2621fe98f82SClément Léger .it = AT91C_ID_SECUMOD, 2631fe98f82SClément Léger .handler = secumod_it_handler, 2641fe98f82SClément Léger }; 2651fe98f82SClément Léger 2661fe98f82SClément Léger static void secumod_interrupt_init(void) 2671fe98f82SClément Léger { 2681fe98f82SClément Léger itr_add_type_prio(&secumod_itr_handler, IRQ_TYPE_LEVEL_HIGH, 7); 2691fe98f82SClément Léger itr_enable(secumod_itr_handler.it); 2701fe98f82SClément Léger } 2711fe98f82SClément Léger 2721fe98f82SClément Léger static void secumod_cfg_input_pio(uint8_t gpio_pin, uint32_t config) 2731fe98f82SClément Léger { 2741fe98f82SClément Léger vaddr_t piobu_addr = 0; 2751fe98f82SClément Léger uint8_t afv = 0; 2761fe98f82SClément Léger uint8_t rfv = 0; 2771fe98f82SClément Léger uint8_t pull_mode = PIOBU_PIN_PULL_NONE; 2781fe98f82SClément Léger uint8_t def_level = PIOBU_PIN_DEF_LEVEL_LOW; 2791fe98f82SClément Léger 2801fe98f82SClément Léger assert(gpio_pin < SECUMOD_MAX_PINS); 2811fe98f82SClément Léger 2821fe98f82SClément Léger piobu_addr = secumod_base + SECUMOD_PIOBU(gpio_pin); 2831fe98f82SClément Léger 2841fe98f82SClément Léger /* Set GPIO as input */ 2851fe98f82SClément Léger io_clrbits32(piobu_addr, SECUMOD_PIOBU_OUTPUT); 2861fe98f82SClément Léger 2871fe98f82SClément Léger afv = PIOBU_PIN_AFV(config); 2881fe98f82SClément Léger rfv = PIOBU_PIN_RFV(config); 2891fe98f82SClément Léger pull_mode = PIOBU_PIN_PULL_MODE(config); 2901fe98f82SClément Léger def_level = PIOBU_PIN_DEF_LEVEL(config); 2911fe98f82SClément Léger 2921fe98f82SClément Léger io_write32(piobu_addr, afv | rfv << SECUMOD_PIOBU_RFV_SHIFT | 2931fe98f82SClément Léger pull_mode << SECUMOD_PIOBU_PULLUP_SHIFT | 2941fe98f82SClément Léger def_level << SECUMOD_PIOBU_SWITCH_SHIFT); 2951fe98f82SClément Léger 2961fe98f82SClément Léger /* Enable Tampering Interrupt */ 2978bc270b1SClément Léger secumod_gpio_set_interrupt(&secumod_chip, gpio_pin, 2988bc270b1SClément Léger GPIO_INTERRUPT_ENABLE); 2991fe98f82SClément Léger 3001fe98f82SClément Léger /* Enable Intrusion Detection */ 3011fe98f82SClément Léger io_setbits32(secumod_base + SECUMOD_NMPR, SECUMOD_PIN_VAL(gpio_pin)); 3021fe98f82SClément Léger 3031fe98f82SClément Léger /* Enable Wakeup */ 3041fe98f82SClément Léger if (PIOBU_PIN_WAKEUP(config)) 3051fe98f82SClément Léger io_setbits32(secumod_base + SECUMOD_WKPR, 3061fe98f82SClément Léger SECUMOD_PIN_VAL(gpio_pin)); 3071fe98f82SClément Léger 3081fe98f82SClément Léger gpio_protected |= BIT32(gpio_pin); 3091fe98f82SClément Léger } 3101fe98f82SClément Léger 3111fe98f82SClément Léger static void secumod_hw_init(const void *fdt, int node) 3121fe98f82SClément Léger { 3131fe98f82SClément Léger int i = 0; 3141fe98f82SClément Léger int len = 0; 3151fe98f82SClément Léger uint8_t gpio_pin = 0; 3161fe98f82SClément Léger uint32_t config = 0; 3171fe98f82SClément Léger const uint32_t *prop = NULL; 3181fe98f82SClément Léger 3191fe98f82SClément Léger /* Disable JTAG Reset and Debug */ 3201fe98f82SClément Léger io_write32(secumod_base + SECUMOD_JTAGCR, SECUMOD_JTAGCR_FNTRST); 3211fe98f82SClément Léger 3221fe98f82SClément Léger /* Switch IOs to normal mode */ 3231fe98f82SClément Léger io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY | 3241fe98f82SClément Léger SECUMOD_CR_NORMAL); 3251fe98f82SClément Léger 3261fe98f82SClément Léger /* Clear all detection intrusion in normal mode */ 3271fe98f82SClément Léger io_write32(secumod_base + SECUMOD_NMPR, 0); 3281fe98f82SClément Léger 3291fe98f82SClément Léger /* Clear Alarms */ 3301fe98f82SClément Léger io_write32(secumod_base + SECUMOD_SCR, 3311fe98f82SClément Léger SECUMOD_PIN_MASK << SECUMOD_PIN_SHIFT); 3321fe98f82SClément Léger 3331fe98f82SClément Léger /* Configure each IOs */ 3341fe98f82SClément Léger prop = fdt_getprop(fdt, node, "gpios", &len); 3351fe98f82SClément Léger if (!prop) 3361fe98f82SClément Léger return; 3371fe98f82SClément Léger 3381fe98f82SClément Léger len /= sizeof(uint32_t); 3391fe98f82SClément Léger for (i = 0; i < len; i += DT_GPIO_CELLS) { 3401fe98f82SClément Léger gpio_pin = fdt32_to_cpu(prop[i]); 3411fe98f82SClément Léger config = fdt32_to_cpu(prop[i + 1]); 3421fe98f82SClément Léger 3431fe98f82SClément Léger secumod_cfg_input_pio(gpio_pin, config); 3441fe98f82SClément Léger } 3451fe98f82SClément Léger } 3461fe98f82SClément Léger 3471fe98f82SClément Léger #ifdef CFG_PM_ARM32 3481fe98f82SClément Léger static TEE_Result piobu_pm(enum pm_op op, uint32_t pm_hint __unused, 3491fe98f82SClément Léger const struct pm_callback_handle *hdl __unused) 3501fe98f82SClément Léger { 3511fe98f82SClément Léger switch (op) { 3521fe98f82SClément Léger case PM_OP_RESUME: 3531fe98f82SClément Léger io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY | 3541fe98f82SClément Léger SECUMOD_CR_NORMAL); 3551fe98f82SClément Léger break; 3561fe98f82SClément Léger case PM_OP_SUSPEND: 3571fe98f82SClément Léger /* Enter backup mode before suspending */ 3581fe98f82SClément Léger io_write32(secumod_base + SECUMOD_CR, SECUMOD_CR_KEY | 3591fe98f82SClément Léger SECUMOD_CR_BACKUP); 3601fe98f82SClément Léger break; 3611fe98f82SClément Léger default: 3621fe98f82SClément Léger panic("Invalid PM operation"); 3631fe98f82SClément Léger } 3641fe98f82SClément Léger 3651fe98f82SClément Léger return TEE_SUCCESS; 3661fe98f82SClément Léger } 3671fe98f82SClément Léger 3681fe98f82SClément Léger static void piobu_register_pm(void) 3691fe98f82SClément Léger { 3701fe98f82SClément Léger register_pm_driver_cb(piobu_pm, NULL, "piobu"); 3711fe98f82SClément Léger } 3721fe98f82SClément Léger #else 3731fe98f82SClément Léger static void piobu_register_pm(void) {} 3741fe98f82SClément Léger #endif 3751fe98f82SClément Léger 3761fe98f82SClément Léger static TEE_Result atmel_secumod_probe(const void *fdt, int node, 3771fe98f82SClément Léger const void *compat_data __unused) 3781fe98f82SClément Léger { 3791fe98f82SClément Léger size_t size = 0; 3801fe98f82SClément Léger 3811fe98f82SClément Léger if (secumod_base) 3821fe98f82SClément Léger return TEE_ERROR_GENERIC; 3831fe98f82SClément Léger 384a5d5bbc8SVesa Jääskeläinen if (dt_map_dev(fdt, node, &secumod_base, &size, DT_MAP_AUTO) < 0) 3851fe98f82SClément Léger return TEE_ERROR_GENERIC; 3861fe98f82SClément Léger 3871fe98f82SClément Léger secumod_hw_init(fdt, node); 3881fe98f82SClément Léger secumod_interrupt_init(); 3891fe98f82SClément Léger 3901fe98f82SClément Léger secumod_chip.ops = &atmel_piobu_ops; 3911fe98f82SClément Léger 3921fe98f82SClément Léger piobu_register_pm(); 3931fe98f82SClément Léger 394*b786cc03SClément Léger assert(gpio_ops_is_valid(&atmel_piobu_ops)); 395*b786cc03SClément Léger 396*b786cc03SClément Léger return gpio_register_provider(fdt, node, secumod_dt_get, &secumod_chip); 3971fe98f82SClément Léger } 3981fe98f82SClément Léger 3991fe98f82SClément Léger static const struct dt_device_match atmel_secumod_match_table[] = { 4001fe98f82SClément Léger { .compatible = "atmel,sama5d2-secumod" }, 4011fe98f82SClément Léger { } 4021fe98f82SClément Léger }; 4031fe98f82SClément Léger 4041fe98f82SClément Léger DEFINE_DT_DRIVER(atmel_secumod_dt_driver) = { 4051fe98f82SClément Léger .name = "atmel_secumod", 4061fe98f82SClément Léger .type = DT_DRIVER_NOTYPE, 4071fe98f82SClément Léger .match_table = atmel_secumod_match_table, 4081fe98f82SClément Léger .probe = atmel_secumod_probe, 4091fe98f82SClément Léger }; 410