| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <console/console.h> |
| #include <soc/gpio.h> |
| #include <device/mmio.h> |
| #include <endian.h> |
| #include <soc/addressmap.h> |
| |
| union gpio_const { |
| u64 u; |
| struct { |
| u64 gpios:8; /** Number of GPIOs implemented */ |
| u64 pp:8; /** Number of PP vectors */ |
| u64:48; /* Reserved */ |
| } s; |
| }; |
| union bit_cfg { |
| u64 u; |
| struct { |
| u64 tx_oe : 1; /* Output Enable */ |
| u64 xor : 1; /* Invert */ |
| u64 int_en : 1; /* Interrupt Enable */ |
| u64 int_type : 1; /* Type of Interrupt */ |
| u64 filt_cnt : 4; /* Glitch filter counter */ |
| u64 filt_sel : 4; /* Glitch filter select */ |
| u64 tx_od : 1; /* Set Output to Open Drain */ |
| u64 : 3; |
| u64 pin_sel : 10; /* Select type of pin */ |
| u64 : 38; |
| } s; |
| }; |
| |
| struct cavium_gpio { |
| u64 rx_dat; |
| u64 tx_set; |
| u64 tx_clr; |
| u64 multicast; |
| u64 ocla_exten_trg; |
| u64 strap; |
| u64 reserved[12]; |
| union gpio_const gpio_const; /* Offset 90 */ |
| u64 reserved2[109]; |
| union bit_cfg bit_cfg[48]; /* Offset 400 */ |
| }; |
| |
| /* Base address of GPIO BAR */ |
| static const void *gpio_get_baseaddr(void) |
| { |
| return (const void *)GPIO_PF_BAR0; |
| } |
| |
| /* Number of GPIO pins. Usually 48. */ |
| gpio_t gpio_pin_count(void) |
| { |
| struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); |
| union gpio_const gpio_const; |
| |
| gpio_const.u = read64(®s->gpio_const.u); |
| |
| if (gpio_const.s.gpios > 64) |
| return 64; // FIXME: Add support for more than 64 GPIOs |
| return gpio_const.s.gpios; |
| } |
| |
| /* Set GPIO to software control and direction INPUT */ |
| void gpio_input(gpio_t gpio) |
| { |
| struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); |
| union bit_cfg bit_cfg; |
| |
| if (gpio >= gpio_pin_count()) |
| return; |
| |
| printk(BIOS_SPEW, "GPIO(%u): direction input\n", gpio); |
| |
| bit_cfg.u = read64(®s->bit_cfg[gpio]); |
| bit_cfg.s.pin_sel = 0; |
| bit_cfg.s.tx_oe = 0; |
| write64(®s->bit_cfg[gpio], bit_cfg.u); |
| } |
| |
| /* Set GPIO of direction OUTPUT to level */ |
| void gpio_set(gpio_t gpio, int value) |
| { |
| struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); |
| |
| if (gpio >= gpio_pin_count()) |
| return; |
| |
| printk(BIOS_SPEW, "GPIO(%u): level: %u\n", gpio, !!value); |
| |
| if (value) |
| write64(®s->tx_set, 1ULL << gpio); |
| else |
| write64(®s->tx_clr, 1ULL << gpio); |
| } |
| |
| /* Set GPIO direction to OUTPUT with level */ |
| void gpio_output(gpio_t gpio, int value) |
| { |
| struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); |
| union bit_cfg bit_cfg; |
| |
| if (gpio >= gpio_pin_count()) |
| return; |
| |
| gpio_set(gpio, value); |
| |
| printk(BIOS_SPEW, "GPIO(%u): direction output with level: %u\n", gpio, |
| !!value); |
| |
| bit_cfg.u = read64(®s->bit_cfg[gpio]); |
| bit_cfg.s.pin_sel = 0; |
| bit_cfg.s.tx_oe = 1; |
| write64(®s->bit_cfg[gpio], bit_cfg.u); |
| } |
| |
| /* Set GPIO invert flag, that affects INPUT and OUTPUT */ |
| void gpio_invert(gpio_t gpio, int value) |
| { |
| struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); |
| union bit_cfg bit_cfg; |
| |
| if (gpio >= gpio_pin_count()) |
| return; |
| |
| bit_cfg.u = read64(®s->bit_cfg[gpio]); |
| bit_cfg.s.xor = !!value; |
| write64(®s->bit_cfg[gpio], bit_cfg.u); |
| |
| printk(BIOS_SPEW, "GPIO(%u): invert: %s\n", gpio, value ? "ON" : "OFF"); |
| } |
| |
| /* Read GPIO level with direction set to INPUT */ |
| int gpio_get(gpio_t gpio) |
| { |
| struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); |
| |
| if (gpio >= gpio_pin_count()) |
| return 0; |
| |
| const u64 reg = read64(®s->rx_dat); |
| printk(BIOS_SPEW, "GPIO(%u): input: %u\n", gpio, |
| !!(reg & (1ULL << gpio))); |
| |
| return !!(reg & (1ULL << gpio)); |
| } |
| |
| /* Read GPIO STRAP level sampled at cold boot */ |
| int gpio_strap_value(gpio_t gpio) |
| { |
| struct cavium_gpio *regs = (struct cavium_gpio *)gpio_get_baseaddr(); |
| |
| if (gpio >= gpio_pin_count()) |
| return 0; |
| |
| const u64 reg = read64(®s->strap); |
| printk(BIOS_SPEW, "GPIO(%u): strap: %u\n", gpio, |
| !!(reg & (1ULL << gpio))); |
| |
| return !!(reg & (1ULL << gpio)); |
| } |
| |
| /* FIXME: Parse devicetree ? */ |
| void gpio_init(void) |
| { |
| const size_t pin_count = gpio_pin_count(); |
| |
| printk(BIOS_DEBUG, "GPIO: base address: %p, pin count: %zd\n", |
| gpio_get_baseaddr(), pin_count); |
| |
| if (!pin_count) |
| return; |
| } |
| |
| void gpio_input_pulldown(gpio_t gpio) |
| { |
| } |
| |
| void gpio_input_pullup(gpio_t gpio) |
| { |
| } |