Merge branch 'master' of git://git.denx.de/u-boot-mips
This commit is contained in:
@@ -20,6 +20,14 @@ config SPL_CLK
|
||||
setting up clocks within SPL, and allows the same drivers to be
|
||||
used as U-Boot proper.
|
||||
|
||||
config CLK_BCM6345
|
||||
bool "Clock controller driver for BCM6345"
|
||||
depends on CLK && ARCH_BMIPS
|
||||
default y
|
||||
help
|
||||
This clock driver adds support for enabling and disabling peripheral
|
||||
clocks on BCM6345 SoCs. HW has no rate changing capabilities.
|
||||
|
||||
config CLK_BOSTON
|
||||
def_bool y if TARGET_BOSTON
|
||||
depends on CLK
|
||||
|
||||
@@ -17,6 +17,7 @@ obj-y += tegra/
|
||||
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
|
||||
obj-$(CONFIG_CLK_EXYNOS) += exynos/
|
||||
obj-$(CONFIG_CLK_AT91) += at91/
|
||||
obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o
|
||||
obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
|
||||
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
|
||||
obj-$(CONFIG_STM32F7) += clk_stm32f7.o
|
||||
|
||||
78
drivers/clk/clk_bcm6345.c
Normal file
78
drivers/clk/clk_bcm6345.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* Derived from linux/arch/mips/bcm63xx/clk.c:
|
||||
* Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define MAX_CLKS 32
|
||||
|
||||
struct bcm6345_clk_priv {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static int bcm6345_clk_enable(struct clk *clk)
|
||||
{
|
||||
struct bcm6345_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
|
||||
if (clk->id >= MAX_CLKS)
|
||||
return -EINVAL;
|
||||
|
||||
setbits_be32(priv->regs, BIT(clk->id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_clk_disable(struct clk *clk)
|
||||
{
|
||||
struct bcm6345_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
|
||||
if (clk->id >= MAX_CLKS)
|
||||
return -EINVAL;
|
||||
|
||||
clrbits_be32(priv->regs, BIT(clk->id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops bcm6345_clk_ops = {
|
||||
.disable = bcm6345_clk_disable,
|
||||
.enable = bcm6345_clk_enable,
|
||||
};
|
||||
|
||||
static const struct udevice_id bcm6345_clk_ids[] = {
|
||||
{ .compatible = "brcm,bcm6345-clk" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int bcm63xx_clk_probe(struct udevice *dev)
|
||||
{
|
||||
struct bcm6345_clk_priv *priv = dev_get_priv(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
|
||||
addr = dev_get_addr_size_index(dev, 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = ioremap(addr, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(clk_bcm6345) = {
|
||||
.name = "clk_bcm6345",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = bcm6345_clk_ids,
|
||||
.ops = &bcm6345_clk_ops,
|
||||
.probe = bcm63xx_clk_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct bcm6345_clk_priv),
|
||||
};
|
||||
@@ -5,3 +5,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
obj-$(CONFIG_CPU) += cpu-uclass.o
|
||||
|
||||
obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
|
||||
|
||||
310
drivers/cpu/bmips_cpu.c
Normal file
310
drivers/cpu/bmips_cpu.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* Derived from linux/arch/mips/bcm63xx/cpu.c:
|
||||
* Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
|
||||
* Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <cpu.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define REV_CHIPID_SHIFT 16
|
||||
#define REV_CHIPID_MASK (0xffff << REV_CHIPID_SHIFT)
|
||||
#define REV_LONG_CHIPID_SHIFT 12
|
||||
#define REV_LONG_CHIPID_MASK (0xfffff << REV_LONG_CHIPID_SHIFT)
|
||||
#define REV_REVID_SHIFT 0
|
||||
#define REV_REVID_MASK (0xff << REV_REVID_SHIFT)
|
||||
|
||||
#define REG_BCM6328_OTP 0x62c
|
||||
#define BCM6328_TP1_DISABLED BIT(9)
|
||||
|
||||
#define REG_BCM6328_MISC_STRAPBUS 0x1a40
|
||||
#define STRAPBUS_6328_FCVO_SHIFT 7
|
||||
#define STRAPBUS_6328_FCVO_MASK (0x1f << STRAPBUS_6328_FCVO_SHIFT)
|
||||
|
||||
#define REG_BCM6358_DDR_DMIPSPLLCFG 0x12b8
|
||||
#define DMIPSPLLCFG_6358_M1_SHIFT 0
|
||||
#define DMIPSPLLCFG_6358_M1_MASK (0xff << DMIPSPLLCFG_6358_M1_SHIFT)
|
||||
#define DMIPSPLLCFG_6358_N1_SHIFT 23
|
||||
#define DMIPSPLLCFG_6358_N1_MASK (0x3f << DMIPSPLLCFG_6358_N1_SHIFT)
|
||||
#define DMIPSPLLCFG_6358_N2_SHIFT 29
|
||||
#define DMIPSPLLCFG_6358_N2_MASK (0x7 << DMIPSPLLCFG_6358_N2_SHIFT)
|
||||
|
||||
#define REG_BCM63268_MISC_STRAPBUS 0x1814
|
||||
#define STRAPBUS_63268_FCVO_SHIFT 21
|
||||
#define STRAPBUS_63268_FCVO_MASK (0xf << STRAPBUS_63268_FCVO_SHIFT)
|
||||
|
||||
struct bmips_cpu_priv;
|
||||
|
||||
struct bmips_cpu_hw {
|
||||
int (*get_cpu_desc)(struct bmips_cpu_priv *priv, char *buf, int size);
|
||||
ulong (*get_cpu_freq)(struct bmips_cpu_priv *);
|
||||
int (*get_cpu_count)(struct bmips_cpu_priv *);
|
||||
};
|
||||
|
||||
struct bmips_cpu_priv {
|
||||
void __iomem *regs;
|
||||
const struct bmips_cpu_hw *hw;
|
||||
};
|
||||
|
||||
/* Specific CPU Ops */
|
||||
static int bcm6358_get_cpu_desc(struct bmips_cpu_priv *priv, char *buf,
|
||||
int size)
|
||||
{
|
||||
unsigned short cpu_id;
|
||||
unsigned char cpu_rev;
|
||||
u32 val;
|
||||
|
||||
val = readl_be(priv->regs);
|
||||
cpu_id = (val & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;
|
||||
cpu_rev = (val & REV_REVID_MASK) >> REV_REVID_SHIFT;
|
||||
|
||||
snprintf(buf, size, "BCM%04X%02X", cpu_id, cpu_rev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6328_get_cpu_desc(struct bmips_cpu_priv *priv, char *buf,
|
||||
int size)
|
||||
{
|
||||
unsigned int cpu_id;
|
||||
unsigned char cpu_rev;
|
||||
u32 val;
|
||||
|
||||
val = readl_be(priv->regs);
|
||||
cpu_id = (val & REV_LONG_CHIPID_MASK) >> REV_LONG_CHIPID_SHIFT;
|
||||
cpu_rev = (val & REV_REVID_MASK) >> REV_REVID_SHIFT;
|
||||
|
||||
snprintf(buf, size, "BCM%05X%02X", cpu_id, cpu_rev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ulong bcm6328_get_cpu_freq(struct bmips_cpu_priv *priv)
|
||||
{
|
||||
unsigned int mips_pll_fcvo;
|
||||
|
||||
mips_pll_fcvo = readl_be(priv->regs + REG_BCM6328_MISC_STRAPBUS);
|
||||
mips_pll_fcvo = (mips_pll_fcvo & STRAPBUS_6328_FCVO_MASK)
|
||||
>> STRAPBUS_6328_FCVO_SHIFT;
|
||||
|
||||
switch (mips_pll_fcvo) {
|
||||
case 0x12:
|
||||
case 0x14:
|
||||
case 0x19:
|
||||
return 160000000;
|
||||
case 0x1c:
|
||||
return 192000000;
|
||||
case 0x13:
|
||||
case 0x15:
|
||||
return 200000000;
|
||||
case 0x1a:
|
||||
return 384000000;
|
||||
case 0x16:
|
||||
return 400000000;
|
||||
default:
|
||||
return 320000000;
|
||||
}
|
||||
}
|
||||
|
||||
static ulong bcm6358_get_cpu_freq(struct bmips_cpu_priv *priv)
|
||||
{
|
||||
unsigned int tmp, n1, n2, m1;
|
||||
|
||||
tmp = readl_be(priv->regs + REG_BCM6358_DDR_DMIPSPLLCFG);
|
||||
n1 = (tmp & DMIPSPLLCFG_6358_N1_MASK) >> DMIPSPLLCFG_6358_N1_SHIFT;
|
||||
n2 = (tmp & DMIPSPLLCFG_6358_N2_MASK) >> DMIPSPLLCFG_6358_N2_SHIFT;
|
||||
m1 = (tmp & DMIPSPLLCFG_6358_M1_MASK) >> DMIPSPLLCFG_6358_M1_SHIFT;
|
||||
|
||||
return (16 * 1000000 * n1 * n2) / m1;
|
||||
}
|
||||
|
||||
static ulong bcm63268_get_cpu_freq(struct bmips_cpu_priv *priv)
|
||||
{
|
||||
unsigned int mips_pll_fcvo;
|
||||
|
||||
mips_pll_fcvo = readl_be(priv->regs + REG_BCM63268_MISC_STRAPBUS);
|
||||
mips_pll_fcvo = (mips_pll_fcvo & STRAPBUS_63268_FCVO_MASK)
|
||||
>> STRAPBUS_63268_FCVO_SHIFT;
|
||||
|
||||
switch (mips_pll_fcvo) {
|
||||
case 0x3:
|
||||
case 0xe:
|
||||
return 320000000;
|
||||
case 0xa:
|
||||
return 333000000;
|
||||
case 0x2:
|
||||
case 0xb:
|
||||
case 0xf:
|
||||
return 400000000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int bcm6328_get_cpu_count(struct bmips_cpu_priv *priv)
|
||||
{
|
||||
u32 val = readl_be(priv->regs + REG_BCM6328_OTP);
|
||||
|
||||
if (val & BCM6328_TP1_DISABLED)
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int bcm6358_get_cpu_count(struct bmips_cpu_priv *priv)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
static const struct bmips_cpu_hw bmips_cpu_bcm6328 = {
|
||||
.get_cpu_desc = bcm6328_get_cpu_desc,
|
||||
.get_cpu_freq = bcm6328_get_cpu_freq,
|
||||
.get_cpu_count = bcm6328_get_cpu_count,
|
||||
};
|
||||
|
||||
static const struct bmips_cpu_hw bmips_cpu_bcm6358 = {
|
||||
.get_cpu_desc = bcm6358_get_cpu_desc,
|
||||
.get_cpu_freq = bcm6358_get_cpu_freq,
|
||||
.get_cpu_count = bcm6358_get_cpu_count,
|
||||
};
|
||||
|
||||
static const struct bmips_cpu_hw bmips_cpu_bcm63268 = {
|
||||
.get_cpu_desc = bcm6328_get_cpu_desc,
|
||||
.get_cpu_freq = bcm63268_get_cpu_freq,
|
||||
.get_cpu_count = bcm6358_get_cpu_count,
|
||||
};
|
||||
|
||||
/* Generic CPU Ops */
|
||||
static int bmips_cpu_get_desc(struct udevice *dev, char *buf, int size)
|
||||
{
|
||||
struct bmips_cpu_priv *priv = dev_get_priv(dev);
|
||||
const struct bmips_cpu_hw *hw = priv->hw;
|
||||
|
||||
return hw->get_cpu_desc(priv, buf, size);
|
||||
}
|
||||
|
||||
static int bmips_cpu_get_info(struct udevice *dev, struct cpu_info *info)
|
||||
{
|
||||
struct bmips_cpu_priv *priv = dev_get_priv(dev);
|
||||
const struct bmips_cpu_hw *hw = priv->hw;
|
||||
|
||||
info->cpu_freq = hw->get_cpu_freq(priv);
|
||||
info->features = BIT(CPU_FEAT_L1_CACHE);
|
||||
info->features |= BIT(CPU_FEAT_MMU);
|
||||
info->features |= BIT(CPU_FEAT_DEVICE_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bmips_cpu_get_count(struct udevice *dev)
|
||||
{
|
||||
struct bmips_cpu_priv *priv = dev_get_priv(dev);
|
||||
const struct bmips_cpu_hw *hw = priv->hw;
|
||||
|
||||
return hw->get_cpu_count(priv);
|
||||
}
|
||||
|
||||
static int bmips_cpu_get_vendor(struct udevice *dev, char *buf, int size)
|
||||
{
|
||||
snprintf(buf, size, "Broadcom");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cpu_ops bmips_cpu_ops = {
|
||||
.get_desc = bmips_cpu_get_desc,
|
||||
.get_info = bmips_cpu_get_info,
|
||||
.get_count = bmips_cpu_get_count,
|
||||
.get_vendor = bmips_cpu_get_vendor,
|
||||
};
|
||||
|
||||
/* BMIPS CPU driver */
|
||||
int bmips_cpu_bind(struct udevice *dev)
|
||||
{
|
||||
struct cpu_platdata *plat = dev_get_parent_platdata(dev);
|
||||
|
||||
plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
|
||||
"reg", -1);
|
||||
plat->device_id = read_c0_prid();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bmips_cpu_probe(struct udevice *dev)
|
||||
{
|
||||
struct bmips_cpu_priv *priv = dev_get_priv(dev);
|
||||
const struct bmips_cpu_hw *hw =
|
||||
(const struct bmips_cpu_hw *)dev_get_driver_data(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
|
||||
addr = dev_get_addr_size_index(dev_get_parent(dev), 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = ioremap(addr, size);
|
||||
priv->hw = hw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id bmips_cpu_ids[] = {
|
||||
{
|
||||
.compatible = "brcm,bcm6328-cpu",
|
||||
.data = (ulong)&bmips_cpu_bcm6328,
|
||||
}, {
|
||||
.compatible = "brcm,bcm6358-cpu",
|
||||
.data = (ulong)&bmips_cpu_bcm6358,
|
||||
}, {
|
||||
.compatible = "brcm,bcm63268-cpu",
|
||||
.data = (ulong)&bmips_cpu_bcm63268,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bmips_cpu_drv) = {
|
||||
.name = "bmips_cpu",
|
||||
.id = UCLASS_CPU,
|
||||
.of_match = bmips_cpu_ids,
|
||||
.bind = bmips_cpu_bind,
|
||||
.probe = bmips_cpu_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct bmips_cpu_priv),
|
||||
.ops = &bmips_cpu_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DISPLAY_CPUINFO
|
||||
int print_cpuinfo(void)
|
||||
{
|
||||
struct cpu_info cpu;
|
||||
struct udevice *dev;
|
||||
int err;
|
||||
char desc[100];
|
||||
|
||||
err = uclass_get_device(UCLASS_CPU, 0, &dev);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
err = cpu_get_info(dev, &cpu);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
err = cpu_get_desc(dev, desc, sizeof(desc));
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
printf("Chip ID: %s, MIPS: ", desc);
|
||||
print_freq(cpu.cpu_freq, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -21,6 +21,12 @@ config ALTERA_PIO
|
||||
Select this to enable PIO for Altera devices. Please find
|
||||
details on the "Embedded Peripherals IP User Guide" of Altera.
|
||||
|
||||
config BCM6345_GPIO
|
||||
bool "BCM6345 GPIO driver"
|
||||
depends on DM_GPIO && ARCH_BMIPS
|
||||
help
|
||||
This driver supports the GPIO banks on BCM6345 SoCs.
|
||||
|
||||
config DWAPB_GPIO
|
||||
bool "DWAPB GPIO driver"
|
||||
depends on DM && DM_GPIO
|
||||
|
||||
@@ -16,6 +16,7 @@ obj-$(CONFIG_DM_74X164) += 74x164_gpio.o
|
||||
|
||||
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
|
||||
obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
|
||||
obj-$(CONFIG_BCM6345_GPIO) += bcm6345_gpio.o
|
||||
obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
|
||||
obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o
|
||||
obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o
|
||||
|
||||
125
drivers/gpio/bcm6345_gpio.c
Normal file
125
drivers/gpio/bcm6345_gpio.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* Derived from linux/arch/mips/bcm63xx/gpio.c:
|
||||
* Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
|
||||
* Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/device.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct bcm6345_gpio_priv {
|
||||
void __iomem *reg_dirout;
|
||||
void __iomem *reg_data;
|
||||
};
|
||||
|
||||
static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return !!(readl_be(priv->reg_data) & BIT(offset));
|
||||
}
|
||||
|
||||
static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (value)
|
||||
setbits_be32(priv->reg_data, BIT(offset));
|
||||
else
|
||||
clrbits_be32(priv->reg_data, BIT(offset));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset,
|
||||
bool input)
|
||||
{
|
||||
if (input)
|
||||
clrbits_be32(dirout, BIT(offset));
|
||||
else
|
||||
setbits_be32(dirout, BIT(offset));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_gpio_direction_input(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 1);
|
||||
}
|
||||
|
||||
static int bcm6345_gpio_direction_output(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0);
|
||||
}
|
||||
|
||||
static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (readl_be(priv->reg_dirout) & BIT(offset))
|
||||
return GPIOF_OUTPUT;
|
||||
else
|
||||
return GPIOF_INPUT;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops bcm6345_gpio_ops = {
|
||||
.direction_input = bcm6345_gpio_direction_input,
|
||||
.direction_output = bcm6345_gpio_direction_output,
|
||||
.get_value = bcm6345_gpio_get_value,
|
||||
.set_value = bcm6345_gpio_set_value,
|
||||
.get_function = bcm6345_gpio_get_function,
|
||||
};
|
||||
|
||||
static int bcm6345_gpio_probe(struct udevice *dev)
|
||||
{
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
|
||||
fdt_addr_t data_addr, dirout_addr;
|
||||
fdt_size_t data_size, dirout_size;
|
||||
|
||||
dirout_addr = dev_get_addr_size_index(dev, 0, &dirout_size);
|
||||
if (dirout_addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
data_addr = dev_get_addr_size_index(dev, 1, &data_size);
|
||||
if (data_addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->reg_data = ioremap(data_addr, data_size);
|
||||
priv->reg_dirout = ioremap(dirout_addr, dirout_size);
|
||||
|
||||
uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
|
||||
"ngpios", 32);
|
||||
uc_priv->bank_name = dev->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id bcm6345_gpio_ids[] = {
|
||||
{ .compatible = "brcm,bcm6345-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bcm6345_gpio) = {
|
||||
.name = "bcm6345-gpio",
|
||||
.id = UCLASS_GPIO,
|
||||
.of_match = bcm6345_gpio_ids,
|
||||
.ops = &bcm6345_gpio_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct bcm6345_gpio_priv),
|
||||
.probe = bcm6345_gpio_probe,
|
||||
};
|
||||
@@ -9,6 +9,25 @@ config LED
|
||||
can provide access to board-specific LEDs. Use of the device tree
|
||||
for configuration is encouraged.
|
||||
|
||||
config LED_BCM6328
|
||||
bool "LED Support for BCM6328"
|
||||
depends on LED && ARCH_BMIPS
|
||||
help
|
||||
This option enables support for LEDs connected to the BCM6328
|
||||
LED HW controller accessed via MMIO registers.
|
||||
HW blinking is supported and up to 24 LEDs can be controlled.
|
||||
All LEDs can blink at the same time but the delay is shared, which
|
||||
means that if one LED is set to blink at 100ms and then a different
|
||||
LED is set to blink at 200ms, both will blink at 200ms.
|
||||
|
||||
config LED_BCM6358
|
||||
bool "LED Support for BCM6358"
|
||||
depends on LED && ARCH_BMIPS
|
||||
help
|
||||
This option enables support for LEDs connected to the BCM6358
|
||||
LED HW controller accessed via MMIO registers.
|
||||
HW has no blinking capabilities and up to 32 LEDs can be controlled.
|
||||
|
||||
config LED_BLINK
|
||||
bool "Support LED blinking"
|
||||
depends on LED
|
||||
|
||||
@@ -6,4 +6,6 @@
|
||||
#
|
||||
|
||||
obj-y += led-uclass.o
|
||||
obj-$(CONFIG_LED_BCM6328) += led_bcm6328.o
|
||||
obj-$(CONFIG_LED_BCM6358) += led_bcm6358.o
|
||||
obj-$(CONFIG_$(SPL_)LED_GPIO) += led_gpio.o
|
||||
|
||||
262
drivers/led/led_bcm6328.c
Normal file
262
drivers/led/led_bcm6328.c
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <led.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/lists.h>
|
||||
|
||||
#define LEDS_MAX 24
|
||||
|
||||
/* LED Init register */
|
||||
#define LED_INIT_REG 0x00
|
||||
#define LED_INIT_FASTINTV_MS 20
|
||||
#define LED_INIT_FASTINTV_SHIFT 6
|
||||
#define LED_INIT_FASTINTV_MASK (0x3f << LED_INIT_FASTINTV_SHIFT)
|
||||
#define LED_INIT_SLEDEN_SHIFT 12
|
||||
#define LED_INIT_SLEDEN_MASK (1 << LED_INIT_SLEDEN_SHIFT)
|
||||
#define LED_INIT_SLEDMUX_SHIFT 13
|
||||
#define LED_INIT_SLEDMUX_MASK (1 << LED_INIT_SLEDMUX_SHIFT)
|
||||
#define LED_INIT_SLEDCLKNPOL_SHIFT 14
|
||||
#define LED_INIT_SLEDCLKNPOL_MASK (1 << LED_INIT_SLEDCLKNPOL_SHIFT)
|
||||
#define LED_INIT_SLEDDATAPPOL_SHIFT 15
|
||||
#define LED_INIT_SLEDDATANPOL_MASK (1 << LED_INIT_SLEDDATAPPOL_SHIFT)
|
||||
#define LED_INIT_SLEDSHIFTDIR_SHIFT 16
|
||||
#define LED_INIT_SLEDSHIFTDIR_MASK (1 << LED_INIT_SLEDSHIFTDIR_SHIFT)
|
||||
|
||||
/* LED Mode registers */
|
||||
#define LED_MODE_REG_HI 0x04
|
||||
#define LED_MODE_REG_LO 0x08
|
||||
#define LED_MODE_ON 0
|
||||
#define LED_MODE_FAST 1
|
||||
#define LED_MODE_BLINK 2
|
||||
#define LED_MODE_OFF 3
|
||||
#define LED_MODE_MASK 0x3
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct bcm6328_led_priv {
|
||||
void __iomem *regs;
|
||||
void __iomem *mode;
|
||||
uint8_t shift;
|
||||
bool active_low;
|
||||
};
|
||||
|
||||
static unsigned long bcm6328_led_get_mode(struct bcm6328_led_priv *priv)
|
||||
{
|
||||
return ((readl_be(priv->mode) >> priv->shift) & LED_MODE_MASK);
|
||||
}
|
||||
|
||||
static int bcm6328_led_set_mode(struct bcm6328_led_priv *priv, uint8_t mode)
|
||||
{
|
||||
clrsetbits_be32(priv->mode, (LED_MODE_MASK << priv->shift),
|
||||
(mode << priv->shift));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum led_state_t bcm6328_led_get_state(struct udevice *dev)
|
||||
{
|
||||
struct bcm6328_led_priv *priv = dev_get_priv(dev);
|
||||
enum led_state_t state = LEDST_OFF;
|
||||
|
||||
switch (bcm6328_led_get_mode(priv)) {
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
case LED_MODE_BLINK:
|
||||
case LED_MODE_FAST:
|
||||
state = LEDST_BLINK;
|
||||
break;
|
||||
#endif
|
||||
case LED_MODE_OFF:
|
||||
state = (priv->active_low ? LEDST_ON : LEDST_OFF);
|
||||
break;
|
||||
case LED_MODE_ON:
|
||||
state = (priv->active_low ? LEDST_OFF : LEDST_ON);
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static int bcm6328_led_set_state(struct udevice *dev, enum led_state_t state)
|
||||
{
|
||||
struct bcm6328_led_priv *priv = dev_get_priv(dev);
|
||||
unsigned long mode;
|
||||
|
||||
switch (state) {
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
case LEDST_BLINK:
|
||||
mode = LED_MODE_BLINK;
|
||||
break;
|
||||
#endif
|
||||
case LEDST_OFF:
|
||||
mode = (priv->active_low ? LED_MODE_ON : LED_MODE_OFF);
|
||||
break;
|
||||
case LEDST_ON:
|
||||
mode = (priv->active_low ? LED_MODE_OFF : LED_MODE_ON);
|
||||
break;
|
||||
case LEDST_TOGGLE:
|
||||
if (bcm6328_led_get_state(dev) == LEDST_OFF)
|
||||
return bcm6328_led_set_state(dev, LEDST_ON);
|
||||
else
|
||||
return bcm6328_led_set_state(dev, LEDST_OFF);
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return bcm6328_led_set_mode(priv, mode);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
static unsigned long bcm6328_blink_delay(int delay)
|
||||
{
|
||||
unsigned long bcm6328_delay = delay;
|
||||
|
||||
bcm6328_delay += (LED_INIT_FASTINTV_MS / 2);
|
||||
bcm6328_delay /= LED_INIT_FASTINTV_MS;
|
||||
bcm6328_delay <<= LED_INIT_FASTINTV_SHIFT;
|
||||
|
||||
if (bcm6328_delay > LED_INIT_FASTINTV_MASK)
|
||||
return LED_INIT_FASTINTV_MASK;
|
||||
else
|
||||
return bcm6328_delay;
|
||||
}
|
||||
|
||||
static int bcm6328_led_set_period(struct udevice *dev, int period_ms)
|
||||
{
|
||||
struct bcm6328_led_priv *priv = dev_get_priv(dev);
|
||||
|
||||
clrsetbits_be32(priv->regs + LED_INIT_REG, LED_INIT_FASTINTV_MASK,
|
||||
bcm6328_blink_delay(period_ms));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct led_ops bcm6328_led_ops = {
|
||||
.get_state = bcm6328_led_get_state,
|
||||
.set_state = bcm6328_led_set_state,
|
||||
#ifdef CONFIG_LED_BLINK
|
||||
.set_period = bcm6328_led_set_period,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int bcm6328_led_probe(struct udevice *dev)
|
||||
{
|
||||
struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
|
||||
/* Top-level LED node */
|
||||
if (!uc_plat->label) {
|
||||
void __iomem *regs;
|
||||
u32 set_bits = 0;
|
||||
|
||||
addr = dev_get_addr_size_index(dev, 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
regs = ioremap(addr, size);
|
||||
|
||||
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"brcm,serial-leds"))
|
||||
set_bits |= LED_INIT_SLEDEN_MASK;
|
||||
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"brcm,serial-mux"))
|
||||
set_bits |= LED_INIT_SLEDMUX_MASK;
|
||||
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"brcm,serial-clk-low"))
|
||||
set_bits |= LED_INIT_SLEDCLKNPOL_MASK;
|
||||
if (!fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"brcm,serial-dat-low"))
|
||||
set_bits |= LED_INIT_SLEDDATANPOL_MASK;
|
||||
if (!fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"brcm,serial-shift-inv"))
|
||||
set_bits |= LED_INIT_SLEDSHIFTDIR_MASK;
|
||||
|
||||
clrsetbits_be32(regs + LED_INIT_REG, ~0, set_bits);
|
||||
} else {
|
||||
struct bcm6328_led_priv *priv = dev_get_priv(dev);
|
||||
unsigned int pin;
|
||||
|
||||
addr = dev_get_addr_size_index(dev_get_parent(dev), 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
pin = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "reg",
|
||||
LEDS_MAX);
|
||||
if (pin >= LEDS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = ioremap(addr, size);
|
||||
if (pin < 8) {
|
||||
/* LEDs 0-7 (bits 47:32) */
|
||||
priv->mode = priv->regs + LED_MODE_REG_HI;
|
||||
priv->shift = (pin << 1);
|
||||
} else {
|
||||
/* LEDs 8-23 (bits 31:0) */
|
||||
priv->mode = priv->regs + LED_MODE_REG_LO;
|
||||
priv->shift = ((pin - 8) << 1);
|
||||
}
|
||||
|
||||
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"active-low"))
|
||||
priv->active_low = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6328_led_bind(struct udevice *parent)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node;
|
||||
|
||||
for (node = fdt_first_subnode(blob, dev_of_offset(parent));
|
||||
node > 0;
|
||||
node = fdt_next_subnode(blob, node)) {
|
||||
struct led_uc_plat *uc_plat;
|
||||
struct udevice *dev;
|
||||
const char *label;
|
||||
int ret;
|
||||
|
||||
label = fdt_getprop(blob, node, "label", NULL);
|
||||
if (!label) {
|
||||
debug("%s: node %s has no label\n", __func__,
|
||||
fdt_get_name(blob, node, NULL));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = device_bind_driver_to_node(parent, "bcm6328-led",
|
||||
fdt_get_name(blob, node, NULL),
|
||||
node, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uc_plat = dev_get_uclass_platdata(dev);
|
||||
uc_plat->label = label;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id bcm6328_led_ids[] = {
|
||||
{ .compatible = "brcm,bcm6328-leds" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bcm6328_led) = {
|
||||
.name = "bcm6328-led",
|
||||
.id = UCLASS_LED,
|
||||
.of_match = bcm6328_led_ids,
|
||||
.ops = &bcm6328_led_ops,
|
||||
.bind = bcm6328_led_bind,
|
||||
.probe = bcm6328_led_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct bcm6328_led_priv),
|
||||
};
|
||||
227
drivers/led/led_bcm6358.c
Normal file
227
drivers/led/led_bcm6358.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <led.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/lists.h>
|
||||
|
||||
#define LEDS_MAX 32
|
||||
#define LEDS_WAIT 100
|
||||
|
||||
/* LED Mode register */
|
||||
#define LED_MODE_REG 0x0
|
||||
#define LED_MODE_OFF 0
|
||||
#define LED_MODE_ON 1
|
||||
#define LED_MODE_MASK 1
|
||||
|
||||
/* LED Control register */
|
||||
#define LED_CTRL_REG 0x4
|
||||
#define LED_CTRL_CLK_MASK 0x3
|
||||
#define LED_CTRL_CLK_1 0
|
||||
#define LED_CTRL_CLK_2 1
|
||||
#define LED_CTRL_CLK_4 2
|
||||
#define LED_CTRL_CLK_8 3
|
||||
#define LED_CTRL_POL_SHIFT 2
|
||||
#define LED_CTRL_POL_MASK (1 << LED_CTRL_POL_SHIFT)
|
||||
#define LED_CTRL_BUSY_SHIFT 3
|
||||
#define LED_CTRL_BUSY_MASK (1 << LED_CTRL_BUSY_SHIFT)
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct bcm6358_led_priv {
|
||||
void __iomem *regs;
|
||||
uint8_t pin;
|
||||
bool active_low;
|
||||
};
|
||||
|
||||
static void bcm6358_led_busy(void __iomem *regs)
|
||||
{
|
||||
while (readl_be(regs + LED_CTRL_REG) & LED_CTRL_BUSY_MASK)
|
||||
udelay(LEDS_WAIT);
|
||||
}
|
||||
|
||||
static unsigned long bcm6358_led_get_mode(struct bcm6358_led_priv *priv)
|
||||
{
|
||||
bcm6358_led_busy(priv->regs);
|
||||
|
||||
return (readl_be(priv->regs + LED_MODE_REG) >> priv->pin) &
|
||||
LED_MODE_MASK;
|
||||
}
|
||||
|
||||
static int bcm6358_led_set_mode(struct bcm6358_led_priv *priv, uint8_t mode)
|
||||
{
|
||||
bcm6358_led_busy(priv->regs);
|
||||
|
||||
clrsetbits_be32(priv->regs + LED_MODE_REG,
|
||||
(LED_MODE_MASK << priv->pin),
|
||||
(mode << priv->pin));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum led_state_t bcm6358_led_get_state(struct udevice *dev)
|
||||
{
|
||||
struct bcm6358_led_priv *priv = dev_get_priv(dev);
|
||||
enum led_state_t state = LEDST_OFF;
|
||||
|
||||
switch (bcm6358_led_get_mode(priv)) {
|
||||
case LED_MODE_OFF:
|
||||
state = (priv->active_low ? LEDST_ON : LEDST_OFF);
|
||||
break;
|
||||
case LED_MODE_ON:
|
||||
state = (priv->active_low ? LEDST_OFF : LEDST_ON);
|
||||
break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static int bcm6358_led_set_state(struct udevice *dev, enum led_state_t state)
|
||||
{
|
||||
struct bcm6358_led_priv *priv = dev_get_priv(dev);
|
||||
unsigned long mode;
|
||||
|
||||
switch (state) {
|
||||
case LEDST_OFF:
|
||||
mode = (priv->active_low ? LED_MODE_ON : LED_MODE_OFF);
|
||||
break;
|
||||
case LEDST_ON:
|
||||
mode = (priv->active_low ? LED_MODE_OFF : LED_MODE_ON);
|
||||
break;
|
||||
case LEDST_TOGGLE:
|
||||
if (bcm6358_led_get_state(dev) == LEDST_OFF)
|
||||
return bcm6358_led_set_state(dev, LEDST_ON);
|
||||
else
|
||||
return bcm6358_led_set_state(dev, LEDST_OFF);
|
||||
break;
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return bcm6358_led_set_mode(priv, mode);
|
||||
}
|
||||
|
||||
static const struct led_ops bcm6358_led_ops = {
|
||||
.get_state = bcm6358_led_get_state,
|
||||
.set_state = bcm6358_led_set_state,
|
||||
};
|
||||
|
||||
static int bcm6358_led_probe(struct udevice *dev)
|
||||
{
|
||||
struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
|
||||
/* Top-level LED node */
|
||||
if (!uc_plat->label) {
|
||||
void __iomem *regs;
|
||||
unsigned int clk_div;
|
||||
u32 set_bits = 0;
|
||||
|
||||
addr = dev_get_addr_size_index(dev, 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
regs = ioremap(addr, size);
|
||||
|
||||
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"brcm,clk-dat-low"))
|
||||
set_bits |= LED_CTRL_POL_MASK;
|
||||
clk_div = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
|
||||
"brcm,clk-div", LED_CTRL_CLK_1);
|
||||
switch (clk_div) {
|
||||
case 8:
|
||||
set_bits |= LED_CTRL_CLK_8;
|
||||
break;
|
||||
case 4:
|
||||
set_bits |= LED_CTRL_CLK_4;
|
||||
break;
|
||||
case 2:
|
||||
set_bits |= LED_CTRL_CLK_2;
|
||||
break;
|
||||
default:
|
||||
set_bits |= LED_CTRL_CLK_1;
|
||||
break;
|
||||
}
|
||||
|
||||
bcm6358_led_busy(regs);
|
||||
clrsetbits_be32(regs + LED_CTRL_REG,
|
||||
LED_CTRL_POL_MASK | LED_CTRL_CLK_MASK,
|
||||
set_bits);
|
||||
} else {
|
||||
struct bcm6358_led_priv *priv = dev_get_priv(dev);
|
||||
unsigned int pin;
|
||||
|
||||
addr = dev_get_addr_size_index(dev_get_parent(dev), 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
pin = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "reg",
|
||||
LEDS_MAX);
|
||||
if (pin >= LEDS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = ioremap(addr, size);
|
||||
priv->pin = pin;
|
||||
|
||||
if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"active-low"))
|
||||
priv->active_low = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6358_led_bind(struct udevice *parent)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node;
|
||||
|
||||
for (node = fdt_first_subnode(blob, dev_of_offset(parent));
|
||||
node > 0;
|
||||
node = fdt_next_subnode(blob, node)) {
|
||||
struct led_uc_plat *uc_plat;
|
||||
struct udevice *dev;
|
||||
const char *label;
|
||||
int ret;
|
||||
|
||||
label = fdt_getprop(blob, node, "label", NULL);
|
||||
if (!label) {
|
||||
debug("%s: node %s has no label\n", __func__,
|
||||
fdt_get_name(blob, node, NULL));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = device_bind_driver_to_node(parent, "bcm6358-led",
|
||||
fdt_get_name(blob, node, NULL),
|
||||
node, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
uc_plat = dev_get_uclass_platdata(dev);
|
||||
uc_plat->label = label;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id bcm6358_led_ids[] = {
|
||||
{ .compatible = "brcm,bcm6358-leds" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bcm6358_led) = {
|
||||
.name = "bcm6358-led",
|
||||
.id = UCLASS_LED,
|
||||
.of_match = bcm6358_led_ids,
|
||||
.bind = bcm6358_led_bind,
|
||||
.probe = bcm6358_led_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct bcm6358_led_priv),
|
||||
.ops = &bcm6358_led_ops,
|
||||
};
|
||||
@@ -9,6 +9,13 @@ config POWER_DOMAIN
|
||||
domains). This may be used to save power. This API provides the
|
||||
means to control such power management hardware.
|
||||
|
||||
config BCM6328_POWER_DOMAIN
|
||||
bool "Enable the BCM6328 power domain driver"
|
||||
depends on POWER_DOMAIN && ARCH_BMIPS
|
||||
help
|
||||
Enable support for manipulating BCM6345 power domains via MMIO
|
||||
mapped registers.
|
||||
|
||||
config SANDBOX_POWER_DOMAIN
|
||||
bool "Enable the sandbox power domain test driver"
|
||||
depends on POWER_DOMAIN && SANDBOX
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_POWER_DOMAIN) += power-domain-uclass.o
|
||||
obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
|
||||
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
|
||||
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
|
||||
obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
|
||||
|
||||
83
drivers/power/domain/bcm6328-power-domain.c
Normal file
83
drivers/power/domain/bcm6328-power-domain.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <power-domain-uclass.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define MAX_DOMAINS 32
|
||||
|
||||
struct bcm6328_power_domain {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static int bcm6328_power_domain_request(struct power_domain *power_domain)
|
||||
{
|
||||
if (power_domain->id >= MAX_DOMAINS)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6328_power_domain_free(struct power_domain *power_domain)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6328_power_domain_on(struct power_domain *power_domain)
|
||||
{
|
||||
struct bcm6328_power_domain *priv = dev_get_priv(power_domain->dev);
|
||||
|
||||
clrbits_be32(priv->regs, BIT(power_domain->id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6328_power_domain_off(struct power_domain *power_domain)
|
||||
{
|
||||
struct bcm6328_power_domain *priv = dev_get_priv(power_domain->dev);
|
||||
|
||||
setbits_be32(priv->regs, BIT(power_domain->id));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6328_power_domain_probe(struct udevice *dev)
|
||||
{
|
||||
struct bcm6328_power_domain *priv = dev_get_priv(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
|
||||
addr = dev_get_addr_size_index(dev, 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = ioremap(addr, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id bcm6328_power_domain_ids[] = {
|
||||
{ .compatible = "brcm,bcm6328-power-domain" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
struct power_domain_ops bcm6328_power_domain_ops = {
|
||||
.free = bcm6328_power_domain_free,
|
||||
.off = bcm6328_power_domain_off,
|
||||
.on = bcm6328_power_domain_on,
|
||||
.request = bcm6328_power_domain_request,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bcm6328_power_domain) = {
|
||||
.name = "bcm6328_power_domain",
|
||||
.id = UCLASS_POWER_DOMAIN,
|
||||
.of_match = bcm6328_power_domain_ids,
|
||||
.ops = &bcm6328_power_domain_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct bcm6328_power_domain),
|
||||
.probe = bcm6328_power_domain_probe,
|
||||
};
|
||||
@@ -7,3 +7,4 @@
|
||||
obj-$(CONFIG_RAM) += ram-uclass.o
|
||||
obj-$(CONFIG_SANDBOX) += sandbox_ram.o
|
||||
obj-$(CONFIG_STM32_SDRAM) += stm32_sdram.o
|
||||
obj-$(CONFIG_ARCH_BMIPS) += bmips_ram.o
|
||||
|
||||
126
drivers/ram/bmips_ram.c
Normal file
126
drivers/ram/bmips_ram.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* Derived from linux/arch/mips/bcm63xx/cpu.c:
|
||||
* Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
|
||||
* Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <ram.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm/device.h>
|
||||
|
||||
#define MEMC_CFG_REG 0x4
|
||||
#define MEMC_CFG_32B_SHIFT 1
|
||||
#define MEMC_CFG_32B_MASK (1 << MEMC_CFG_32B_SHIFT)
|
||||
#define MEMC_CFG_COL_SHIFT 3
|
||||
#define MEMC_CFG_COL_MASK (0x3 << MEMC_CFG_COL_SHIFT)
|
||||
#define MEMC_CFG_ROW_SHIFT 6
|
||||
#define MEMC_CFG_ROW_MASK (0x3 << MEMC_CFG_ROW_SHIFT)
|
||||
|
||||
#define DDR_CSEND_REG 0x8
|
||||
|
||||
struct bmips_ram_priv;
|
||||
|
||||
struct bmips_ram_hw {
|
||||
ulong (*get_ram_size)(struct bmips_ram_priv *);
|
||||
};
|
||||
|
||||
struct bmips_ram_priv {
|
||||
void __iomem *regs;
|
||||
const struct bmips_ram_hw *hw;
|
||||
};
|
||||
|
||||
static ulong bcm6328_get_ram_size(struct bmips_ram_priv *priv)
|
||||
{
|
||||
return readl_be(priv->regs + DDR_CSEND_REG) << 24;
|
||||
}
|
||||
|
||||
static ulong bcm6358_get_ram_size(struct bmips_ram_priv *priv)
|
||||
{
|
||||
unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;
|
||||
u32 val;
|
||||
|
||||
val = readl_be(priv->regs + MEMC_CFG_REG);
|
||||
rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;
|
||||
cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT;
|
||||
is_32bits = (val & MEMC_CFG_32B_MASK) ? 0 : 1;
|
||||
banks = 2;
|
||||
|
||||
/* 0 => 11 address bits ... 2 => 13 address bits */
|
||||
rows += 11;
|
||||
|
||||
/* 0 => 8 address bits ... 2 => 10 address bits */
|
||||
cols += 8;
|
||||
|
||||
return 1 << (cols + rows + (is_32bits + 1) + banks);
|
||||
}
|
||||
|
||||
static int bmips_ram_get_info(struct udevice *dev, struct ram_info *info)
|
||||
{
|
||||
struct bmips_ram_priv *priv = dev_get_priv(dev);
|
||||
const struct bmips_ram_hw *hw = priv->hw;
|
||||
|
||||
info->base = 0x80000000;
|
||||
info->size = hw->get_ram_size(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ram_ops bmips_ram_ops = {
|
||||
.get_info = bmips_ram_get_info,
|
||||
};
|
||||
|
||||
static const struct bmips_ram_hw bmips_ram_bcm6328 = {
|
||||
.get_ram_size = bcm6328_get_ram_size,
|
||||
};
|
||||
|
||||
static const struct bmips_ram_hw bmips_ram_bcm6358 = {
|
||||
.get_ram_size = bcm6358_get_ram_size,
|
||||
};
|
||||
|
||||
static const struct udevice_id bmips_ram_ids[] = {
|
||||
{
|
||||
.compatible = "brcm,bcm6328-mc",
|
||||
.data = (ulong)&bmips_ram_bcm6328,
|
||||
}, {
|
||||
.compatible = "brcm,bcm6358-mc",
|
||||
.data = (ulong)&bmips_ram_bcm6358,
|
||||
}, {
|
||||
.compatible = "brcm,bcm63268-mc",
|
||||
.data = (ulong)&bmips_ram_bcm6328,
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int bmips_ram_probe(struct udevice *dev)
|
||||
{
|
||||
struct bmips_ram_priv *priv = dev_get_priv(dev);
|
||||
const struct bmips_ram_hw *hw =
|
||||
(const struct bmips_ram_hw *)dev_get_driver_data(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
|
||||
addr = dev_get_addr_size_index(dev, 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = ioremap(addr, size);
|
||||
priv->hw = hw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(bmips_ram) = {
|
||||
.name = "bmips-mc",
|
||||
.id = UCLASS_RAM,
|
||||
.of_match = bmips_ram_ids,
|
||||
.probe = bmips_ram_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct bmips_ram_priv),
|
||||
.ops = &bmips_ram_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -42,6 +42,12 @@ config TEGRA186_RESET
|
||||
Enable support for manipulating Tegra's on-SoC reset signals via IPC
|
||||
requests to the BPMP (Boot and Power Management Processor).
|
||||
|
||||
config RESET_BCM6345
|
||||
bool "Reset controller driver for BCM6345"
|
||||
depends on DM_RESET && ARCH_BMIPS
|
||||
help
|
||||
Support reset controller on BCM6345.
|
||||
|
||||
config RESET_UNIPHIER
|
||||
bool "Reset controller driver for UniPhier SoCs"
|
||||
depends on ARCH_UNIPHIER
|
||||
|
||||
@@ -8,5 +8,6 @@ obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o
|
||||
obj-$(CONFIG_STI_RESET) += sti-reset.o
|
||||
obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o
|
||||
obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o
|
||||
obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
|
||||
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
|
||||
obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o
|
||||
|
||||
89
drivers/reset/reset-bcm6345.c
Normal file
89
drivers/reset/reset-bcm6345.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* Derived from linux/arch/mips/bcm63xx/reset.c:
|
||||
* Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <reset-uclass.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define MAX_RESETS 32
|
||||
|
||||
struct bcm6345_reset_priv {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
static int bcm6345_reset_assert(struct reset_ctl *rst)
|
||||
{
|
||||
struct bcm6345_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
|
||||
clrbits_be32(priv->regs, BIT(rst->id));
|
||||
mdelay(20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_reset_deassert(struct reset_ctl *rst)
|
||||
{
|
||||
struct bcm6345_reset_priv *priv = dev_get_priv(rst->dev);
|
||||
|
||||
setbits_be32(priv->regs, BIT(rst->id));
|
||||
mdelay(20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_reset_free(struct reset_ctl *rst)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_reset_request(struct reset_ctl *rst)
|
||||
{
|
||||
if (rst->id >= MAX_RESETS)
|
||||
return -EINVAL;
|
||||
|
||||
return bcm6345_reset_assert(rst);
|
||||
}
|
||||
|
||||
struct reset_ops bcm6345_reset_reset_ops = {
|
||||
.free = bcm6345_reset_free,
|
||||
.request = bcm6345_reset_request,
|
||||
.rst_assert = bcm6345_reset_assert,
|
||||
.rst_deassert = bcm6345_reset_deassert,
|
||||
};
|
||||
|
||||
static const struct udevice_id bcm6345_reset_ids[] = {
|
||||
{ .compatible = "brcm,bcm6345-reset" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int bcm6345_reset_probe(struct udevice *dev)
|
||||
{
|
||||
struct bcm6345_reset_priv *priv = dev_get_priv(dev);
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
|
||||
addr = dev_get_addr_size_index(dev, 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = ioremap(addr, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(bcm6345_reset) = {
|
||||
.name = "bcm6345-reset",
|
||||
.id = UCLASS_RESET,
|
||||
.of_match = bcm6345_reset_ids,
|
||||
.ops = &bcm6345_reset_reset_ops,
|
||||
.probe = bcm6345_reset_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct bcm6345_reset_priv),
|
||||
};
|
||||
@@ -145,6 +145,14 @@ config DEBUG_UART_ATMEL
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_BCM6345
|
||||
bool "BCM6345 UART"
|
||||
depends on BCM6345_SERIAL
|
||||
help
|
||||
Select this to enable a debug UART on BCM6345 SoCs. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_UART_NS16550
|
||||
bool "ns16550"
|
||||
help
|
||||
@@ -350,6 +358,12 @@ config ATMEL_USART
|
||||
configured in the device tree, and input clock frequency can
|
||||
be got from the clk node.
|
||||
|
||||
config BCM6345_SERIAL
|
||||
bool "Support for BCM6345 UART"
|
||||
depends on DM_SERIAL && ARCH_BMIPS
|
||||
help
|
||||
Select this to enable UART on BCM6345 SoCs.
|
||||
|
||||
config FSL_LPUART
|
||||
bool "Freescale LPUART support"
|
||||
help
|
||||
|
||||
@@ -20,6 +20,7 @@ obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
|
||||
obj-$(CONFIG_AR933X_UART) += serial_ar933x.o
|
||||
obj-$(CONFIG_ARM_DCC) += arm_dcc.o
|
||||
obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
|
||||
obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o
|
||||
obj-$(CONFIG_EFI_APP) += serial_efi.o
|
||||
obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
|
||||
obj-$(CONFIG_MCFUART) += mcfuart.o
|
||||
|
||||
300
drivers/serial/serial_bcm6345.c
Normal file
300
drivers/serial/serial_bcm6345.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* Derived from linux/drivers/tty/serial/bcm63xx_uart.c:
|
||||
* Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <clk.h>
|
||||
#include <debug_uart.h>
|
||||
#include <errno.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/types.h>
|
||||
#include <dm/device.h>
|
||||
|
||||
/* UART Control register */
|
||||
#define UART_CTL_REG 0x0
|
||||
#define UART_CTL_RXTIMEOUT_MASK 0x1f
|
||||
#define UART_CTL_RXTIMEOUT_5 0x5
|
||||
#define UART_CTL_RSTRXFIFO_SHIFT 6
|
||||
#define UART_CTL_RSTRXFIFO_MASK (1 << UART_CTL_RSTRXFIFO_SHIFT)
|
||||
#define UART_CTL_RSTTXFIFO_SHIFT 7
|
||||
#define UART_CTL_RSTTXFIFO_MASK (1 << UART_CTL_RSTTXFIFO_SHIFT)
|
||||
#define UART_CTL_STOPBITS_SHIFT 8
|
||||
#define UART_CTL_STOPBITS_MASK (0xf << UART_CTL_STOPBITS_SHIFT)
|
||||
#define UART_CTL_STOPBITS_1 (0x7 << UART_CTL_STOPBITS_SHIFT)
|
||||
#define UART_CTL_BITSPERSYM_SHIFT 12
|
||||
#define UART_CTL_BITSPERSYM_MASK (0x3 << UART_CTL_BITSPERSYM_SHIFT)
|
||||
#define UART_CTL_BITSPERSYM_8 (0x3 << UART_CTL_BITSPERSYM_SHIFT)
|
||||
#define UART_CTL_XMITBRK_SHIFT 14
|
||||
#define UART_CTL_XMITBRK_MASK (1 << UART_CTL_XMITBRK_SHIFT)
|
||||
#define UART_CTL_RSVD_SHIFT 15
|
||||
#define UART_CTL_RSVD_MASK (1 << UART_CTL_RSVD_SHIFT)
|
||||
#define UART_CTL_RXPAREVEN_SHIFT 16
|
||||
#define UART_CTL_RXPAREVEN_MASK (1 << UART_CTL_RXPAREVEN_SHIFT)
|
||||
#define UART_CTL_RXPAREN_SHIFT 17
|
||||
#define UART_CTL_RXPAREN_MASK (1 << UART_CTL_RXPAREN_SHIFT)
|
||||
#define UART_CTL_TXPAREVEN_SHIFT 18
|
||||
#define UART_CTL_TXPAREVEN_MASK (1 << UART_CTL_TXPAREVEN_SHIFT)
|
||||
#define UART_CTL_TXPAREN_SHIFT 19
|
||||
#define UART_CTL_TXPAREN_MASK (1 << UART_CTL_TXPAREN_SHIFT)
|
||||
#define UART_CTL_LOOPBACK_SHIFT 20
|
||||
#define UART_CTL_LOOPBACK_MASK (1 << UART_CTL_LOOPBACK_SHIFT)
|
||||
#define UART_CTL_RXEN_SHIFT 21
|
||||
#define UART_CTL_RXEN_MASK (1 << UART_CTL_RXEN_SHIFT)
|
||||
#define UART_CTL_TXEN_SHIFT 22
|
||||
#define UART_CTL_TXEN_MASK (1 << UART_CTL_TXEN_SHIFT)
|
||||
#define UART_CTL_BRGEN_SHIFT 23
|
||||
#define UART_CTL_BRGEN_MASK (1 << UART_CTL_BRGEN_SHIFT)
|
||||
|
||||
/* UART Baudword register */
|
||||
#define UART_BAUD_REG 0x4
|
||||
|
||||
/* UART FIFO Config register */
|
||||
#define UART_FIFO_CFG_REG 0x8
|
||||
#define UART_FIFO_CFG_RX_SHIFT 8
|
||||
#define UART_FIFO_CFG_RX_MASK (0xf << UART_FIFO_CFG_RX_SHIFT)
|
||||
#define UART_FIFO_CFG_RX_4 (0x4 << UART_FIFO_CFG_RX_SHIFT)
|
||||
#define UART_FIFO_CFG_TX_SHIFT 12
|
||||
#define UART_FIFO_CFG_TX_MASK (0xf << UART_FIFO_CFG_TX_SHIFT)
|
||||
#define UART_FIFO_CFG_TX_4 (0x4 << UART_FIFO_CFG_TX_SHIFT)
|
||||
|
||||
/* UART Interrupt register */
|
||||
#define UART_IR_REG 0x10
|
||||
#define UART_IR_STAT(x) (1 << (x))
|
||||
#define UART_IR_TXEMPTY 5
|
||||
#define UART_IR_RXOVER 7
|
||||
#define UART_IR_RXNOTEMPTY 11
|
||||
|
||||
/* UART FIFO register */
|
||||
#define UART_FIFO_REG 0x14
|
||||
#define UART_FIFO_VALID_MASK 0xff
|
||||
#define UART_FIFO_FRAMEERR_SHIFT 8
|
||||
#define UART_FIFO_FRAMEERR_MASK (1 << UART_FIFO_FRAMEERR_SHIFT)
|
||||
#define UART_FIFO_PARERR_SHIFT 9
|
||||
#define UART_FIFO_PARERR_MASK (1 << UART_FIFO_PARERR_SHIFT)
|
||||
#define UART_FIFO_BRKDET_SHIFT 10
|
||||
#define UART_FIFO_BRKDET_MASK (1 << UART_FIFO_BRKDET_SHIFT)
|
||||
#define UART_FIFO_ANYERR_MASK (UART_FIFO_FRAMEERR_MASK | \
|
||||
UART_FIFO_PARERR_MASK | \
|
||||
UART_FIFO_BRKDET_MASK)
|
||||
|
||||
struct bcm6345_serial_priv {
|
||||
void __iomem *base;
|
||||
ulong uartclk;
|
||||
};
|
||||
|
||||
/* enable rx & tx operation on uart */
|
||||
static void bcm6345_serial_enable(void __iomem *base)
|
||||
{
|
||||
setbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK |
|
||||
UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
|
||||
}
|
||||
|
||||
/* disable rx & tx operation on uart */
|
||||
static void bcm6345_serial_disable(void __iomem *base)
|
||||
{
|
||||
clrbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK |
|
||||
UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
|
||||
}
|
||||
|
||||
/* clear all unread data in rx fifo and unsent data in tx fifo */
|
||||
static void bcm6345_serial_flush(void __iomem *base)
|
||||
{
|
||||
/* empty rx and tx fifo */
|
||||
setbits_be32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK |
|
||||
UART_CTL_RSTTXFIFO_MASK);
|
||||
|
||||
/* read any pending char to make sure all irq status are cleared */
|
||||
readl_be(base + UART_FIFO_REG);
|
||||
}
|
||||
|
||||
static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* mask all irq and flush port */
|
||||
bcm6345_serial_disable(base);
|
||||
bcm6345_serial_flush(base);
|
||||
|
||||
/* set uart control config */
|
||||
clrsetbits_be32(base + UART_CTL_REG,
|
||||
/* clear rx timeout */
|
||||
UART_CTL_RXTIMEOUT_MASK |
|
||||
/* clear stop bits */
|
||||
UART_CTL_STOPBITS_MASK |
|
||||
/* clear bits per symbol */
|
||||
UART_CTL_BITSPERSYM_MASK |
|
||||
/* clear xmit break */
|
||||
UART_CTL_XMITBRK_MASK |
|
||||
/* clear reserved bit */
|
||||
UART_CTL_RSVD_MASK |
|
||||
/* disable parity */
|
||||
UART_CTL_RXPAREN_MASK |
|
||||
UART_CTL_TXPAREN_MASK |
|
||||
/* disable loopback */
|
||||
UART_CTL_LOOPBACK_MASK,
|
||||
/* set timeout to 5 */
|
||||
UART_CTL_RXTIMEOUT_5 |
|
||||
/* set 8 bits/symbol */
|
||||
UART_CTL_BITSPERSYM_8 |
|
||||
/* set parity to even */
|
||||
UART_CTL_RXPAREVEN_MASK |
|
||||
UART_CTL_TXPAREVEN_MASK);
|
||||
|
||||
/* set uart fifo config */
|
||||
clrsetbits_be32(base + UART_FIFO_CFG_REG,
|
||||
/* clear fifo config */
|
||||
UART_FIFO_CFG_RX_MASK |
|
||||
UART_FIFO_CFG_TX_MASK,
|
||||
/* set fifo config to 4 */
|
||||
UART_FIFO_CFG_RX_4 |
|
||||
UART_FIFO_CFG_TX_4);
|
||||
|
||||
/* set baud rate */
|
||||
val = (clk / baudrate) / 16;
|
||||
if (val & 0x1)
|
||||
val = val;
|
||||
else
|
||||
val = val / 2 - 1;
|
||||
writel_be(val, base + UART_BAUD_REG);
|
||||
|
||||
/* clear interrupts */
|
||||
writel_be(0, base + UART_IR_REG);
|
||||
|
||||
/* enable uart */
|
||||
bcm6345_serial_enable(base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 val = readl_be(priv->base + UART_IR_REG);
|
||||
|
||||
if (input)
|
||||
return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY));
|
||||
else
|
||||
return !(val & UART_IR_STAT(UART_IR_TXEMPTY));
|
||||
}
|
||||
|
||||
static int bcm6345_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return bcm6345_serial_init(priv->base, priv->uartclk, baudrate);
|
||||
}
|
||||
|
||||
static int bcm6345_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 val;
|
||||
|
||||
val = readl_be(priv->base + UART_IR_REG);
|
||||
if (!(val & UART_IR_STAT(UART_IR_TXEMPTY)))
|
||||
return -EAGAIN;
|
||||
|
||||
writel_be(ch, priv->base + UART_FIFO_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 val;
|
||||
|
||||
val = readl_be(priv->base + UART_IR_REG);
|
||||
if (val & UART_IR_STAT(UART_IR_RXOVER))
|
||||
setbits_be32(priv->base + UART_CTL_REG,
|
||||
UART_CTL_RSTRXFIFO_MASK);
|
||||
if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
|
||||
return -EAGAIN;
|
||||
|
||||
val = readl_be(priv->base + UART_FIFO_REG);
|
||||
if (val & UART_FIFO_ANYERR_MASK)
|
||||
return -EAGAIN;
|
||||
|
||||
return val & UART_FIFO_VALID_MASK;
|
||||
}
|
||||
|
||||
static int bcm6345_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
struct clk clk;
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
int ret;
|
||||
|
||||
/* get address */
|
||||
addr = dev_get_addr_size_index(dev, 0, &size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->base = ioremap(addr, size);
|
||||
|
||||
/* get clock rate */
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
priv->uartclk = clk_get_rate(&clk) / 2;
|
||||
clk_free(&clk);
|
||||
|
||||
/* initialize serial */
|
||||
return bcm6345_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops bcm6345_serial_ops = {
|
||||
.putc = bcm6345_serial_putc,
|
||||
.pending = bcm6345_serial_pending,
|
||||
.getc = bcm6345_serial_getc,
|
||||
.setbrg = bcm6345_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id bcm6345_serial_ids[] = {
|
||||
{ .compatible = "brcm,bcm6345-uart" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bcm6345_serial) = {
|
||||
.name = "bcm6345-uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = bcm6345_serial_ids,
|
||||
.probe = bcm6345_serial_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct bcm6345_serial_priv),
|
||||
.ops = &bcm6345_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_BCM6345
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
bcm6345_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void wait_xfered(void __iomem *base)
|
||||
{
|
||||
do {
|
||||
u32 val = readl_be(base + UART_IR_REG);
|
||||
if (val & UART_IR_STAT(UART_IR_TXEMPTY))
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
wait_xfered(base);
|
||||
writel_be(ch, base + UART_FIFO_REG);
|
||||
wait_xfered(base);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
@@ -23,4 +23,12 @@ config SYSRESET_PSCI
|
||||
must be running on your system.
|
||||
|
||||
endif
|
||||
|
||||
config SYSRESET_SYSCON
|
||||
bool "Enable support for mfd syscon reboot driver"
|
||||
select REGMAP
|
||||
select SYSCON
|
||||
help
|
||||
Reboot support for generic SYSCON mapped register reset.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
obj-$(CONFIG_SYSRESET) += sysreset-uclass.o
|
||||
obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
|
||||
obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_ROCKCHIP_RK3036) += sysreset_rk3036.o
|
||||
|
||||
78
drivers/sysreset/sysreset_syscon.c
Normal file
78
drivers/sysreset/sysreset_syscon.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* Derived from linux/drivers/power/reset/syscon-reboot.c:
|
||||
* Copyright (C) 2013, Applied Micro Circuits Corporation
|
||||
* Author: Feng Kan <fkan@apm.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <regmap.h>
|
||||
#include <sysreset.h>
|
||||
#include <syscon.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct syscon_reboot_priv {
|
||||
struct regmap *regmap;
|
||||
unsigned int offset;
|
||||
unsigned int mask;
|
||||
};
|
||||
|
||||
static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type)
|
||||
{
|
||||
struct syscon_reboot_priv *priv = dev_get_priv(dev);
|
||||
|
||||
regmap_write(priv->regmap, priv->offset, priv->mask);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static struct sysreset_ops syscon_reboot_ops = {
|
||||
.request = syscon_reboot_request,
|
||||
};
|
||||
|
||||
int syscon_reboot_probe(struct udevice *dev)
|
||||
{
|
||||
struct udevice *syscon;
|
||||
struct syscon_reboot_priv *priv = dev_get_priv(dev);
|
||||
int err;
|
||||
|
||||
err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
|
||||
"regmap", &syscon);
|
||||
if (err) {
|
||||
error("unable to find syscon device\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->regmap = syscon_get_regmap(syscon);
|
||||
if (!priv->regmap) {
|
||||
error("unable to find regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->offset = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
|
||||
"offset", 0);
|
||||
priv->mask = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
|
||||
"mask", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id syscon_reboot_ids[] = {
|
||||
{ .compatible = "syscon-reboot" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(syscon_reboot) = {
|
||||
.name = "syscon_reboot",
|
||||
.id = UCLASS_SYSRESET,
|
||||
.of_match = syscon_reboot_ids,
|
||||
.probe = syscon_reboot_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct syscon_reboot_priv),
|
||||
.ops = &syscon_reboot_ops,
|
||||
};
|
||||
Reference in New Issue
Block a user