Merge tag 'u-boot-imx-20201105' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
u-boot-imx for 2021.1 --------------------- - new boards : GE (new B1x5v2), phytec phyCORE-i.MX8MM - converted doc to reST - fixes for verdin-imx8mm (Toradex) - fixes for i.MX thermal driver - mx7ulp: Align the PLL_USB frequency - mx53: primary/secondary bmode Travis: https://travis-ci.org/github/sbabic/u-boot-imx/builds/741465284
This commit is contained in:
@@ -108,6 +108,16 @@ config DM_BOOTCOUNT_I2C_EEPROM
|
||||
pointing to the underlying i2c eeprom device) and an optional 'offset'
|
||||
property are supported.
|
||||
|
||||
config DM_BOOTCOUNT_SPI_FLASH
|
||||
bool "Support SPI flash devices as a backing store for bootcount"
|
||||
depends on DM_SPI_FLASH
|
||||
help
|
||||
Enabled reading/writing the bootcount in a DM SPI flash device.
|
||||
The wrapper device is to be specified with the compatible string
|
||||
'u-boot,bootcount-spi-flash' and the 'spi-flash'-property (a phandle
|
||||
pointing to the underlying SPI flash device) and an optional 'offset'
|
||||
property are supported.
|
||||
|
||||
config BOOTCOUNT_MEM
|
||||
bool "Support memory based bootcounter"
|
||||
help
|
||||
|
||||
@@ -12,3 +12,4 @@ obj-$(CONFIG_BOOTCOUNT_EXT) += bootcount_ext.o
|
||||
obj-$(CONFIG_DM_BOOTCOUNT) += bootcount-uclass.o
|
||||
obj-$(CONFIG_DM_BOOTCOUNT_RTC) += rtc.o
|
||||
obj-$(CONFIG_DM_BOOTCOUNT_I2C_EEPROM) += i2c-eeprom.o
|
||||
obj-$(CONFIG_DM_BOOTCOUNT_SPI_FLASH) += spi-flash.o
|
||||
|
||||
125
drivers/bootcount/spi-flash.c
Normal file
125
drivers/bootcount/spi-flash.c
Normal file
@@ -0,0 +1,125 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2019 Collabora
|
||||
* (C) Copyright 2019 GE
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <bootcount.h>
|
||||
#include <dm.h>
|
||||
#include <spi_flash.h>
|
||||
|
||||
static const u8 bootcount_magic = 0xbc;
|
||||
|
||||
struct bootcount_spi_flash_priv {
|
||||
struct udevice *spi_flash;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
static int bootcount_spi_flash_update(struct udevice *dev, u32 offset, u32 len, const void *buf)
|
||||
{
|
||||
struct spi_flash *flash = dev_get_uclass_priv(dev);
|
||||
u32 sector_size = flash->sector_size;
|
||||
u32 sector_offset = offset % sector_size;
|
||||
u32 sector = offset - sector_offset;
|
||||
int err = 0;
|
||||
|
||||
/* code only supports updating a single sector */
|
||||
if (sector_offset + len > sector_size)
|
||||
return -ENOSYS;
|
||||
|
||||
u8 *buffer = malloc(sector_size);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
err = spi_flash_read_dm(dev, sector, sector_size, buffer);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
memcpy(buffer + sector_offset, buf, len);
|
||||
|
||||
err = spi_flash_erase_dm(dev, sector, sector_size);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = spi_flash_write_dm(dev, sector, sector_size, buffer);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
free(buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bootcount_spi_flash_set(struct udevice *dev, const u32 a)
|
||||
{
|
||||
struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
|
||||
const u16 val = bootcount_magic << 8 | (a & 0xff);
|
||||
|
||||
if (bootcount_spi_flash_update(priv->spi_flash, priv->offset, 2, &val) < 0) {
|
||||
debug("%s: write failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bootcount_spi_flash_get(struct udevice *dev, u32 *a)
|
||||
{
|
||||
struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
|
||||
u16 val;
|
||||
|
||||
if (spi_flash_read_dm(priv->spi_flash, priv->offset, 2, &val) < 0) {
|
||||
debug("%s: read failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (val >> 8 == bootcount_magic) {
|
||||
*a = val & 0xff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
debug("%s: bootcount magic does not match on %04x\n", __func__, val);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int bootcount_spi_flash_probe(struct udevice *dev)
|
||||
{
|
||||
struct ofnode_phandle_args phandle_args;
|
||||
struct bootcount_spi_flash_priv *priv = dev_get_priv(dev);
|
||||
struct udevice *spi_flash;
|
||||
|
||||
if (dev_read_phandle_with_args(dev, "spi-flash", NULL, 0, 0, &phandle_args)) {
|
||||
debug("%s: spi-flash backing device not specified\n", dev->name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (uclass_get_device_by_ofnode(UCLASS_SPI_FLASH, phandle_args.node, &spi_flash)) {
|
||||
debug("%s: could not get backing device\n", dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->spi_flash = spi_flash;
|
||||
priv->offset = dev_read_u32_default(dev, "offset", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bootcount_ops bootcount_spi_flash_ops = {
|
||||
.get = bootcount_spi_flash_get,
|
||||
.set = bootcount_spi_flash_set,
|
||||
};
|
||||
|
||||
static const struct udevice_id bootcount_spi_flash_ids[] = {
|
||||
{ .compatible = "u-boot,bootcount-spi-flash" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bootcount_spi_flash) = {
|
||||
.name = "bootcount-spi-flash",
|
||||
.id = UCLASS_BOOTCOUNT,
|
||||
.priv_auto_alloc_size = sizeof(struct bootcount_spi_flash_priv),
|
||||
.probe = bootcount_spi_flash_probe,
|
||||
.of_match = bootcount_spi_flash_ids,
|
||||
.ops = &bootcount_spi_flash_ops,
|
||||
};
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <log.h>
|
||||
#include <rtc.h>
|
||||
#include <i2c.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define M41T62_REG_SSEC 0
|
||||
#define M41T62_REG_SEC 1
|
||||
@@ -47,8 +49,14 @@
|
||||
#define M41T62_ALMON_SQWE (1 << 6) /* SQWE: SQW Enable Bit */
|
||||
#define M41T62_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */
|
||||
#define M41T62_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */
|
||||
#define M41T62_FLAGS_OF (1 << 2) /* OF: Oscillator Flag Bit */
|
||||
#define M41T62_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */
|
||||
|
||||
#define M41T62_WDAY_SQW_FREQ_MASK 0xf0
|
||||
#define M41T62_WDAY_SQW_FREQ_SHIFT 4
|
||||
|
||||
#define M41T62_SQW_MAX_FREQ 32768
|
||||
|
||||
#define M41T62_FEATURE_HT (1 << 0)
|
||||
#define M41T62_FEATURE_BL (1 << 1)
|
||||
|
||||
@@ -139,21 +147,140 @@ static int m41t62_rtc_set(struct udevice *dev, const struct rtc_time *tm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m41t62_rtc_reset(struct udevice *dev)
|
||||
static int m41t62_sqw_enable(struct udevice *dev, bool enable)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
ret = dm_i2c_read(dev, M41T62_REG_ALARM_MON, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (enable)
|
||||
val |= M41T62_ALMON_SQWE;
|
||||
else
|
||||
val &= ~M41T62_ALMON_SQWE;
|
||||
|
||||
return dm_i2c_write(dev, M41T62_REG_ALARM_MON, &val, sizeof(val));
|
||||
}
|
||||
|
||||
static int m41t62_sqw_set_rate(struct udevice *dev, unsigned int rate)
|
||||
{
|
||||
u8 val, newval, sqwrateval;
|
||||
int ret;
|
||||
|
||||
if (rate >= M41T62_SQW_MAX_FREQ)
|
||||
sqwrateval = 1;
|
||||
else if (rate >= M41T62_SQW_MAX_FREQ / 4)
|
||||
sqwrateval = 2;
|
||||
else if (rate)
|
||||
sqwrateval = 15 - ilog2(rate);
|
||||
|
||||
ret = dm_i2c_read(dev, M41T62_REG_WDAY, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
newval = val;
|
||||
newval &= ~M41T62_WDAY_SQW_FREQ_MASK;
|
||||
newval |= (sqwrateval << M41T62_WDAY_SQW_FREQ_SHIFT);
|
||||
|
||||
/*
|
||||
* Try to avoid writing unchanged values. Writing to this register
|
||||
* will reset the internal counter pipeline and thus affect system
|
||||
* time.
|
||||
*/
|
||||
if (newval == val)
|
||||
return 0;
|
||||
|
||||
return dm_i2c_write(dev, M41T62_REG_WDAY, &newval, sizeof(newval));
|
||||
}
|
||||
|
||||
static int m41t62_rtc_restart_osc(struct udevice *dev)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
/* 0. check if oscillator failure happened */
|
||||
ret = dm_i2c_read(dev, M41T62_REG_FLAGS, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(val & M41T62_FLAGS_OF))
|
||||
return 0;
|
||||
|
||||
ret = dm_i2c_read(dev, M41T62_REG_SEC, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 1. Set stop bit */
|
||||
val |= M41T62_SEC_ST;
|
||||
ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 2. Clear stop bit */
|
||||
val &= ~M41T62_SEC_ST;
|
||||
ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 3. wait 4 seconds */
|
||||
mdelay(4000);
|
||||
|
||||
ret = dm_i2c_read(dev, M41T62_REG_FLAGS, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 4. clear M41T62_FLAGS_OF bit */
|
||||
val &= ~M41T62_FLAGS_OF;
|
||||
ret = dm_i2c_write(dev, M41T62_REG_FLAGS, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m41t62_rtc_clear_ht(struct udevice *dev)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* M41T82: Make sure HT (Halt Update) bit is cleared.
|
||||
* This bit is 0 in M41T62 so its save to clear it always.
|
||||
*/
|
||||
|
||||
int ret = dm_i2c_read(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
|
||||
|
||||
ret = dm_i2c_read(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
val &= ~M41T80_ALHOUR_HT;
|
||||
ret |= dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
|
||||
ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m41t62_rtc_reset(struct udevice *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = m41t62_rtc_restart_osc(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = m41t62_rtc_clear_ht(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Some boards feed the square wave as clock input into
|
||||
* the SoC. This enables a 32.768kHz square wave, which is
|
||||
* also the hardware default after power-loss.
|
||||
*/
|
||||
ret = m41t62_sqw_set_rate(dev, 32768);
|
||||
if (ret)
|
||||
return ret;
|
||||
return m41t62_sqw_enable(dev, true);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -162,7 +289,7 @@ static int m41t62_rtc_reset(struct udevice *dev)
|
||||
*/
|
||||
static int m41t62_rtc_probe(struct udevice *dev)
|
||||
{
|
||||
return m41t62_rtc_reset(dev);
|
||||
return m41t62_rtc_clear_ht(dev);
|
||||
}
|
||||
|
||||
static const struct rtc_ops m41t62_rtc_ops = {
|
||||
|
||||
@@ -43,6 +43,13 @@ config SYSRESET_CMD_POWEROFF
|
||||
|
||||
endif
|
||||
|
||||
config POWEROFF_GPIO
|
||||
bool "Enable support for GPIO poweroff driver"
|
||||
select DM_GPIO
|
||||
help
|
||||
Support for system poweroff using a GPIO pin. This can be used
|
||||
for systems having a single GPIO to trigger a system poweroff.
|
||||
|
||||
config SYSRESET_GPIO
|
||||
bool "Enable support for GPIO reset driver"
|
||||
select DM_GPIO
|
||||
|
||||
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_ASPEED) += sysreset_ast.o
|
||||
obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
|
||||
obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
|
||||
obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
|
||||
obj-$(CONFIG_POWEROFF_GPIO) += poweroff_gpio.o
|
||||
obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
|
||||
obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o
|
||||
obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
|
||||
|
||||
92
drivers/sysreset/poweroff_gpio.c
Normal file
92
drivers/sysreset/poweroff_gpio.c
Normal file
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Toggles a GPIO pin to power down a device
|
||||
*
|
||||
* Created using the Linux driver as reference, which
|
||||
* has been written by:
|
||||
*
|
||||
* Jamie Lentin <jm@lentin.co.uk>
|
||||
* Andrew Lunn <andrew@lunn.ch>
|
||||
*
|
||||
* Copyright (C) 2012 Jamie Lentin
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <log.h>
|
||||
#include <sysreset.h>
|
||||
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
struct poweroff_gpio_info {
|
||||
struct gpio_desc gpio;
|
||||
u32 active_delay_ms;
|
||||
u32 inactive_delay_ms;
|
||||
u32 timeout_ms;
|
||||
};
|
||||
|
||||
static int poweroff_gpio_request(struct udevice *dev, enum sysreset_t type)
|
||||
{
|
||||
struct poweroff_gpio_info *priv = dev_get_priv(dev);
|
||||
int r;
|
||||
|
||||
if (type != SYSRESET_POWER_OFF)
|
||||
return -ENOSYS;
|
||||
|
||||
debug("GPIO poweroff\n");
|
||||
|
||||
/* drive it active, also inactive->active edge */
|
||||
r = dm_gpio_set_value(&priv->gpio, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
mdelay(priv->active_delay_ms);
|
||||
|
||||
/* drive inactive, also active->inactive edge */
|
||||
r = dm_gpio_set_value(&priv->gpio, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
mdelay(priv->inactive_delay_ms);
|
||||
|
||||
/* drive it active, also inactive->active edge */
|
||||
r = dm_gpio_set_value(&priv->gpio, 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* give it some time */
|
||||
mdelay(priv->timeout_ms);
|
||||
|
||||
return -EINPROGRESS;
|
||||
}
|
||||
|
||||
static int poweroff_gpio_probe(struct udevice *dev)
|
||||
{
|
||||
struct poweroff_gpio_info *priv = dev_get_priv(dev);
|
||||
int flags;
|
||||
|
||||
flags = dev_read_bool(dev, "input") ? GPIOD_IS_IN : GPIOD_IS_OUT;
|
||||
priv->active_delay_ms = dev_read_u32_default(dev, "active-delay-ms", 100);
|
||||
priv->inactive_delay_ms = dev_read_u32_default(dev, "inactive-delay-ms", 100);
|
||||
priv->timeout_ms = dev_read_u32_default(dev, "timeout-ms", 3000);
|
||||
|
||||
return gpio_request_by_name(dev, "gpios", 0, &priv->gpio, flags);
|
||||
}
|
||||
|
||||
static struct sysreset_ops poweroff_gpio_ops = {
|
||||
.request = poweroff_gpio_request,
|
||||
};
|
||||
|
||||
static const struct udevice_id poweroff_gpio_ids[] = {
|
||||
{ .compatible = "gpio-poweroff", },
|
||||
{},
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(poweroff_gpio) = {
|
||||
.name = "poweroff-gpio",
|
||||
.id = UCLASS_SYSRESET,
|
||||
.ops = &poweroff_gpio_ops,
|
||||
.probe = poweroff_gpio_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct poweroff_gpio_info),
|
||||
.of_match = poweroff_gpio_ids,
|
||||
};
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <dm/device.h>
|
||||
#include <errno.h>
|
||||
#include <fuse.h>
|
||||
#include <linux/delay.h>
|
||||
#include <malloc.h>
|
||||
#include <thermal.h>
|
||||
|
||||
|
||||
@@ -21,12 +21,6 @@ config WATCHDOG_TIMEOUT_MSECS
|
||||
config HW_WATCHDOG
|
||||
bool
|
||||
|
||||
config WATCHDOG_RESET_DISABLE
|
||||
bool "Disable reset watchdog"
|
||||
help
|
||||
Disable reset watchdog, which can let WATCHDOG_RESET invalid, so
|
||||
that the watchdog will not be fed in u-boot.
|
||||
|
||||
config IMX_WATCHDOG
|
||||
bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
|
||||
select HW_WATCHDOG if !WDT
|
||||
@@ -34,6 +28,13 @@ config IMX_WATCHDOG
|
||||
Select this to enable the IMX and LSCH2 of Layerscape watchdog
|
||||
driver.
|
||||
|
||||
config WATCHDOG_RESET_DISABLE
|
||||
bool "Disable reset watchdog"
|
||||
depends on IMX_WATCHDOG
|
||||
help
|
||||
Disable reset watchdog, which can let WATCHDOG_RESET invalid, so
|
||||
that the watchdog will not be fed in u-boot.
|
||||
|
||||
config OMAP_WATCHDOG
|
||||
bool "TI OMAP watchdog driver"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
|
||||
Reference in New Issue
Block a user