Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/23753
Change subject: soc/cavium: Add GPIO driver ......................................................................
soc/cavium: Add GPIO driver
Change-Id: I77b83eaebc94b1e311e6834658074c2c7c5faf55 Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M src/soc/cavium/cn81xx/Makefile.inc M src/soc/cavium/common/Makefile.inc M src/soc/cavium/common/gpio.c M src/soc/cavium/common/include/soc/gpio.h 4 files changed, 169 insertions(+), 174 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/53/23753/1
diff --git a/src/soc/cavium/cn81xx/Makefile.inc b/src/soc/cavium/cn81xx/Makefile.inc index 8fe8f44..6c129e8 100644 --- a/src/soc/cavium/cn81xx/Makefile.inc +++ b/src/soc/cavium/cn81xx/Makefile.inc @@ -70,7 +70,6 @@ romstage-y += ../common/lame_string.c
- #verstage-y += ../common/cbmem.c #verstage-y += ../common/gpio.c #verstage-y += gpio.c diff --git a/src/soc/cavium/common/Makefile.inc b/src/soc/cavium/common/Makefile.inc index 48cc7bd..f51e13e 100644 --- a/src/soc/cavium/common/Makefile.inc +++ b/src/soc/cavium/common/Makefile.inc @@ -18,16 +18,19 @@ bootblock-$(CONFIG_BOOTBLOCK_CUSTOM) += bootblock.c bootblock-y += twsi.c bootblock-y += clock.c +bootblock-y += gpio.c
romstage-y += twsi.c romstage-y += clock.c +romstage-y += gpio.c
ramstage-y += twsi.c ramstage-y += clock.c +ramstage-y += gpio.c
CPPFLAGS_common += -Isrc/soc/cavium/common/include
diff --git a/src/soc/cavium/common/gpio.c b/src/soc/cavium/common/gpio.c index add2100..b7620e5 100644 --- a/src/soc/cavium/common/gpio.c +++ b/src/soc/cavium/common/gpio.c @@ -1,138 +1,183 @@ /* - * This file is part of the coreboot project. + * Copyright 2018-present Facebook, Inc. * - * Copyright 2017-present Facebook, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * SPDX-License-Identifier: GPL-2.0+ */
-/* FIXME: scaffolding based on rk3399 */ - -#include <arch/io.h> -#include <assert.h> #include <console/console.h> -#include <gpio.h> #include <soc/gpio.h> -//#include <soc/grf.h> -#include <soc/soc.h> -#include <stdlib.h> +#include <arch/io.h> +#include <endian.h>
-static void gpio_set_dir(gpio_t gpio, enum gpio_dir dir) +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 void *gpio_get_baseaddr(void) { -#if 0 - clrsetbits_le32(&gpio_port[gpio.port]->swporta_ddr, - 1 << gpio.num, dir << gpio.num); -#endif + return (void *)0x803000000000ULL; }
-static void gpio_set_pull(gpio_t gpio, enum gpio_pull pull) +/* Number of GPIO pins. Usually 48. */ +gpio_t gpio_pin_count(void) { -#if 0 - u32 pull_val = gpio_get_pull_val(gpio, pull); - if (is_pmu_gpio(gpio) && IS_ENABLED(CONFIG_SOC_ROCKCHIP_RK3288)) - clrsetbits_le32(gpio_grf_reg(gpio), 3 << (gpio.idx * 2), - pull_val << (gpio.idx * 2)); - else - write32(gpio_grf_reg(gpio), RK_CLRSETBITS(3 << (gpio.idx * 2), - pull_val << (gpio.idx * 2))); -#endif + 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) { -#if 0 - gpio_set_pull(gpio, GPIO_PULLNONE); - gpio_set_dir(gpio, GPIO_INPUT); -#endif + 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, 1 << gpio); + else + write64(®s->tx_clr, 1 << 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 & (1 << gpio))); + + return !!(reg & (1 << 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 & (1 << gpio))); + + return !!(reg & (1 << 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: %d\n", + gpio_get_baseaddr(), pin_count); + + if (!pin_count) + return; }
void gpio_input_pulldown(gpio_t gpio) { -#if 0 - gpio_set_pull(gpio, GPIO_PULLDOWN); - gpio_set_dir(gpio, GPIO_INPUT); -#endif }
void gpio_input_pullup(gpio_t gpio) { -#if 0 - gpio_set_pull(gpio, GPIO_PULLUP); - gpio_set_dir(gpio, GPIO_INPUT); -#endif -} - -void gpio_input_irq(gpio_t gpio, enum gpio_irq_type type, enum gpio_pull pull) -{ -#if 0 - uint32_t int_polarity, inttype_level; - uint32_t mask = BIT(gpio.num); - - /* gpio pull only PULLNONE, PULLUP, PULLDOWN status */ - assert(pull <= GPIO_PULLDOWN); - - gpio_set_dir(gpio, GPIO_INPUT); - gpio_set_pull(gpio, pull); - - int_polarity = inttype_level = 0; - switch (type) { - case IRQ_TYPE_EDGE_RISING: - int_polarity = mask; - inttype_level = mask; - break; - case IRQ_TYPE_EDGE_FALLING: - inttype_level = mask; - break; - case IRQ_TYPE_LEVEL_HIGH: - int_polarity = mask; - break; - case IRQ_TYPE_LEVEL_LOW: - break; - } - clrsetbits_le32(&gpio_port[gpio.port]->int_polarity, - mask, int_polarity); - clrsetbits_le32(&gpio_port[gpio.port]->inttype_level, - mask, inttype_level); - - setbits_le32(&gpio_port[gpio.port]->inten, mask); - clrbits_le32(&gpio_port[gpio.port]->intmask, mask); -#endif -} - -int gpio_irq_status(gpio_t gpio) -{ -#if 0 - uint32_t mask = BIT(gpio.num); - uint32_t int_status = read32(&gpio_port[gpio.port]->int_status); - - if (!(int_status & mask)) - return 0; - - setbits_le32(&gpio_port[gpio.port]->porta_eoi, mask); - return 1; -#endif -} - -int gpio_get(gpio_t gpio) -{ -#if 0 - return (read32(&gpio_port[gpio.port]->ext_porta) >> gpio.num) & 0x1; -#endif -} - -void gpio_output(gpio_t gpio, int value) -{ -#if 0 - clrsetbits_le32(&gpio_port[gpio.port]->swporta_dr, 1 << gpio.num, - !!value << gpio.num); - gpio_set_dir(gpio, GPIO_OUTPUT); - gpio_set_pull(gpio, GPIO_PULLNONE); -#endif } diff --git a/src/soc/cavium/common/include/soc/gpio.h b/src/soc/cavium/common/include/soc/gpio.h index 666f7bb..6986482 100644 --- a/src/soc/cavium/common/include/soc/gpio.h +++ b/src/soc/cavium/common/include/soc/gpio.h @@ -19,68 +19,16 @@
#include <types.h>
-typedef union { - u32 raw; -#if 0 - struct { - union { - struct { - u32 num : 5; - u32 reserved1 : 27; - }; - struct { - u32 idx : 3; - u32 bank : 2; - u32 port : 4; - u32 reserved2 : 23; - }; - }; - }; -#endif -} gpio_t; +typedef u32 gpio_t; +#include <gpio.h>
-#if 0 -enum { - GPIO_A = 0, - GPIO_B, - GPIO_C, - GPIO_D, -}; +/* The following functions must be implemented by SoC/board code. */
-extern struct rockchip_gpio_regs *gpio_port[];
-/* Check if the gpio port is a pmu gpio */ -int is_pmu_gpio(gpio_t gpio); +gpio_t gpio_pin_count(void); +void gpio_invert(gpio_t gpio, int value); +int gpio_strap_value(gpio_t gpio);
-/* Return the io addr of gpio register */ -void *gpio_grf_reg(gpio_t gpio); - -enum gpio_pull { - GPIO_PULLNONE = 0, - GPIO_PULLUP = 1, - GPIO_PULLDOWN = 2, -}; - -enum gpio_dir { - GPIO_INPUT = 0, - GPIO_OUTPUT = 1, -}; - -enum gpio_irq_type { - IRQ_TYPE_EDGE_RISING = 0, - IRQ_TYPE_EDGE_FALLING, - IRQ_TYPE_LEVEL_HIGH, - IRQ_TYPE_LEVEL_LOW, -}; - -/* Setup and enable irq */ -void gpio_input_irq(gpio_t gpio, enum gpio_irq_type type, enum gpio_pull pull); - -/* Check and clear irq status */ -int gpio_irq_status(gpio_t gpio); - -/* The gpio pull bias setting may be different between SoCs */ -u32 gpio_get_pull_val(gpio_t gpio, enum gpio_pull pull); -#endif +void gpio_init(void);
#endif