Unverified Commit d4dcadb0 authored by Antonio Niño Díaz's avatar Antonio Niño Díaz Committed by GitHub
Browse files

Merge pull request #1773 from grandpaul/rpi3-gpio-driver

Rpi3 gpio driver
Showing with 236 additions and 0 deletions
+236 -0
/*
* Copyright (c) 2019, Linaro Limited
* Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <assert.h>
#include <lib/mmio.h>
#include <drivers/delay_timer.h>
#include <drivers/rpi3/gpio/rpi3_gpio.h>
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);
}
/*
* Copyright (c) 2019, Linaro Limited
* Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef RPI3_GPIO_H
#define RPI3_GPIO_H
#include <stdint.h>
#include <drivers/gpio.h>
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 */
......@@ -27,6 +27,10 @@ BL2_SOURCES += common/desc_image_load.c \
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 \
......
......@@ -15,12 +15,25 @@
#include <lib/optee_utils.h>
#include <lib/xlat_tables/xlat_mmu_helpers.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
#include <drivers/generic_delay_timer.h>
#include <drivers/rpi3/gpio/rpi3_gpio.h>
#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(&params, 0, sizeof(struct rpi3_gpio_params));
params.reg_base = RPI3_GPIO_BASE;
rpi3_gpio_init(&params);
}
/*******************************************************************************
* 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 @@ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1,
/* 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;
......
......@@ -83,6 +83,12 @@
#define RPI3_MINI_UART_BASE (RPI3_IO_BASE + RPI3_IO_MINI_UART_OFFSET)
#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
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment