// SPDX-License-Identifier: MIT /* * Copyright (C) 2002 - 2021 Xilinx, Inc. All rights reserved. * Copyright (c) 2022 Foundries.io Ltd. (jorge@foundries.io) */ #include #include #include #include #include #include #include #include #include #include #include #include "drivers/versal_gpio.h" #define VERSAL_GPIO_LEN 0x10000 #define DATA_LSW_OFFSET(__bank) (0x000 + 0x08 * (__bank)) #define DATA_MSW_OFFSET(__bank) (0x004 + 0x08 * (__bank)) #define DATA_RO_OFFSET(__bank) (0x060 + 0x04 * (__bank)) #define DIRM_OFFSET(__bank) (0x204 + 0x40 * (__bank)) #define OUTEN_OFFSET(__bank) (0x208 + 0x40 * (__bank)) #define VERSAL_GPIO_MID_PIN 16 #define VERSAL_GPIO_UPPER_MASK 0xFFFF0000 /* Max pins in the PMC_GPIO devices * 00 - 025, Bank 0 * 26 - 051, Bank 1 * 52 - 083, Bank 3 * 84 - 115, Bank 4 */ #define VERSAL_GPIO_PMC_BASE 0xf1020000 #define VERSAL_GPIO_PMC_NR_GPIOS 116 #define VERSAL_GPIO_PMC_MAX_BANK 5 static const struct versal_gpio_platform_data versal_gpio_pmc_def = { .max_bank = VERSAL_GPIO_PMC_MAX_BANK, .ngpio = VERSAL_GPIO_PMC_NR_GPIOS, .label = "versal_pmc_gpio", .bank_min[0] = 0, .bank_max[0] = 25, .bank_min[1] = 26, .bank_max[1] = 51, .bank_min[3] = 52, .bank_max[3] = 83, .bank_min[4] = 84, .bank_max[4] = 115, }; /* Max pins in the PS_GPIO devices * 00 - 25, Bank 0 * 26 - 57, Bank 3 */ #define VERSAL_GPIO_PS_BASE 0xff0b0000 #define VERSAL_GPIO_PS_NR_GPIOS 58 #define VERSAL_GPIO_PS_MAX_BANK 4 static const struct versal_gpio_platform_data versal_gpio_ps_def = { .max_bank = VERSAL_GPIO_PS_MAX_BANK, .ngpio = VERSAL_GPIO_PS_NR_GPIOS, .label = "versal_ps_gpio", .bank_min[0] = 0, .bank_max[0] = 25, .bank_min[3] = 26, .bank_max[3] = 57, }; static void versal_gpio_get_pin(struct versal_gpio_chip *chip, uint32_t gpio, uint32_t *bank, uint32_t *pin) { struct versal_gpio_platdata *platdata = &chip->plat; uint32_t bnk = 0; assert(gpio < platdata->p_data->ngpio); for (bnk = 0; bnk < platdata->p_data->max_bank; bnk++) { if (gpio < platdata->p_data->bank_min[bnk]) continue; if (gpio > platdata->p_data->bank_max[bnk]) continue; *bank = bnk; *pin = gpio - platdata->p_data->bank_min[bnk]; return; } EMSG("GPIO_%d not found", gpio); panic(); } static enum gpio_level versal_gpio_get_value(struct versal_gpio_chip *chip, uint32_t gpio) { uint32_t bank = 0; uint32_t pin = 0; versal_gpio_get_pin(chip, gpio, &bank, &pin); return (io_read32(chip->base + DATA_RO_OFFSET(bank)) >> pin) & 1; } static void versal_gpio_set_value(struct versal_gpio_chip *chip, uint32_t gpio, enum gpio_level val) { uint32_t bank = 0; uint32_t off = 0; uint32_t pin = 0; versal_gpio_get_pin(chip, gpio, &bank, &pin); if (bank >= VERSAL_GPIO_MID_PIN) { bank -= VERSAL_GPIO_MID_PIN; off = DATA_MSW_OFFSET(bank); } else { off = DATA_LSW_OFFSET(bank); } /* * get the 32 bit value to be written to the mask/data register where * the upper 16 bits is the mask and lower 16 bits is the data */ val = !!val; val = ~BIT32(pin + VERSAL_GPIO_MID_PIN) & (SHIFT_U32(val, pin) | VERSAL_GPIO_UPPER_MASK); io_write32(chip->base + off, val); } static void versal_gpio_set_direction(struct versal_gpio_chip *chip, uint32_t gpio, enum gpio_dir direction) { uint32_t bank = 0; uint32_t reg = 0; uint32_t pin = 0; versal_gpio_get_pin(chip, gpio, &bank, &pin); if (direction == GPIO_DIR_OUT) { /* set the GPIO pin as output */ reg = io_read32(chip->base + DIRM_OFFSET(bank)); reg |= BIT(pin); io_write32(chip->base + DIRM_OFFSET(bank), reg); /* configure the output enable reg for the pin */ reg = io_read32(chip->base + OUTEN_OFFSET(bank)); reg |= BIT(pin); io_write32(chip->base + OUTEN_OFFSET(bank), reg); /* set the state of the pin */ versal_gpio_set_value(chip, gpio, GPIO_LEVEL_LOW); } else { /* bnk 0 pins 7 and 8 cannot be used as inputs */ assert(!(bank == 0 && (pin == 7 || pin == 8))); reg = io_read32(chip->base + DIRM_OFFSET(bank)); reg &= ~BIT(pin); io_write32(chip->base + DIRM_OFFSET(bank), reg); } } static enum gpio_dir versal_gpio_get_direction(struct versal_gpio_chip *chip, uint32_t gpio) { uint32_t pin = 0; uint32_t bank = 0; versal_gpio_get_pin(chip, gpio, &bank, &pin); if (io_read32(chip->base + DIRM_OFFSET(bank)) & BIT(pin)) return GPIO_DIR_OUT; return GPIO_DIR_IN; } static enum gpio_level do_get_value(struct gpio_chip *chip, uint32_t gpio) { struct versal_gpio_chip *p = container_of(chip, struct versal_gpio_chip, chip); return versal_gpio_get_value(p, gpio); } static void do_set_value(struct gpio_chip *chip, uint32_t gpio, enum gpio_level val) { struct versal_gpio_chip *p = container_of(chip, struct versal_gpio_chip, chip); return versal_gpio_set_value(p, gpio, val); } static void do_set_dir(struct gpio_chip *chip, uint32_t gpio, enum gpio_dir direction) { struct versal_gpio_chip *p = container_of(chip, struct versal_gpio_chip, chip); return versal_gpio_set_direction(p, gpio, direction); } static enum gpio_dir do_get_dir(struct gpio_chip *chip, uint32_t gpio) { struct versal_gpio_chip *p = container_of(chip, struct versal_gpio_chip, chip); return versal_gpio_get_direction(p, gpio); } static const struct gpio_ops versal_gpio_ops = { .get_direction = do_get_dir, .set_direction = do_set_dir, .get_value = do_get_value, .set_value = do_set_value, .get_interrupt = NULL, .set_interrupt = NULL, }; TEE_Result versal_gpio_pmc_init(struct versal_gpio_chip *chip) { if (chip->base) return TEE_SUCCESS; chip->plat.p_data = &versal_gpio_pmc_def; chip->plat.base = VERSAL_GPIO_PMC_BASE; chip->chip.ops = &versal_gpio_ops; chip->base = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC, VERSAL_GPIO_PMC_BASE, VERSAL_GPIO_LEN); if (!chip->base) { EMSG("Failed to map gpio"); chip->chip.ops = NULL; return TEE_ERROR_GENERIC; } return TEE_SUCCESS; } TEE_Result versal_gpio_ps_init(struct versal_gpio_chip *chip) { if (chip->base) return TEE_SUCCESS; chip->plat.p_data = &versal_gpio_ps_def; chip->plat.base = VERSAL_GPIO_PS_BASE; chip->chip.ops = &versal_gpio_ops; chip->base = (vaddr_t)core_mmu_add_mapping(MEM_AREA_IO_SEC, VERSAL_GPIO_PS_BASE, VERSAL_GPIO_LEN); if (!chip->base) { EMSG("Failed to map gpio"); chip->chip.ops = NULL; return TEE_ERROR_GENERIC; } return TEE_SUCCESS; }