diff options
author | Tom Rini <trini@konsulko.com> | 2019-04-21 18:59:30 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-04-21 18:59:30 -0400 |
commit | b4fde1633e67bb618fd33aad6e6322b7cecf1154 (patch) | |
tree | d427acfe3e80e6614a6b9312cb91892dd3dfd8ac /drivers | |
parent | 1f4ae66eaab29bfb5d1eb44996f7826c9cd01ed1 (diff) | |
parent | e09c1a133155724d3369e150f3ab7b63c875101c (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-socfpga
- Various stratix10, gen5 updates
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ddr/altera/Kconfig | 2 | ||||
-rw-r--r-- | drivers/ddr/altera/sdram_gen5.c | 143 | ||||
-rw-r--r-- | drivers/ddr/altera/sdram_s10.c | 136 | ||||
-rw-r--r-- | drivers/ddr/altera/sequencer.c | 9 | ||||
-rw-r--r-- | drivers/ddr/altera/sequencer.h | 35 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/denali.h | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/raw/denali_dt.c | 15 | ||||
-rw-r--r-- | drivers/reset/reset-socfpga.c | 55 | ||||
-rw-r--r-- | drivers/spi/cadence_qspi.c | 17 | ||||
-rw-r--r-- | drivers/spi/cadence_qspi.h | 4 | ||||
-rw-r--r-- | drivers/timer/dw-apb-timer.c | 2 |
11 files changed, 396 insertions, 24 deletions
diff --git a/drivers/ddr/altera/Kconfig b/drivers/ddr/altera/Kconfig index 2b28a97f6e..8f60b56eb8 100644 --- a/drivers/ddr/altera/Kconfig +++ b/drivers/ddr/altera/Kconfig @@ -1,5 +1,7 @@ config ALTERA_SDRAM bool "SoCFPGA DDR SDRAM driver" depends on TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10 + select RAM if TARGET_SOCFPGA_GEN5 + select SPL_RAM if TARGET_SOCFPGA_GEN5 help Enable DDR SDRAM controller for the SoCFPGA devices. diff --git a/drivers/ddr/altera/sdram_gen5.c b/drivers/ddr/altera/sdram_gen5.c index 821060459c..fcd89b619d 100644 --- a/drivers/ddr/altera/sdram_gen5.c +++ b/drivers/ddr/altera/sdram_gen5.c @@ -3,14 +3,30 @@ * Copyright Altera Corporation (C) 2014-2015 */ #include <common.h> +#include <dm.h> #include <errno.h> #include <div64.h> +#include <ram.h> +#include <reset.h> #include <watchdog.h> #include <asm/arch/fpga_manager.h> +#include <asm/arch/reset_manager.h> #include <asm/arch/sdram.h> #include <asm/arch/system_manager.h> #include <asm/io.h> +#include "sequencer.h" + +#ifdef CONFIG_SPL_BUILD + +struct altera_gen5_sdram_priv { + struct ram_info info; +}; + +struct altera_gen5_sdram_platdata { + struct socfpga_sdr *sdr; +}; + struct sdram_prot_rule { u32 sdram_start; /* SDRAM start address */ u32 sdram_end; /* SDRAM end address */ @@ -26,8 +42,8 @@ struct sdram_prot_rule { static struct socfpga_system_manager *sysmgr_regs = (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; -static struct socfpga_sdr_ctrl *sdr_ctrl = - (struct socfpga_sdr_ctrl *)SDR_CTRLGRP_ADDRESS; + +static unsigned long sdram_calculate_size(struct socfpga_sdr_ctrl *sdr_ctrl); /** * get_errata_rows() - Up the number of DRAM rows to cover entire address space @@ -104,7 +120,8 @@ static int get_errata_rows(const struct socfpga_sdram_config *cfg) } /* SDRAM protection rules vary from 0-19, a total of 20 rules. */ -static void sdram_set_rule(struct sdram_prot_rule *prule) +static void sdram_set_rule(struct socfpga_sdr_ctrl *sdr_ctrl, + struct sdram_prot_rule *prule) { u32 lo_addr_bits; u32 hi_addr_bits; @@ -141,7 +158,8 @@ static void sdram_set_rule(struct sdram_prot_rule *prule) writel(0, &sdr_ctrl->prot_rule_rdwr); } -static void sdram_get_rule(struct sdram_prot_rule *prule) +static void sdram_get_rule(struct socfpga_sdr_ctrl *sdr_ctrl, + struct sdram_prot_rule *prule) { u32 addr; u32 id; @@ -172,7 +190,8 @@ static void sdram_get_rule(struct sdram_prot_rule *prule) } static void -sdram_set_protection_config(const u32 sdram_start, const u32 sdram_end) +sdram_set_protection_config(struct socfpga_sdr_ctrl *sdr_ctrl, + const u32 sdram_start, const u32 sdram_end) { struct sdram_prot_rule rule; int rules; @@ -185,7 +204,7 @@ sdram_set_protection_config(const u32 sdram_start, const u32 sdram_end) for (rules = 0; rules < 20; rules++) { rule.rule = rules; - sdram_set_rule(&rule); + sdram_set_rule(sdr_ctrl, &rule); } /* new rule: accept SDRAM */ @@ -200,13 +219,13 @@ sdram_set_protection_config(const u32 sdram_start, const u32 sdram_end) rule.rule = 0; /* set new rule */ - sdram_set_rule(&rule); + sdram_set_rule(sdr_ctrl, &rule); /* default rule: reject everything */ writel(0x3ff, &sdr_ctrl->protport_default); } -static void sdram_dump_protection_config(void) +static void sdram_dump_protection_config(struct socfpga_sdr_ctrl *sdr_ctrl) { struct sdram_prot_rule rule; int rules; @@ -216,7 +235,7 @@ static void sdram_dump_protection_config(void) for (rules = 0; rules < 20; rules++) { rule.rule = rules; - sdram_get_rule(&rule); + sdram_get_rule(sdr_ctrl, &rule); debug("Rule %d, rules ...\n", rules); debug(" sdram start %x\n", rule.sdram_start); debug(" sdram end %x\n", rule.sdram_end); @@ -322,7 +341,8 @@ static u32 sdr_get_addr_rw(const struct socfpga_sdram_config *cfg) * * This function loads the register values into the SDRAM controller block. */ -static void sdr_load_regs(const struct socfpga_sdram_config *cfg) +static void sdr_load_regs(struct socfpga_sdr_ctrl *sdr_ctrl, + const struct socfpga_sdram_config *cfg) { const u32 ctrl_cfg = sdr_get_ctrlcfg(cfg); const u32 dram_addrw = sdr_get_addr_rw(cfg); @@ -426,7 +446,8 @@ static void sdr_load_regs(const struct socfpga_sdram_config *cfg) * * Initialize the SDRAM MMR. */ -int sdram_mmr_init_full(unsigned int sdr_phy_reg) +int sdram_mmr_init_full(struct socfpga_sdr_ctrl *sdr_ctrl, + unsigned int sdr_phy_reg) { const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config(); const unsigned int rows = @@ -436,7 +457,7 @@ int sdram_mmr_init_full(unsigned int sdr_phy_reg) writel(rows, &sysmgr_regs->iswgrp_handoff[4]); - sdr_load_regs(cfg); + sdr_load_regs(sdr_ctrl, cfg); /* saving this value to SYSMGR.ISWGRP.HANDOFF.FPGA2SDR */ writel(cfg->fpgaport_rst, &sysmgr_regs->iswgrp_handoff[3]); @@ -459,9 +480,10 @@ int sdram_mmr_init_full(unsigned int sdr_phy_reg) SDR_CTRLGRP_STATICCFG_APPLYCFG_MASK, 1 << SDR_CTRLGRP_STATICCFG_APPLYCFG_LSB); - sdram_set_protection_config(0, sdram_calculate_size() - 1); + sdram_set_protection_config(sdr_ctrl, 0, + sdram_calculate_size(sdr_ctrl) - 1); - sdram_dump_protection_config(); + sdram_dump_protection_config(sdr_ctrl); return 0; } @@ -472,7 +494,7 @@ int sdram_mmr_init_full(unsigned int sdr_phy_reg) * Calculate SDRAM device size based on SDRAM controller parameters. * Size is specified in bytes. */ -unsigned long sdram_calculate_size(void) +static unsigned long sdram_calculate_size(struct socfpga_sdr_ctrl *sdr_ctrl) { unsigned long temp; unsigned long row, bank, col, cs, width; @@ -534,3 +556,94 @@ unsigned long sdram_calculate_size(void) return temp; } + +static int altera_gen5_sdram_ofdata_to_platdata(struct udevice *dev) +{ + struct altera_gen5_sdram_platdata *plat = dev->platdata; + + plat->sdr = (struct socfpga_sdr *)devfdt_get_addr_index(dev, 0); + if (!plat->sdr) + return -ENODEV; + + return 0; +} + +static int altera_gen5_sdram_probe(struct udevice *dev) +{ + int ret; + unsigned long sdram_size; + struct altera_gen5_sdram_platdata *plat = dev->platdata; + struct altera_gen5_sdram_priv *priv = dev_get_priv(dev); + struct socfpga_sdr_ctrl *sdr_ctrl = &plat->sdr->sdr_ctrl; + struct reset_ctl_bulk resets; + + ret = reset_get_bulk(dev, &resets); + if (ret) { + dev_err(dev, "Can't get reset: %d\n", ret); + return -ENODEV; + } + reset_deassert_bulk(&resets); + + if (sdram_mmr_init_full(sdr_ctrl, 0xffffffff) != 0) { + puts("SDRAM init failed.\n"); + goto failed; + } + + debug("SDRAM: Calibrating PHY\n"); + /* SDRAM calibration */ + if (sdram_calibration_full(plat->sdr) == 0) { + puts("SDRAM calibration failed.\n"); + goto failed; + } + + sdram_size = sdram_calculate_size(sdr_ctrl); + debug("SDRAM: %ld MiB\n", sdram_size >> 20); + + /* Sanity check ensure correct SDRAM size specified */ + if (get_ram_size(0, sdram_size) != sdram_size) { + puts("SDRAM size check failed!\n"); + goto failed; + } + + priv->info.base = 0; + priv->info.size = sdram_size; + + return 0; + +failed: + reset_release_bulk(&resets); + return -ENODEV; +} + +static int altera_gen5_sdram_get_info(struct udevice *dev, + struct ram_info *info) +{ + struct altera_gen5_sdram_priv *priv = dev_get_priv(dev); + + info->base = priv->info.base; + info->size = priv->info.size; + + return 0; +} + +static struct ram_ops altera_gen5_sdram_ops = { + .get_info = altera_gen5_sdram_get_info, +}; + +static const struct udevice_id altera_gen5_sdram_ids[] = { + { .compatible = "altr,sdr-ctl" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(altera_gen5_sdram) = { + .name = "altr_sdr_ctl", + .id = UCLASS_RAM, + .of_match = altera_gen5_sdram_ids, + .ops = &altera_gen5_sdram_ops, + .ofdata_to_platdata = altera_gen5_sdram_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct altera_gen5_sdram_platdata), + .probe = altera_gen5_sdram_probe, + .priv_auto_alloc_size = sizeof(struct altera_gen5_sdram_priv), +}; + +#endif /* CONFIG_SPL_BUILD */ diff --git a/drivers/ddr/altera/sdram_s10.c b/drivers/ddr/altera/sdram_s10.c index a48567c109..e4d4a02ca2 100644 --- a/drivers/ddr/altera/sdram_s10.c +++ b/drivers/ddr/altera/sdram_s10.c @@ -7,12 +7,14 @@ #include <common.h> #include <errno.h> #include <div64.h> +#include <fdtdec.h> #include <asm/io.h> #include <wait_bit.h> #include <asm/arch/firewall_s10.h> #include <asm/arch/sdram_s10.h> #include <asm/arch/system_manager.h> #include <asm/arch/reset_manager.h> +#include <linux/sizes.h> DECLARE_GLOBAL_DATA_PTR; @@ -21,6 +23,8 @@ static const struct socfpga_system_manager *sysmgr_regs = #define DDR_CONFIG(A, B, C, R) (((A) << 24) | ((B) << 16) | ((C) << 8) | (R)) +#define PGTABLE_OFF 0x4000 + /* The followring are the supported configurations */ u32 ddr_config[] = { /* DDR_CONFIG(Address order,Bank,Column,Row) */ @@ -134,6 +138,108 @@ static int poll_hmc_clock_status(void) SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false); } +static void sdram_clear_mem(phys_addr_t addr, phys_size_t size) +{ + phys_size_t i; + + if (addr % CONFIG_SYS_CACHELINE_SIZE) { + printf("DDR: address 0x%llx is not cacheline size aligned.\n", + addr); + hang(); + } + + if (size % CONFIG_SYS_CACHELINE_SIZE) { + printf("DDR: size 0x%llx is not multiple of cacheline size\n", + size); + hang(); + } + + /* Use DC ZVA instruction to clear memory to zeros by a cache line */ + for (i = 0; i < size; i = i + CONFIG_SYS_CACHELINE_SIZE) { + asm volatile("dc zva, %0" + : + : "r"(addr) + : "memory"); + addr += CONFIG_SYS_CACHELINE_SIZE; + } +} + +static void sdram_init_ecc_bits(bd_t *bd) +{ + phys_size_t size, size_init; + phys_addr_t start_addr; + int bank = 0; + unsigned int start = get_timer(0); + + icache_enable(); + + start_addr = bd->bi_dram[0].start; + size = bd->bi_dram[0].size; + + /* Initialize small block for page table */ + memset((void *)start_addr, 0, PGTABLE_SIZE + PGTABLE_OFF); + gd->arch.tlb_addr = start_addr + PGTABLE_OFF; + gd->arch.tlb_size = PGTABLE_SIZE; + start_addr += PGTABLE_SIZE + PGTABLE_OFF; + size -= (PGTABLE_OFF + PGTABLE_SIZE); + dcache_enable(); + + while (1) { + while (size) { + size_init = min((phys_addr_t)SZ_1G, (phys_addr_t)size); + sdram_clear_mem(start_addr, size_init); + size -= size_init; + start_addr += size_init; + WATCHDOG_RESET(); + } + + bank++; + if (bank >= CONFIG_NR_DRAM_BANKS) + break; + + start_addr = bd->bi_dram[bank].start; + size = bd->bi_dram[bank].size; + } + + dcache_disable(); + icache_disable(); + + printf("SDRAM-ECC: Initialized success with %d ms\n", + (unsigned int)get_timer(start)); +} + +static void sdram_size_check(bd_t *bd) +{ + phys_size_t total_ram_check = 0; + phys_size_t ram_check = 0; + phys_addr_t start = 0; + int bank; + + /* Sanity check ensure correct SDRAM size specified */ + debug("DDR: Running SDRAM size sanity check\n"); + + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { + start = bd->bi_dram[bank].start; + while (ram_check < bd->bi_dram[bank].size) { + ram_check += get_ram_size((void *)(start + ram_check), + (phys_size_t)SZ_1G); + } + total_ram_check += ram_check; + ram_check = 0; + } + + /* If the ram_size is 2GB smaller, we can assume the IO space is + * not mapped in. gd->ram_size is the actual size of the dram + * not the accessible size. + */ + if (total_ram_check != gd->ram_size) { + puts("DDR: SDRAM size check failed!\n"); + hang(); + } + + debug("DDR: SDRAM size check passed!\n"); +} + /** * sdram_mmr_init_full() - Function to initialize SDRAM MMR * @@ -144,6 +250,8 @@ int sdram_mmr_init_full(unsigned int unused) u32 update_value, io48_value, ddrioctl; u32 i; int ret; + phys_size_t hw_size; + bd_t bd = {0}; /* Enable access to DDR from CPU master */ clrbits_le32(CCU_REG_ADDR(CCU_CPU0_MPRT_ADBASE_DDRREG), @@ -335,9 +443,22 @@ int sdram_mmr_init_full(unsigned int unused) unsigned long long size = sdram_calculate_size(); /* If the size is invalid, use default Config size */ if (size <= 0) - gd->ram_size = PHYS_SDRAM_1_SIZE; + hw_size = PHYS_SDRAM_1_SIZE; else - gd->ram_size = size; + hw_size = size; + + /* Get bank configuration from devicetree */ + ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL, + (phys_size_t *)&gd->ram_size, &bd); + if (ret) { + puts("DDR: Failed to decode memory node\n"); + return -1; + } + + if (gd->ram_size != hw_size) + printf("DDR: Warning: DRAM size from device tree mismatch with hardware.\n"); + + printf("DDR: %lld MiB\n", gd->ram_size >> 20); /* Enable or disable the SDRAM ECC */ if (CTRLCFG1_CFG_CTRL_EN_ECC(ctrlcfg1)) { @@ -351,6 +472,15 @@ int sdram_mmr_init_full(unsigned int unused) setbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL2, (DDR_HMC_ECCCTL2_RMW_EN_SET_MSK | DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); + writel(DDR_HMC_ERRINTEN_INTMASK, + SOCFPGA_SDR_ADDRESS + ERRINTENS); + + /* Enable non-secure writes to HMC Adapter for SDRAM ECC */ + writel(FW_HMC_ADAPTOR_MPU_MASK, FW_HMC_ADAPTOR_REG_ADDR); + + /* Initialize memory content if not from warm reset */ + if (!cpu_has_been_warmreset()) + sdram_init_ecc_bits(&bd); } else { clrbits_le32(SOCFPGA_SDR_ADDRESS + ECCCTRL1, (DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK | @@ -361,6 +491,8 @@ int sdram_mmr_init_full(unsigned int unused) DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); } + sdram_size_check(&bd); + debug("DDR: HMC init success\n"); return 0; } diff --git a/drivers/ddr/altera/sequencer.c b/drivers/ddr/altera/sequencer.c index 5e7a943b68..0e4526288e 100644 --- a/drivers/ddr/altera/sequencer.c +++ b/drivers/ddr/altera/sequencer.c @@ -3705,12 +3705,19 @@ static void initialize_tracking(void) &sdr_reg_file->trk_rfsh); } -int sdram_calibration_full(void) +int sdram_calibration_full(struct socfpga_sdr *sdr) { struct param_type my_param; struct gbl_type my_gbl; u32 pass; + /* + * For size reasons, this file uses hard coded addresses. + * Check if we are called with the correct address. + */ + if (sdr != (struct socfpga_sdr *)SOCFPGA_SDR_ADDRESS) + return -ENODEV; + memset(&my_param, 0, sizeof(my_param)); memset(&my_gbl, 0, sizeof(my_gbl)); diff --git a/drivers/ddr/altera/sequencer.h b/drivers/ddr/altera/sequencer.h index a5760b03a5..d7f6935201 100644 --- a/drivers/ddr/altera/sequencer.h +++ b/drivers/ddr/altera/sequencer.h @@ -223,4 +223,39 @@ struct socfpga_data_mgr { u32 mem_t_add; u32 t_rl_add; }; + +/* This struct describes the controller @ SOCFPGA_SDR_ADDRESS */ +struct socfpga_sdr { + /* SDR_PHYGRP_SCCGRP_ADDRESS */ + u8 _align1[0xe00]; + /* SDR_PHYGRP_SCCGRP_ADDRESS | 0xe00 */ + struct socfpga_sdr_scc_mgr sdr_scc_mgr; + u8 _align2[0x1bc]; + /* SDR_PHYGRP_PHYMGRGRP_ADDRESS */ + struct socfpga_phy_mgr_cmd phy_mgr_cmd; + u8 _align3[0x2c]; + /* SDR_PHYGRP_PHYMGRGRP_ADDRESS | 0x40 */ + struct socfpga_phy_mgr_cfg phy_mgr_cfg; + u8 _align4[0xfa0]; + /* SDR_PHYGRP_RWMGRGRP_ADDRESS */ + u8 rwmgr_grp[0x800]; + /* SDR_PHYGRP_RWMGRGRP_ADDRESS | 0x800 */ + struct socfpga_sdr_rw_load_manager sdr_rw_load_mgr_regs; + u8 _align5[0x3f0]; + /* SDR_PHYGRP_RWMGRGRP_ADDRESS | 0xC00 */ + struct socfpga_sdr_rw_load_jump_manager sdr_rw_load_jump_mgr_regs; + u8 _align6[0x13f0]; + /* SDR_PHYGRP_DATAMGRGRP_ADDRESS */ + struct socfpga_data_mgr data_mgr; + u8 _align7[0x7f0]; + /* SDR_PHYGRP_REGFILEGRP_ADDRESS */ + struct socfpga_sdr_reg_file sdr_reg_file; + u8 _align8[0x7c8]; + /* SDR_CTRLGRP_ADDRESS */ + struct socfpga_sdr_ctrl sdr_ctrl; + u8 _align9[0xea4]; +}; + +int sdram_calibration_full(struct socfpga_sdr *sdr); + #endif /* _SEQUENCER_H_ */ diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h index 019deda094..63ae828768 100644 --- a/drivers/mtd/nand/raw/denali.h +++ b/drivers/mtd/nand/raw/denali.h @@ -10,6 +10,7 @@ #include <linux/bitops.h> #include <linux/mtd/rawnand.h> #include <linux/types.h> +#include <reset.h> #define DEVICE_RESET 0x0 #define DEVICE_RESET__BANK(bank) BIT(bank) @@ -315,6 +316,7 @@ struct denali_nand_info { void (*host_write)(struct denali_nand_info *denali, u32 addr, u32 data); void (*setup_dma)(struct denali_nand_info *denali, dma_addr_t dma_addr, int page, int write); + struct reset_ctl_bulk resets; }; #define DENALI_CAP_HW_ECC_FIXUP BIT(0) diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c index d384b974df..0ce81324b9 100644 --- a/drivers/mtd/nand/raw/denali_dt.c +++ b/drivers/mtd/nand/raw/denali_dt.c @@ -131,15 +131,30 @@ static int denali_dt_probe(struct udevice *dev) denali->clk_x_rate = 200000000; } + ret = reset_get_bulk(dev, &denali->resets); + if (ret) + dev_warn(dev, "Can't get reset: %d\n", ret); + else + reset_deassert_bulk(&denali->resets); + return denali_init(denali); } +static int denali_dt_remove(struct udevice *dev) +{ + struct denali_nand_info *denali = dev_get_priv(dev); + + return reset_release_bulk(&denali->resets); +} + U_BOOT_DRIVER(denali_nand_dt) = { .name = "denali-nand-dt", .id = UCLASS_MISC, .of_match = denali_nand_dt_ids, .probe = denali_dt_probe, .priv_auto_alloc_size = sizeof(struct denali_nand_info), + .remove = denali_dt_remove, + .flags = DM_FLAG_OS_PREPARE, }; void board_nand_init(void) diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index b2acfcd2ec..cb8312619f 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -24,9 +24,39 @@ #define NR_BANKS 8 struct socfpga_reset_data { - void __iomem *membase; + void __iomem *modrst_base; }; +/* + * For compatibility with Kernels that don't support peripheral reset, this + * driver can keep the old behaviour of not asserting peripheral reset before + * starting the OS and deasserting all peripheral resets (enabling all + * peripherals). + * + * For that, the reset driver checks the environment variable + * "socfpga_legacy_reset_compat". If this variable is '1', perihperals are not + * reset again once taken out of reset and all peripherals in 'permodrst' are + * taken out of reset before booting into the OS. + * Note that this should be required for gen5 systems only that are running + * Linux kernels without proper peripheral reset support for all drivers used. + */ +static bool socfpga_reset_keep_enabled(void) +{ +#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(ENV_SUPPORT) + const char *env_str; + long val; + + env_str = env_get("socfpga_legacy_reset_compat"); + if (env_str) { + val = simple_strtol(env_str, NULL, 0); + if (val == 1) + return true; + } +#endif + + return false; +} + static int socfpga_reset_assert(struct reset_ctl *reset_ctl) { struct socfpga_reset_data *data = dev_get_priv(reset_ctl->dev); @@ -35,7 +65,7 @@ static int socfpga_reset_assert(struct reset_ctl *reset_ctl) int bank = id / (reg_width * BITS_PER_BYTE); int offset = id % (reg_width * BITS_PER_BYTE); - setbits_le32(data->membase + (bank * BANK_INCREMENT), BIT(offset)); + setbits_le32(data->modrst_base + (bank * BANK_INCREMENT), BIT(offset)); return 0; } @@ -47,7 +77,7 @@ static int socfpga_reset_deassert(struct reset_ctl *reset_ctl) int bank = id / (reg_width * BITS_PER_BYTE); int offset = id % (reg_width * BITS_PER_BYTE); - clrbits_le32(data->membase + (bank * BANK_INCREMENT), BIT(offset)); + clrbits_le32(data->modrst_base + (bank * BANK_INCREMENT), BIT(offset)); return 0; } @@ -80,11 +110,24 @@ static int socfpga_reset_probe(struct udevice *dev) const void *blob = gd->fdt_blob; int node = dev_of_offset(dev); u32 modrst_offset; + void __iomem *membase; - data->membase = devfdt_get_addr_ptr(dev); + membase = devfdt_get_addr_ptr(dev); modrst_offset = fdtdec_get_int(blob, node, "altr,modrst-offset", 0x10); - data->membase += modrst_offset; + data->modrst_base = membase + modrst_offset; + + return 0; +} + +static int socfpga_reset_remove(struct udevice *dev) +{ + struct socfpga_reset_data *data = dev_get_priv(dev); + + if (socfpga_reset_keep_enabled()) { + puts("Deasserting all peripheral resets\n"); + writel(0, data->modrst_base + 4); + } return 0; } @@ -101,4 +144,6 @@ U_BOOT_DRIVER(socfpga_reset) = { .probe = socfpga_reset_probe, .priv_auto_alloc_size = sizeof(struct socfpga_reset_data), .ops = &socfpga_reset_ops, + .remove = socfpga_reset_remove, + .flags = DM_FLAG_OS_PREPARE, }; diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index efdb178450..41c87004d8 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -8,6 +8,7 @@ #include <dm.h> #include <fdtdec.h> #include <malloc.h> +#include <reset.h> #include <spi.h> #include <linux/errno.h> #include "cadence_qspi.h" @@ -154,10 +155,17 @@ static int cadence_spi_probe(struct udevice *bus) { struct cadence_spi_platdata *plat = bus->platdata; struct cadence_spi_priv *priv = dev_get_priv(bus); + int ret; priv->regbase = plat->regbase; priv->ahbbase = plat->ahbbase; + ret = reset_get_bulk(bus, &priv->resets); + if (ret) + dev_warn(bus, "Can't get reset: %d\n", ret); + else + reset_deassert_bulk(&priv->resets); + if (!priv->qspi_is_init) { cadence_qspi_apb_controller_init(plat); priv->qspi_is_init = 1; @@ -166,6 +174,13 @@ static int cadence_spi_probe(struct udevice *bus) return 0; } +static int cadence_spi_remove(struct udevice *dev) +{ + struct cadence_spi_priv *priv = dev_get_priv(dev); + + return reset_release_bulk(&priv->resets); +} + static int cadence_spi_set_mode(struct udevice *bus, uint mode) { struct cadence_spi_priv *priv = dev_get_priv(bus); @@ -342,4 +357,6 @@ U_BOOT_DRIVER(cadence_spi) = { .platdata_auto_alloc_size = sizeof(struct cadence_spi_platdata), .priv_auto_alloc_size = sizeof(struct cadence_spi_priv), .probe = cadence_spi_probe, + .remove = cadence_spi_remove, + .flags = DM_FLAG_OS_PREPARE, }; diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h index b491407130..20cceca239 100644 --- a/drivers/spi/cadence_qspi.h +++ b/drivers/spi/cadence_qspi.h @@ -7,6 +7,8 @@ #ifndef __CADENCE_QSPI_H__ #define __CADENCE_QSPI_H__ +#include <reset.h> + #define CQSPI_IS_ADDR(cmd_len) (cmd_len > 1 ? 1 : 0) #define CQSPI_NO_DECODER_MAX_CS 4 @@ -42,6 +44,8 @@ struct cadence_spi_priv { unsigned int qspi_calibrated_hz; unsigned int qspi_calibrated_cs; unsigned int previous_hz; + + struct reset_ctl_bulk resets; }; /* Functions call declaration */ diff --git a/drivers/timer/dw-apb-timer.c b/drivers/timer/dw-apb-timer.c index 085bfb02c5..cb48801af1 100644 --- a/drivers/timer/dw-apb-timer.c +++ b/drivers/timer/dw-apb-timer.c @@ -32,7 +32,7 @@ static int dw_apb_timer_get_count(struct udevice *dev, u64 *count) * requires the count to be incrementing. Invert the * result. */ - *count = ~readl(priv->regs + DW_APB_CURR_VAL); + *count = timer_conv_64(~readl(priv->regs + DW_APB_CURR_VAL)); return 0; } |