summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ddr/altera/sdram_gen5.c6
-rw-r--r--drivers/ddr/altera/sequencer.c194
-rw-r--r--drivers/ddr/altera/sequencer.h1
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/cortina_gpio.c111
-rw-r--r--drivers/net/mtk_eth.c57
-rw-r--r--drivers/net/mtk_eth.h15
-rw-r--r--drivers/reset/reset-socfpga.c6
-rw-r--r--drivers/serial/Kconfig7
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_cortina.c164
-rw-r--r--drivers/watchdog/Kconfig15
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/cortina_wdt.c139
-rw-r--r--drivers/watchdog/designware_wdt.c150
16 files changed, 808 insertions, 68 deletions
diff --git a/drivers/ddr/altera/sdram_gen5.c b/drivers/ddr/altera/sdram_gen5.c
index a3b914fdfc..3ea5a7c0c0 100644
--- a/drivers/ddr/altera/sdram_gen5.c
+++ b/drivers/ddr/altera/sdram_gen5.c
@@ -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);
+ }
}
/**
diff --git a/drivers/ddr/altera/sequencer.c b/drivers/ddr/altera/sequencer.c
index b85b56efe5..35bda9b34c 100644
--- a/drivers/ddr/altera/sequencer.c
+++ b/drivers/ddr/altera/sequencer.c
@@ -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)
{
@@ -936,6 +1018,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
*
* 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
+ */
+
+ /*
+ * 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);
+ /* 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)
diff --git a/drivers/ddr/altera/sequencer.h b/drivers/ddr/altera/sequencer.h
index 4a03c3fdf9..c72a683ffe 100644
--- a/drivers/ddr/altera/sequencer.h
+++ b/drivers/ddr/altera/sequencer.h
@@ -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_ */
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 4e5a70780a..f751a8b9ea 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -60,6 +60,14 @@ config BCM6345_GPIO
help
This driver supports the GPIO banks on BCM6345 SoCs.
+config CORTINA_GPIO
+ bool "Cortina-Access GPIO driver"
+ depends on DM_GPIO && CORTINA_PLATFORM
+ help
+ Enable support for the GPIO controller in Cortina CAxxxx SoCs.
+ This driver supports all CPU ISA variants supported by Cortina
+ Access CAxxxx SoCs.
+
config DWAPB_GPIO
bool "DWAPB GPIO driver"
depends on DM && DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 449046b64c..ceae6126c7 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -17,6 +17,7 @@ endif
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
obj-$(CONFIG_BCM6345_GPIO) += bcm6345_gpio.o
+obj-$(CONFIG_CORTINA_GPIO) += cortina_gpio.o
obj-$(CONFIG_INTEL_GPIO) += intel_gpio.o
obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o
diff --git a/drivers/gpio/cortina_gpio.c b/drivers/gpio/cortina_gpio.c
new file mode 100644
index 0000000000..e2374ce1e7
--- /dev/null
+++ b/drivers/gpio/cortina_gpio.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Cortina-Access
+ *
+ * GPIO Driver for Cortina Access CAxxxx Line of SoCs
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <linux/compat.h>
+#include <linux/compiler.h>
+
+/* GPIO Register Map */
+#define CORTINA_GPIO_CFG 0x00
+#define CORTINA_GPIO_OUT 0x04
+#define CORTINA_GPIO_IN 0x08
+#define CORTINA_GPIO_LVL 0x0C
+#define CORTINA_GPIO_EDGE 0x10
+#define CORTINA_GPIO_BOTHEDGE 0x14
+#define CORTINA_GPIO_IE 0x18
+#define CORTINA_GPIO_INT 0x1C
+#define CORTINA_GPIO_STAT 0x20
+
+struct cortina_gpio_bank {
+ void __iomem *base;
+};
+
+#ifdef CONFIG_DM_GPIO
+static int ca_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ setbits_32(priv->base, BIT(offset));
+ return 0;
+}
+
+static int
+ca_gpio_direction_output(struct udevice *dev, unsigned int offset, int value)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ clrbits_32(priv->base, BIT(offset));
+ return 0;
+}
+
+static int ca_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ return readl(priv->base + CORTINA_GPIO_IN) & BIT(offset);
+}
+
+static int ca_gpio_set_value(struct udevice *dev, unsigned int offset,
+ int value)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ setbits_32(priv->base + CORTINA_GPIO_OUT, BIT(offset));
+ return 0;
+}
+
+static int ca_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ if (readl(priv->base) & BIT(offset))
+ return GPIOF_INPUT;
+ else
+ return GPIOF_OUTPUT;
+}
+
+static const struct dm_gpio_ops gpio_cortina_ops = {
+ .direction_input = ca_gpio_direction_input,
+ .direction_output = ca_gpio_direction_output,
+ .get_value = ca_gpio_get_value,
+ .set_value = ca_gpio_set_value,
+ .get_function = ca_gpio_get_function,
+};
+
+static int ca_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct cortina_gpio_bank *priv = dev_get_priv(dev);
+
+ priv->base = dev_remap_addr_index(dev, 0);
+ if (!priv->base)
+ return -EINVAL;
+
+ uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", 32);
+ uc_priv->bank_name = dev->name;
+
+ debug("Done Cortina GPIO init\n");
+ return 0;
+}
+
+static const struct udevice_id ca_gpio_ids[] = {
+ {.compatible = "cortina,ca-gpio"},
+ {}
+};
+
+U_BOOT_DRIVER(cortina_gpio) = {
+ .name = "cortina-gpio",
+ .id = UCLASS_GPIO,
+ .ops = &gpio_cortina_ops,
+ .probe = ca_gpio_probe,
+ .priv_auto_alloc_size = sizeof(struct cortina_gpio_bank),
+ .of_match = ca_gpio_ids,
+};
+#endif /* CONFIG_DM_GPIO */
diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c
index c22e590387..edfa5d1ce8 100644
--- a/drivers/net/mtk_eth.c
+++ b/drivers/net/mtk_eth.c
@@ -136,7 +136,8 @@ enum mtk_switch {
enum mtk_soc {
SOC_MT7623,
- SOC_MT7629
+ SOC_MT7629,
+ SOC_MT7622
};
struct mtk_eth_priv {
@@ -151,6 +152,7 @@ struct mtk_eth_priv {
void __iomem *fe_base;
void __iomem *gmac_base;
void __iomem *ethsys_base;
+ void __iomem *sgmii_base;
struct mii_dev *mdio_bus;
int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg);
@@ -750,6 +752,24 @@ static int mtk_phy_probe(struct udevice *dev)
return 0;
}
+static void mtk_sgmii_init(struct mtk_eth_priv *priv)
+{
+ /* Set SGMII GEN2 speed(2.5G) */
+ clrsetbits_le32(priv->sgmii_base + SGMSYS_GEN2_SPEED,
+ SGMSYS_SPEED_2500, SGMSYS_SPEED_2500);
+
+ /* Disable SGMII AN */
+ clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
+ SGMII_AN_ENABLE, 0);
+
+ /* SGMII force mode setting */
+ writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
+
+ /* Release PHYA power down state */
+ clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
+ SGMII_PHYA_PWD, 0);
+}
+
static void mtk_mac_init(struct mtk_eth_priv *priv)
{
int i, ge_mode = 0;
@@ -758,8 +778,13 @@ static void mtk_mac_init(struct mtk_eth_priv *priv)
switch (priv->phy_interface) {
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII:
+ ge_mode = GE_MODE_RGMII;
+ break;
case PHY_INTERFACE_MODE_SGMII:
ge_mode = GE_MODE_RGMII;
+ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, SYSCFG0_SGMII_SEL_M,
+ SYSCFG0_SGMII_SEL(priv->gmac_id));
+ mtk_sgmii_init(priv);
break;
case PHY_INTERFACE_MODE_MII:
case PHY_INTERFACE_MODE_GMII:
@@ -828,7 +853,8 @@ static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
memset(priv->rx_ring_noc, 0, NUM_RX_DESC * sizeof(struct pdma_rxdesc));
memset(priv->pkt_pool, 0, TOTAL_PKT_BUF_SIZE);
- flush_dcache_range((u32)pkt_base, (u32)(pkt_base + TOTAL_PKT_BUF_SIZE));
+ flush_dcache_range((ulong)pkt_base,
+ (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE));
priv->rx_dma_owner_idx0 = 0;
priv->tx_cpu_owner_idx0 = 0;
@@ -940,7 +966,7 @@ static int mtk_eth_send(struct udevice *dev, void *packet, int length)
pkt_base = (void *)phys_to_virt(priv->tx_ring_noc[idx].txd_info1.SDP0);
memcpy(pkt_base, packet, length);
- flush_dcache_range((u32)pkt_base, (u32)pkt_base +
+ flush_dcache_range((ulong)pkt_base, (ulong)pkt_base +
roundup(length, ARCH_DMA_MINALIGN));
priv->tx_ring_noc[idx].txd_info2.SDL0 = length;
@@ -966,7 +992,7 @@ static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp)
length = priv->rx_ring_noc[idx].rxd_info2.PLEN0;
pkt_base = (void *)phys_to_virt(priv->rx_ring_noc[idx].rxd_info1.PDP0);
- invalidate_dcache_range((u32)pkt_base, (u32)pkt_base +
+ invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base +
roundup(length, ARCH_DMA_MINALIGN));
if (packetp)
@@ -994,7 +1020,7 @@ static int mtk_eth_probe(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct mtk_eth_priv *priv = dev_get_priv(dev);
- u32 iobase = pdata->iobase;
+ ulong iobase = pdata->iobase;
int ret;
/* Frame Engine Register Base */
@@ -1104,6 +1130,26 @@ static int mtk_eth_ofdata_to_platdata(struct udevice *dev)
}
}
+ if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+ /* get corresponding sgmii phandle */
+ ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys",
+ NULL, 0, 0, &args);
+ if (ret)
+ return ret;
+
+ regmap = syscon_node_to_regmap(args.node);
+
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ priv->sgmii_base = regmap_get_range(regmap, 0);
+
+ if (!priv->sgmii_base) {
+ dev_err(dev, "Unable to find sgmii\n");
+ return -ENODEV;
+ }
+ }
+
/* check for switch first, otherwise phy will be used */
priv->sw = SW_NONE;
priv->switch_init = NULL;
@@ -1151,6 +1197,7 @@ static int mtk_eth_ofdata_to_platdata(struct udevice *dev)
static const struct udevice_id mtk_eth_ids[] = {
{ .compatible = "mediatek,mt7629-eth", .data = SOC_MT7629 },
{ .compatible = "mediatek,mt7623-eth", .data = SOC_MT7623 },
+ { .compatible = "mediatek,mt7622-eth", .data = SOC_MT7622 },
{}
};
diff --git a/drivers/net/mtk_eth.h b/drivers/net/mtk_eth.h
index fe89a03739..9bb037d440 100644
--- a/drivers/net/mtk_eth.h
+++ b/drivers/net/mtk_eth.h
@@ -20,6 +20,8 @@
#define ETHSYS_SYSCFG0_REG 0x14
#define SYSCFG0_GE_MODE_S(n) (12 + ((n) * 2))
#define SYSCFG0_GE_MODE_M 0x3
+#define SYSCFG0_SGMII_SEL_M (0x3 << 8)
+#define SYSCFG0_SGMII_SEL(gmac) ((!(gmac)) ? BIT(9) : BIT(8))
#define ETHSYS_CLKCFG0_REG 0x2c
#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
@@ -30,6 +32,19 @@
#define GE_MODE_MII_PHY 2
#define GE_MODE_RMII 3
+/* SGMII subsystem config registers */
+#define SGMSYS_PCS_CONTROL_1 0x0
+#define SGMII_AN_ENABLE BIT(12)
+
+#define SGMSYS_SGMII_MODE 0x20
+#define SGMII_FORCE_MODE 0x31120019
+
+#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
+#define SGMII_PHYA_PWD BIT(4)
+
+#define SGMSYS_GEN2_SPEED 0x2028
+#define SGMSYS_SPEED_2500 BIT(2)
+
/* Frame Engine Registers */
/* PDMA */
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
index 93ec9cfdb6..105ce94c71 100644
--- a/drivers/reset/reset-socfpga.c
+++ b/drivers/reset/reset-socfpga.c
@@ -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)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index cd2e098883..90e3983170 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -553,6 +553,13 @@ config COREBOOT_SERIAL
a serial console on any platform without needing to change the
device tree, etc.
+config CORTINA_UART
+ bool "Cortina UART support"
+ depends on DM_SERIAL
+ help
+ Select this to enable UART support for Cortina-Access UART devices
+ found on CAxxxx SoCs.
+
config FSL_LINFLEXUART
bool "Freescale Linflex UART support"
depends on DM_SERIAL
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 76b1811510..e26b64494e 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_ARM_DCC) += arm_dcc.o
obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o
obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o
+obj-$(CONFIG_CORTINA_UART) += serial_cortina.o
obj-$(CONFIG_EFI_APP) += serial_efi.o
obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
obj-$(CONFIG_MCFUART) += mcfuart.o
diff --git a/drivers/serial/serial_cortina.c b/drivers/serial/serial_cortina.c
new file mode 100644
index 0000000000..4f227bfe0a
--- /dev/null
+++ b/drivers/serial/serial_cortina.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2020 Cortina-Access Ltd.
+ * Common UART Driver for Cortina Access CAxxxx line of SoCs
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <watchdog.h>
+#include <asm/io.h>
+#include <serial.h>
+#include <linux/compiler.h>
+
+/* Register definitions */
+#define UCFG 0x00 /* UART config register */
+#define UFC 0x04 /* Flow Control */
+#define URX_SAMPLE 0x08 /* UART RX Sample register */
+#define URT_TUNE 0x0C /* Fine tune of UART clk */
+#define UTX_DATA 0x10 /* UART TX Character data */
+#define URX_DATA 0x14 /* UART RX Character data */
+#define UINFO 0x18 /* UART Info */
+#define UINT_EN0 0x1C /* UART Interrupt enable 0 */
+#define UINT_EN1 0x20 /* UART Interrupt enable 1 */
+#define UINT0 0x24 /* UART Interrupt 0 setting/clearing */
+#define UINT1 0x28 /* UART Interrupt 1 setting/clearing */
+#define UINT_STAT 0x2C /* UART Interrupt Status */
+
+/* UART Control Register Bit Fields */
+#define UCFG_BAUD_COUNT_MASK 0xFFFFFF00
+#define UCFG_BAUD_COUNT(x) ((x << 8) & UCFG_BAUD_COUNT_MASK)
+#define UCFG_EN BIT(7)
+#define UCFG_RX_EN BIT(6)
+#define UCFG_TX_EN BIT(5)
+#define UCFG_PARITY_EN BIT(4)
+#define UCFG_PARITY_SEL BIT(3)
+#define UCFG_2STOP_BIT BIT(2)
+#define UCFG_CNT1 BIT(1)
+#define UCFG_CNT0 BIT(0)
+#define UCFG_CHAR_5 0
+#define UCFG_CHAR_6 1
+#define UCFG_CHAR_7 2
+#define UCFG_CHAR_8 3
+
+#define UINFO_TX_FIFO_EMPTY BIT(3)
+#define UINFO_TX_FIFO_FULL BIT(2)
+#define UINFO_RX_FIFO_EMPTY BIT(1)
+#define UINFO_RX_FIFO_FULL BIT(0)
+
+#define UINT_RX_NON_EMPTY BIT(6)
+#define UINT_TX_EMPTY BIT(5)
+#define UINT_RX_UNDERRUN BIT(4)
+#define UINT_RX_OVERRUN BIT(3)
+#define UINT_RX_PARITY_ERR BIT(2)
+#define UINT_RX_STOP_ERR BIT(1)
+#define UINT_TX_OVERRUN BIT(0)
+#define UINT_MASK_ALL 0x7F
+
+struct ca_uart_priv {
+ void __iomem *base;
+};
+
+int ca_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct ca_uart_priv *priv = dev_get_priv(dev);
+ unsigned int uart_ctrl, baud, sample;
+
+ baud = CORTINA_UART_CLOCK / baudrate;
+
+ uart_ctrl = readl(priv->base + UCFG);
+ uart_ctrl &= ~UCFG_BAUD_COUNT_MASK;
+ uart_ctrl |= UCFG_BAUD_COUNT(baud);
+ writel(uart_ctrl, priv->base + UCFG);
+
+ sample = baud / 2;
+ sample = (sample < 7) ? 7 : sample;
+ writel(sample, priv->base + URX_SAMPLE);
+
+ return 0;
+}
+
+static int ca_serial_getc(struct udevice *dev)
+{
+ struct ca_uart_priv *priv = dev_get_priv(dev);
+ int ch;
+
+ ch = readl(priv->base + URX_DATA) & 0xFF;
+
+ return (int)ch;
+}
+
+static int ca_serial_putc(struct udevice *dev, const char ch)
+{
+ struct ca_uart_priv *priv = dev_get_priv(dev);
+ unsigned int status;
+
+ /* Retry if TX FIFO full */
+ status = readl(priv->base + UINFO);
+ if (status & UINFO_TX_FIFO_FULL)
+ return -EAGAIN;
+
+ writel(ch, priv->base + UTX_DATA);
+
+ return 0;
+}
+
+static int ca_serial_pending(struct udevice *dev, bool input)
+{
+ struct ca_uart_priv *priv = dev_get_priv(dev);
+ unsigned int status;
+
+ status = readl(priv->base + UINFO);
+
+ if (input)
+ return (status & UINFO_RX_FIFO_EMPTY) ? 0 : 1;
+ else
+ return (status & UINFO_TX_FIFO_FULL) ? 1 : 0;
+}
+
+static int ca_serial_probe(struct udevice *dev)
+{
+ struct ca_uart_priv *priv = dev_get_priv(dev);
+ u32 uart_ctrl;
+
+ /* Set data, parity and stop bits */
+ uart_ctrl = UCFG_EN | UCFG_TX_EN | UCFG_RX_EN | UCFG_CHAR_8;
+ writel(uart_ctrl, priv->base + UCFG);
+
+ return 0;
+}
+
+static int ca_serial_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ca_uart_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_remap_addr_index(dev, 0);
+ if (!priv->base)
+ return -ENOENT;
+
+ return 0;
+}
+
+static const struct dm_serial_ops ca_serial_ops = {
+ .putc = ca_serial_putc,
+ .pending = ca_serial_pending,
+ .getc = ca_serial_getc,
+ .setbrg = ca_serial_setbrg,
+};
+
+static const struct udevice_id ca_serial_ids[] = {
+ {.compatible = "cortina,ca-uart"},
+ {}
+};
+
+U_BOOT_DRIVER(serial_cortina) = {
+ .name = "serial_cortina",
+ .id = UCLASS_SERIAL,
+ .of_match = ca_serial_ids,
+ .ofdata_to_platdata = ca_serial_ofdata_to_platdata,
+ .priv_auto_alloc_size = sizeof(struct ca_uart_priv),
+ .probe = ca_serial_probe,
+ .ops = &ca_serial_ops
+};
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 2b8064dfae..36fbdce552 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -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
@@ -100,6 +107,14 @@ config WDT_CDNS
Select this to enable Cadence watchdog timer, which can be found on some
Xilinx Microzed Platform.
+config WDT_CORTINA
+ bool "Cortina Access CAxxxx watchdog timer support"
+ depends on WDT
+ help
+ Cortina Access CAxxxx watchdog timer support.
+ This driver support all CPU ISAs supported by Cortina
+ Access CAxxxx SoCs.
+
config WDT_MPC8xx
bool "MPC8xx watchdog timer support"
depends on WDT && MPC8xx
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 955caef815..87f92a43b1 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o
+obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
obj-$(CONFIG_WDT_ORION) += orion_wdt.o
obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
diff --git a/drivers/watchdog/cortina_wdt.c b/drivers/watchdog/cortina_wdt.c
new file mode 100644
index 0000000000..7ab9d7b2db
--- /dev/null
+++ b/drivers/watchdog/cortina_wdt.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Cortina-Access
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <hang.h>
+#include <asm/io.h>
+#include <wdt.h>
+#include <linux/bitops.h>
+
+#define CA_WDT_CTRL 0x00
+#define CA_WDT_PS 0x04
+#define CA_WDT_DIV 0x08
+#define CA_WDT_LD 0x0C
+#define CA_WDT_LOADE 0x10
+#define CA_WDT_CNT 0x14
+#define CA_WDT_IE 0x18
+#define CA_WDT_INT 0x1C
+#define CA_WDT_STAT 0x20
+
+/* CA_WDT_CTRL */
+#define CTL_WDT_EN BIT(0)
+#define CTL_WDT_RSTEN BIT(1)
+#define CTL_WDT_CLK_SEL BIT(2)
+/* CA_WDT_LOADE */
+#define WDT_UPD BIT(0)
+#define WDT_UPD_PS BIT(1)
+
+/* Global config */
+#define WDT_RESET_SUB BIT(4)
+#define WDT_RESET_ALL_BLOCK BIT(6)
+#define WDT_RESET_REMAP BIT(7)
+#define WDT_EXT_RESET BIT(8)
+#define WDT_RESET_DEFAULT (WDT_EXT_RESET | WDT_RESET_REMAP | \
+ WDT_RESET_ALL_BLOCK | WDT_RESET_SUB)
+
+struct ca_wdt_priv {
+ void __iomem *base;
+ void __iomem *global_config;
+};
+
+static void cortina_wdt_set_timeout(struct udevice *dev, u64 timeout_ms)
+{
+ struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+ /* Prescale using millisecond unit */
+ writel(CORTINA_PER_IO_FREQ / 1000, priv->base + CA_WDT_PS);
+
+ /* Millisecond */
+ writel(1, priv->base + CA_WDT_DIV);
+
+ writel(timeout_ms, priv->base + CA_WDT_LD);
+ writel(WDT_UPD | WDT_UPD_PS, priv->base + CA_WDT_LOADE);
+}
+
+static int cortina_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+ struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+ cortina_wdt_set_timeout(dev, timeout);
+
+ /* WDT Reset option */
+ setbits_32(priv->global_config, WDT_RESET_DEFAULT);
+
+ /* Enable WDT */
+ setbits_32(priv->base, CTL_WDT_EN | CTL_WDT_RSTEN | CTL_WDT_CLK_SEL);
+
+ return 0;
+}
+
+static int cortina_wdt_stop(struct udevice *dev)
+{
+ struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+ /* Disable WDT */
+ writel(0, priv->base);
+
+ return 0;
+}
+
+static int cortina_wdt_reset(struct udevice *dev)
+{
+ struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+ /* Reload WDT counter */
+ writel(WDT_UPD, priv->base + CA_WDT_LOADE);
+
+ return 0;
+}
+
+static int cortina_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+ /* Set 1ms timeout to reset system */
+ cortina_wdt_set_timeout(dev, 1);
+ hang();
+
+ return 0;
+}
+
+static int cortina_wdt_probe(struct udevice *dev)
+{
+ struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+ priv->base = dev_remap_addr_index(dev, 0);
+ if (!priv->base)
+ return -ENOENT;
+
+ priv->global_config = dev_remap_addr_index(dev, 1);
+ if (!priv->global_config)
+ return -ENOENT;
+
+ /* Stop WDT */
+ cortina_wdt_stop(dev);
+
+ return 0;
+}
+
+static const struct wdt_ops cortina_wdt_ops = {
+ .start = cortina_wdt_start,
+ .reset = cortina_wdt_reset,
+ .stop = cortina_wdt_stop,
+ .expire_now = cortina_wdt_expire_now,
+};
+
+static const struct udevice_id cortina_wdt_ids[] = {
+ {.compatible = "cortina,ca-wdt"},
+ {}
+};
+
+U_BOOT_DRIVER(cortina_wdt) = {
+ .name = "cortina_wdt",
+ .id = UCLASS_WDT,
+ .probe = cortina_wdt_probe,
+ .of_match = cortina_wdt_ids,
+ .ops = &cortina_wdt_ops,
+};
diff --git a/drivers/watchdog/designware_wdt.c b/drivers/watchdog/designware_wdt.c
index c668567c66..1024a04596 100644
--- a/drivers/watchdog/designware_wdt.c
+++ b/drivers/watchdog/designware_wdt.c
@@ -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)
-void hw_watchdog_reset(void)
+static void designware_wdt_reset_common(void __iomem *base)
{
- if (designware_wdt_is_enabled())
+ if (designware_wdt_is_enabled(base))
/* restart the watchdog counter */
- writel(DW_WDT_CRR_RESTART_VAL,
- (CONFIG_DW_WDT_BASE + DW_WDT_CRR));
+ writel(DW_WDT_CRR_RESTART_VAL, base + DW_WDT_CRR);
+}
+
+#if !CONFIG_IS_ENABLED(WDT)
+void hw_watchdog_reset(void)
+{
+ 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