mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 21:21:37 +00:00
- Support sifive DM based gpio driver for FU540-SoC. - Align boot image header with Linux v5.3
This commit is contained in:
commit
cce99479af
7 changed files with 235 additions and 5 deletions
35
arch/riscv/include/asm/arch-generic/gpio.h
Normal file
35
arch/riscv/include/asm/arch-generic/gpio.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2019 SiFive, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _GPIO_SIFIVE_H
|
||||
#define _GPIO_SIFIVE_H
|
||||
|
||||
#define GPIO_INPUT_VAL 0x00
|
||||
#define GPIO_INPUT_EN 0x04
|
||||
#define GPIO_OUTPUT_EN 0x08
|
||||
#define GPIO_OUTPUT_VAL 0x0C
|
||||
#define GPIO_RISE_IE 0x18
|
||||
#define GPIO_RISE_IP 0x1C
|
||||
#define GPIO_FALL_IE 0x20
|
||||
#define GPIO_FALL_IP 0x24
|
||||
#define GPIO_HIGH_IE 0x28
|
||||
#define GPIO_HIGH_IP 0x2C
|
||||
#define GPIO_LOW_IE 0x30
|
||||
#define GPIO_LOW_IP 0x34
|
||||
#define GPIO_OUTPUT_XOR 0x40
|
||||
|
||||
#define NR_GPIOS 16
|
||||
|
||||
enum gpio_state {
|
||||
LOW,
|
||||
HIGH
|
||||
};
|
||||
|
||||
/* Details about a GPIO bank */
|
||||
struct sifive_gpio_platdata {
|
||||
void *base; /* address of registers in physical memory */
|
||||
};
|
||||
|
||||
#endif /* _GPIO_SIFIVE_H */
|
6
arch/riscv/include/asm/gpio.h
Normal file
6
arch/riscv/include/asm/gpio.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2018 SiFive, Inc.
|
||||
*/
|
||||
|
||||
#include <asm-generic/gpio.h>
|
|
@ -14,20 +14,21 @@
|
|||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* ASCII version of "RISCV" defined in Linux kernel */
|
||||
#define LINUX_RISCV_IMAGE_MAGIC 0x5643534952
|
||||
/* ASCII version of "RSC\0x5" defined in Linux kernel */
|
||||
#define LINUX_RISCV_IMAGE_MAGIC 0x05435352
|
||||
|
||||
struct linux_image_h {
|
||||
uint32_t code0; /* Executable code */
|
||||
uint32_t code1; /* Executable code */
|
||||
uint64_t text_offset; /* Image load offset */
|
||||
uint64_t image_size; /* Effective Image size */
|
||||
uint64_t res1; /* reserved */
|
||||
uint64_t flags; /* kernel flags (little endian) */
|
||||
uint32_t version; /* version of the header */
|
||||
uint32_t res1; /* reserved */
|
||||
uint64_t res2; /* reserved */
|
||||
uint64_t res3; /* reserved */
|
||||
uint64_t magic; /* Magic number */
|
||||
uint32_t magic; /* Magic number */
|
||||
uint32_t res4; /* reserved */
|
||||
uint32_t res5; /* reserved */
|
||||
};
|
||||
|
||||
int booti_setup(ulong image, ulong *relocated_addr, ulong *size,
|
||||
|
|
|
@ -44,6 +44,9 @@ config BOARD_SPECIFIC_OPTIONS # dummy
|
|||
imply MMC_SPI
|
||||
imply MMC_BROKEN_CD
|
||||
imply CMD_MMC
|
||||
imply DM_GPIO
|
||||
imply SIFIVE_GPIO
|
||||
imply CMD_GPIO
|
||||
imply SMP
|
||||
|
||||
endif
|
||||
|
|
|
@ -285,6 +285,13 @@ config STM32_GPIO
|
|||
usable on many stm32 families like stm32f4/f7/h7 and stm32mp1.
|
||||
Tested on STM32F7.
|
||||
|
||||
config SIFIVE_GPIO
|
||||
bool "SiFive GPIO driver"
|
||||
depends on DM_GPIO
|
||||
help
|
||||
Device model driver for GPIO controller present in SiFive FU540 SoC. This
|
||||
driver enables GPIO interface on HiFive Unleashed A00 board.
|
||||
|
||||
config MVEBU_GPIO
|
||||
bool "Marvell MVEBU GPIO driver"
|
||||
depends on DM_GPIO && ARCH_MVEBU
|
||||
|
|
|
@ -61,3 +61,4 @@ obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o
|
|||
obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o
|
||||
obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
|
||||
obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
|
||||
obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
|
||||
|
|
177
drivers/gpio/sifive-gpio.c
Normal file
177
drivers/gpio/sifive-gpio.c
Normal file
|
@ -0,0 +1,177 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* SiFive GPIO driver
|
||||
*
|
||||
* Copyright (C) 2019 SiFive, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <errno.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
static int sifive_gpio_probe(struct udevice *dev)
|
||||
{
|
||||
struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
char name[18], *str;
|
||||
|
||||
sprintf(name, "gpio@%4lx_", (uintptr_t)plat->base);
|
||||
str = strdup(name);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
uc_priv->bank_name = str;
|
||||
|
||||
/*
|
||||
* Use the gpio count mentioned in device tree,
|
||||
* if not specified in dt, set NR_GPIOS as default
|
||||
*/
|
||||
uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", NR_GPIOS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sifive_update_gpio_reg(void *bptr, u32 offset, bool value)
|
||||
{
|
||||
void __iomem *ptr = (void __iomem *)bptr;
|
||||
|
||||
u32 bit = BIT(offset);
|
||||
u32 old = readl(ptr);
|
||||
|
||||
if (value)
|
||||
writel(old | bit, ptr);
|
||||
else
|
||||
writel(old & ~bit, ptr);
|
||||
}
|
||||
|
||||
static int sifive_gpio_direction_input(struct udevice *dev, u32 offset)
|
||||
{
|
||||
struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
|
||||
if (offset > uc_priv->gpio_count)
|
||||
return -EINVAL;
|
||||
|
||||
/* Configure gpio direction as input */
|
||||
sifive_update_gpio_reg(plat->base + GPIO_INPUT_EN, offset, true);
|
||||
sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sifive_gpio_direction_output(struct udevice *dev, u32 offset,
|
||||
int value)
|
||||
{
|
||||
struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
|
||||
if (offset > uc_priv->gpio_count)
|
||||
return -EINVAL;
|
||||
|
||||
/* Configure gpio direction as output */
|
||||
sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_EN, offset, true);
|
||||
sifive_update_gpio_reg(plat->base + GPIO_INPUT_EN, offset, false);
|
||||
|
||||
/* Set the output state of the pin */
|
||||
sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sifive_gpio_get_value(struct udevice *dev, u32 offset)
|
||||
{
|
||||
struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
int val;
|
||||
int dir;
|
||||
|
||||
if (offset > uc_priv->gpio_count)
|
||||
return -EINVAL;
|
||||
|
||||
/* Get direction of the pin */
|
||||
dir = !(readl(plat->base + GPIO_OUTPUT_EN) & BIT(offset));
|
||||
|
||||
if (dir)
|
||||
val = readl(plat->base + GPIO_INPUT_VAL) & BIT(offset);
|
||||
else
|
||||
val = readl(plat->base + GPIO_OUTPUT_VAL) & BIT(offset);
|
||||
|
||||
return val ? HIGH : LOW;
|
||||
}
|
||||
|
||||
static int sifive_gpio_set_value(struct udevice *dev, u32 offset, int value)
|
||||
{
|
||||
struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
|
||||
if (offset > uc_priv->gpio_count)
|
||||
return -EINVAL;
|
||||
|
||||
sifive_update_gpio_reg(plat->base + GPIO_OUTPUT_VAL, offset, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sifive_gpio_get_function(struct udevice *dev, unsigned int offset)
|
||||
{
|
||||
struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
u32 outdir, indir, val;
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
|
||||
if (offset > uc_priv->gpio_count)
|
||||
return -1;
|
||||
|
||||
/* Get direction of the pin */
|
||||
outdir = readl(plat->base + GPIO_OUTPUT_EN) & BIT(offset);
|
||||
indir = readl(plat->base + GPIO_INPUT_EN) & BIT(offset);
|
||||
|
||||
if (outdir)
|
||||
/* Pin at specified offset is configured as output */
|
||||
val = GPIOF_OUTPUT;
|
||||
else if (indir)
|
||||
/* Pin at specified offset is configured as input */
|
||||
val = GPIOF_INPUT;
|
||||
else
|
||||
/*The requested GPIO is not set as input or output */
|
||||
val = GPIOF_UNUSED;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const struct udevice_id sifive_gpio_match[] = {
|
||||
{ .compatible = "sifive,gpio0" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct dm_gpio_ops sifive_gpio_ops = {
|
||||
.direction_input = sifive_gpio_direction_input,
|
||||
.direction_output = sifive_gpio_direction_output,
|
||||
.get_value = sifive_gpio_get_value,
|
||||
.set_value = sifive_gpio_set_value,
|
||||
.get_function = sifive_gpio_get_function,
|
||||
};
|
||||
|
||||
static int sifive_gpio_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct sifive_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
fdt_addr_t addr;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
plat->base = (void *)addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(gpio_sifive) = {
|
||||
.name = "gpio_sifive",
|
||||
.id = UCLASS_GPIO,
|
||||
.of_match = sifive_gpio_match,
|
||||
.ofdata_to_platdata = of_match_ptr(sifive_gpio_ofdata_to_platdata),
|
||||
.platdata_auto_alloc_size = sizeof(struct sifive_gpio_platdata),
|
||||
.ops = &sifive_gpio_ops,
|
||||
.probe = sifive_gpio_probe,
|
||||
};
|
Loading…
Add table
Reference in a new issue