Merge branch 'master' of git://git.denx.de/u-boot-mips

This commit is contained in:
Tom Rini
2017-05-10 15:50:21 -04:00
87 changed files with 3737 additions and 37 deletions

View File

@@ -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

View File

@@ -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
View 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),
};

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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
View 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,
};

View File

@@ -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

View File

@@ -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
View 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
View 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,
};

View File

@@ -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

View File

@@ -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

View 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,
};

View File

@@ -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
View 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,
};

View File

@@ -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

View File

@@ -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

View 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),
};

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View 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,
};