diff options
author | Tom Rini <trini@konsulko.com> | 2020-02-06 23:18:42 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-02-06 23:18:42 -0500 |
commit | 457faef262c5c9533c344f25eafb10e757149a34 (patch) | |
tree | 9c1b2e777e37d997410b5f4e97b883fa0bb2ad7d /drivers | |
parent | 8a6ffeda97dfda5263ef40e1a4efb25b032ce04c (diff) | |
parent | 9a5a90ad9b3234c4739427cbe11219c51f0e9bd1 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-socfpga
- Gen 5 and Watchdog fixes
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ddr/altera/sdram_gen5.c | 6 | ||||
-rw-r--r-- | drivers/ddr/altera/sequencer.c | 194 | ||||
-rw-r--r-- | drivers/ddr/altera/sequencer.h | 1 | ||||
-rw-r--r-- | drivers/reset/reset-socfpga.c | 6 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 7 | ||||
-rw-r--r-- | drivers/watchdog/designware_wdt.c | 150 |
6 files changed, 301 insertions, 63 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/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/watchdog/Kconfig b/drivers/watchdog/Kconfig index 2b8064dfae..77354ad209 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 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 |