diff options
| author | Tom Rini <[email protected]> | 2025-11-04 07:50:35 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-11-04 07:50:35 -0600 |
| commit | b4c3869292ea88a9753c65691e02a21e2264b181 (patch) | |
| tree | 055f05dba5a479080dd7154a53bcdfc8f75cfc9d /drivers | |
| parent | c9fdb9ac4d5234953ffaaef0cfc9d4ccb03f0ce5 (diff) | |
| parent | 200549b09614e3cb17214e652aeb191902b8b303 (diff) | |
Merge branch 'staging' of https://source.denx.de/u-boot/custodians/u-boot-tegra
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/crypto/tegra/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/gpio/tegra_gpio.c | 40 | ||||
| -rw-r--r-- | drivers/timer/tegra-timer.c | 10 | ||||
| -rw-r--r-- | drivers/video/tegra/tegra124/dp.c | 2 | ||||
| -rw-r--r-- | drivers/video/tegra/tegra124/sor.c | 2 | ||||
| -rw-r--r-- | drivers/watchdog/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
| -rw-r--r-- | drivers/watchdog/tegra_wdt.c | 118 |
8 files changed, 159 insertions, 22 deletions
diff --git a/drivers/crypto/tegra/Kconfig b/drivers/crypto/tegra/Kconfig index b027609307b..0f2acaaade1 100644 --- a/drivers/crypto/tegra/Kconfig +++ b/drivers/crypto/tegra/Kconfig @@ -1,6 +1,6 @@ config TEGRA_AES bool "Support the Tegra AES" - depends on DM_AES + depends on ARCH_TEGRA && DM_AES help This provides a means to encrypt and decrypt data using the Tegra Bit Stream Engine for Video/Audio. Also may provide a mean to diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 3d1e18854f2..c61419ef980 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -182,21 +182,6 @@ static int tegra_gpio_get_value(struct udevice *dev, unsigned offset) return (val >> GPIO_BIT(gpio)) & 1; } -/* write GPIO OUT value to pin 'gpio' */ -static int tegra_gpio_set_value(struct udevice *dev, unsigned offset, int value) -{ - struct tegra_port_info *state = dev_get_priv(dev); - int gpio = state->base_gpio + offset; - - debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n", - gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value); - - /* Configure GPIO output value. */ - set_level(gpio, value); - - return 0; -} - void gpio_config_table(const struct tegra_gpio_config *config, int len) { int i; @@ -258,11 +243,30 @@ static int tegra_gpio_rfree(struct udevice *dev, unsigned int offset) return 0; } +static int tegra_gpio_set_flags(struct udevice *dev, unsigned int offset, ulong flags) +{ + struct tegra_port_info *state = dev_get_priv(dev); + int gpio = state->base_gpio + offset; + + debug("gpio_set_flags: pin = %d (port %d:bit %d), flag = %lx\n", + gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), flags); + + if (flags & GPIOD_IS_AF) { + return tegra_gpio_rfree(dev, offset); + } else if (flags & GPIOD_IS_IN) { + return tegra_gpio_direction_input(dev, offset); + } else if (flags & GPIOD_IS_OUT) { + bool value = flags & GPIOD_IS_OUT_ACTIVE; + + return tegra_gpio_direction_output(dev, offset, value); + } + + return 0; +} + static const struct dm_gpio_ops gpio_tegra_ops = { - .direction_input = tegra_gpio_direction_input, - .direction_output = tegra_gpio_direction_output, + .set_flags = tegra_gpio_set_flags, .get_value = tegra_gpio_get_value, - .set_value = tegra_gpio_set_value, .get_function = tegra_gpio_get_function, .xlate = tegra_gpio_xlate, .rfree = tegra_gpio_rfree, diff --git a/drivers/timer/tegra-timer.c b/drivers/timer/tegra-timer.c index 3545424889d..778b65b6062 100644 --- a/drivers/timer/tegra-timer.c +++ b/drivers/timer/tegra-timer.c @@ -4,6 +4,7 @@ */ #include <dm.h> +#include <dm/lists.h> #include <errno.h> #include <timer.h> @@ -106,6 +107,14 @@ static int tegra_timer_probe(struct udevice *dev) return 0; } +static int tegra_timer_bind(struct udevice *dev) +{ + if (CONFIG_IS_ENABLED(WDT_TEGRA)) + return device_bind_driver_to_node(dev, "tegra_wdt", "tegra-wdt", + dev_ofnode(dev), NULL); + return 0; +} + static const struct timer_ops tegra_timer_ops = { .get_count = tegra_timer_get_count, }; @@ -123,6 +132,7 @@ U_BOOT_DRIVER(tegra_timer) = { .name = "tegra_timer", .id = UCLASS_TIMER, .of_match = tegra_timer_ids, + .bind = tegra_timer_bind, .probe = tegra_timer_probe, .ops = &tegra_timer_ops, .flags = DM_FLAG_PRE_RELOC, diff --git a/drivers/video/tegra/tegra124/dp.c b/drivers/video/tegra/tegra124/dp.c index b95b14da77d..611bf2f81a6 100644 --- a/drivers/video/tegra/tegra124/dp.c +++ b/drivers/video/tegra/tegra124/dp.c @@ -1515,7 +1515,6 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, if (ret || retry >= DP_POWER_ON_MAX_TRIES) { debug("dp: failed to power on panel (0x%x)\n", ret); return -ENETUNREACH; - goto error_enable; } /* Confirm DP plugging status */ @@ -1561,7 +1560,6 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, } priv->enabled = true; -error_enable: return 0; } diff --git a/drivers/video/tegra/tegra124/sor.c b/drivers/video/tegra/tegra124/sor.c index 1ce5330c6bc..ccdeefbcbb1 100644 --- a/drivers/video/tegra/tegra124/sor.c +++ b/drivers/video/tegra/tegra124/sor.c @@ -336,7 +336,7 @@ static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up) } reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_REQ); - reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON || + reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON | APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK); reg_val = up ? APBDEV_PMC_IO_DPD2_REQ_LVDS_ON | diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 309f9cd4829..35ae7d106b1 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -456,6 +456,12 @@ config WDT_TANGIER Intel Tangier SoC. If you're using a board with Intel Tangier SoC, say Y here. +config WDT_TEGRA + bool "Tegra watchdog" + depends on WDT && ARCH_TEGRA + help + Enable support for the watchdog timer found in Tegra SoCs. + config WDT_ARM_SMC bool "ARM SMC watchdog timer support" depends on WDT && ARM_SMCCC diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index d52d17e1c90..02e2674f8af 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_WDT_STARFIVE) += starfive_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o +obj-$(CONFIG_WDT_TEGRA) += tegra_wdt.o obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o obj-$(CONFIG_WDT_ADI) += adi_wdt.o obj-$(CONFIG_WDT_QCOM) += qcom-wdt.o diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c new file mode 100644 index 00000000000..adc30da579a --- /dev/null +++ b/drivers/watchdog/tegra_wdt.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVIDIA Tegra Watchdog driver + * + * Copyright (C) 2025 NABLA Software Engineering + * Lukasz Majewski, NABLA Software Engineering, [email protected] + */ + +#include <dm.h> +#include <wdt.h> +#include <hang.h> +#include <asm/io.h> +#include <watchdog.h> + +/* Timer registers */ +#define TIMER_PTV 0x0 +#define TIMER_EN BIT(31) +#define TIMER_PERIODIC BIT(30) + +/* WDT registers */ +#define WDT_CFG 0x0 +#define WDT_CFG_PERIOD_SHIFT 4 +#define WDT_CFG_PERIOD_MASK GENMASK(7, 0) +#define WDT_CFG_INT_EN BIT(12) +#define WDT_CFG_PMC2CAR_RST_EN BIT(15) +#define WDT_CMD 0x8 +#define WDT_CMD_START_COUNTER BIT(0) +#define WDT_CMD_DISABLE_COUNTER BIT(1) +#define WDT_UNLOCK 0xc +#define WDT_UNLOCK_PATTERN 0xc45a + +/* Use watchdog ID 0 */ +#define WDT_BASE 0x100 + +/* Use Timer 5 as WDT counter */ +#define WDT_TIMER_BASE 0x60 +#define WDT_TIMER_ID 5 + +struct tegra_wdt_priv { + void __iomem *wdt_base; + void __iomem *tmr_base; +}; + +static int tegra_wdt_reset(struct udevice *dev) +{ + struct tegra_wdt_priv *priv = dev_get_priv(dev); + + writel(WDT_CMD_START_COUNTER, priv->wdt_base + WDT_CMD); + + return 0; +} + +static int tegra_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct tegra_wdt_priv *priv = dev_get_priv(dev); + u32 timeout_sec = timeout / 1000; + + /* Support for timeout from 1 to 255 seconds */ + if (timeout_sec < 1 || timeout_sec > 255) + return -EINVAL; + + /* + * Timer for WDT has a fixed 1MHz clock, so for 1 second period one + * shall write 1000000ul. + * + * On Tegra the watchdog reset actually occurs on the 4th expiration + * of this counter, so we set the period to 1/4. + */ + writel(TIMER_EN | TIMER_PERIODIC | (1000000ul / 4), + priv->tmr_base + TIMER_PTV); + + writel(WDT_CFG_PMC2CAR_RST_EN | (timeout_sec << WDT_CFG_PERIOD_SHIFT) | + WDT_TIMER_ID, priv->wdt_base + WDT_CFG); + + writel(WDT_CMD_START_COUNTER, priv->wdt_base + WDT_CMD); + + return 0; +} + +static int tegra_wdt_stop(struct udevice *dev) +{ + struct tegra_wdt_priv *priv = dev_get_priv(dev); + + writel(WDT_UNLOCK_PATTERN, priv->wdt_base + WDT_UNLOCK); + writel(WDT_CMD_DISABLE_COUNTER, priv->wdt_base + WDT_CMD); + writel(0, priv->tmr_base + TIMER_PTV); + + return 0; +} + +static int tegra_wdt_probe(struct udevice *dev) +{ + struct tegra_wdt_priv *priv = dev_get_priv(dev); + void __iomem *base; + + base = dev_read_addr_ptr(dev); + if (!base) + return -ENOENT; + + priv->wdt_base = base + WDT_BASE; + priv->tmr_base = base + WDT_TIMER_BASE; + + return 0; +} + +static const struct wdt_ops tegra_wdt_ops = { + .start = tegra_wdt_start, + .stop = tegra_wdt_stop, + .reset = tegra_wdt_reset, +}; + +U_BOOT_DRIVER(tegra_wdt) = { + .name = "tegra_wdt", + .id = UCLASS_WDT, + .probe = tegra_wdt_probe, + .ops = &tegra_wdt_ops, + .priv_auto = sizeof(struct tegra_wdt_priv), +}; |
