diff --git a/drivers/rpi3/gpio/rpi3_gpio.c b/drivers/rpi3/gpio/rpi3_gpio.c new file mode 100644 index 0000000..b39808f --- /dev/null +++ b/drivers/rpi3/gpio/rpi3_gpio.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2019, Linaro Limited + * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +static struct rpi3_gpio_params rpi3_gpio_params; + +static int rpi3_gpio_get_direction(int gpio); +static void rpi3_gpio_set_direction(int gpio, int direction); +static int rpi3_gpio_get_value(int gpio); +static void rpi3_gpio_set_value(int gpio, int value); +static void rpi3_gpio_set_pull(int gpio, int pull); + +static const gpio_ops_t rpi3_gpio_ops = { + .get_direction = rpi3_gpio_get_direction, + .set_direction = rpi3_gpio_set_direction, + .get_value = rpi3_gpio_get_value, + .set_value = rpi3_gpio_set_value, + .set_pull = rpi3_gpio_set_pull, +}; + +/** + * Get selection of GPIO pinmux settings. + * + * @param gpio The pin number of GPIO. From 0 to 53. + * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input, + * RPI3_GPIO_FUNC_OUTPUT: output, + * RPI3_GPIO_FUNC_ALT0: alt-0, + * RPI3_GPIO_FUNC_ALT1: alt-1, + * RPI3_GPIO_FUNC_ALT2: alt-2, + * RPI3_GPIO_FUNC_ALT3: alt-3, + * RPI3_GPIO_FUNC_ALT4: alt-4, + * RPI3_GPIO_FUNC_ALT5: alt-5 + */ +int rpi3_gpio_get_select(int gpio) +{ + int ret; + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 10; + int shift = 3 * (gpio % 10); + uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN); + uint32_t sel = mmio_read_32(reg_sel); + + ret = (sel >> shift) & 0x07; + + return ret; +} + +/** + * Set selection of GPIO pinmux settings. + * + * @param gpio The pin number of GPIO. From 0 to 53. + * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input, + * RPI3_GPIO_FUNC_OUTPUT: output, + * RPI3_GPIO_FUNC_ALT0: alt-0, + * RPI3_GPIO_FUNC_ALT1: alt-1, + * RPI3_GPIO_FUNC_ALT2: alt-2, + * RPI3_GPIO_FUNC_ALT3: alt-3, + * RPI3_GPIO_FUNC_ALT4: alt-4, + * RPI3_GPIO_FUNC_ALT5: alt-5 + */ +void rpi3_gpio_set_select(int gpio, int fsel) +{ + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 10; + int shift = 3 * (gpio % 10); + uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN); + uint32_t sel = mmio_read_32(reg_sel); + uint32_t mask = U(0x07) << shift; + + sel = (sel & (~mask)) | ((fsel << shift) & mask); + mmio_write_32(reg_sel, sel); +} + +static int rpi3_gpio_get_direction(int gpio) +{ + int result = rpi3_gpio_get_select(gpio); + + if (result == RPI3_GPIO_FUNC_INPUT) + return GPIO_DIR_IN; + else if (result == RPI3_GPIO_FUNC_OUTPUT) + return GPIO_DIR_OUT; + + return GPIO_DIR_IN; +} + +static void rpi3_gpio_set_direction(int gpio, int direction) +{ + switch (direction) { + case GPIO_DIR_IN: + rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT); + break; + case GPIO_DIR_OUT: + rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT); + break; + } +} + +static int rpi3_gpio_get_value(int gpio) +{ + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 32; + int shift = gpio % 32; + uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN); + uint32_t value = mmio_read_32(reg_lev); + + if ((value >> shift) & 0x01) + return GPIO_LEVEL_HIGH; + return GPIO_LEVEL_LOW; +} + +static void rpi3_gpio_set_value(int gpio, int value) +{ + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 32; + int shift = gpio % 32; + uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN); + uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN); + + switch (value) { + case GPIO_LEVEL_LOW: + mmio_write_32(reg_clr, U(1) << shift); + break; + case GPIO_LEVEL_HIGH: + mmio_write_32(reg_set, U(1) << shift); + break; + } +} + +static void rpi3_gpio_set_pull(int gpio, int pull) +{ + uintptr_t reg_base = rpi3_gpio_params.reg_base; + int regN = gpio / 32; + int shift = gpio % 32; + uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD; + uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN); + + switch (pull) { + case GPIO_PULL_NONE: + mmio_write_32(reg_pud, 0x0); + break; + case GPIO_PULL_UP: + mmio_write_32(reg_pud, 0x2); + break; + case GPIO_PULL_DOWN: + mmio_write_32(reg_pud, 0x1); + break; + } + mdelay(150); + mmio_write_32(reg_clk, U(1) << shift); + mdelay(150); + mmio_write_32(reg_clk, 0x0); + mmio_write_32(reg_pud, 0x0); +} + +void rpi3_gpio_init(struct rpi3_gpio_params *params) +{ + assert(params != 0); + memcpy(&rpi3_gpio_params, params, sizeof(struct rpi3_gpio_params)); + gpio_init(&rpi3_gpio_ops); +} diff --git a/include/drivers/rpi3/gpio/rpi3_gpio.h b/include/drivers/rpi3/gpio/rpi3_gpio.h new file mode 100644 index 0000000..159a2e0 --- /dev/null +++ b/include/drivers/rpi3/gpio/rpi3_gpio.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019, Linaro Limited + * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RPI3_GPIO_H +#define RPI3_GPIO_H + +#include +#include + +struct rpi3_gpio_params { + uintptr_t reg_base; +}; + +void rpi3_gpio_init(struct rpi3_gpio_params *params); +int rpi3_gpio_get_select(int gpio); +void rpi3_gpio_set_select(int gpio, int fsel); + +#define RPI3_GPIO_GPFSEL(n) ((n) * U(0x04)) +#define RPI3_GPIO_GPSET(n) (((n) * U(0x04)) + U(0x1C)) +#define RPI3_GPIO_GPCLR(n) (((n) * U(0x04)) + U(0x28)) +#define RPI3_GPIO_GPLEV(n) (((n) * U(0x04)) + U(0x34)) +#define RPI3_GPIO_GPPUD U(0x94) +#define RPI3_GPIO_GPPUDCLK(n) (((n) * U(0x04)) + U(0x98)) + +#define RPI3_GPIO_FUNC_INPUT U(0) +#define RPI3_GPIO_FUNC_OUTPUT U(1) +#define RPI3_GPIO_FUNC_ALT0 U(4) +#define RPI3_GPIO_FUNC_ALT1 U(5) +#define RPI3_GPIO_FUNC_ALT2 U(6) +#define RPI3_GPIO_FUNC_ALT3 U(7) +#define RPI3_GPIO_FUNC_ALT4 U(3) +#define RPI3_GPIO_FUNC_ALT5 U(2) + +#endif /* RPI3_GPIO_H */ diff --git a/plat/rpi3/platform.mk b/plat/rpi3/platform.mk index 5e76345..ded92bd 100644 --- a/plat/rpi3/platform.mk +++ b/plat/rpi3/platform.mk @@ -27,6 +27,10 @@ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ + drivers/gpio/gpio.c \ + drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + drivers/rpi3/gpio/rpi3_gpio.c \ plat/common/aarch64/platform_mp_stack.S \ plat/rpi3/aarch64/plat_helpers.S \ plat/rpi3/aarch64/rpi3_bl2_mem_params_desc.c \ diff --git a/plat/rpi3/rpi3_bl2_setup.c b/plat/rpi3/rpi3_bl2_setup.c index 53a2c72..09f0562 100644 --- a/plat/rpi3/rpi3_bl2_setup.c +++ b/plat/rpi3/rpi3_bl2_setup.c @@ -15,12 +15,25 @@ #include #include #include +#include +#include #include "rpi3_private.h" /* Data structure which holds the extents of the trusted SRAM for BL2 */ static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); +/* rpi3 GPIO setup function. */ +static void rpi3_gpio_setup(void) +{ + struct rpi3_gpio_params params; + + memset(¶ms, 0, sizeof(struct rpi3_gpio_params)); + params.reg_base = RPI3_GPIO_BASE; + + rpi3_gpio_init(¶ms); +} + /******************************************************************************* * BL1 has passed the extents of the trusted SRAM that should be visible to BL2 * in x0. This memory layout is sitting at the base of the free trusted SRAM. @@ -35,6 +48,12 @@ /* Initialize the console to provide early debug support */ rpi3_console_init(); + /* Enable arch timer */ + generic_delay_timer_init(); + + /* Setup GPIO driver */ + rpi3_gpio_setup(); + /* Setup the BL2 memory layout */ bl2_tzram_layout = *mem_layout; diff --git a/plat/rpi3/rpi3_hw.h b/plat/rpi3/rpi3_hw.h index 9d86eb8..61d1837 100644 --- a/plat/rpi3/rpi3_hw.h +++ b/plat/rpi3/rpi3_hw.h @@ -84,6 +84,12 @@ #define RPI3_MINI_UART_CLK_IN_HZ ULL(500000000) /* + * GPIO controller + */ +#define RPI3_IO_GPIO_OFFSET ULL(0x00200000) +#define RPI3_GPIO_BASE (RPI3_IO_BASE + RPI3_IO_GPIO_OFFSET) + +/* * Local interrupt controller */ #define RPI3_INTC_BASE_ADDRESS ULL(0x40000000)