Merge branch 'master' of git://git.denx.de/u-boot-socfpga
- Gen 5 and Watchdog fixes
This commit is contained in:
@@ -434,8 +434,10 @@ static void sdr_load_regs(struct socfpga_sdr_ctrl *sdr_ctrl,
|
||||
debug("Configuring DRAMODT\n");
|
||||
writel(cfg->dram_odt, &sdr_ctrl->dram_odt);
|
||||
|
||||
debug("Configuring EXTRATIME1\n");
|
||||
writel(cfg->extratime1, &sdr_ctrl->extratime1);
|
||||
if (dram_is_ddr(3)) {
|
||||
debug("Configuring EXTRATIME1\n");
|
||||
writel(cfg->extratime1, &sdr_ctrl->extratime1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/sdram.h>
|
||||
#include <errno.h>
|
||||
#include <hang.h>
|
||||
#include "sequencer.h"
|
||||
|
||||
static const struct socfpga_sdr_rw_load_manager *sdr_rw_load_mgr_regs =
|
||||
@@ -54,6 +55,21 @@ static const struct socfpga_sdr_ctrl *sdr_ctrl =
|
||||
#define SKIP_DELAY_LOOP_VALUE_OR_ZERO(non_skip_value) \
|
||||
((non_skip_value) & seq->skip_delay_mask)
|
||||
|
||||
bool dram_is_ddr(const u8 ddr)
|
||||
{
|
||||
const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config();
|
||||
const u8 type = (cfg->ctrl_cfg >> SDR_CTRLGRP_CTRLCFG_MEMTYPE_LSB) &
|
||||
SDR_CTRLGRP_CTRLCFG_MEMTYPE_MASK;
|
||||
|
||||
if (ddr == 2 && type == 1) /* DDR2 */
|
||||
return true;
|
||||
|
||||
if (ddr == 3 && type == 2) /* DDR3 */
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void set_failing_group_stage(struct socfpga_sdrseq *seq,
|
||||
u32 group, u32 stage, u32 substage)
|
||||
{
|
||||
@@ -164,6 +180,8 @@ static void set_rank_and_odt_mask(struct socfpga_sdrseq *seq,
|
||||
*/
|
||||
odt_mask_0 = 0x3 & ~(1 << rank);
|
||||
odt_mask_1 = 0x3;
|
||||
if (dram_is_ddr(2))
|
||||
odt_mask_1 &= ~(1 << rank);
|
||||
} else {
|
||||
/*
|
||||
* - Single-Slot , Dual-Rank (2 CS per DIMM)
|
||||
@@ -176,10 +194,11 @@ static void set_rank_and_odt_mask(struct socfpga_sdrseq *seq,
|
||||
}
|
||||
break;
|
||||
case 4: /* 4 Ranks */
|
||||
/* Read:
|
||||
/*
|
||||
* DDR3 Read, DDR2 Read/Write:
|
||||
* ----------+-----------------------+
|
||||
* | ODT |
|
||||
* Read From +-----------------------+
|
||||
* +-----------------------+
|
||||
* Rank | 3 | 2 | 1 | 0 |
|
||||
* ----------+-----+-----+-----+-----+
|
||||
* 0 | 0 | 1 | 0 | 0 |
|
||||
@@ -188,7 +207,7 @@ static void set_rank_and_odt_mask(struct socfpga_sdrseq *seq,
|
||||
* 3 | 0 | 0 | 1 | 0 |
|
||||
* ----------+-----+-----+-----+-----+
|
||||
*
|
||||
* Write:
|
||||
* DDR3 Write:
|
||||
* ----------+-----------------------+
|
||||
* | ODT |
|
||||
* Write To +-----------------------+
|
||||
@@ -203,19 +222,31 @@ static void set_rank_and_odt_mask(struct socfpga_sdrseq *seq,
|
||||
switch (rank) {
|
||||
case 0:
|
||||
odt_mask_0 = 0x4;
|
||||
odt_mask_1 = 0x5;
|
||||
if (dram_is_ddr(2))
|
||||
odt_mask_1 = 0x4;
|
||||
else if (dram_is_ddr(3))
|
||||
odt_mask_1 = 0x5;
|
||||
break;
|
||||
case 1:
|
||||
odt_mask_0 = 0x8;
|
||||
odt_mask_1 = 0xA;
|
||||
if (dram_is_ddr(2))
|
||||
odt_mask_1 = 0x8;
|
||||
else if (dram_is_ddr(3))
|
||||
odt_mask_1 = 0xA;
|
||||
break;
|
||||
case 2:
|
||||
odt_mask_0 = 0x1;
|
||||
odt_mask_1 = 0x5;
|
||||
if (dram_is_ddr(2))
|
||||
odt_mask_1 = 0x1;
|
||||
else if (dram_is_ddr(3))
|
||||
odt_mask_1 = 0x5;
|
||||
break;
|
||||
case 3:
|
||||
odt_mask_0 = 0x2;
|
||||
odt_mask_1 = 0xA;
|
||||
if (dram_is_ddr(2))
|
||||
odt_mask_1 = 0x2;
|
||||
else if (dram_is_ddr(3))
|
||||
odt_mask_1 = 0xA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -839,6 +870,12 @@ static void delay_for_n_mem_clocks(struct socfpga_sdrseq *seq,
|
||||
debug("%s:%d clocks=%u ... end\n", __func__, __LINE__, clocks);
|
||||
}
|
||||
|
||||
static void delay_for_n_ns(struct socfpga_sdrseq *seq, const u32 ns)
|
||||
{
|
||||
delay_for_n_mem_clocks(seq, (ns * seq->misccfg->afi_clk_freq *
|
||||
seq->misccfg->afi_rate_ratio) / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* rw_mgr_mem_init_load_regs() - Load instruction registers
|
||||
* @cntr0: Counter 0 value
|
||||
@@ -872,14 +909,59 @@ static void rw_mgr_mem_init_load_regs(struct socfpga_sdrseq *seq,
|
||||
}
|
||||
|
||||
/**
|
||||
* rw_mgr_mem_load_user() - Load user calibration values
|
||||
* rw_mgr_mem_load_user_ddr2() - Load user calibration values for DDR2
|
||||
* @handoff: Indicate whether this is initialization or handoff phase
|
||||
*
|
||||
* Load user calibration values and optionally precharge the banks.
|
||||
*/
|
||||
static void rw_mgr_mem_load_user_ddr2(struct socfpga_sdrseq *seq,
|
||||
const int handoff)
|
||||
{
|
||||
u32 grpaddr = SDR_PHYGRP_RWMGRGRP_ADDRESS |
|
||||
RW_MGR_RUN_SINGLE_GROUP_OFFSET;
|
||||
u32 r;
|
||||
|
||||
for (r = 0; r < seq->rwcfg->mem_number_of_ranks; r++) {
|
||||
/* set rank */
|
||||
set_rank_and_odt_mask(seq, r, RW_MGR_ODT_MODE_OFF);
|
||||
|
||||
/* precharge all banks ... */
|
||||
writel(seq->rwcfg->precharge_all, grpaddr);
|
||||
|
||||
writel(seq->rwcfg->emr2, grpaddr);
|
||||
writel(seq->rwcfg->emr3, grpaddr);
|
||||
writel(seq->rwcfg->emr, grpaddr);
|
||||
|
||||
if (handoff) {
|
||||
writel(seq->rwcfg->mr_user, grpaddr);
|
||||
continue;
|
||||
}
|
||||
|
||||
writel(seq->rwcfg->mr_dll_reset, grpaddr);
|
||||
|
||||
writel(seq->rwcfg->precharge_all, grpaddr);
|
||||
|
||||
writel(seq->rwcfg->refresh, grpaddr);
|
||||
delay_for_n_ns(seq, 200);
|
||||
writel(seq->rwcfg->refresh, grpaddr);
|
||||
delay_for_n_ns(seq, 200);
|
||||
|
||||
writel(seq->rwcfg->mr_calib, grpaddr);
|
||||
writel(/*seq->rwcfg->*/0x0b, grpaddr); // EMR_OCD_ENABLE
|
||||
writel(seq->rwcfg->emr, grpaddr);
|
||||
delay_for_n_mem_clocks(seq, 200);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rw_mgr_mem_load_user_ddr3() - Load user calibration values
|
||||
* @fin1: Final instruction 1
|
||||
* @fin2: Final instruction 2
|
||||
* @precharge: If 1, precharge the banks at the end
|
||||
*
|
||||
* Load user calibration values and optionally precharge the banks.
|
||||
*/
|
||||
static void rw_mgr_mem_load_user(struct socfpga_sdrseq *seq,
|
||||
static void rw_mgr_mem_load_user_ddr3(struct socfpga_sdrseq *seq,
|
||||
const u32 fin1, const u32 fin2,
|
||||
const int precharge)
|
||||
{
|
||||
@@ -935,6 +1017,25 @@ static void rw_mgr_mem_load_user(struct socfpga_sdrseq *seq,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* rw_mgr_mem_load_user() - Load user calibration values
|
||||
* @fin1: Final instruction 1
|
||||
* @fin2: Final instruction 2
|
||||
* @precharge: If 1, precharge the banks at the end
|
||||
*
|
||||
* Load user calibration values and optionally precharge the banks.
|
||||
*/
|
||||
static void rw_mgr_mem_load_user(struct socfpga_sdrseq *seq,
|
||||
const u32 fin1, const u32 fin2,
|
||||
const int precharge)
|
||||
{
|
||||
if (dram_is_ddr(2))
|
||||
rw_mgr_mem_load_user_ddr2(seq, precharge);
|
||||
else if (dram_is_ddr(3))
|
||||
rw_mgr_mem_load_user_ddr3(seq, fin1, fin2, precharge);
|
||||
else
|
||||
hang();
|
||||
}
|
||||
/**
|
||||
* rw_mgr_mem_initialize() - Initialize RW Manager
|
||||
*
|
||||
@@ -945,8 +1046,10 @@ static void rw_mgr_mem_initialize(struct socfpga_sdrseq *seq)
|
||||
debug("%s:%d\n", __func__, __LINE__);
|
||||
|
||||
/* The reset / cke part of initialization is broadcasted to all ranks */
|
||||
writel(RW_MGR_RANK_ALL, SDR_PHYGRP_RWMGRGRP_ADDRESS |
|
||||
RW_MGR_SET_CS_AND_ODT_MASK_OFFSET);
|
||||
if (dram_is_ddr(3)) {
|
||||
writel(RW_MGR_RANK_ALL, SDR_PHYGRP_RWMGRGRP_ADDRESS |
|
||||
RW_MGR_SET_CS_AND_ODT_MASK_OFFSET);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here's how you load register for a loop
|
||||
@@ -979,29 +1082,38 @@ static void rw_mgr_mem_initialize(struct socfpga_sdrseq *seq)
|
||||
/* Indicate that memory is stable. */
|
||||
writel(1, &phy_mgr_cfg->reset_mem_stbl);
|
||||
|
||||
/*
|
||||
* transition the RESET to high
|
||||
* Wait for 500us
|
||||
*/
|
||||
if (dram_is_ddr(2)) {
|
||||
writel(seq->rwcfg->nop, SDR_PHYGRP_RWMGRGRP_ADDRESS |
|
||||
RW_MGR_RUN_SINGLE_GROUP_OFFSET);
|
||||
|
||||
/*
|
||||
* 500us @ 266MHz (3.75 ns) ~ 134000 clock cycles
|
||||
* If a and b are the number of iteration in 2 nested loops
|
||||
* it takes the following number of cycles to complete the operation
|
||||
* number_of_cycles = ((2 + n) * a + 2) * b
|
||||
* where n is the number of instruction in the inner loop
|
||||
* One possible solution is n = 2 , a = 131 , b = 256 => a = 83,
|
||||
* b = FF
|
||||
*/
|
||||
rw_mgr_mem_init_load_regs(seq, seq->misccfg->treset_cntr0_val,
|
||||
seq->misccfg->treset_cntr1_val,
|
||||
seq->misccfg->treset_cntr2_val,
|
||||
seq->rwcfg->init_reset_1_cke_0);
|
||||
/* Bring up clock enable. */
|
||||
|
||||
/* Bring up clock enable. */
|
||||
/* tXRP < 400 ck cycles */
|
||||
delay_for_n_ns(seq, 400);
|
||||
} else if (dram_is_ddr(3)) {
|
||||
/*
|
||||
* transition the RESET to high
|
||||
* Wait for 500us
|
||||
*/
|
||||
|
||||
/* tXRP < 250 ck cycles */
|
||||
delay_for_n_mem_clocks(seq, 250);
|
||||
/*
|
||||
* 500us @ 266MHz (3.75 ns) ~ 134000 clock cycles
|
||||
* If a and b are the number of iteration in 2 nested loops
|
||||
* it takes the following number of cycles to complete the
|
||||
* operation number_of_cycles = ((2 + n) * a + 2) * b
|
||||
* where n is the number of instruction in the inner loop
|
||||
* One possible solution is
|
||||
* n = 2 , a = 131 , b = 256 => a = 83, b = FF
|
||||
*/
|
||||
rw_mgr_mem_init_load_regs(seq, seq->misccfg->treset_cntr0_val,
|
||||
seq->misccfg->treset_cntr1_val,
|
||||
seq->misccfg->treset_cntr2_val,
|
||||
seq->rwcfg->init_reset_1_cke_0);
|
||||
/* Bring up clock enable. */
|
||||
|
||||
/* tXRP < 250 ck cycles */
|
||||
delay_for_n_mem_clocks(seq, 250);
|
||||
}
|
||||
|
||||
rw_mgr_mem_load_user(seq, seq->rwcfg->mrs0_dll_reset_mirr,
|
||||
seq->rwcfg->mrs0_dll_reset, 0);
|
||||
@@ -3769,16 +3881,26 @@ static void initialize_tracking(struct socfpga_sdrseq *seq)
|
||||
&sdr_reg_file->delays);
|
||||
|
||||
/* mux delay */
|
||||
writel((seq->rwcfg->idle << 24) | (seq->rwcfg->activate_1 << 16) |
|
||||
(seq->rwcfg->sgle_read << 8) | (seq->rwcfg->precharge_all << 0),
|
||||
&sdr_reg_file->trk_rw_mgr_addr);
|
||||
if (dram_is_ddr(2)) {
|
||||
writel(0, &sdr_reg_file->trk_rw_mgr_addr);
|
||||
} else if (dram_is_ddr(3)) {
|
||||
writel((seq->rwcfg->idle << 24) |
|
||||
(seq->rwcfg->activate_1 << 16) |
|
||||
(seq->rwcfg->sgle_read << 8) |
|
||||
(seq->rwcfg->precharge_all << 0),
|
||||
&sdr_reg_file->trk_rw_mgr_addr);
|
||||
}
|
||||
|
||||
writel(seq->rwcfg->mem_if_read_dqs_width,
|
||||
&sdr_reg_file->trk_read_dqs_width);
|
||||
|
||||
/* trefi [7:0] */
|
||||
writel((seq->rwcfg->refresh_all << 24) | (1000 << 0),
|
||||
&sdr_reg_file->trk_rfsh);
|
||||
if (dram_is_ddr(2)) {
|
||||
writel(1000 << 0, &sdr_reg_file->trk_rfsh);
|
||||
} else if (dram_is_ddr(3)) {
|
||||
writel((seq->rwcfg->refresh_all << 24) | (1000 << 0),
|
||||
&sdr_reg_file->trk_rfsh);
|
||||
}
|
||||
}
|
||||
|
||||
int sdram_calibration_full(struct socfpga_sdr *sdr)
|
||||
|
||||
@@ -279,5 +279,6 @@ struct socfpga_sdrseq {
|
||||
};
|
||||
|
||||
int sdram_calibration_full(struct socfpga_sdr *sdr);
|
||||
bool dram_is_ddr(const u8 ddr);
|
||||
|
||||
#endif /* _SEQUENCER_H_ */
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <dm/of_access.h>
|
||||
#include <env.h>
|
||||
#include <reset-uclass.h>
|
||||
#include <wait_bit.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/sizes.h>
|
||||
@@ -80,7 +81,10 @@ static int socfpga_reset_deassert(struct reset_ctl *reset_ctl)
|
||||
int offset = id % (reg_width * BITS_PER_BYTE);
|
||||
|
||||
clrbits_le32(data->modrst_base + (bank * BANK_INCREMENT), BIT(offset));
|
||||
return 0;
|
||||
|
||||
return wait_for_bit_le32(data->modrst_base + (bank * BANK_INCREMENT),
|
||||
BIT(offset),
|
||||
false, 500, false);
|
||||
}
|
||||
|
||||
static int socfpga_reset_request(struct reset_ctl *reset_ctl)
|
||||
|
||||
@@ -45,6 +45,13 @@ config ULP_WATCHDOG
|
||||
help
|
||||
Say Y here to enable i.MX7ULP watchdog driver.
|
||||
|
||||
config DESIGNWARE_WATCHDOG
|
||||
bool "Designware watchdog timer support"
|
||||
select HW_WATCHDOG if !WDT
|
||||
help
|
||||
Enable this to support Designware Watchdog Timer IP, present e.g.
|
||||
on Altera SoCFPGA SoCs.
|
||||
|
||||
config WDT
|
||||
bool "Enable driver model for watchdog timer drivers"
|
||||
depends on DM
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
* Copyright (C) 2013 Altera Corporation <www.altera.com>
|
||||
*/
|
||||
|
||||
#include <clk.h>
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <dm.h>
|
||||
#include <reset.h>
|
||||
#include <wdt.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/utils.h>
|
||||
|
||||
@@ -14,49 +17,52 @@
|
||||
|
||||
#define DW_WDT_CR_EN_OFFSET 0x00
|
||||
#define DW_WDT_CR_RMOD_OFFSET 0x01
|
||||
#define DW_WDT_CR_RMOD_VAL 0x00
|
||||
#define DW_WDT_CRR_RESTART_VAL 0x76
|
||||
|
||||
struct designware_wdt_priv {
|
||||
void __iomem *base;
|
||||
unsigned int clk_khz;
|
||||
};
|
||||
|
||||
/*
|
||||
* Set the watchdog time interval.
|
||||
* Counter is 32 bit.
|
||||
*/
|
||||
static int designware_wdt_settimeout(unsigned int timeout)
|
||||
static int designware_wdt_settimeout(void __iomem *base, unsigned int clk_khz,
|
||||
unsigned int timeout)
|
||||
{
|
||||
signed int i;
|
||||
|
||||
/* calculate the timeout range value */
|
||||
i = (log_2_n_round_up(timeout * CONFIG_DW_WDT_CLOCK_KHZ)) - 16;
|
||||
if (i > 15)
|
||||
i = 15;
|
||||
if (i < 0)
|
||||
i = 0;
|
||||
i = log_2_n_round_up(timeout * clk_khz) - 16;
|
||||
i = clamp(i, 0, 15);
|
||||
|
||||
writel(i | (i << 4), base + DW_WDT_TORR);
|
||||
|
||||
writel((i | (i << 4)), (CONFIG_DW_WDT_BASE + DW_WDT_TORR));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void designware_wdt_enable(void)
|
||||
static void designware_wdt_enable(void __iomem *base)
|
||||
{
|
||||
writel(((DW_WDT_CR_RMOD_VAL << DW_WDT_CR_RMOD_OFFSET) |
|
||||
(0x1 << DW_WDT_CR_EN_OFFSET)),
|
||||
(CONFIG_DW_WDT_BASE + DW_WDT_CR));
|
||||
writel(BIT(DW_WDT_CR_EN_OFFSET), base + DW_WDT_CR);
|
||||
}
|
||||
|
||||
static unsigned int designware_wdt_is_enabled(void)
|
||||
static unsigned int designware_wdt_is_enabled(void __iomem *base)
|
||||
{
|
||||
unsigned long val;
|
||||
val = readl((CONFIG_DW_WDT_BASE + DW_WDT_CR));
|
||||
return val & 0x1;
|
||||
return readl(base + DW_WDT_CR) & BIT(0);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_HW_WATCHDOG)
|
||||
static void designware_wdt_reset_common(void __iomem *base)
|
||||
{
|
||||
if (designware_wdt_is_enabled(base))
|
||||
/* restart the watchdog counter */
|
||||
writel(DW_WDT_CRR_RESTART_VAL, base + DW_WDT_CRR);
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(WDT)
|
||||
void hw_watchdog_reset(void)
|
||||
{
|
||||
if (designware_wdt_is_enabled())
|
||||
/* restart the watchdog counter */
|
||||
writel(DW_WDT_CRR_RESTART_VAL,
|
||||
(CONFIG_DW_WDT_BASE + DW_WDT_CRR));
|
||||
designware_wdt_reset_common((void __iomem *)CONFIG_DW_WDT_BASE);
|
||||
}
|
||||
|
||||
void hw_watchdog_init(void)
|
||||
@@ -64,10 +70,106 @@ void hw_watchdog_init(void)
|
||||
/* reset to disable the watchdog */
|
||||
hw_watchdog_reset();
|
||||
/* set timer in miliseconds */
|
||||
designware_wdt_settimeout(CONFIG_WATCHDOG_TIMEOUT_MSECS);
|
||||
designware_wdt_settimeout((void __iomem *)CONFIG_DW_WDT_BASE,
|
||||
CONFIG_DW_WDT_CLOCK_KHZ,
|
||||
CONFIG_WATCHDOG_TIMEOUT_MSECS);
|
||||
/* enable the watchdog */
|
||||
designware_wdt_enable();
|
||||
designware_wdt_enable((void __iomem *)CONFIG_DW_WDT_BASE);
|
||||
/* reset the watchdog */
|
||||
hw_watchdog_reset();
|
||||
}
|
||||
#else
|
||||
static int designware_wdt_reset(struct udevice *dev)
|
||||
{
|
||||
struct designware_wdt_priv *priv = dev_get_priv(dev);
|
||||
|
||||
designware_wdt_reset_common(priv->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int designware_wdt_stop(struct udevice *dev)
|
||||
{
|
||||
struct designware_wdt_priv *priv = dev_get_priv(dev);
|
||||
|
||||
designware_wdt_reset(dev);
|
||||
writel(0, priv->base + DW_WDT_CR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int designware_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
|
||||
{
|
||||
struct designware_wdt_priv *priv = dev_get_priv(dev);
|
||||
|
||||
designware_wdt_stop(dev);
|
||||
|
||||
/* set timer in miliseconds */
|
||||
designware_wdt_settimeout(priv->base, priv->clk_khz, timeout);
|
||||
|
||||
designware_wdt_enable(priv->base);
|
||||
|
||||
/* reset the watchdog */
|
||||
return designware_wdt_reset(dev);
|
||||
}
|
||||
|
||||
static int designware_wdt_probe(struct udevice *dev)
|
||||
{
|
||||
struct designware_wdt_priv *priv = dev_get_priv(dev);
|
||||
__maybe_unused int ret;
|
||||
|
||||
priv->base = dev_remap_addr(dev);
|
||||
if (!priv->base)
|
||||
return -EINVAL;
|
||||
|
||||
#if CONFIG_IS_ENABLED(CLK)
|
||||
struct clk clk;
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->clk_khz = clk_get_rate(&clk);
|
||||
if (!priv->clk_khz)
|
||||
return -EINVAL;
|
||||
#else
|
||||
priv->clk_khz = CONFIG_DW_WDT_CLOCK_KHZ;
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_RESET)
|
||||
struct reset_ctl_bulk resets;
|
||||
|
||||
ret = reset_get_bulk(dev, &resets);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_deassert_bulk(&resets);
|
||||
if (ret)
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
/* reset to disable the watchdog */
|
||||
return designware_wdt_stop(dev);
|
||||
}
|
||||
|
||||
static const struct wdt_ops designware_wdt_ops = {
|
||||
.start = designware_wdt_start,
|
||||
.reset = designware_wdt_reset,
|
||||
.stop = designware_wdt_stop,
|
||||
};
|
||||
|
||||
static const struct udevice_id designware_wdt_ids[] = {
|
||||
{ .compatible = "snps,dw-wdt"},
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(designware_wdt) = {
|
||||
.name = "designware_wdt",
|
||||
.id = UCLASS_WDT,
|
||||
.of_match = designware_wdt_ids,
|
||||
.priv_auto_alloc_size = sizeof(struct designware_wdt_priv),
|
||||
.probe = designware_wdt_probe,
|
||||
.ops = &designware_wdt_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user