diff options
Diffstat (limited to 'drivers')
50 files changed, 2909 insertions, 567 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index 8eec4e8176c..e7b5d22b1da 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ +obj-$(CONFIG_$(SPL_TPL_)CACHE) += cache/ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk/ obj-$(CONFIG_$(SPL_TPL_)DM) += core/ obj-$(CONFIG_$(SPL_TPL_)DFU) += dfu/ @@ -26,6 +27,7 @@ obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/ obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/ obj-$(CONFIG_$(SPL_TPL_)TPM) += tpm/ obj-$(CONFIG_$(SPL_TPL_)ACPI_PMC) += power/acpi_pmc/ +obj-$(CONFIG_$(SPL_)BOARD) += board/ ifndef CONFIG_TPL_BUILD ifdef CONFIG_SPL_BUILD @@ -75,7 +77,6 @@ obj-y += ata/ obj-$(CONFIG_DM_DEMO) += demo/ obj-$(CONFIG_BIOSEMU) += bios_emulator/ obj-y += block/ -obj-y += board/ obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/ obj-y += cache/ obj-$(CONFIG_CPU) += cpu/ diff --git a/drivers/ata/fsl_sata.c b/drivers/ata/fsl_sata.c index 6609bf8a761..c6680dc1c98 100644 --- a/drivers/ata/fsl_sata.c +++ b/drivers/ata/fsl_sata.c @@ -22,6 +22,7 @@ #include <dm.h> #include <ahci.h> #include <blk.h> +#include <dm/device-internal.h> #else #ifndef CONFIG_SYS_SATA1_FLAGS #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA @@ -122,7 +123,7 @@ static int init_sata(struct fsl_ata_priv *priv, int dev) /* Zero all of the device driver struct */ memset((void *)sata, 0, sizeof(fsl_sata_t)); - snprintf(sata->name, 12, "SATA%d:\n", dev); + snprintf(sata->name, 12, "SATA%d:", dev); /* Set the controller register base address to device struct */ #if !CONFIG_IS_ENABLED(BLK) @@ -233,10 +234,7 @@ static int init_sata(struct fsl_ata_priv *priv, int dev) mdelay(100); /* print sata device name */ - if (!dev) - printf("%s ", sata->name); - else - printf(" %s ", sata->name); + printf("%s ", sata->name); /* Wait PHY RDY signal changed for 500ms */ ata_wait_register(®->hstatus, HSTATUS_PHY_RDY, @@ -917,15 +915,32 @@ static int fsl_ata_ofdata_to_platdata(struct udevice *dev) return 0; } +static int fsl_unbind_device(struct udevice *dev) +{ + int ret; + + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return ret; + + ret = device_unbind(dev); + if (ret) + return ret; + + return 0; +} + static int fsl_ata_probe(struct udevice *dev) { struct fsl_ata_priv *blk_priv, *priv; struct udevice *blk; + int failed_number; char sata_name[10]; int nr_ports; int ret; int i; + failed_number = 0; priv = dev_get_priv(dev); nr_ports = priv->number; nr_ports = min(nr_ports, CONFIG_SYS_SATA_MAX_DEVICE); @@ -943,7 +958,12 @@ static int fsl_ata_probe(struct udevice *dev) ret = init_sata(priv, i); if (ret) { debug("%s: Failed to init sata\n", __func__); - return ret; + ret = fsl_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; } blk_priv = dev_get_platdata(blk); @@ -952,10 +972,33 @@ static int fsl_ata_probe(struct udevice *dev) ret = scan_sata(blk); if (ret) { debug("%s: Failed to scan bus\n", __func__); - return ret; + ret = fsl_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; } } + if (failed_number == nr_ports) + return -ENODEV; + else + return 0; +} + +static int fsl_ata_remove(struct udevice *dev) +{ + fsl_sata_t *sata; + struct fsl_ata_priv *priv; + + priv = dev_get_priv(dev); + sata = priv->fsl_sata; + + free(sata->cmd_hdr_tbl_offset); + free(sata->cmd_desc_offset); + free(sata); + return 0; } @@ -982,6 +1025,7 @@ U_BOOT_DRIVER(fsl_ahci) = { .ops = &sata_fsl_ahci_ops, .ofdata_to_platdata = fsl_ata_ofdata_to_platdata, .probe = fsl_ata_probe, + .remove = fsl_ata_remove, .priv_auto_alloc_size = sizeof(struct fsl_ata_priv), }; #endif diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 4a50460c5ac..71ee0c04efa 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -20,6 +20,7 @@ #if CONFIG_IS_ENABLED(BLK) #include <dm.h> #include <blk.h> +#include <dm/device-internal.h> #endif #include "sata_sil.h" @@ -763,15 +764,33 @@ U_BOOT_DRIVER(sata_sil_driver) = { .platdata_auto_alloc_size = sizeof(struct sil_sata_priv), }; +static int sil_unbind_device(struct udevice *dev) +{ + int ret; + + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return ret; + + ret = device_unbind(dev); + if (ret) + return ret; + + return 0; +} + static int sil_pci_probe(struct udevice *dev) { struct udevice *blk; + int failed_number; char sata_name[10]; pci_dev_t devno; u16 word; int ret; int i; + failed_number = 0; + /* Get PCI device number */ devno = dm_pci_get_bdf(dev); if (devno == -1) @@ -824,12 +843,44 @@ static int sil_pci_probe(struct udevice *dev) } ret = sil_init_sata(blk, i); - if (ret) - return -ENODEV; + if (ret) { + ret = sil_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; + } ret = scan_sata(blk, i); - if (ret) - return -ENODEV; + if (ret) { + ret = sil_unbind_device(blk); + if (ret) + return ret; + + failed_number++; + continue; + } + } + + if (failed_number == sata_info.maxport) + return -ENODEV; + else + return 0; +} + +static int sil_pci_remove(struct udevice *dev) +{ + int i; + struct sil_sata *sata; + struct sil_sata_priv *priv; + + priv = dev_get_priv(dev); + + for (i = sata_info.portbase; i < sata_info.maxport; i++) { + sata = priv->sil_sata_desc[i]; + if (sata) + free(sata); } return 0; @@ -857,6 +908,7 @@ U_BOOT_DRIVER(sil_ahci_pci) = { .of_match = sil_pci_ids, .ops = &sata_sil_ops, .probe = sil_pci_probe, + .remove = sil_pci_remove, .priv_auto_alloc_size = sizeof(struct sil_sata_priv), }; diff --git a/drivers/board/Kconfig b/drivers/board/Kconfig index 2a3fc9c049b..254f657049d 100644 --- a/drivers/board/Kconfig +++ b/drivers/board/Kconfig @@ -8,6 +8,9 @@ menuconfig BOARD if BOARD +config SPL_BOARD + depends on SPL_DM + bool "Enable board driver support in SPL" config BOARD_GAZERBEAM bool "Enable board driver for the Gazerbeam board" diff --git a/drivers/board/Makefile b/drivers/board/Makefile index c8dab4fa0ba..cc16361755a 100644 --- a/drivers/board/Makefile +++ b/drivers/board/Makefile @@ -2,6 +2,6 @@ # # (C) Copyright 2017 # Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc -obj-$(CONFIG_BOARD) += board-uclass.o +obj-y += board-uclass.o obj-$(CONFIG_BOARD_GAZERBEAM) += gazerbeam.o obj-$(CONFIG_BOARD_SANDBOX) += sandbox.o diff --git a/drivers/board/board-uclass.c b/drivers/board/board-uclass.c index a516ba49629..b5485e9895b 100644 --- a/drivers/board/board-uclass.c +++ b/drivers/board/board-uclass.c @@ -23,6 +23,17 @@ int board_detect(struct udevice *dev) return ops->detect(dev); } +int board_get_fit_loadable(struct udevice *dev, int index, + const char *type, const char **strp) +{ + struct board_ops *ops = board_get_ops(dev); + + if (!ops->get_fit_loadable) + return -ENOSYS; + + return ops->get_fit_loadable(dev, index, type, strp); +} + int board_get_bool(struct udevice *dev, int id, bool *val) { struct board_ops *ops = board_get_ops(dev); diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index 629039e7a88..1e452ad6d9f 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -31,4 +31,12 @@ config V5L2_CACHE It will configure tag and data ram timing control from the device tree and enable L2 cache. +config NCORE_CACHE + bool "Arteris Ncore cache coherent unit driver" + select CACHE + help + This driver is for the Arteris Ncore cache coherent unit (CCU) + controller. The driver initializes cache directories and coherent + agent interfaces. + endmenu diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile index 4a6458c6027..fed50be3f98 100644 --- a/drivers/cache/Makefile +++ b/drivers/cache/Makefile @@ -1,5 +1,6 @@ -obj-$(CONFIG_CACHE) += cache-uclass.o +obj-$(CONFIG_$(SPL_TPL_)CACHE) += cache-uclass.o obj-$(CONFIG_SANDBOX) += sandbox_cache.o obj-$(CONFIG_L2X0_CACHE) += cache-l2x0.o +obj-$(CONFIG_NCORE_CACHE) += cache-ncore.o obj-$(CONFIG_V5L2_CACHE) += cache-v5l2.o diff --git a/drivers/cache/cache-ncore.c b/drivers/cache/cache-ncore.c new file mode 100644 index 00000000000..e3aca360713 --- /dev/null +++ b/drivers/cache/cache-ncore.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Intel Corporation <www.intel.com> + * + */ +#include <dm.h> +#include <wait_bit.h> + +#include <asm/io.h> + +/* Directory */ +#define DIRUSFER 0x80010 +#define DIRUCASER0 0x80040 +#define DIRUSFMCR 0x80080 +#define DIRUSFMAR 0x80084 + +#define DIRUSFMCR_SFID_SHIFT 16 + +/* Coherent cache agent interface */ +#define CAIUIDR 0x00ffc + +#define CAIUIDR_CA_GET(v) (((v) & 0x00008000) >> 15) +#define CAIUIDR_TYPE_GET(v) (((v) & 0x000f0000) >> 16) +#define CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT 0 +#define CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT 1 + +/* Coherent subsystem */ +#define CSADSER0 0xff040 +#define CSUIDR 0xffff8 +#define CSIDR 0xffffc + +#define CSUIDR_NUMCAIUS_GET(v) (((v) & 0x0000007f) >> 0) +#define CSUIDR_NUMDIRUS_GET(v) (((v) & 0x003f0000) >> 16) +#define CSUIDR_NUMCMIUS_GET(v) (((v) & 0x3f000000) >> 24) + +#define CSIDR_NUMSFS_GET(v) (((v) & 0x007c0000) >> 18) + +#define DIR_REG_SZ 0x1000 +#define CAIU_REG_SZ 0x1000 + +#define CCU_DIR_REG_ADDR(base, reg, dir) \ + ((base) + (reg) + ((dir) * DIR_REG_SZ)) + +/* OCRAM firewall register */ +#define OCRAM_FW_01 0x100204 +#define OCRAM_SECURE_REGIONS 4 + +#define OCRAM_PRIVILEGED_MASK BIT(29) +#define OCRAM_SECURE_MASK BIT(30) + +static void ncore_ccu_init_dirs(void __iomem *base) +{ + ulong i, f; + int ret; + u32 num_of_dirs; + u32 num_of_snoop_filters; + u32 reg; + + num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR)); + num_of_snoop_filters = + CSIDR_NUMSFS_GET(readl(base + CSIDR)) + 1; + + /* Initialize each snoop filter in each directory */ + for (f = 0; f < num_of_snoop_filters; f++) { + reg = f << DIRUSFMCR_SFID_SHIFT; + for (i = 0; i < num_of_dirs; i++) { + /* Initialize all entries */ + writel(reg, CCU_DIR_REG_ADDR(base, DIRUSFMCR, i)); + + /* Poll snoop filter maintenance operation active + * bit become 0. + */ + ret = wait_for_bit_le32((const void *) + CCU_DIR_REG_ADDR(base, + DIRUSFMAR, i), + BIT(0), false, 1000, false); + if (ret) { + puts("CCU: Directory initialization failed!\n"); + hang(); + } + + /* Enable snoop filter, a bit per snoop filter */ + setbits_le32((ulong)CCU_DIR_REG_ADDR(base, DIRUSFER, i), + BIT(f)); + } + } +} + +static void ncore_ccu_init_coh_agent(void __iomem *base) +{ + u32 num_of_coh_agent_intf; + u32 num_of_dirs; + u32 reg; + u32 type; + u32 i, dir; + + num_of_coh_agent_intf = + CSUIDR_NUMCAIUS_GET(readl(base + CSUIDR)); + num_of_dirs = CSUIDR_NUMDIRUS_GET(readl(base + CSUIDR)); + + for (i = 0; i < num_of_coh_agent_intf; i++) { + reg = readl(base + CAIUIDR + (i * CAIU_REG_SZ)); + if (CAIUIDR_CA_GET(reg)) { + /* Caching agent bit is enabled, enable caching agent + * snoop in each directory + */ + for (dir = 0; dir < num_of_dirs; dir++) { + setbits_le32((ulong) + CCU_DIR_REG_ADDR(base, DIRUCASER0, + dir), + BIT(i)); + } + } + + type = CAIUIDR_TYPE_GET(reg); + if (type == CAIUIDR_TYPE_ACE_CAI_DVM_SUPPORT || + type == CAIUIDR_TYPE_ACELITE_CAI_DVM_SUPPORT) { + /* DVM support is enabled, enable ACE DVM snoop*/ + setbits_le32((ulong)(base + CSADSER0), + BIT(i)); + } + } +} + +static void ocram_bypass_firewall(void __iomem *base) +{ + int i; + + for (i = 0; i < OCRAM_SECURE_REGIONS; i++) { + clrbits_le32(base + OCRAM_FW_01 + (i * sizeof(u32)), + OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK); + } +} + +static int ncore_ccu_probe(struct udevice *dev) +{ + void __iomem *base; + fdt_addr_t addr; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + base = (void __iomem *)addr; + + ncore_ccu_init_dirs(base); + ncore_ccu_init_coh_agent(base); + ocram_bypass_firewall(base); + + return 0; +} + +static const struct udevice_id ncore_ccu_ids[] = { + { .compatible = "arteris,ncore-ccu" }, + {} +}; + +U_BOOT_DRIVER(ncore_ccu) = { + .name = "ncore_ccu", + .id = UCLASS_CACHE, + .of_match = ncore_ccu_ids, + .probe = ncore_ccu_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/altera/Makefile b/drivers/clk/altera/Makefile index a3ae8b24b0d..96215ad5c42 100644 --- a/drivers/clk/altera/Makefile +++ b/drivers/clk/altera/Makefile @@ -3,4 +3,5 @@ # Copyright (C) 2018 Marek Vasut <marex@denx.de> # +obj-$(CONFIG_TARGET_SOCFPGA_AGILEX) += clk-agilex.o obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += clk-arria10.o diff --git a/drivers/clk/altera/clk-agilex.c b/drivers/clk/altera/clk-agilex.c new file mode 100644 index 00000000000..5fedec549d1 --- /dev/null +++ b/drivers/clk/altera/clk-agilex.c @@ -0,0 +1,579 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Intel Corporation <www.intel.com> + */ + +#include <common.h> +#include <asm/io.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/lists.h> +#include <dm/util.h> +#include <dt-bindings/clock/agilex-clock.h> + +#include <asm/arch/clock_manager.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct socfpga_clk_platdata { + void __iomem *regs; +}; + +/* + * function to write the bypass register which requires a poll of the + * busy bit + */ +static void clk_write_bypass_mainpll(struct socfpga_clk_platdata *plat, u32 val) +{ + CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_BYPASS); + cm_wait_for_fsm(); +} + +static void clk_write_bypass_perpll(struct socfpga_clk_platdata *plat, u32 val) +{ + CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_BYPASS); + cm_wait_for_fsm(); +} + +/* function to write the ctrl register which requires a poll of the busy bit */ +static void clk_write_ctrl(struct socfpga_clk_platdata *plat, u32 val) +{ + CM_REG_WRITEL(plat, val, CLKMGR_CTRL); + cm_wait_for_fsm(); +} + +#define MEMBUS_MAINPLL 0 +#define MEMBUS_PERPLL 1 +#define MEMBUS_TIMEOUT 1000 +#define MEMBUS_ADDR_CLKSLICE 0x27 +#define MEMBUS_CLKSLICE_SYNC_MODE_EN 0x80 + +static int membus_wait_for_req(struct socfpga_clk_platdata *plat, u32 pll, + int timeout) +{ + int cnt = 0; + u32 req_status; + + if (pll == MEMBUS_MAINPLL) + req_status = CM_REG_READL(plat, CLKMGR_MAINPLL_MEM); + else + req_status = CM_REG_READL(plat, CLKMGR_PERPLL_MEM); + + while ((cnt < timeout) && (req_status & CLKMGR_MEM_REQ_SET_MSK)) { + if (pll == MEMBUS_MAINPLL) + req_status = CM_REG_READL(plat, CLKMGR_MAINPLL_MEM); + else + req_status = CM_REG_READL(plat, CLKMGR_PERPLL_MEM); + cnt++; + } + + if (cnt >= timeout) + return -ETIMEDOUT; + + return 0; +} + +static int membus_write_pll(struct socfpga_clk_platdata *plat, u32 pll, + u32 addr_offset, u32 wdat, int timeout) +{ + u32 addr; + u32 val; + + addr = ((addr_offset | CLKMGR_MEM_ADDR_START) & CLKMGR_MEM_ADDR_MASK); + + val = (CLKMGR_MEM_REQ_SET_MSK | CLKMGR_MEM_WR_SET_MSK | + (wdat << CLKMGR_MEM_WDAT_LSB_OFFSET) | addr); + + if (pll == MEMBUS_MAINPLL) + CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_MEM); + else + CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_MEM); + + debug("MEMBUS: Write 0x%08x to addr = 0x%08x\n", wdat, addr); + + return membus_wait_for_req(plat, pll, timeout); +} + +static int membus_read_pll(struct socfpga_clk_platdata *plat, u32 pll, + u32 addr_offset, u32 *rdata, int timeout) +{ + u32 addr; + u32 val; + + addr = ((addr_offset | CLKMGR_MEM_ADDR_START) & CLKMGR_MEM_ADDR_MASK); + + val = ((CLKMGR_MEM_REQ_SET_MSK & ~CLKMGR_MEM_WR_SET_MSK) | addr); + + if (pll == MEMBUS_MAINPLL) + CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_MEM); + else + CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_MEM); + + *rdata = 0; + + if (membus_wait_for_req(plat, pll, timeout)) + return -ETIMEDOUT; + + if (pll == MEMBUS_MAINPLL) + *rdata = CM_REG_READL(plat, CLKMGR_MAINPLL_MEMSTAT); + else + *rdata = CM_REG_READL(plat, CLKMGR_PERPLL_MEMSTAT); + + debug("MEMBUS: Read 0x%08x from addr = 0x%08x\n", *rdata, addr); + + return 0; +} + +static u32 calc_vocalib_pll(u32 pllm, u32 pllglob) +{ + u32 mdiv, refclkdiv, arefclkdiv, drefclkdiv, mscnt, hscnt, vcocalib; + + mdiv = pllm & CLKMGR_PLLM_MDIV_MASK; + arefclkdiv = (pllglob & CLKMGR_PLLGLOB_AREFCLKDIV_MASK) >> + CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET; + drefclkdiv = (pllglob & CLKMGR_PLLGLOB_DREFCLKDIV_MASK) >> + CLKMGR_PLLGLOB_DREFCLKDIV_OFFSET; + refclkdiv = (pllglob & CLKMGR_PLLGLOB_REFCLKDIV_MASK) >> + CLKMGR_PLLGLOB_REFCLKDIV_OFFSET; + mscnt = CLKMGR_VCOCALIB_MSCNT_CONST / (mdiv * BIT(drefclkdiv)); + if (!mscnt) + mscnt = 1; + hscnt = (mdiv * mscnt * BIT(drefclkdiv) / refclkdiv) - + CLKMGR_VCOCALIB_HSCNT_CONST; + vcocalib = (hscnt & CLKMGR_VCOCALIB_HSCNT_MASK) | + ((mscnt << CLKMGR_VCOCALIB_MSCNT_OFFSET) & + CLKMGR_VCOCALIB_MSCNT_MASK); + + /* Dump all the pll calibration settings for debug purposes */ + debug("mdiv : %d\n", mdiv); + debug("arefclkdiv : %d\n", arefclkdiv); + debug("drefclkdiv : %d\n", drefclkdiv); + debug("refclkdiv : %d\n", refclkdiv); + debug("mscnt : %d\n", mscnt); + debug("hscnt : %d\n", hscnt); + debug("vcocalib : 0x%08x\n", vcocalib); + + return vcocalib; +} + +/* + * Setup clocks while making no assumptions about previous state of the clocks. + */ +static void clk_basic_init(struct udevice *dev, + const struct cm_config * const cfg) +{ + struct socfpga_clk_platdata *plat = dev_get_platdata(dev); + u32 vcocalib; + u32 rdata; + + if (!cfg) + return; + + /* Put both PLLs in bypass */ + clk_write_bypass_mainpll(plat, CLKMGR_BYPASS_MAINPLL_ALL); + clk_write_bypass_perpll(plat, CLKMGR_BYPASS_PERPLL_ALL); + + /* Put both PLLs in Reset and Power Down */ + CM_REG_CLRBITS(plat, CLKMGR_MAINPLL_PLLGLOB, + CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK); + CM_REG_CLRBITS(plat, CLKMGR_PERPLL_PLLGLOB, + CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK); + + /* setup main PLL dividers where calculate the vcocalib value */ + vcocalib = calc_vocalib_pll(cfg->main_pll_pllm, cfg->main_pll_pllglob); + CM_REG_WRITEL(plat, cfg->main_pll_pllglob & ~CLKMGR_PLLGLOB_RST_MASK, + CLKMGR_MAINPLL_PLLGLOB); + CM_REG_WRITEL(plat, cfg->main_pll_fdbck, CLKMGR_MAINPLL_FDBCK); + CM_REG_WRITEL(plat, vcocalib, CLKMGR_MAINPLL_VCOCALIB); + CM_REG_WRITEL(plat, cfg->main_pll_pllc0, CLKMGR_MAINPLL_PLLC0); + CM_REG_WRITEL(plat, cfg->main_pll_pllc1, CLKMGR_MAINPLL_PLLC1); + CM_REG_WRITEL(plat, cfg->main_pll_pllc2, CLKMGR_MAINPLL_PLLC2); + CM_REG_WRITEL(plat, cfg->main_pll_pllc3, CLKMGR_MAINPLL_PLLC3); + CM_REG_WRITEL(plat, cfg->main_pll_pllm, CLKMGR_MAINPLL_PLLM); + CM_REG_WRITEL(plat, cfg->main_pll_mpuclk, CLKMGR_MAINPLL_MPUCLK); + CM_REG_WRITEL(plat, cfg->main_pll_nocclk, CLKMGR_MAINPLL_NOCCLK); + CM_REG_WRITEL(plat, cfg->main_pll_nocdiv, CLKMGR_MAINPLL_NOCDIV); + + /* setup peripheral PLL dividers where calculate the vcocalib value */ + vcocalib = calc_vocalib_pll(cfg->per_pll_pllm, cfg->per_pll_pllglob); + CM_REG_WRITEL(plat, cfg->per_pll_pllglob & ~CLKMGR_PLLGLOB_RST_MASK, + CLKMGR_PERPLL_PLLGLOB); + CM_REG_WRITEL(plat, cfg->per_pll_fdbck, CLKMGR_PERPLL_FDBCK); + CM_REG_WRITEL(plat, vcocalib, CLKMGR_PERPLL_VCOCALIB); + CM_REG_WRITEL(plat, cfg->per_pll_pllc0, CLKMGR_PERPLL_PLLC0); + CM_REG_WRITEL(plat, cfg->per_pll_pllc1, CLKMGR_PERPLL_PLLC1); + CM_REG_WRITEL(plat, cfg->per_pll_pllc2, CLKMGR_PERPLL_PLLC2); + CM_REG_WRITEL(plat, cfg->per_pll_pllc3, CLKMGR_PERPLL_PLLC3); + CM_REG_WRITEL(plat, cfg->per_pll_pllm, CLKMGR_PERPLL_PLLM); + CM_REG_WRITEL(plat, cfg->per_pll_emacctl, CLKMGR_PERPLL_EMACCTL); + CM_REG_WRITEL(plat, cfg->per_pll_gpiodiv, CLKMGR_PERPLL_GPIODIV); + + /* Take both PLL out of reset and power up */ + CM_REG_SETBITS(plat, CLKMGR_MAINPLL_PLLGLOB, + CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK); + CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLGLOB, + CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK); + + /* Membus programming to set mainpll and perripll to + * source synchronous mode + */ + membus_read_pll(plat, MEMBUS_MAINPLL, MEMBUS_ADDR_CLKSLICE, &rdata, + MEMBUS_TIMEOUT); + membus_write_pll(plat, MEMBUS_MAINPLL, MEMBUS_ADDR_CLKSLICE, + (rdata | MEMBUS_CLKSLICE_SYNC_MODE_EN), + MEMBUS_TIMEOUT); + membus_read_pll(plat, MEMBUS_PERPLL, MEMBUS_ADDR_CLKSLICE, &rdata, + MEMBUS_TIMEOUT); + membus_write_pll(plat, MEMBUS_PERPLL, MEMBUS_ADDR_CLKSLICE, + (rdata | MEMBUS_CLKSLICE_SYNC_MODE_EN), + MEMBUS_TIMEOUT); + + cm_wait_for_lock(CLKMGR_STAT_ALLPLL_LOCKED_MASK); + + /* Configure ping pong counters in altera group */ + CM_REG_WRITEL(plat, cfg->alt_emacactr, CLKMGR_ALTR_EMACACTR); + CM_REG_WRITEL(plat, cfg->alt_emacbctr, CLKMGR_ALTR_EMACBCTR); + CM_REG_WRITEL(plat, cfg->alt_emacptpctr, CLKMGR_ALTR_EMACPTPCTR); + CM_REG_WRITEL(plat, cfg->alt_gpiodbctr, CLKMGR_ALTR_GPIODBCTR); + CM_REG_WRITEL(plat, cfg->alt_sdmmcctr, CLKMGR_ALTR_SDMMCCTR); + CM_REG_WRITEL(plat, cfg->alt_s2fuser0ctr, CLKMGR_ALTR_S2FUSER0CTR); + CM_REG_WRITEL(plat, cfg->alt_s2fuser1ctr, CLKMGR_ALTR_S2FUSER1CTR); + CM_REG_WRITEL(plat, cfg->alt_psirefctr, CLKMGR_ALTR_PSIREFCTR); + + CM_REG_WRITEL(plat, CLKMGR_LOSTLOCK_SET_MASK, CLKMGR_MAINPLL_LOSTLOCK); + CM_REG_WRITEL(plat, CLKMGR_LOSTLOCK_SET_MASK, CLKMGR_PERPLL_LOSTLOCK); + + CM_REG_WRITEL(plat, CM_REG_READL(plat, CLKMGR_MAINPLL_PLLGLOB) | + CLKMGR_PLLGLOB_CLR_LOSTLOCK_BYPASS_MASK, + CLKMGR_MAINPLL_PLLGLOB); + CM_REG_WRITEL(plat, CM_REG_READL(plat, CLKMGR_PERPLL_PLLGLOB) | + CLKMGR_PLLGLOB_CLR_LOSTLOCK_BYPASS_MASK, + CLKMGR_PERPLL_PLLGLOB); + + /* Take all PLLs out of bypass */ + clk_write_bypass_mainpll(plat, 0); + clk_write_bypass_perpll(plat, 0); + + /* Clear the loss of lock bits (write 1 to clear) */ + CM_REG_CLRBITS(plat, CLKMGR_INTRCLR, + CLKMGR_INTER_PERPLLLOST_MASK | + CLKMGR_INTER_MAINPLLLOST_MASK); + + /* Take all ping pong counters out of reset */ + CM_REG_CLRBITS(plat, CLKMGR_ALTR_EXTCNTRST, + CLKMGR_ALT_EXTCNTRST_ALLCNTRST); + + /* Out of boot mode */ + clk_write_ctrl(plat, + CM_REG_READL(plat, CLKMGR_CTRL) & ~CLKMGR_CTRL_BOOTMODE); +} + +static u64 clk_get_vco_clk_hz(struct socfpga_clk_platdata *plat, + u32 pllglob_reg, u32 pllm_reg) +{ + u64 fref, arefdiv, mdiv, reg, vco; + + reg = CM_REG_READL(plat, pllglob_reg); + + fref = (reg & CLKMGR_PLLGLOB_VCO_PSRC_MASK) >> + CLKMGR_PLLGLOB_VCO_PSRC_OFFSET; + + switch (fref) { + case CLKMGR_VCO_PSRC_EOSC1: + fref = cm_get_osc_clk_hz(); + break; + case CLKMGR_VCO_PSRC_INTOSC: + fref = cm_get_intosc_clk_hz(); + break; + case CLKMGR_VCO_PSRC_F2S: + fref = cm_get_fpga_clk_hz(); + break; + } + + arefdiv = (reg & CLKMGR_PLLGLOB_AREFCLKDIV_MASK) >> + CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET; + + mdiv = CM_REG_READL(plat, pllm_reg) & CLKMGR_PLLM_MDIV_MASK; + + vco = fref / arefdiv; + vco = vco * mdiv; + + return vco; +} + +static u64 clk_get_main_vco_clk_hz(struct socfpga_clk_platdata *plat) +{ + return clk_get_vco_clk_hz(plat, CLKMGR_MAINPLL_PLLGLOB, + CLKMGR_MAINPLL_PLLM); +} + +static u64 clk_get_per_vco_clk_hz(struct socfpga_clk_platdata *plat) +{ + return clk_get_vco_clk_hz(plat, CLKMGR_PERPLL_PLLGLOB, + CLKMGR_PERPLL_PLLM); +} + +static u32 clk_get_5_1_clk_src(struct socfpga_clk_platdata *plat, u64 reg) +{ + u32 clksrc = CM_REG_READL(plat, reg); + + return (clksrc & CLKMGR_CLKSRC_MASK) >> CLKMGR_CLKSRC_OFFSET; +} + +static u64 clk_get_clksrc_hz(struct socfpga_clk_platdata *plat, u32 clksrc_reg, + u32 main_reg, u32 per_reg) +{ + u64 clock; + u32 clklsrc = clk_get_5_1_clk_src(plat, clksrc_reg); + + switch (clklsrc) { + case CLKMGR_CLKSRC_MAIN: + clock = clk_get_main_vco_clk_hz(plat); + clock /= (CM_REG_READL(plat, main_reg) & + CLKMGR_CLKCNT_MSK); + break; + + case CLKMGR_CLKSRC_PER: + clock = clk_get_per_vco_clk_hz(plat); + clock /= (CM_REG_READL(plat, per_reg) & + CLKMGR_CLKCNT_MSK); + break; + + case CLKMGR_CLKSRC_OSC1: + clock = cm_get_osc_clk_hz(); + break; + + case CLKMGR_CLKSRC_INTOSC: + clock = cm_get_intosc_clk_hz(); + break; + + case CLKMGR_CLKSRC_FPGA: + clock = cm_get_fpga_clk_hz(); + break; + default: + return 0; + } + + return clock; +} + +static u64 clk_get_mpu_clk_hz(struct socfpga_clk_platdata *plat) +{ + u64 clock = clk_get_clksrc_hz(plat, CLKMGR_MAINPLL_MPUCLK, + CLKMGR_MAINPLL_PLLC0, + CLKMGR_PERPLL_PLLC0); + + clock /= 1 + (CM_REG_READL(plat, CLKMGR_MAINPLL_MPUCLK) & + CLKMGR_CLKCNT_MSK); + + return clock; +} + +static u32 clk_get_l3_main_clk_hz(struct socfpga_clk_platdata *plat) +{ + return clk_get_clksrc_hz(plat, CLKMGR_MAINPLL_NOCCLK, + CLKMGR_MAINPLL_PLLC1, + CLKMGR_PERPLL_PLLC1); +} + +static u32 clk_get_l4_main_clk_hz(struct socfpga_clk_platdata *plat) +{ + u64 clock = clk_get_l3_main_clk_hz(plat); + + clock /= BIT((CM_REG_READL(plat, CLKMGR_MAINPLL_NOCDIV) >> + CLKMGR_NOCDIV_L4MAIN_OFFSET) & + CLKMGR_NOCDIV_DIVIDER_MASK); + + return clock; +} + +static u32 clk_get_sdmmc_clk_hz(struct socfpga_clk_platdata *plat) +{ + u64 clock = clk_get_clksrc_hz(plat, CLKMGR_ALTR_SDMMCCTR, + CLKMGR_MAINPLL_PLLC3, + CLKMGR_PERPLL_PLLC3); + + clock /= 1 + (CM_REG_READL(plat, CLKMGR_ALTR_SDMMCCTR) & + CLKMGR_CLKCNT_MSK); + + return clock / 4; +} + +static u32 clk_get_l4_sp_clk_hz(struct socfpga_clk_platdata *plat) +{ + u64 clock = clk_get_l3_main_clk_hz(plat); + + clock /= BIT((CM_REG_READL(plat, CLKMGR_MAINPLL_NOCDIV) >> + CLKMGR_NOCDIV_L4SPCLK_OFFSET) & + CLKMGR_NOCDIV_DIVIDER_MASK); + + return clock; +} + +static u32 clk_get_l4_mp_clk_hz(struct socfpga_clk_platdata *plat) +{ + u64 clock = clk_get_l3_main_clk_hz(plat); + + clock /= BIT((CM_REG_READL(plat, CLKMGR_MAINPLL_NOCDIV) >> + CLKMGR_NOCDIV_L4MPCLK_OFFSET) & + CLKMGR_NOCDIV_DIVIDER_MASK); + + return clock; +} + +static u32 clk_get_l4_sys_free_clk_hz(struct socfpga_clk_platdata *plat) +{ + if (CM_REG_READL(plat, CLKMGR_STAT) & CLKMGR_STAT_BOOTMODE) + return clk_get_l3_main_clk_hz(plat) / 2; + + return clk_get_l3_main_clk_hz(plat) / 4; +} + +static u32 clk_get_emac_clk_hz(struct socfpga_clk_platdata *plat, u32 emac_id) +{ + bool emacsel_a; + u32 ctl; + u32 ctr_reg; + u32 clock; + u32 div; + u32 reg; + + /* Get EMAC clock source */ + ctl = CM_REG_READL(plat, CLKMGR_PERPLL_EMACCTL); + if (emac_id == AGILEX_EMAC0_CLK) + ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET) & + CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK; + else if (emac_id == AGILEX_EMAC1_CLK) + ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET) & + CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK; + else if (emac_id == AGILEX_EMAC2_CLK) + ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_OFFSET) & + CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK; + else + return 0; + + if (ctl) { + /* EMAC B source */ + emacsel_a = false; + ctr_reg = CLKMGR_ALTR_EMACBCTR; + } else { + /* EMAC A source */ + emacsel_a = true; + ctr_reg = CLKMGR_ALTR_EMACACTR; + } + + reg = CM_REG_READL(plat, ctr_reg); + clock = (reg & CLKMGR_ALT_EMACCTR_SRC_MASK) + >> CLKMGR_ALT_EMACCTR_SRC_OFFSET; + div = (reg & CLKMGR_ALT_EMACCTR_CNT_MASK) + >> CLKMGR_ALT_EMACCTR_CNT_OFFSET; + + switch (clock) { + case CLKMGR_CLKSRC_MAIN: + clock = clk_get_main_vco_clk_hz(plat); + if (emacsel_a) { + clock /= (CM_REG_READL(plat, CLKMGR_MAINPLL_PLLC2) & + CLKMGR_CLKCNT_MSK); + } else { + clock /= (CM_REG_READL(plat, CLKMGR_MAINPLL_PLLC3) & + CLKMGR_CLKCNT_MSK); + } + break; + + case CLKMGR_CLKSRC_PER: + clock = clk_get_per_vco_clk_hz(plat); + if (emacsel_a) { + clock /= (CM_REG_READL(plat, CLKMGR_PERPLL_PLLC2) & + CLKMGR_CLKCNT_MSK); + } else { + clock /= (CM_REG_READL(plat, CLKMGR_PERPLL_PLLC3) & + CLKMGR_CLKCNT_MSK); + } + break; + + case CLKMGR_CLKSRC_OSC1: + clock = cm_get_osc_clk_hz(); + break; + + case CLKMGR_CLKSRC_INTOSC: + clock = cm_get_intosc_clk_hz(); + break; + + case CLKMGR_CLKSRC_FPGA: + clock = cm_get_fpga_clk_hz(); + break; + } + + clock /= 1 + div; + + return clock; +} + +static ulong socfpga_clk_get_rate(struct clk *clk) +{ + struct socfpga_clk_platdata *plat = dev_get_platdata(clk->dev); + + switch (clk->id) { + case AGILEX_MPU_CLK: + return clk_get_mpu_clk_hz(plat); + case AGILEX_L4_MAIN_CLK: + return clk_get_l4_main_clk_hz(plat); + case AGILEX_L4_SYS_FREE_CLK: + return clk_get_l4_sys_free_clk_hz(plat); + case AGILEX_L4_MP_CLK: + return clk_get_l4_mp_clk_hz(plat); + case AGILEX_L4_SP_CLK: + return clk_get_l4_sp_clk_hz(plat); + case AGILEX_SDMMC_CLK: + return clk_get_sdmmc_clk_hz(plat); + case AGILEX_EMAC0_CLK: + case AGILEX_EMAC1_CLK: + case AGILEX_EMAC2_CLK: + return clk_get_emac_clk_hz(plat, clk->id); + case AGILEX_USB_CLK: + return clk_get_l4_mp_clk_hz(plat); + default: + return -ENXIO; + } +} + +static int socfpga_clk_probe(struct udevice *dev) +{ + const struct cm_config *cm_default_cfg = cm_get_default_config(); + + clk_basic_init(dev, cm_default_cfg); + + return 0; +} + +static int socfpga_clk_ofdata_to_platdata(struct udevice *dev) +{ + struct socfpga_clk_platdata *plat = dev_get_platdata(dev); + fdt_addr_t addr; + + addr = devfdt_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + plat->regs = (void __iomem *)addr; + + return 0; +} + +static struct clk_ops socfpga_clk_ops = { + .get_rate = socfpga_clk_get_rate, +}; + +static const struct udevice_id socfpga_clk_match[] = { + { .compatible = "intel,agilex-clkmgr" }, + {} +}; + +U_BOOT_DRIVER(socfpga_agilex_clk) = { + .name = "clk-agilex", + .id = UCLASS_CLK, + .of_match = socfpga_clk_match, + .ops = &socfpga_clk_ops, + .probe = socfpga_clk_probe, + .ofdata_to_platdata = socfpga_clk_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct socfpga_clk_platdata), +}; diff --git a/drivers/clk/altera/clk-agilex.h b/drivers/clk/altera/clk-agilex.h new file mode 100644 index 00000000000..d93328ef299 --- /dev/null +++ b/drivers/clk/altera/clk-agilex.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 Intel Corporation <www.intel.com> + */ + +#ifndef _CLK_AGILEX_ +#define _CLK_AGILEX_ + +#define CM_REG_READL(plat, reg) \ + readl((plat)->regs + (reg)) + +#define CM_REG_WRITEL(plat, data, reg) \ + writel(data, (plat)->regs + (reg)) + +#define CM_REG_CLRBITS(plat, reg, clear) \ + clrbits_le32((plat)->regs + (reg), (clear)) + +#define CM_REG_SETBITS(plat, reg, set) \ + setbits_le32((plat)->regs + (reg), (set)) + +struct cm_config { + /* main group */ + u32 main_pll_mpuclk; + u32 main_pll_nocclk; + u32 main_pll_nocdiv; + u32 main_pll_pllglob; + u32 main_pll_fdbck; + u32 main_pll_pllc0; + u32 main_pll_pllc1; + u32 main_pll_pllc2; + u32 main_pll_pllc3; + u32 main_pll_pllm; + + /* peripheral group */ + u32 per_pll_emacctl; + u32 per_pll_gpiodiv; + u32 per_pll_pllglob; + u32 per_pll_fdbck; + u32 per_pll_pllc0; + u32 per_pll_pllc1; + u32 per_pll_pllc2; + u32 per_pll_pllc3; + u32 per_pll_pllm; + + /* altera group */ + u32 alt_emacactr; + u32 alt_emacbctr; + u32 alt_emacptpctr; + u32 alt_gpiodbctr; + u32 alt_sdmmcctr; + u32 alt_s2fuser0ctr; + u32 alt_s2fuser1ctr; + u32 alt_psirefctr; + + /* incoming clock */ + u32 hps_osc_clk_hz; + u32 fpga_clk_hz; + u32 spare[3]; +}; + +/* Clock Manager registers */ +#define CLKMGR_CTRL 0 +#define CLKMGR_STAT 4 +#define CLKMGR_TESTIOCTRL 8 +#define CLKMGR_INTRGEN 0x0c +#define CLKMGR_INTRMSK 0x10 +#define CLKMGR_INTRCLR 0x14 +#define CLKMGR_INTRSTS 0x18 +#define CLKMGR_INTRSTK 0x1c +#define CLKMGR_INTRRAW 0x20 + +/* Clock Manager Main PPL group registers */ +#define CLKMGR_MAINPLL_EN 0x24 +#define CLKMGR_MAINPLL_ENS 0x28 +#define CLKMGR_MAINPLL_ENR 0x2c +#define CLKMGR_MAINPLL_BYPASS 0x30 +#define CLKMGR_MAINPLL_BYPASSS 0x34 +#define CLKMGR_MAINPLL_BYPASSR 0x38 +#define CLKMGR_MAINPLL_MPUCLK 0x3c +#define CLKMGR_MAINPLL_NOCCLK 0x40 +#define CLKMGR_MAINPLL_NOCDIV 0x44 +#define CLKMGR_MAINPLL_PLLGLOB 0x48 +#define CLKMGR_MAINPLL_FDBCK 0x4c +#define CLKMGR_MAINPLL_MEM 0x50 +#define CLKMGR_MAINPLL_MEMSTAT 0x54 +#define CLKMGR_MAINPLL_PLLC0 0x58 +#define CLKMGR_MAINPLL_PLLC1 0x5c +#define CLKMGR_MAINPLL_VCOCALIB 0x60 +#define CLKMGR_MAINPLL_PLLC2 0x64 +#define CLKMGR_MAINPLL_PLLC3 0x68 +#define CLKMGR_MAINPLL_PLLM 0x6c +#define CLKMGR_MAINPLL_FHOP 0x70 +#define CLKMGR_MAINPLL_SSC 0x74 +#define CLKMGR_MAINPLL_LOSTLOCK 0x78 + +/* Clock Manager Peripheral PPL group registers */ +#define CLKMGR_PERPLL_EN 0x7c +#define CLKMGR_PERPLL_ENS 0x80 +#define CLKMGR_PERPLL_ENR 0x84 +#define CLKMGR_PERPLL_BYPASS 0x88 +#define CLKMGR_PERPLL_BYPASSS 0x8c +#define CLKMGR_PERPLL_BYPASSR 0x90 +#define CLKMGR_PERPLL_EMACCTL 0x94 +#define CLKMGR_PERPLL_GPIODIV 0x98 +#define CLKMGR_PERPLL_PLLGLOB 0x9c +#define CLKMGR_PERPLL_FDBCK 0xa0 +#define CLKMGR_PERPLL_MEM 0xa4 +#define CLKMGR_PERPLL_MEMSTAT 0xa8 +#define CLKMGR_PERPLL_PLLC0 0xac +#define CLKMGR_PERPLL_PLLC1 0xb0 +#define CLKMGR_PERPLL_VCOCALIB 0xb4 +#define CLKMGR_PERPLL_PLLC2 0xb8 +#define CLKMGR_PERPLL_PLLC3 0xbc +#define CLKMGR_PERPLL_PLLM 0xc0 +#define CLKMGR_PERPLL_FHOP 0xc4 +#define CLKMGR_PERPLL_SSC 0xc8 +#define CLKMGR_PERPLL_LOSTLOCK 0xcc + +/* Clock Manager Altera group registers */ +#define CLKMGR_ALTR_JTAG 0xd0 +#define CLKMGR_ALTR_EMACACTR 0xd4 +#define CLKMGR_ALTR_EMACBCTR 0xd8 +#define CLKMGR_ALTR_EMACPTPCTR 0xdc +#define CLKMGR_ALTR_GPIODBCTR 0xe0 +#define CLKMGR_ALTR_SDMMCCTR 0xe4 +#define CLKMGR_ALTR_S2FUSER0CTR 0xe8 +#define CLKMGR_ALTR_S2FUSER1CTR 0xec +#define CLKMGR_ALTR_PSIREFCTR 0xf0 +#define CLKMGR_ALTR_EXTCNTRST 0xf4 + +#define CLKMGR_CTRL_BOOTMODE BIT(0) + +#define CLKMGR_STAT_BUSY BIT(0) +#define CLKMGR_STAT_MAINPLL_LOCKED BIT(8) +#define CLKMGR_STAT_MAIN_TRANS BIT(9) +#define CLKMGR_STAT_PERPLL_LOCKED BIT(16) +#define CLKMGR_STAT_PERF_TRANS BIT(17) +#define CLKMGR_STAT_BOOTMODE BIT(24) +#define CLKMGR_STAT_BOOTCLKSRC BIT(25) + +#define CLKMGR_STAT_ALLPLL_LOCKED_MASK \ + (CLKMGR_STAT_MAINPLL_LOCKED | CLKMGR_STAT_PERPLL_LOCKED) + +#define CLKMGR_INTER_MAINPLLLOCKED_MASK 0x00000001 +#define CLKMGR_INTER_PERPLLLOCKED_MASK 0x00000002 +#define CLKMGR_INTER_MAINPLLLOST_MASK 0x00000004 +#define CLKMGR_INTER_PERPLLLOST_MASK 0x00000008 + +#define CLKMGR_CLKSRC_MASK GENMASK(18, 16) +#define CLKMGR_CLKSRC_OFFSET 16 +#define CLKMGR_CLKSRC_MAIN 0 +#define CLKMGR_CLKSRC_PER 1 +#define CLKMGR_CLKSRC_OSC1 2 +#define CLKMGR_CLKSRC_INTOSC 3 +#define CLKMGR_CLKSRC_FPGA 4 +#define CLKMGR_CLKCNT_MSK GENMASK(10, 0) + +#define CLKMGR_BYPASS_MAINPLL_ALL 0x7 +#define CLKMGR_BYPASS_PERPLL_ALL 0x7f + +#define CLKMGR_NOCDIV_L4MAIN_OFFSET 0 +#define CLKMGR_NOCDIV_L4MPCLK_OFFSET 8 +#define CLKMGR_NOCDIV_L4SPCLK_OFFSET 16 +#define CLKMGR_NOCDIV_CSATCLK_OFFSET 24 +#define CLKMGR_NOCDIV_CSTRACECLK_OFFSET 26 +#define CLKMGR_NOCDIV_CSPDBGCLK_OFFSET 28 +#define CLKMGR_NOCDIV_DIVIDER_MASK 0x3 + +#define CLKMGR_PLLGLOB_PD_MASK BIT(0) +#define CLKMGR_PLLGLOB_RST_MASK BIT(1) +#define CLKMGR_PLLGLOB_AREFCLKDIV_MASK GENMASK(11, 8) +#define CLKMGR_PLLGLOB_DREFCLKDIV_MASK GENMASK(13, 12) +#define CLKMGR_PLLGLOB_REFCLKDIV_MASK GENMASK(13, 8) +#define CLKMGR_PLLGLOB_MODCLKDIV_MASK GENMASK(24, 27) +#define CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET 8 +#define CLKMGR_PLLGLOB_DREFCLKDIV_OFFSET 12 +#define CLKMGR_PLLGLOB_REFCLKDIV_OFFSET 8 +#define CLKMGR_PLLGLOB_MODCLKDIV_OFFSET 24 +#define CLKMGR_PLLGLOB_VCO_PSRC_MASK GENMASK(17, 16) +#define CLKMGR_PLLGLOB_VCO_PSRC_OFFSET 16 +#define CLKMGR_PLLGLOB_CLR_LOSTLOCK_BYPASS_MASK BIT(29) + +#define CLKMGR_VCO_PSRC_EOSC1 0 +#define CLKMGR_VCO_PSRC_INTOSC 1 +#define CLKMGR_VCO_PSRC_F2S 2 + +#define CLKMGR_MEM_REQ_SET_MSK BIT(24) +#define CLKMGR_MEM_WR_SET_MSK BIT(25) +#define CLKMGR_MEM_ERR_MSK BIT(26) +#define CLKMGR_MEM_WDAT_LSB_OFFSET 16 +#define CLKMGR_MEM_ADDR_MASK GENMASK(15, 0) +#define CLKMGR_MEM_ADDR_START 0x00004000 + +#define CLKMGR_PLLCX_EN_SET_MSK BIT(27) +#define CLKMGR_PLLCX_MUTE_SET_MSK BIT(28) + +#define CLKMGR_VCOCALIB_MSCNT_MASK GENMASK(23, 16) +#define CLKMGR_VCOCALIB_MSCNT_OFFSET 16 +#define CLKMGR_VCOCALIB_HSCNT_MASK GENMASK(9, 0) +#define CLKMGR_VCOCALIB_MSCNT_CONST 100 +#define CLKMGR_VCOCALIB_HSCNT_CONST 4 + +#define CLKMGR_PLLM_MDIV_MASK GENMASK(9, 0) + +#define CLKMGR_LOSTLOCK_SET_MASK BIT(0) + +#define CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK BIT(5) +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET 26 +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK BIT(26) +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET 27 +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK BIT(27) +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_OFFSET 28 +#define CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK BIT(28) + +#define CLKMGR_ALT_EMACCTR_SRC_OFFSET 16 +#define CLKMGR_ALT_EMACCTR_SRC_MASK GENMASK(18, 16) +#define CLKMGR_ALT_EMACCTR_CNT_OFFSET 0 +#define CLKMGR_ALT_EMACCTR_CNT_MASK GENMASK(10, 0) + +#define CLKMGR_ALT_EXTCNTRST_EMACACNTRST BIT(0) +#define CLKMGR_ALT_EXTCNTRST_EMACBCNTRST BIT(1) +#define CLKMGR_ALT_EXTCNTRST_EMACPTPCNTRST BIT(2) +#define CLKMGR_ALT_EXTCNTRST_GPIODBCNTRST BIT(3) +#define CLKMGR_ALT_EXTCNTRST_SDMMCCNTRST BIT(4) +#define CLKMGR_ALT_EXTCNTRST_S2FUSER0CNTRST BIT(5) +#define CLKMGR_ALT_EXTCNTRST_S2FUSER1CNTRST BIT(6) +#define CLKMGR_ALT_EXTCNTRST_PSIREFCNTRST BIT(7) +#define CLKMGR_ALT_EXTCNTRST_ALLCNTRST \ + (CLKMGR_ALT_EXTCNTRST_EMACACNTRST | \ + CLKMGR_ALT_EXTCNTRST_EMACBCNTRST | \ + CLKMGR_ALT_EXTCNTRST_EMACPTPCNTRST | \ + CLKMGR_ALT_EXTCNTRST_GPIODBCNTRST | \ + CLKMGR_ALT_EXTCNTRST_SDMMCCNTRST | \ + CLKMGR_ALT_EXTCNTRST_S2FUSER0CNTRST | \ + CLKMGR_ALT_EXTCNTRST_S2FUSER1CNTRST | \ + CLKMGR_ALT_EXTCNTRST_PSIREFCNTRST) +#endif /* _CLK_AGILEX_ */ diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 0ba8bc9f63f..2f149ff6f8a 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -52,3 +52,19 @@ config CLK_IMX8MN select CLK_CCF help This enables support clock driver for i.MX8MN platforms. + +config SPL_CLK_IMX8MP + bool "SPL clock support for i.MX8MP" + depends on ARCH_IMX8M && SPL + select SPL_CLK + select SPL_CLK_CCF + help + This enables SPL DM/DTS support for clock driver in i.MX8MP + +config CLK_IMX8MP + bool "Clock support for i.MX8MP" + depends on ARCH_IMX8M + select CLK + select CLK_CCF + help + This enables support clock driver for i.MX8MP platforms. diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 222c5a4e08d..255a87b18e8 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -14,3 +14,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o clk-pll14xx.o \ clk-composite-8m.o obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ clk-composite-8m.o +obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \ + clk-composite-8m.o diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c new file mode 100644 index 00000000000..a2693d2f7a0 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mp.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP + * Peng Fan <peng.fan@nxp.com> + */ + +#include <common.h> +#include <clk.h> +#include <clk-uclass.h> +#include <dm.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <dt-bindings/clock/imx8mp-clock.h> + +#include "clk.h" + +#define PLL_1416X_RATE(_rate, _m, _p, _s) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + } + +static const struct imx_pll14xx_rate_table imx8mp_pll1416x_tbl[] = { + PLL_1416X_RATE(1800000000U, 225, 3, 0), + PLL_1416X_RATE(1600000000U, 200, 3, 0), + PLL_1416X_RATE(1200000000U, 300, 3, 1), + PLL_1416X_RATE(1000000000U, 250, 3, 1), + PLL_1416X_RATE(800000000U, 200, 3, 1), + PLL_1416X_RATE(750000000U, 250, 2, 2), + PLL_1416X_RATE(700000000U, 350, 3, 2), + PLL_1416X_RATE(600000000U, 300, 3, 2), +}; + +static const struct imx_pll14xx_rate_table imx8mp_drampll_tbl[] = { + PLL_1443X_RATE(650000000U, 325, 3, 2, 0), +}; + +static struct imx_pll14xx_clk imx8mp_dram_pll __initdata = { + .type = PLL_1443X, + .rate_table = imx8mp_drampll_tbl, + .rate_count = ARRAY_SIZE(imx8mp_drampll_tbl), +}; + +static struct imx_pll14xx_clk imx8mp_arm_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mp_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mp_pll1416x_tbl), +}; + +static struct imx_pll14xx_clk imx8mp_sys_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mp_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mp_pll1416x_tbl), +}; + +static const char *pll_ref_sels[] = { "clock-osc-24m", "dummy", "dummy", "dummy", }; +static const char *dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", }; +static const char *sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", }; +static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", }; + +static const char *imx8mp_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m", + "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m", + "audio_pll1_out", "sys_pll3_out", }; + +static const char *imx8mp_main_axi_sels[] = {"clock-osc-24m", "sys_pll2_333m", "sys_pll1_800m", + "sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out", + "video_pll1_out", "sys_pll1_100m",}; + +static const char *imx8mp_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", + "sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll1_out", }; + +static const char *imx8mp_noc_sels[] = {"clock-osc-24m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mp_noc_io_sels[] = {"clock-osc-24m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_1000m", "sys_pll2_500m", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mp_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_800m", + "sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out", + "audio_pll1_out", "video_pll1_out", }; + +static const char *imx8mp_dram_alt_sels[] = {"clock-osc-24m", "sys_pll1_800m", "sys_pll1_100m", + "sys_pll2_500m", "sys_pll2_1000m", "sys_pll3_out", + "audio_pll1_out", "sys_pll1_266m", }; + +static const char *imx8mp_dram_apb_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char *imx8mp_i2c5_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mp_i2c6_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mp_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", + "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", + "audio_pll2_out", "sys_pll1_100m", }; + +static const char *imx8mp_usdhc2_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", + "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", + "audio_pll2_out", "sys_pll1_100m", }; + +static const char *imx8mp_i2c1_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mp_i2c2_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mp_i2c3_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mp_i2c4_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mp_uart1_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + +static const char *imx8mp_uart2_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mp_uart3_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + +static const char *imx8mp_uart4_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char *imx8mp_gic_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll2_100m", "sys_pll1_800m", + "sys_pll2_500m", "clk_ext4", "audio_pll2_out" }; + +static const char *imx8mp_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_160m", + "vpu_pll_out", "sys_pll2_125m", "sys_pll3_out", + "sys_pll1_80m", "sys_pll2_166m" }; + +static const char *imx8mp_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", + "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", + "audio_pll2_out", "sys_pll1_100m", }; + +static const char *imx8mp_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; + + +static ulong imx8mp_clk_get_rate(struct clk *clk) +{ + struct clk *c; + int ret; + + debug("%s(#%lu)\n", __func__, clk->id); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_get_rate(c); +} + +static ulong imx8mp_clk_set_rate(struct clk *clk, unsigned long rate) +{ + struct clk *c; + int ret; + + debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_set_rate(c, rate); +} + +static int __imx8mp_clk_enable(struct clk *clk, bool enable) +{ + struct clk *c; + int ret; + + debug("%s(#%lu) en: %d\n", __func__, clk->id, enable); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + if (enable) + ret = clk_enable(c); + else + ret = clk_disable(c); + + return ret; +} + +static int imx8mp_clk_disable(struct clk *clk) +{ + return __imx8mp_clk_enable(clk, 0); +} + +static int imx8mp_clk_enable(struct clk *clk) +{ + return __imx8mp_clk_enable(clk, 1); +} + +static struct clk_ops imx8mp_clk_ops = { + .set_rate = imx8mp_clk_set_rate, + .get_rate = imx8mp_clk_get_rate, + .enable = imx8mp_clk_enable, + .disable = imx8mp_clk_disable, +}; + +static int imx8mp_clk_probe(struct udevice *dev) +{ + void __iomem *base; + + base = (void *)ANATOP_BASE_ADDR; + + clk_dm(IMX8MP_DRAM_PLL_REF_SEL, imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MP_ARM_PLL_REF_SEL, imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MP_SYS_PLL1_REF_SEL, imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MP_SYS_PLL2_REF_SEL, imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MP_SYS_PLL3_REF_SEL, imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + + clk_dm(IMX8MP_DRAM_PLL, imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mp_dram_pll)); + clk_dm(IMX8MP_ARM_PLL, imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mp_arm_pll)); + clk_dm(IMX8MP_SYS_PLL1, imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mp_sys_pll)); + clk_dm(IMX8MP_SYS_PLL2, imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mp_sys_pll)); + clk_dm(IMX8MP_SYS_PLL3, imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mp_sys_pll)); + + clk_dm(IMX8MP_DRAM_PLL_BYPASS, imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1, dram_pll_bypass_sels, ARRAY_SIZE(dram_pll_bypass_sels), CLK_SET_RATE_PARENT)); + clk_dm(IMX8MP_ARM_PLL_BYPASS, imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT)); + clk_dm(IMX8MP_SYS_PLL1_BYPASS, imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1, sys_pll1_bypass_sels, ARRAY_SIZE(sys_pll1_bypass_sels), CLK_SET_RATE_PARENT)); + clk_dm(IMX8MP_SYS_PLL2_BYPASS, imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1, sys_pll2_bypass_sels, ARRAY_SIZE(sys_pll2_bypass_sels), CLK_SET_RATE_PARENT)); + clk_dm(IMX8MP_SYS_PLL3_BYPASS, imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1, sys_pll3_bypass_sels, ARRAY_SIZE(sys_pll3_bypass_sels), CLK_SET_RATE_PARENT)); + + clk_dm(IMX8MP_DRAM_PLL_OUT, imx_clk_gate("dram_pll_out", "dram_pll_bypass", base + 0x50, 13)); + clk_dm(IMX8MP_ARM_PLL_OUT, imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x84, 11)); + clk_dm(IMX8MP_SYS_PLL1_OUT, imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", base + 0x94, 11)); + clk_dm(IMX8MP_SYS_PLL2_OUT, imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", base + 0x104, 11)); + clk_dm(IMX8MP_SYS_PLL3_OUT, imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", base + 0x114, 11)); + + clk_dm(IMX8MP_SYS_PLL1_40M, imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20)); + clk_dm(IMX8MP_SYS_PLL1_80M, imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10)); + clk_dm(IMX8MP_SYS_PLL1_100M, imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8)); + clk_dm(IMX8MP_SYS_PLL1_133M, imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6)); + clk_dm(IMX8MP_SYS_PLL1_160M, imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5)); + clk_dm(IMX8MP_SYS_PLL1_200M, imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4)); + clk_dm(IMX8MP_SYS_PLL1_266M, imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3)); + clk_dm(IMX8MP_SYS_PLL1_400M, imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2)); + clk_dm(IMX8MP_SYS_PLL1_800M, imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1)); + + clk_dm(IMX8MP_SYS_PLL2_50M, imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20)); + clk_dm(IMX8MP_SYS_PLL2_100M, imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10)); + clk_dm(IMX8MP_SYS_PLL2_125M, imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8)); + clk_dm(IMX8MP_SYS_PLL2_166M, imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6)); + clk_dm(IMX8MP_SYS_PLL2_200M, imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5)); + clk_dm(IMX8MP_SYS_PLL2_250M, imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4)); + clk_dm(IMX8MP_SYS_PLL2_333M, imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3)); + clk_dm(IMX8MP_SYS_PLL2_500M, imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2)); + clk_dm(IMX8MP_SYS_PLL2_1000M, imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1)); + + base = dev_read_addr_ptr(dev); + if (base == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + clk_dm(IMX8MP_CLK_A53_SRC, imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, imx8mp_a53_sels, ARRAY_SIZE(imx8mp_a53_sels))); + clk_dm(IMX8MP_CLK_A53_CG, imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28)); + clk_dm(IMX8MP_CLK_A53_DIV, imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3)); + + clk_dm(IMX8MP_CLK_MAIN_AXI, imx8m_clk_composite_critical("main_axi", imx8mp_main_axi_sels, base + 0x8800)); + clk_dm(IMX8MP_CLK_NAND_USDHC_BUS, imx8m_clk_composite_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, base + 0x8900)); + clk_dm(IMX8MP_CLK_NOC, imx8m_clk_composite_critical("noc", imx8mp_noc_sels, base + 0x8d00)); + clk_dm(IMX8MP_CLK_NOC_IO, imx8m_clk_composite_critical("noc_io", imx8mp_noc_io_sels, base + 0x8d80)); + + clk_dm(IMX8MP_CLK_AHB, imx8m_clk_composite_critical("ahb_root", imx8mp_ahb_sels, base + 0x9000)); + + clk_dm(IMX8MP_CLK_IPG_ROOT, imx_clk_divider2("ipg_root", "ahb_root", base + 0x9080, 0, 1)); + + clk_dm(IMX8MP_CLK_DRAM_ALT, imx8m_clk_composite("dram_alt", imx8mp_dram_alt_sels, base + 0xa000)); + clk_dm(IMX8MP_CLK_DRAM_APB, imx8m_clk_composite_critical("dram_apb", imx8mp_dram_apb_sels, base + 0xa080)); + clk_dm(IMX8MP_CLK_I2C5, imx8m_clk_composite("i2c5", imx8mp_i2c5_sels, base + 0xa480)); + clk_dm(IMX8MP_CLK_I2C6, imx8m_clk_composite("i2c6", imx8mp_i2c6_sels, base + 0xa500)); + clk_dm(IMX8MP_CLK_USDHC1, imx8m_clk_composite("usdhc1", imx8mp_usdhc1_sels, base + 0xac00)); + clk_dm(IMX8MP_CLK_USDHC2, imx8m_clk_composite("usdhc2", imx8mp_usdhc2_sels, base + 0xac80)); + clk_dm(IMX8MP_CLK_I2C1, imx8m_clk_composite("i2c1", imx8mp_i2c1_sels, base + 0xad00)); + clk_dm(IMX8MP_CLK_I2C2, imx8m_clk_composite("i2c2", imx8mp_i2c2_sels, base + 0xad80)); + clk_dm(IMX8MP_CLK_I2C3, imx8m_clk_composite("i2c3", imx8mp_i2c3_sels, base + 0xae00)); + clk_dm(IMX8MP_CLK_I2C4, imx8m_clk_composite("i2c4", imx8mp_i2c4_sels, base + 0xae80)); + + clk_dm(IMX8MP_CLK_UART1, imx8m_clk_composite("uart1", imx8mp_uart1_sels, base + 0xaf00)); + clk_dm(IMX8MP_CLK_UART2, imx8m_clk_composite("uart2", imx8mp_uart2_sels, base + 0xaf80)); + clk_dm(IMX8MP_CLK_UART3, imx8m_clk_composite("uart3", imx8mp_uart3_sels, base + 0xb000)); + clk_dm(IMX8MP_CLK_UART4, imx8m_clk_composite("uart4", imx8mp_uart4_sels, base + 0xb080)); + clk_dm(IMX8MP_CLK_GIC, imx8m_clk_composite_critical("gic", imx8mp_gic_sels, base + 0xb200)); + + clk_dm(IMX8MP_CLK_WDOG, imx8m_clk_composite("wdog", imx8mp_wdog_sels, base + 0xb900)); + clk_dm(IMX8MP_CLK_USDHC3, imx8m_clk_composite("usdhc3", imx8mp_usdhc3_sels, base + 0xbc80)); + + clk_dm(IMX8MP_CLK_DRAM_ALT_ROOT, imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4)); + clk_dm(IMX8MP_CLK_DRAM_CORE, imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mp_dram_core_sels, ARRAY_SIZE(imx8mp_dram_core_sels), CLK_IS_CRITICAL)); + + clk_dm(IMX8MP_CLK_DRAM1_ROOT, imx_clk_gate4_flags("dram1_root_clk", "dram_core_clk", base + 0x4050, 0, CLK_IS_CRITICAL)); + clk_dm(IMX8MP_CLK_GPIO1_ROOT, imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0)); + clk_dm(IMX8MP_CLK_GPIO2_ROOT, imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0)); + clk_dm(IMX8MP_CLK_GPIO3_ROOT, imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0)); + clk_dm(IMX8MP_CLK_GPIO4_ROOT, imx_clk_gate4("gpio4_root_clk", "ipg_root", base + 0x40e0, 0)); + clk_dm(IMX8MP_CLK_GPIO5_ROOT, imx_clk_gate4("gpio5_root_clk", "ipg_root", base + 0x40f0, 0)); + clk_dm(IMX8MP_CLK_I2C1_ROOT, imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0)); + clk_dm(IMX8MP_CLK_I2C2_ROOT, imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0)); + clk_dm(IMX8MP_CLK_I2C3_ROOT, imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0)); + clk_dm(IMX8MP_CLK_I2C4_ROOT, imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0)); + clk_dm(IMX8MP_CLK_I2C5_ROOT, imx_clk_gate2("i2c5_root_clk", "i2c5", base + 0x4330, 0)); + clk_dm(IMX8MP_CLK_I2C6_ROOT, imx_clk_gate2("i2c6_root_clk", "i2c6", base + 0x4340, 0)); + clk_dm(IMX8MP_CLK_UART1_ROOT, imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0)); + clk_dm(IMX8MP_CLK_UART2_ROOT, imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0)); + clk_dm(IMX8MP_CLK_UART3_ROOT, imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0)); + clk_dm(IMX8MP_CLK_UART4_ROOT, imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0)); + clk_dm(IMX8MP_CLK_USDHC1_ROOT, imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0)); + clk_dm(IMX8MP_CLK_USDHC2_ROOT, imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0)); + clk_dm(IMX8MP_CLK_WDOG1_ROOT, imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0)); + clk_dm(IMX8MP_CLK_WDOG2_ROOT, imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0)); + clk_dm(IMX8MP_CLK_WDOG3_ROOT, imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0)); + + clk_dm(IMX8MP_CLK_USDHC3_ROOT, imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0)); + + return 0; +} + +static const struct udevice_id imx8mp_clk_ids[] = { + { .compatible = "fsl,imx8mp-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imx8mp_clk) = { + .name = "clk_imx8mp", + .id = UCLASS_CLK, + .of_match = imx8mp_clk_ids, + .ops = &imx8mp_clk_ops, + .probe = imx8mp_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 07dcf94ea58..60f287046b9 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -125,6 +125,16 @@ static inline struct clk *imx_clk_mux_flags(const char *name, width, 0); } +static inline struct clk *imx_clk_mux2_flags(const char *name, + void __iomem *reg, u8 shift, u8 width, + const char * const *parents, + int num_parents, unsigned long flags) +{ + return clk_register_mux(NULL, name, parents, num_parents, + flags | CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE, + reg, shift, width, 0); +} + static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, u8 shift, u8 width, const char * const *parents, int num_parents) diff --git a/drivers/ddr/altera/Kconfig b/drivers/ddr/altera/Kconfig index 2b1c1be3b51..8f590dc5f61 100644 --- a/drivers/ddr/altera/Kconfig +++ b/drivers/ddr/altera/Kconfig @@ -1,8 +1,8 @@ config SPL_ALTERA_SDRAM bool "SoCFPGA DDR SDRAM driver in SPL" depends on SPL - depends on TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10 || TARGET_SOCFPGA_STRATIX10 - select RAM if TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_STRATIX10 - select SPL_RAM if TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_STRATIX10 + depends on TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10 || TARGET_SOCFPGA_STRATIX10 || TARGET_SOCFPGA_AGILEX + select RAM if TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_STRATIX10 || TARGET_SOCFPGA_AGILEX + select SPL_RAM if TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_STRATIX10 || TARGET_SOCFPGA_AGILEX help Enable DDR SDRAM controller for the SoCFPGA devices. diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile index 341ac0d73b8..39dfee5d5a6 100644 --- a/drivers/ddr/altera/Makefile +++ b/drivers/ddr/altera/Makefile @@ -9,5 +9,6 @@ ifdef CONFIG_$(SPL_)ALTERA_SDRAM obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += sdram_gen5.o sequencer.o obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += sdram_arria10.o -obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_s10.o +obj-$(CONFIG_TARGET_SOCFPGA_STRATIX10) += sdram_soc64.o sdram_s10.o +obj-$(CONFIG_TARGET_SOCFPGA_AGILEX) += sdram_soc64.o sdram_agilex.o endif diff --git a/drivers/ddr/altera/sdram_agilex.c b/drivers/ddr/altera/sdram_agilex.c new file mode 100644 index 00000000000..0cbcd140560 --- /dev/null +++ b/drivers/ddr/altera/sdram_agilex.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Intel Corporation <www.intel.com> + * + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <div64.h> +#include <fdtdec.h> +#include <ram.h> +#include <reset.h> +#include "sdram_soc64.h" +#include <wait_bit.h> +#include <asm/arch/firewall.h> +#include <asm/arch/reset_manager.h> +#include <asm/arch/system_manager.h> +#include <asm/io.h> +#include <linux/sizes.h> + +DECLARE_GLOBAL_DATA_PTR; + +int sdram_mmr_init_full(struct udevice *dev) +{ + struct altera_sdram_platdata *plat = dev->platdata; + struct altera_sdram_priv *priv = dev_get_priv(dev); + u32 i; + int ret; + phys_size_t hw_size; + bd_t bd = {0}; + + /* Ensure HMC clock is running */ + if (poll_hmc_clock_status()) { + debug("DDR: Error as HMC clock was not running\n"); + return -EPERM; + } + + /* Trying 3 times to do a calibration */ + for (i = 0; i < 3; i++) { + ret = wait_for_bit_le32((const void *)(plat->hmc + + DDRCALSTAT), + DDR_HMC_DDRCALSTAT_CAL_MSK, true, 1000, + false); + if (!ret) + break; + + emif_reset(plat); + } + + if (ret) { + puts("DDR: Error as SDRAM calibration failed\n"); + return -EPERM; + } + debug("DDR: Calibration success\n"); + + /* + * Configure the DDR IO size + * niosreserve0: Used to indicate DDR width & + * bit[7:0] = Number of data bits (bit[6:5] 0x01=32bit, 0x10=64bit) + * bit[8] = 1 if user-mode OCT is present + * bit[9] = 1 if warm reset compiled into EMIF Cal Code + * bit[10] = 1 if warm reset is on during generation in EMIF Cal + * niosreserve1: IP ADCDS version encoded as 16 bit value + * bit[2:0] = Variant (0=not special,1=FAE beta, 2=Customer beta, + * 3=EAP, 4-6 are reserved) + * bit[5:3] = Service Pack # (e.g. 1) + * bit[9:6] = Minor Release # + * bit[14:10] = Major Release # + */ + /* Configure DDR IO size x16, x32 and x64 mode */ + u32 update_value; + + update_value = hmc_readl(plat, NIOSRESERVED0); + update_value = (update_value & 0xFF) >> 5; + + /* Configure DDR data rate 0-HAlf-rate 1-Quarter-rate */ + update_value |= (hmc_readl(plat, CTRLCFG3) & 0x4); + hmc_ecc_writel(plat, update_value, DDRIOCTRL); + + /* Copy values MMR IOHMC dramaddrw to HMC adp DRAMADDRWIDTH */ + hmc_ecc_writel(plat, hmc_readl(plat, DRAMADDRW), DRAMADDRWIDTH); + + /* assigning the SDRAM size */ + phys_size_t size = sdram_calculate_size(plat); + + if (size <= 0) + hw_size = PHYS_SDRAM_1_SIZE; + else + 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 -ENXIO; + } + + if (gd->ram_size != hw_size) { + printf("DDR: Warning: DRAM size from device tree (%lld MiB)\n", + gd->ram_size >> 20); + printf(" mismatch with hardware (%lld MiB).\n", + hw_size >> 20); + } + + if (gd->ram_size > hw_size) { + printf("DDR: Error: DRAM size from device tree is greater\n"); + printf(" than hardware size.\n"); + hang(); + } + + printf("DDR: %lld MiB\n", gd->ram_size >> 20); + + /* This enables nonsecure access to DDR */ + /* mpuregion0addr_limit */ + FW_MPU_DDR_SCR_WRITEL(gd->ram_size - 1, + FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT); + FW_MPU_DDR_SCR_WRITEL(0x1F, FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT); + + /* nonmpuregion0addr_limit */ + FW_MPU_DDR_SCR_WRITEL(gd->ram_size - 1, + FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT); + + /* Enable mpuregion0enable and nonmpuregion0enable */ + FW_MPU_DDR_SCR_WRITEL(MPUREGION0_ENABLE | NONMPUREGION0_ENABLE, + FW_MPU_DDR_SCR_EN_SET); + + u32 ctrlcfg1 = hmc_readl(plat, CTRLCFG1); + + /* Enable or disable the DDR ECC */ + if (CTRLCFG1_CFG_CTRL_EN_ECC(ctrlcfg1)) { + setbits_le32(plat->hmc + ECCCTRL1, + (DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_ECC_EN_SET_MSK)); + clrbits_le32(plat->hmc + ECCCTRL1, + (DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_CNT_RST_SET_MSK)); + setbits_le32(plat->hmc + ECCCTRL2, + (DDR_HMC_ECCCTL2_RMW_EN_SET_MSK | + DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); + setbits_le32(plat->hmc + ERRINTEN, + DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK); + + if (!cpu_has_been_warmreset()) + sdram_init_ecc_bits(&bd); + } else { + clrbits_le32(plat->hmc + ECCCTRL1, + (DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_CNT_RST_SET_MSK | + DDR_HMC_ECCCTL_ECC_EN_SET_MSK)); + clrbits_le32(plat->hmc + ECCCTRL2, + (DDR_HMC_ECCCTL2_RMW_EN_SET_MSK | + DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); + } + + /* Enable non-secure reads/writes to HMC Adapter for SDRAM ECC */ + writel(FW_HMC_ADAPTOR_MPU_MASK, FW_HMC_ADAPTOR_REG_ADDR); + + sdram_size_check(&bd); + + priv->info.base = bd.bi_dram[0].start; + priv->info.size = gd->ram_size; + + debug("DDR: HMC init success\n"); + return 0; +} diff --git a/drivers/ddr/altera/sdram_gen5.c b/drivers/ddr/altera/sdram_gen5.c index 8c8ea19eb9c..435f42bc0ab 100644 --- a/drivers/ddr/altera/sdram_gen5.c +++ b/drivers/ddr/altera/sdram_gen5.c @@ -40,9 +40,6 @@ struct sdram_prot_rule { u32 hi_prot_id; }; -static struct socfpga_system_manager *sysmgr_regs = - (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; - static unsigned long sdram_calculate_size(struct socfpga_sdr_ctrl *sdr_ctrl); /** @@ -455,12 +452,14 @@ int sdram_mmr_init_full(struct socfpga_sdr_ctrl *sdr_ctrl, SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB; int ret; - writel(rows, &sysmgr_regs->iswgrp_handoff[4]); + writel(rows, + socfpga_get_sysmgr_addr() + SYSMGR_ISWGRP_HANDOFF_OFFSET(4)); sdr_load_regs(sdr_ctrl, cfg); /* saving this value to SYSMGR.ISWGRP.HANDOFF.FPGA2SDR */ - writel(cfg->fpgaport_rst, &sysmgr_regs->iswgrp_handoff[3]); + writel(cfg->fpgaport_rst, + socfpga_get_sysmgr_addr() + SYSMGR_ISWGRP_HANDOFF_OFFSET(3)); /* only enable if the FPGA is programmed */ if (fpgamgr_test_fpga_ready()) { @@ -516,7 +515,8 @@ static unsigned long sdram_calculate_size(struct socfpga_sdr_ctrl *sdr_ctrl) * since the FB specifies we modify ROWBITs to work around SDRAM * controller issue. */ - row = readl(&sysmgr_regs->iswgrp_handoff[4]); + row = readl(socfpga_get_sysmgr_addr() + + SYSMGR_ISWGRP_HANDOFF_OFFSET(4)); if (row == 0) row = rowbits; /* diff --git a/drivers/ddr/altera/sdram_s10.c b/drivers/ddr/altera/sdram_s10.c index 82d9a13efad..93c15dd18b3 100644 --- a/drivers/ddr/altera/sdram_s10.c +++ b/drivers/ddr/altera/sdram_s10.c @@ -14,32 +14,15 @@ #include <reset.h> #include "sdram_s10.h" #include <wait_bit.h> -#include <asm/arch/firewall_s10.h> -#include <asm/arch/system_manager.h> +#include <asm/arch/firewall.h> #include <asm/arch/reset_manager.h> #include <asm/io.h> #include <linux/sizes.h> -struct altera_sdram_priv { - struct ram_info info; - struct reset_ctl_bulk resets; -}; - -struct altera_sdram_platdata { - void __iomem *hmc; - void __iomem *ddr_sch; - void __iomem *iomhc; -}; - DECLARE_GLOBAL_DATA_PTR; -static const struct socfpga_system_manager *sysmgr_regs = - (void *)SOCFPGA_SYSMGR_ADDRESS; - #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) */ @@ -66,28 +49,6 @@ u32 ddr_config[] = { DDR_CONFIG(1, 4, 10, 17), }; -static u32 hmc_readl(struct altera_sdram_platdata *plat, u32 reg) -{ - return readl(plat->iomhc + reg); -} - -static u32 hmc_ecc_readl(struct altera_sdram_platdata *plat, u32 reg) -{ - return readl(plat->hmc + reg); -} - -static u32 hmc_ecc_writel(struct altera_sdram_platdata *plat, - u32 data, u32 reg) -{ - return writel(data, plat->hmc + reg); -} - -static u32 ddr_sch_writel(struct altera_sdram_platdata *plat, u32 data, - u32 reg) -{ - return writel(data, plat->ddr_sch + reg); -} - int match_ddr_conf(u32 ddr_conf) { int i; @@ -99,192 +60,12 @@ int match_ddr_conf(u32 ddr_conf) return 0; } -static int emif_clear(struct altera_sdram_platdata *plat) -{ - hmc_ecc_writel(plat, 0, RSTHANDSHAKECTRL); - - return wait_for_bit_le32((const void *)(plat->hmc + - RSTHANDSHAKESTAT), - DDR_HMC_RSTHANDSHAKE_MASK, - false, 1000, false); -} - -static int emif_reset(struct altera_sdram_platdata *plat) -{ - u32 c2s, s2c, ret; - - c2s = hmc_ecc_readl(plat, RSTHANDSHAKECTRL) & DDR_HMC_RSTHANDSHAKE_MASK; - s2c = hmc_ecc_readl(plat, RSTHANDSHAKESTAT) & DDR_HMC_RSTHANDSHAKE_MASK; - - debug("DDR: c2s=%08x s2c=%08x nr0=%08x nr1=%08x nr2=%08x dst=%08x\n", - c2s, s2c, hmc_readl(plat, NIOSRESERVED0), - hmc_readl(plat, NIOSRESERVED1), hmc_readl(plat, NIOSRESERVED2), - hmc_readl(plat, DRAMSTS)); - - if (s2c && emif_clear(plat)) { - printf("DDR: emif_clear() failed\n"); - return -1; - } - - debug("DDR: Triggerring emif reset\n"); - hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL); - - /* if seq2core[3] = 0, we are good */ - ret = wait_for_bit_le32((const void *)(plat->hmc + - RSTHANDSHAKESTAT), - DDR_HMC_SEQ2CORE_INT_RESP_MASK, - false, 1000, false); - if (ret) { - printf("DDR: failed to get ack from EMIF\n"); - return ret; - } - - ret = emif_clear(plat); - if (ret) { - printf("DDR: emif_clear() failed\n"); - return ret; - } - - debug("DDR: %s triggered successly\n", __func__); - return 0; -} - -static int poll_hmc_clock_status(void) -{ - return wait_for_bit_le32(&sysmgr_regs->hmc_clk, - 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_calculate_size() - Calculate SDRAM size - * - * Calculate SDRAM device size based on SDRAM controller parameters. - * Size is specified in bytes. - */ -static phys_size_t sdram_calculate_size(struct altera_sdram_platdata *plat) -{ - u32 dramaddrw = hmc_readl(plat, DRAMADDRW); - - phys_size_t size = 1 << (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) + - DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) + - DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) + - DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) + - DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw)); - - size *= (2 << (hmc_ecc_readl(plat, DDRIOCTRL) & - DDR_HMC_DDRIOCTRL_IOSIZE_MSK)); - - return size; -} - /** * sdram_mmr_init_full() - Function to initialize SDRAM MMR * * Initialize the SDRAM MMR. */ -static int sdram_mmr_init_full(struct udevice *dev) +int sdram_mmr_init_full(struct udevice *dev) { struct altera_sdram_platdata *plat = dev->platdata; struct altera_sdram_priv *priv = dev_get_priv(dev); @@ -324,6 +105,20 @@ static int sdram_mmr_init_full(struct udevice *dev) clrbits_le32(CCU_REG_ADDR(CCU_IOM_MPRT_ADBASE_MEMSPACE1E), CCU_ADBASE_DI_MASK); + /* Enable access to DDR from TCU */ + clrbits_le32(CCU_REG_ADDR(CCU_TCU_MPRT_ADBASE_MEMSPACE0), + CCU_ADBASE_DI_MASK); + clrbits_le32(CCU_REG_ADDR(CCU_TCU_MPRT_ADBASE_MEMSPACE1A), + CCU_ADBASE_DI_MASK); + clrbits_le32(CCU_REG_ADDR(CCU_TCU_MPRT_ADBASE_MEMSPACE1B), + CCU_ADBASE_DI_MASK); + clrbits_le32(CCU_REG_ADDR(CCU_TCU_MPRT_ADBASE_MEMSPACE1C), + CCU_ADBASE_DI_MASK); + clrbits_le32(CCU_REG_ADDR(CCU_TCU_MPRT_ADBASE_MEMSPACE1D), + CCU_ADBASE_DI_MASK); + clrbits_le32(CCU_REG_ADDR(CCU_TCU_MPRT_ADBASE_MEMSPACE1E), + CCU_ADBASE_DI_MASK); + /* this enables nonsecure access to DDR */ /* mpuregion0addr_limit */ FW_MPU_DDR_SCR_WRITEL(0xFFFF0000, FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT); @@ -512,9 +307,6 @@ static int sdram_mmr_init_full(struct udevice *dev) DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); hmc_ecc_writel(plat, DDR_HMC_ERRINTEN_INTMASK, 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); @@ -528,6 +320,9 @@ static int sdram_mmr_init_full(struct udevice *dev) DDR_HMC_ECCCTL2_AWB_EN_SET_MSK)); } + /* Enable non-secure reads/writes to HMC Adapter for SDRAM ECC */ + writel(FW_HMC_ADAPTOR_MPU_MASK, FW_HMC_ADAPTOR_REG_ADDR); + sdram_size_check(&bd); priv->info.base = bd.bi_dram[0].start; @@ -537,80 +332,3 @@ static int sdram_mmr_init_full(struct udevice *dev) return 0; } -static int altera_sdram_ofdata_to_platdata(struct udevice *dev) -{ - struct altera_sdram_platdata *plat = dev->platdata; - fdt_addr_t addr; - - addr = dev_read_addr_index(dev, 0); - if (addr == FDT_ADDR_T_NONE) - return -EINVAL; - plat->ddr_sch = (void __iomem *)addr; - - addr = dev_read_addr_index(dev, 1); - if (addr == FDT_ADDR_T_NONE) - return -EINVAL; - plat->iomhc = (void __iomem *)addr; - - addr = dev_read_addr_index(dev, 2); - if (addr == FDT_ADDR_T_NONE) - return -EINVAL; - plat->hmc = (void __iomem *)addr; - - return 0; -} - -static int altera_sdram_probe(struct udevice *dev) -{ - int ret; - struct altera_sdram_priv *priv = dev_get_priv(dev); - - ret = reset_get_bulk(dev, &priv->resets); - if (ret) { - dev_err(dev, "Can't get reset: %d\n", ret); - return -ENODEV; - } - reset_deassert_bulk(&priv->resets); - - if (sdram_mmr_init_full(dev) != 0) { - puts("SDRAM init failed.\n"); - goto failed; - } - - return 0; - -failed: - reset_release_bulk(&priv->resets); - return -ENODEV; -} - -static int altera_sdram_get_info(struct udevice *dev, - struct ram_info *info) -{ - struct altera_sdram_priv *priv = dev_get_priv(dev); - - info->base = priv->info.base; - info->size = priv->info.size; - - return 0; -} - -static struct ram_ops altera_sdram_ops = { - .get_info = altera_sdram_get_info, -}; - -static const struct udevice_id altera_sdram_ids[] = { - { .compatible = "altr,sdr-ctl-s10" }, - { /* sentinel */ } -}; - -U_BOOT_DRIVER(altera_sdram) = { - .name = "altr_sdr_ctl", - .id = UCLASS_RAM, - .of_match = altera_sdram_ids, - .ops = &altera_sdram_ops, - .ofdata_to_platdata = altera_sdram_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct altera_sdram_platdata), - .probe = altera_sdram_probe, - .priv_auto_alloc_size = sizeof(struct altera_sdram_priv), -}; diff --git a/drivers/ddr/altera/sdram_s10.h b/drivers/ddr/altera/sdram_s10.h index 096c06cba21..cca4cb35ec2 100644 --- a/drivers/ddr/altera/sdram_s10.h +++ b/drivers/ddr/altera/sdram_s10.h @@ -11,48 +11,6 @@ #define DDR_READ_LATENCY_DELAY 40 #define DDR_ACTIVATE_FAWBANK 0x1 -/* ECC HMC registers */ -#define DDRIOCTRL 0x8 -#define DDRCALSTAT 0xc -#define DRAMADDRWIDTH 0xe0 -#define ECCCTRL1 0x100 -#define ECCCTRL2 0x104 -#define ERRINTEN 0x110 -#define ERRINTENS 0x114 -#define INTMODE 0x11c -#define INTSTAT 0x120 -#define AUTOWB_CORRADDR 0x138 -#define ECC_REG2WRECCDATABUS 0x144 -#define ECC_DIAGON 0x150 -#define ECC_DECSTAT 0x154 -#define HPSINTFCSEL 0x210 -#define RSTHANDSHAKECTRL 0x214 -#define RSTHANDSHAKESTAT 0x218 - -#define DDR_HMC_DDRIOCTRL_IOSIZE_MSK 0x00000003 -#define DDR_HMC_DDRCALSTAT_CAL_MSK BIT(0) -#define DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK BIT(16) -#define DDR_HMC_ECCCTL_CNT_RST_SET_MSK BIT(8) -#define DDR_HMC_ECCCTL_ECC_EN_SET_MSK BIT(0) -#define DDR_HMC_ECCCTL2_RMW_EN_SET_MSK BIT(8) -#define DDR_HMC_ECCCTL2_AWB_EN_SET_MSK BIT(0) -#define DDR_HMC_ECC_DIAGON_ECCDIAGON_EN_SET_MSK BIT(16) -#define DDR_HMC_ECC_DIAGON_WRDIAGON_EN_SET_MSK BIT(0) -#define DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK BIT(0) -#define DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK BIT(1) -#define DDR_HMC_INTSTAT_SERRPENA_SET_MSK BIT(0) -#define DDR_HMC_INTSTAT_DERRPENA_SET_MSK BIT(1) -#define DDR_HMC_INTSTAT_ADDRMTCFLG_SET_MSK BIT(16) -#define DDR_HMC_INTMODE_INTMODE_SET_MSK BIT(0) -#define DDR_HMC_RSTHANDSHAKE_MASK 0x000000ff -#define DDR_HMC_CORE2SEQ_INT_REQ 0xF -#define DDR_HMC_SEQ2CORE_INT_RESP_MASK BIT(3) -#define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f - -#define DDR_HMC_ERRINTEN_INTMASK \ - (DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK | \ - DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK) - /* NOC DDR scheduler */ #define DDR_SCH_ID_COREID 0 #define DDR_SCH_ID_REVID 0x4 @@ -79,110 +37,6 @@ #define DDR_SCH_DEVTODEV_BUSRDTOWR_OFF 2 #define DDR_SCH_DEVTODEV_BUSWRTORD_OFF 4 -/* HMC MMR IO48 registers */ -#define CTRLCFG0 0x28 -#define CTRLCFG1 0x2c -#define DRAMTIMING0 0x50 -#define CALTIMING0 0x7c -#define CALTIMING1 0x80 -#define CALTIMING2 0x84 -#define CALTIMING3 0x88 -#define CALTIMING4 0x8c -#define CALTIMING9 0xa0 -#define DRAMADDRW 0xa8 -#define DRAMSTS 0xec -#define NIOSRESERVED0 0x110 -#define NIOSRESERVED1 0x114 -#define NIOSRESERVED2 0x118 - -#define DRAMADDRW_CFG_COL_ADDR_WIDTH(x) \ - (((x) >> 0) & 0x1F) -#define DRAMADDRW_CFG_ROW_ADDR_WIDTH(x) \ - (((x) >> 5) & 0x1F) -#define DRAMADDRW_CFG_BANK_ADDR_WIDTH(x) \ - (((x) >> 10) & 0xF) -#define DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(x) \ - (((x) >> 14) & 0x3) -#define DRAMADDRW_CFG_CS_ADDR_WIDTH(x) \ - (((x) >> 16) & 0x7) - -#define CTRLCFG0_CFG_MEMTYPE(x) \ - (((x) >> 0) & 0xF) -#define CTRLCFG0_CFG_DIMM_TYPE(x) \ - (((x) >> 4) & 0x7) -#define CTRLCFG0_CFG_AC_POS(x) \ - (((x) >> 7) & 0x3) -#define CTRLCFG0_CFG_CTRL_BURST_LEN(x) \ - (((x) >> 9) & 0x1F) - -#define CTRLCFG1_CFG_DBC3_BURST_LEN(x) \ - (((x) >> 0) & 0x1F) -#define CTRLCFG1_CFG_ADDR_ORDER(x) \ - (((x) >> 5) & 0x3) -#define CTRLCFG1_CFG_CTRL_EN_ECC(x) \ - (((x) >> 7) & 0x1) - -#define DRAMTIMING0_CFG_TCL(x) \ - (((x) >> 0) & 0x7F) - -#define CALTIMING0_CFG_ACT_TO_RDWR(x) \ - (((x) >> 0) & 0x3F) -#define CALTIMING0_CFG_ACT_TO_PCH(x) \ - (((x) >> 6) & 0x3F) -#define CALTIMING0_CFG_ACT_TO_ACT(x) \ - (((x) >> 12) & 0x3F) -#define CALTIMING0_CFG_ACT_TO_ACT_DB(x) \ - (((x) >> 18) & 0x3F) - -#define CALTIMING1_CFG_RD_TO_RD(x) \ - (((x) >> 0) & 0x3F) -#define CALTIMING1_CFG_RD_TO_RD_DC(x) \ - (((x) >> 6) & 0x3F) -#define CALTIMING1_CFG_RD_TO_RD_DB(x) \ - (((x) >> 12) & 0x3F) -#define CALTIMING1_CFG_RD_TO_WR(x) \ - (((x) >> 18) & 0x3F) -#define CALTIMING1_CFG_RD_TO_WR_DC(x) \ - (((x) >> 24) & 0x3F) - -#define CALTIMING2_CFG_RD_TO_WR_DB(x) \ - (((x) >> 0) & 0x3F) -#define CALTIMING2_CFG_RD_TO_WR_PCH(x) \ - (((x) >> 6) & 0x3F) -#define CALTIMING2_CFG_RD_AP_TO_VALID(x) \ - (((x) >> 12) & 0x3F) -#define CALTIMING2_CFG_WR_TO_WR(x) \ - (((x) >> 18) & 0x3F) -#define CALTIMING2_CFG_WR_TO_WR_DC(x) \ - (((x) >> 24) & 0x3F) - -#define CALTIMING3_CFG_WR_TO_WR_DB(x) \ - (((x) >> 0) & 0x3F) -#define CALTIMING3_CFG_WR_TO_RD(x) \ - (((x) >> 6) & 0x3F) -#define CALTIMING3_CFG_WR_TO_RD_DC(x) \ - (((x) >> 12) & 0x3F) -#define CALTIMING3_CFG_WR_TO_RD_DB(x) \ - (((x) >> 18) & 0x3F) -#define CALTIMING3_CFG_WR_TO_PCH(x) \ - (((x) >> 24) & 0x3F) - -#define CALTIMING4_CFG_WR_AP_TO_VALID(x) \ - (((x) >> 0) & 0x3F) -#define CALTIMING4_CFG_PCH_TO_VALID(x) \ - (((x) >> 6) & 0x3F) -#define CALTIMING4_CFG_PCH_ALL_TO_VALID(x) \ - (((x) >> 12) & 0x3F) -#define CALTIMING4_CFG_ARF_TO_VALID(x) \ - (((x) >> 18) & 0xFF) -#define CALTIMING4_CFG_PDN_TO_VALID(x) \ - (((x) >> 26) & 0x3F) - -#define CALTIMING9_CFG_4_ACT_TO_ACT(x) \ - (((x) >> 0) & 0xFF) - -/* Firewall DDR scheduler MPFE */ -#define FW_HMC_ADAPTOR_REG_ADDR 0xf8020004 -#define FW_HMC_ADAPTOR_MPU_MASK BIT(0) +#include "sdram_soc64.h" #endif /* _SDRAM_S10_H_ */ diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c new file mode 100644 index 00000000000..985a108b1c5 --- /dev/null +++ b/drivers/ddr/altera/sdram_soc64.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2016-2019 Intel Corporation <www.intel.com> + * + */ + +#include <common.h> +#include <cpu_func.h> +#include <dm.h> +#include <errno.h> +#include <div64.h> +#include <fdtdec.h> +#include <ram.h> +#include <reset.h> +#include "sdram_soc64.h" +#include <wait_bit.h> +#include <asm/arch/firewall.h> +#include <asm/arch/system_manager.h> +#include <asm/arch/reset_manager.h> +#include <asm/io.h> +#include <linux/sizes.h> + +#define PGTABLE_OFF 0x4000 + +u32 hmc_readl(struct altera_sdram_platdata *plat, u32 reg) +{ + return readl(plat->iomhc + reg); +} + +u32 hmc_ecc_readl(struct altera_sdram_platdata *plat, u32 reg) +{ + return readl(plat->hmc + reg); +} + +u32 hmc_ecc_writel(struct altera_sdram_platdata *plat, + u32 data, u32 reg) +{ + return writel(data, plat->hmc + reg); +} + +u32 ddr_sch_writel(struct altera_sdram_platdata *plat, u32 data, + u32 reg) +{ + return writel(data, plat->ddr_sch + reg); +} + +int emif_clear(struct altera_sdram_platdata *plat) +{ + hmc_ecc_writel(plat, 0, RSTHANDSHAKECTRL); + + return wait_for_bit_le32((const void *)(plat->hmc + + RSTHANDSHAKESTAT), + DDR_HMC_RSTHANDSHAKE_MASK, + false, 1000, false); +} + +int emif_reset(struct altera_sdram_platdata *plat) +{ + u32 c2s, s2c, ret; + + c2s = hmc_ecc_readl(plat, RSTHANDSHAKECTRL) & DDR_HMC_RSTHANDSHAKE_MASK; + s2c = hmc_ecc_readl(plat, RSTHANDSHAKESTAT) & DDR_HMC_RSTHANDSHAKE_MASK; + + debug("DDR: c2s=%08x s2c=%08x nr0=%08x nr1=%08x nr2=%08x dst=%08x\n", + c2s, s2c, hmc_readl(plat, NIOSRESERVED0), + hmc_readl(plat, NIOSRESERVED1), hmc_readl(plat, NIOSRESERVED2), + hmc_readl(plat, DRAMSTS)); + + if (s2c && emif_clear(plat)) { + printf("DDR: emif_clear() failed\n"); + return -1; + } + + debug("DDR: Triggerring emif reset\n"); + hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL); + + /* if seq2core[3] = 0, we are good */ + ret = wait_for_bit_le32((const void *)(plat->hmc + + RSTHANDSHAKESTAT), + DDR_HMC_SEQ2CORE_INT_RESP_MASK, + false, 1000, false); + if (ret) { + printf("DDR: failed to get ack from EMIF\n"); + return ret; + } + + ret = emif_clear(plat); + if (ret) { + printf("DDR: emif_clear() failed\n"); + return ret; + } + + debug("DDR: %s triggered successly\n", __func__); + return 0; +} + +int poll_hmc_clock_status(void) +{ + return wait_for_bit_le32((const void *)(socfpga_get_sysmgr_addr() + + SYSMGR_SOC64_HMC_CLK), + SYSMGR_HMC_CLK_STATUS_MSK, true, 1000, false); +} + +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; + } +} + +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)); +} + +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_calculate_size() - Calculate SDRAM size + * + * Calculate SDRAM device size based on SDRAM controller parameters. + * Size is specified in bytes. + */ +phys_size_t sdram_calculate_size(struct altera_sdram_platdata *plat) +{ + u32 dramaddrw = hmc_readl(plat, DRAMADDRW); + + phys_size_t size = 1 << (DRAMADDRW_CFG_CS_ADDR_WIDTH(dramaddrw) + + DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(dramaddrw) + + DRAMADDRW_CFG_BANK_ADDR_WIDTH(dramaddrw) + + DRAMADDRW_CFG_ROW_ADDR_WIDTH(dramaddrw) + + DRAMADDRW_CFG_COL_ADDR_WIDTH(dramaddrw)); + + size *= (2 << (hmc_ecc_readl(plat, DDRIOCTRL) & + DDR_HMC_DDRIOCTRL_IOSIZE_MSK)); + + return size; +} + +static int altera_sdram_ofdata_to_platdata(struct udevice *dev) +{ + struct altera_sdram_platdata *plat = dev->platdata; + fdt_addr_t addr; + + addr = dev_read_addr_index(dev, 0); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + plat->ddr_sch = (void __iomem *)addr; + + addr = dev_read_addr_index(dev, 1); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + plat->iomhc = (void __iomem *)addr; + + addr = dev_read_addr_index(dev, 2); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + plat->hmc = (void __iomem *)addr; + + return 0; +} + +static int altera_sdram_probe(struct udevice *dev) +{ + int ret; + struct altera_sdram_priv *priv = dev_get_priv(dev); + + ret = reset_get_bulk(dev, &priv->resets); + if (ret) { + dev_err(dev, "Can't get reset: %d\n", ret); + return -ENODEV; + } + reset_deassert_bulk(&priv->resets); + + if (sdram_mmr_init_full(dev) != 0) { + puts("SDRAM init failed.\n"); + goto failed; + } + + return 0; + +failed: + reset_release_bulk(&priv->resets); + return -ENODEV; +} + +static int altera_sdram_get_info(struct udevice *dev, + struct ram_info *info) +{ + struct altera_sdram_priv *priv = dev_get_priv(dev); + + info->base = priv->info.base; + info->size = priv->info.size; + + return 0; +} + +static struct ram_ops altera_sdram_ops = { + .get_info = altera_sdram_get_info, +}; + +static const struct udevice_id altera_sdram_ids[] = { + { .compatible = "altr,sdr-ctl-s10" }, + { .compatible = "intel,sdr-ctl-agilex" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(altera_sdram) = { + .name = "altr_sdr_ctl", + .id = UCLASS_RAM, + .of_match = altera_sdram_ids, + .ops = &altera_sdram_ops, + .ofdata_to_platdata = altera_sdram_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct altera_sdram_platdata), + .probe = altera_sdram_probe, + .priv_auto_alloc_size = sizeof(struct altera_sdram_priv), +}; diff --git a/drivers/ddr/altera/sdram_soc64.h b/drivers/ddr/altera/sdram_soc64.h new file mode 100644 index 00000000000..7b25a80ae26 --- /dev/null +++ b/drivers/ddr/altera/sdram_soc64.h @@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017-2019 Intel Corporation <www.intel.com> + */ + +#ifndef _SDRAM_SOC64_H_ +#define _SDRAM_SOC64_H_ + +#include <common.h> +#include <linux/sizes.h> + +struct altera_sdram_priv { + struct ram_info info; + struct reset_ctl_bulk resets; +}; + +struct altera_sdram_platdata { + void __iomem *hmc; + void __iomem *ddr_sch; + void __iomem *iomhc; +}; + +/* ECC HMC registers */ +#define DDRIOCTRL 0x8 +#define DDRCALSTAT 0xc +#define DRAMADDRWIDTH 0xe0 +#define ECCCTRL1 0x100 +#define ECCCTRL2 0x104 +#define ERRINTEN 0x110 +#define ERRINTENS 0x114 +#define INTMODE 0x11c +#define INTSTAT 0x120 +#define AUTOWB_CORRADDR 0x138 +#define ECC_REG2WRECCDATABUS 0x144 +#define ECC_DIAGON 0x150 +#define ECC_DECSTAT 0x154 +#define HPSINTFCSEL 0x210 +#define RSTHANDSHAKECTRL 0x214 +#define RSTHANDSHAKESTAT 0x218 + +#define DDR_HMC_DDRIOCTRL_IOSIZE_MSK 0x00000003 +#define DDR_HMC_DDRCALSTAT_CAL_MSK BIT(0) +#define DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK BIT(16) +#define DDR_HMC_ECCCTL_CNT_RST_SET_MSK BIT(8) +#define DDR_HMC_ECCCTL_ECC_EN_SET_MSK BIT(0) +#define DDR_HMC_ECCCTL2_RMW_EN_SET_MSK BIT(8) +#define DDR_HMC_ECCCTL2_AWB_EN_SET_MSK BIT(0) +#define DDR_HMC_ECC_DIAGON_ECCDIAGON_EN_SET_MSK BIT(16) +#define DDR_HMC_ECC_DIAGON_WRDIAGON_EN_SET_MSK BIT(0) +#define DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK BIT(0) +#define DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK BIT(1) +#define DDR_HMC_INTSTAT_SERRPENA_SET_MSK BIT(0) +#define DDR_HMC_INTSTAT_DERRPENA_SET_MSK BIT(1) +#define DDR_HMC_INTSTAT_ADDRMTCFLG_SET_MSK BIT(16) +#define DDR_HMC_INTMODE_INTMODE_SET_MSK BIT(0) +#define DDR_HMC_RSTHANDSHAKE_MASK 0x000000ff +#define DDR_HMC_CORE2SEQ_INT_REQ 0xF +#define DDR_HMC_SEQ2CORE_INT_RESP_MASK BIT(3) +#define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f + +#define DDR_HMC_ERRINTEN_INTMASK \ + (DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK | \ + DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK) + +/* HMC MMR IO48 registers */ +#define CTRLCFG0 0x28 +#define CTRLCFG1 0x2c +#define CTRLCFG3 0x34 +#define DRAMTIMING0 0x50 +#define CALTIMING0 0x7c +#define CALTIMING1 0x80 +#define CALTIMING2 0x84 +#define CALTIMING3 0x88 +#define CALTIMING4 0x8c +#define CALTIMING9 0xa0 +#define DRAMADDRW 0xa8 +#define DRAMSTS 0xec +#define NIOSRESERVED0 0x110 +#define NIOSRESERVED1 0x114 +#define NIOSRESERVED2 0x118 + +#define DRAMADDRW_CFG_COL_ADDR_WIDTH(x) \ + (((x) >> 0) & 0x1F) +#define DRAMADDRW_CFG_ROW_ADDR_WIDTH(x) \ + (((x) >> 5) & 0x1F) +#define DRAMADDRW_CFG_BANK_ADDR_WIDTH(x) \ + (((x) >> 10) & 0xF) +#define DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(x) \ + (((x) >> 14) & 0x3) +#define DRAMADDRW_CFG_CS_ADDR_WIDTH(x) \ + (((x) >> 16) & 0x7) + +#define CTRLCFG0_CFG_MEMTYPE(x) \ + (((x) >> 0) & 0xF) +#define CTRLCFG0_CFG_DIMM_TYPE(x) \ + (((x) >> 4) & 0x7) +#define CTRLCFG0_CFG_AC_POS(x) \ + (((x) >> 7) & 0x3) +#define CTRLCFG0_CFG_CTRL_BURST_LEN(x) \ + (((x) >> 9) & 0x1F) + +#define CTRLCFG1_CFG_DBC3_BURST_LEN(x) \ + (((x) >> 0) & 0x1F) +#define CTRLCFG1_CFG_ADDR_ORDER(x) \ + (((x) >> 5) & 0x3) +#define CTRLCFG1_CFG_CTRL_EN_ECC(x) \ + (((x) >> 7) & 0x1) + +#define DRAMTIMING0_CFG_TCL(x) \ + (((x) >> 0) & 0x7F) + +#define CALTIMING0_CFG_ACT_TO_RDWR(x) \ + (((x) >> 0) & 0x3F) +#define CALTIMING0_CFG_ACT_TO_PCH(x) \ + (((x) >> 6) & 0x3F) +#define CALTIMING0_CFG_ACT_TO_ACT(x) \ + (((x) >> 12) & 0x3F) +#define CALTIMING0_CFG_ACT_TO_ACT_DB(x) \ + (((x) >> 18) & 0x3F) + +#define CALTIMING1_CFG_RD_TO_RD(x) \ + (((x) >> 0) & 0x3F) +#define CALTIMING1_CFG_RD_TO_RD_DC(x) \ + (((x) >> 6) & 0x3F) +#define CALTIMING1_CFG_RD_TO_RD_DB(x) \ + (((x) >> 12) & 0x3F) +#define CALTIMING1_CFG_RD_TO_WR(x) \ + (((x) >> 18) & 0x3F) +#define CALTIMING1_CFG_RD_TO_WR_DC(x) \ + (((x) >> 24) & 0x3F) + +#define CALTIMING2_CFG_RD_TO_WR_DB(x) \ + (((x) >> 0) & 0x3F) +#define CALTIMING2_CFG_RD_TO_WR_PCH(x) \ + (((x) >> 6) & 0x3F) +#define CALTIMING2_CFG_RD_AP_TO_VALID(x) \ + (((x) >> 12) & 0x3F) +#define CALTIMING2_CFG_WR_TO_WR(x) \ + (((x) >> 18) & 0x3F) +#define CALTIMING2_CFG_WR_TO_WR_DC(x) \ + (((x) >> 24) & 0x3F) + +#define CALTIMING3_CFG_WR_TO_WR_DB(x) \ + (((x) >> 0) & 0x3F) +#define CALTIMING3_CFG_WR_TO_RD(x) \ + (((x) >> 6) & 0x3F) +#define CALTIMING3_CFG_WR_TO_RD_DC(x) \ + (((x) >> 12) & 0x3F) +#define CALTIMING3_CFG_WR_TO_RD_DB(x) \ + (((x) >> 18) & 0x3F) +#define CALTIMING3_CFG_WR_TO_PCH(x) \ + (((x) >> 24) & 0x3F) + +#define CALTIMING4_CFG_WR_AP_TO_VALID(x) \ + (((x) >> 0) & 0x3F) +#define CALTIMING4_CFG_PCH_TO_VALID(x) \ + (((x) >> 6) & 0x3F) +#define CALTIMING4_CFG_PCH_ALL_TO_VALID(x) \ + (((x) >> 12) & 0x3F) +#define CALTIMING4_CFG_ARF_TO_VALID(x) \ + (((x) >> 18) & 0xFF) +#define CALTIMING4_CFG_PDN_TO_VALID(x) \ + (((x) >> 26) & 0x3F) + +#define CALTIMING9_CFG_4_ACT_TO_ACT(x) \ + (((x) >> 0) & 0xFF) + +/* Firewall DDR scheduler MPFE */ +#define FW_HMC_ADAPTOR_REG_ADDR 0xf8020004 +#define FW_HMC_ADAPTOR_MPU_MASK BIT(0) + +u32 hmc_readl(struct altera_sdram_platdata *plat, u32 reg); +u32 hmc_ecc_readl(struct altera_sdram_platdata *plat, u32 reg); +u32 hmc_ecc_writel(struct altera_sdram_platdata *plat, + u32 data, u32 reg); +u32 ddr_sch_writel(struct altera_sdram_platdata *plat, u32 data, + u32 reg); +int emif_clear(struct altera_sdram_platdata *plat); +int emif_reset(struct altera_sdram_platdata *plat); +int poll_hmc_clock_status(void); +void sdram_clear_mem(phys_addr_t addr, phys_size_t size); +void sdram_init_ecc_bits(bd_t *bd); +void sdram_size_check(bd_t *bd); +phys_size_t sdram_calculate_size(struct altera_sdram_platdata *plat); +int sdram_mmr_init_full(struct udevice *dev); + +#endif /* _SDRAM_SOC64_H_ */ diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c index 21af66e4e7f..af8c1427d2e 100644 --- a/drivers/ddr/imx/imx8m/ddr_init.c +++ b/drivers/ddr/imx/imx8m/ddr_init.c @@ -20,9 +20,10 @@ void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num) } } -void ddr_init(struct dram_timing_info *dram_timing) +int ddr_init(struct dram_timing_info *dram_timing) { unsigned int tmp, initial_drate, target_freq; + int ret; debug("DDRINFO: start DRAM init\n"); @@ -98,7 +99,11 @@ void ddr_init(struct dram_timing_info *dram_timing) * accessing relevant PUB registers */ debug("DDRINFO:ddrphy config start\n"); - ddr_cfg_phy(dram_timing); + + ret = ddr_cfg_phy(dram_timing); + if (ret) + return ret; + debug("DDRINFO: ddrphy config done\n"); /* @@ -165,4 +170,6 @@ void ddr_init(struct dram_timing_info *dram_timing) /* save the dram timing config into memory */ dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE); + + return 0; } diff --git a/drivers/ddr/imx/imx8m/ddrphy_train.c b/drivers/ddr/imx/imx8m/ddrphy_train.c index 18f7ed7fea9..306af82504f 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_train.c +++ b/drivers/ddr/imx/imx8m/ddrphy_train.c @@ -8,13 +8,14 @@ #include <asm/arch/ddr.h> #include <asm/arch/lpddr4_define.h> -void ddr_cfg_phy(struct dram_timing_info *dram_timing) +int ddr_cfg_phy(struct dram_timing_info *dram_timing) { struct dram_cfg_param *dram_cfg; struct dram_fsp_msg *fsp_msg; unsigned int num; int i = 0; int j = 0; + int ret; /* initialize PHY configuration */ dram_cfg = dram_timing->ddrphy_cfg; @@ -60,7 +61,9 @@ void ddr_cfg_phy(struct dram_timing_info *dram_timing) dwc_ddrphy_apb_wr(0xd0099, 0x0); /* Wait for the training firmware to complete */ - wait_ddrphy_training_complete(); + ret = wait_ddrphy_training_complete(); + if (ret) + return ret; /* Halt the microcontroller. */ dwc_ddrphy_apb_wr(0xd0099, 0x1); @@ -83,4 +86,6 @@ void ddr_cfg_phy(struct dram_timing_info *dram_timing) /* save the ddr PHY trained CSR in memory for low power use */ ddrphy_trained_csr_save(ddrphy_trained_csr, ddrphy_trained_csr_num); + + return 0; } diff --git a/drivers/ddr/imx/imx8m/ddrphy_utils.c b/drivers/ddr/imx/imx8m/ddrphy_utils.c index e60503309eb..9ac7ca923c7 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_utils.c +++ b/drivers/ddr/imx/imx8m/ddrphy_utils.c @@ -84,7 +84,7 @@ static inline void decode_streaming_message(void) debug("\n"); } -void wait_ddrphy_training_complete(void) +int wait_ddrphy_training_complete(void) { unsigned int mail; @@ -95,10 +95,10 @@ void wait_ddrphy_training_complete(void) decode_streaming_message(); } else if (mail == 0x07) { debug("Training PASS\n"); - break; + return 0; } else if (mail == 0xff) { - printf("Training FAILED\n"); - break; + debug("Training FAILED\n"); + return -1; } } } @@ -106,6 +106,10 @@ void wait_ddrphy_training_complete(void) void ddrphy_init_set_dfi_clk(unsigned int drate) { switch (drate) { + case 4000: + dram_pll_init(MHZ(1000)); + dram_disable_bypass(); + break; case 3200: dram_pll_init(MHZ(800)); dram_disable_bypass(); diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c index 5fb9d6a1911..2853581b975 100644 --- a/drivers/fpga/socfpga_arria10.c +++ b/drivers/fpga/socfpga_arria10.c @@ -30,9 +30,6 @@ DECLARE_GLOBAL_DATA_PTR; static const struct socfpga_fpga_manager *fpga_manager_base = (void *)SOCFPGA_FPGAMGRREGS_ADDRESS; -static const struct socfpga_system_manager *system_manager_base = - (void *)SOCFPGA_SYSMGR_ADDRESS; - static void fpgamgr_set_cd_ratio(unsigned long ratio); static uint32_t fpgamgr_get_msel(void) @@ -818,7 +815,7 @@ int socfpga_loadfs(fpga_fs_info *fpga_fsinfo, const void *buf, size_t bsize, } /* Disable all signals from HPS peripheral controller to FPGA */ - writel(0, &system_manager_base->fpgaintf_en_global); + writel(0, socfpga_get_sysmgr_addr() + SYSMGR_A10_FPGAINTF_EN_GLOBAL); /* Disable all axi bridges (hps2fpga, lwhps2fpga & fpga2hps) */ socfpga_bridges_reset(); @@ -910,7 +907,7 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) memset(&rbfinfo, 0, sizeof(rbfinfo)); /* Disable all signals from hps peripheral controller to fpga */ - writel(0, &system_manager_base->fpgaintf_en_global); + writel(0, socfpga_get_sysmgr_addr() + SYSMGR_A10_FPGAINTF_EN_GLOBAL); /* Disable all axi bridge (hps2fpga, lwhps2fpga & fpga2hps) */ socfpga_bridges_reset(); diff --git a/drivers/fpga/socfpga_gen5.c b/drivers/fpga/socfpga_gen5.c index 6d16e0b37fb..d73474f29ee 100644 --- a/drivers/fpga/socfpga_gen5.c +++ b/drivers/fpga/socfpga_gen5.c @@ -15,8 +15,6 @@ static struct socfpga_fpga_manager *fpgamgr_regs = (struct socfpga_fpga_manager *)SOCFPGA_FPGAMGRREGS_ADDRESS; -static struct socfpga_system_manager *sysmgr_regs = - (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS; /* Set CD ratio */ static void fpgamgr_set_cd_ratio(unsigned long ratio) @@ -214,7 +212,7 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) /* Prior programming the FPGA, all bridges need to be shut off */ /* Disable all signals from hps peripheral controller to fpga */ - writel(0, &sysmgr_regs->fpgaintfgrp_module); + writel(0, socfpga_get_sysmgr_addr() + SYSMGR_GEN5_FPGAINFGRP_MODULE); /* Disable all signals from FPGA to HPS SDRAM */ #define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080 diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c index 1b945e9727a..80cd8dcedac 100644 --- a/drivers/misc/mxc_ocotp.c +++ b/drivers/misc/mxc_ocotp.c @@ -35,7 +35,16 @@ #define BM_OUT_STATUS_LOCKED 0x00000800 #define BM_OUT_STATUS_PROGFAIL 0x00001000 #elif defined(CONFIG_IMX8M) +#ifdef CONFIG_IMX8MP +#undef BM_CTRL_ADDR +#undef BM_CTRL_ERROR +#undef BM_CTRL_BUSY +#define BM_CTRL_ADDR 0x000001ff +#define BM_CTRL_ERROR 0x00000400 +#define BM_CTRL_BUSY 0x00000200 +#else #define BM_CTRL_ADDR 0x000000ff +#endif #else #define BM_CTRL_ADDR 0x0000007f #endif @@ -82,7 +91,11 @@ #define FUSE_BANKS 31 #elif defined(CONFIG_IMX8M) #define FUSE_BANK_SIZE 0x40 +#ifdef CONFIG_IMX8MP +#define FUSE_BANKS 96 +#else #define FUSE_BANKS 64 +#endif #else #error "Unsupported architecture\n" #endif diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 739c1629a27..568a3e77d37 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -18,11 +18,6 @@ DECLARE_GLOBAL_DATA_PTR; -static const struct socfpga_clock_manager *clock_manager_base = - (void *)SOCFPGA_CLKMGR_ADDRESS; -static const struct socfpga_system_manager *system_manager_base = - (void *)SOCFPGA_SYSMGR_ADDRESS; - struct socfpga_dwmci_plat { struct mmc_config cfg; struct mmc mmc; @@ -56,19 +51,19 @@ static void socfpga_dwmci_clksel(struct dwmci_host *host) ((priv->drvsel & 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT); /* Disable SDMMC clock. */ - clrbits_le32(&clock_manager_base->per_pll.en, - CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); + clrbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_PERPLL_EN, + CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); debug("%s: drvsel %d smplsel %d\n", __func__, priv->drvsel, priv->smplsel); - writel(sdmmc_mask, &system_manager_base->sdmmcgrp_ctrl); + writel(sdmmc_mask, socfpga_get_sysmgr_addr() + SYSMGR_SDMMC); debug("%s: SYSMGR_SDMMCGRP_CTRL_REG = 0x%x\n", __func__, - readl(&system_manager_base->sdmmcgrp_ctrl)); + readl(socfpga_get_sysmgr_addr() + SYSMGR_SDMMC)); /* Enable SDMMC clock */ - setbits_le32(&clock_manager_base->per_pll.en, - CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); + setbits_le32(socfpga_get_clkmgr_addr() + CLKMGR_PERPLL_EN, + CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); } static int socfpga_dwmmc_get_clk_rate(struct udevice *dev) diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index eb49a6c11c4..6e7fc2311e1 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -1594,6 +1594,7 @@ struct sfdp_parameter_header { #define SFDP_BFPT_ID 0xff00 /* Basic Flash Parameter Table */ #define SFDP_SECTOR_MAP_ID 0xff81 /* Sector Map Table */ +#define SFDP_SST_ID 0x01bf /* Manufacturer specific Table */ #define SFDP_SIGNATURE 0x50444653U #define SFDP_JESD216_MAJOR 1 @@ -1974,6 +1975,34 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, } /** + * spi_nor_parse_microchip_sfdp() - parse the Microchip manufacturer specific + * SFDP table. + * @nor: pointer to a 'struct spi_nor'. + * @param_header: pointer to the SFDP parameter header. + * + * Return: 0 on success, -errno otherwise. + */ +static int +spi_nor_parse_microchip_sfdp(struct spi_nor *nor, + const struct sfdp_parameter_header *param_header) +{ + size_t size; + u32 addr; + int ret; + + size = param_header->length * sizeof(u32); + addr = SFDP_PARAM_HEADER_PTP(param_header); + + nor->manufacturer_sfdp = devm_kmalloc(nor->dev, size, GFP_KERNEL); + if (!nor->manufacturer_sfdp) + return -ENOMEM; + + ret = spi_nor_read_sfdp(nor, addr, size, nor->manufacturer_sfdp); + + return ret; +} + +/** * spi_nor_parse_sfdp() - parse the Serial Flash Discoverable Parameters. * @nor: pointer to a 'struct spi_nor' * @params: pointer to the 'struct spi_nor_flash_parameter' to be @@ -2069,12 +2098,25 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, dev_info(dev, "non-uniform erase sector maps are not supported yet.\n"); break; + case SFDP_SST_ID: + err = spi_nor_parse_microchip_sfdp(nor, param_header); + break; + default: break; } - if (err) - goto exit; + if (err) { + dev_warn(dev, "Failed to parse optional parameter table: %04x\n", + SFDP_PARAM_HEADER_ID(param_header)); + /* + * Let's not drop all information we extracted so far + * if optional table parsers fail. In case of failing, + * each optional parser is responsible to roll back to + * the previously known spi_nor data. + */ + err = 0; + } } exit: diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index d53d6298bf3..3621636cb28 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -815,6 +815,7 @@ static const struct dm_pci_ops imx_pcie_ops = { static const struct udevice_id imx_pcie_ids[] = { { .compatible = "fsl,imx6q-pcie" }, + { .compatible = "fsl,imx6sx-pcie" }, { } }; diff --git a/drivers/pinctrl/nxp/pinctrl-imx8m.c b/drivers/pinctrl/nxp/pinctrl-imx8m.c index b3844314b3d..5b7cbb69ae8 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx8m.c +++ b/drivers/pinctrl/nxp/pinctrl-imx8m.c @@ -22,6 +22,7 @@ static const struct udevice_id imx8m_pinctrl_match[] = { { .compatible = "fsl,imx8mq-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info }, { .compatible = "fsl,imx8mm-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info }, { .compatible = "fsl,imx8mn-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info }, + { .compatible = "fsl,imx8mp-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info }, { /* sentinel */ } }; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index b4bf0186746..df9372c239e 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -77,6 +77,13 @@ config DM_PMIC_FAN53555 The driver implements read/write operations for use with the FAN53555 regulator driver and binds the regulator driver to its node. +config DM_PMIC_PCA9450 + bool "Enable Driver Model for PMIC PCA9450" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC PCA9450. The driver implements read/write operations. + config DM_PMIC_PFUZE100 bool "Enable Driver Model for PMIC PFUZE100" depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index ec643278056..7b6cb0ee1bd 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o obj-$(CONFIG_$(SPL_)DM_PMIC_BD71837) += bd71837.o obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o @@ -31,6 +32,7 @@ obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o +obj-$(CONFIG_POWER_PCA9450) += pmic_pca9450.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o obj-$(CONFIG_POWER_PFUZE3000) += pmic_pfuze3000.o obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o diff --git a/drivers/power/pmic/pca9450.c b/drivers/power/pmic/pca9450.c new file mode 100644 index 00000000000..77986c47d75 --- /dev/null +++ b/drivers/power/pmic/pca9450.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + */ + +#include <common.h> +#include <fdtdec.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/pca9450.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + /* buck */ + { .prefix = "b", .driver = PCA9450_REGULATOR_DRIVER}, + /* ldo */ + { .prefix = "l", .driver = PCA9450_REGULATOR_DRIVER}, + { }, +}; + +static int pca9450_reg_count(struct udevice *dev) +{ + return PCA9450_REG_NUM; +} + +static int pca9450_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + pr_err("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int pca9450_read(struct udevice *dev, uint reg, uint8_t *buff, + int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + pr_err("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int pca9450_bind(struct udevice *dev) +{ + int children; + ofnode regulators_node; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, + pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops pca9450_ops = { + .reg_count = pca9450_reg_count, + .read = pca9450_read, + .write = pca9450_write, +}; + +static const struct udevice_id pca9450_ids[] = { + { .compatible = "nxp,pca9450a", .data = 0x35, }, + { .compatible = "nxp,pca9450b", .data = 0x25, }, + { } +}; + +U_BOOT_DRIVER(pmic_pca9450) = { + .name = "pca9450 pmic", + .id = UCLASS_PMIC, + .of_match = pca9450_ids, + .bind = pca9450_bind, + .ops = &pca9450_ops, +}; diff --git a/drivers/power/pmic/pmic_pca9450.c b/drivers/power/pmic/pmic_pca9450.c new file mode 100644 index 00000000000..67a90902006 --- /dev/null +++ b/drivers/power/pmic/pmic_pca9450.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + */ + +#include <common.h> +#include <errno.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/pca9450.h> + +static const char pca9450_name[] = "PCA9450"; + +int power_pca9450a_init(unsigned char bus) +{ + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = pca9450_name; + p->interface = PMIC_I2C; + p->number_of_regs = PCA9450_REG_NUM; + p->hw.i2c.addr = 0x35; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} + +int power_pca9450b_init(unsigned char bus) +{ + struct pmic *p = pmic_alloc(); + + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = pca9450_name; + p->interface = PMIC_I2C; + p->number_of_regs = PCA9450_REG_NUM; + p->hw.i2c.addr = 0x25; + p->hw.i2c.tx_num = 1; + p->bus = bus; + + return 0; +} diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c index 20410865672..939efb2c0d0 100644 --- a/drivers/power/regulator/regulator_common.c +++ b/drivers/power/regulator/regulator_common.c @@ -37,7 +37,11 @@ int regulator_common_ofdata_to_platdata(struct udevice *dev, dev_pdata->startup_delay_us = dev_read_u32_default(dev, "startup-delay-us", 0); dev_pdata->off_on_delay_us = + dev_read_u32_default(dev, "off-on-delay-us", 0); + if (!dev_pdata->off_on_delay_us) { + dev_pdata->off_on_delay_us = dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0); + } return 0; } diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c index e8026cdfbb4..538481241f8 100644 --- a/drivers/remoteproc/rproc-elf-loader.c +++ b/drivers/remoteproc/rproc-elf-loader.c @@ -8,6 +8,39 @@ #include <elf.h> #include <remoteproc.h> +/** + * struct resource_table - firmware resource table header + * @ver: version number + * @num: number of resource entries + * @reserved: reserved (must be zero) + * @offset: array of offsets pointing at the various resource entries + * + * A resource table is essentially a list of system resources required + * by the remote processor. It may also include configuration entries. + * If needed, the remote processor firmware should contain this table + * as a dedicated ".resource_table" ELF section. + * + * Some resources entries are mere announcements, where the host is informed + * of specific remoteproc configuration. Other entries require the host to + * do something (e.g. allocate a system resource). Sometimes a negotiation + * is expected, where the firmware requests a resource, and once allocated, + * the host should provide back its details (e.g. address of an allocated + * memory region). + * + * The header of the resource table, as expressed by this structure, + * contains a version number (should we need to change this format in the + * future), the number of available resource entries, and their offsets + * in the table. + * + * Immediately following this header are the resource entries themselves. + */ +struct resource_table { + u32 ver; + u32 num; + u32 reserved[2]; + u32 offset[0]; +} __packed; + /* Basic function to verify ELF32 image format */ int rproc_elf32_sanity_check(ulong addr, ulong size) { @@ -276,3 +309,239 @@ ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr) else return rproc_elf32_get_boot_addr(addr); } + +/* + * Search for the resource table in an ELF32 image. + * Returns the address of the resource table section if found, NULL if there is + * no resource table section, or error pointer. + */ +static Elf32_Shdr *rproc_elf32_find_rsc_table(struct udevice *dev, + ulong fw_addr, ulong fw_size) +{ + int ret; + unsigned int i; + const char *name_table; + struct resource_table *table; + const u8 *elf_data = (void *)fw_addr; + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr; + Elf32_Shdr *shdr; + + ret = rproc_elf32_sanity_check(fw_addr, fw_size); + if (ret) { + pr_debug("Invalid ELF32 Image %d\n", ret); + return ERR_PTR(ret); + } + + /* look for the resource table and handle it */ + shdr = (Elf32_Shdr *)(elf_data + ehdr->e_shoff); + name_table = (const char *)(elf_data + + shdr[ehdr->e_shstrndx].sh_offset); + + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + u32 size = shdr->sh_size; + u32 offset = shdr->sh_offset; + + if (strcmp(name_table + shdr->sh_name, ".resource_table")) + continue; + + table = (struct resource_table *)(elf_data + offset); + + /* make sure we have the entire table */ + if (offset + size > fw_size) { + pr_debug("resource table truncated\n"); + return ERR_PTR(-ENOSPC); + } + + /* make sure table has at least the header */ + if (sizeof(*table) > size) { + pr_debug("header-less resource table\n"); + return ERR_PTR(-ENOSPC); + } + + /* we don't support any version beyond the first */ + if (table->ver != 1) { + pr_debug("unsupported fw ver: %d\n", table->ver); + return ERR_PTR(-EPROTONOSUPPORT); + } + + /* make sure reserved bytes are zeroes */ + if (table->reserved[0] || table->reserved[1]) { + pr_debug("non zero reserved bytes\n"); + return ERR_PTR(-EBADF); + } + + /* make sure the offsets array isn't truncated */ + if (table->num * sizeof(table->offset[0]) + + sizeof(*table) > size) { + pr_debug("resource table incomplete\n"); + return ERR_PTR(-ENOSPC); + } + + return shdr; + } + + return NULL; +} + +/* Load the resource table from an ELF32 image */ +int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr, + ulong fw_size, ulong *rsc_addr, ulong *rsc_size) +{ + const struct dm_rproc_ops *ops; + Elf32_Shdr *shdr; + void *src, *dst; + + shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size); + if (!shdr) + return -ENODATA; + if (IS_ERR(shdr)) + return PTR_ERR(shdr); + + ops = rproc_get_ops(dev); + *rsc_addr = (ulong)shdr->sh_addr; + *rsc_size = (ulong)shdr->sh_size; + + src = (void *)fw_addr + shdr->sh_offset; + if (ops->device_to_virt) + dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size); + else + dst = (void *)rsc_addr; + + dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n", + (ulong)dst, *rsc_size); + + memcpy(dst, src, *rsc_size); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + *rsc_size, + ARCH_DMA_MINALIGN) - + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); + + return 0; +} + +/* + * Search for the resource table in an ELF64 image. + * Returns the address of the resource table section if found, NULL if there is + * no resource table section, or error pointer. + */ +static Elf64_Shdr *rproc_elf64_find_rsc_table(struct udevice *dev, + ulong fw_addr, ulong fw_size) +{ + int ret; + unsigned int i; + const char *name_table; + struct resource_table *table; + const u8 *elf_data = (void *)fw_addr; + Elf64_Ehdr *ehdr = (Elf64_Ehdr *)fw_addr; + Elf64_Shdr *shdr; + + ret = rproc_elf64_sanity_check(fw_addr, fw_size); + if (ret) { + pr_debug("Invalid ELF64 Image %d\n", ret); + return ERR_PTR(ret); + } + + /* look for the resource table and handle it */ + shdr = (Elf64_Shdr *)(elf_data + ehdr->e_shoff); + name_table = (const char *)(elf_data + + shdr[ehdr->e_shstrndx].sh_offset); + + for (i = 0; i < ehdr->e_shnum; i++, shdr++) { + u64 size = shdr->sh_size; + u64 offset = shdr->sh_offset; + + if (strcmp(name_table + shdr->sh_name, ".resource_table")) + continue; + + table = (struct resource_table *)(elf_data + offset); + + /* make sure we have the entire table */ + if (offset + size > fw_size) { + pr_debug("resource table truncated\n"); + return ERR_PTR(-ENOSPC); + } + + /* make sure table has at least the header */ + if (sizeof(*table) > size) { + pr_debug("header-less resource table\n"); + return ERR_PTR(-ENOSPC); + } + + /* we don't support any version beyond the first */ + if (table->ver != 1) { + pr_debug("unsupported fw ver: %d\n", table->ver); + return ERR_PTR(-EPROTONOSUPPORT); + } + + /* make sure reserved bytes are zeroes */ + if (table->reserved[0] || table->reserved[1]) { + pr_debug("non zero reserved bytes\n"); + return ERR_PTR(-EBADF); + } + + /* make sure the offsets array isn't truncated */ + if (table->num * sizeof(table->offset[0]) + + sizeof(*table) > size) { + pr_debug("resource table incomplete\n"); + return ERR_PTR(-ENOSPC); + } + + return shdr; + } + + return NULL; +} + +/* Load the resource table from an ELF64 image */ +int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr, + ulong fw_size, ulong *rsc_addr, ulong *rsc_size) +{ + const struct dm_rproc_ops *ops; + Elf64_Shdr *shdr; + void *src, *dst; + + shdr = rproc_elf64_find_rsc_table(dev, fw_addr, fw_size); + if (!shdr) + return -ENODATA; + if (IS_ERR(shdr)) + return PTR_ERR(shdr); + + ops = rproc_get_ops(dev); + *rsc_addr = (ulong)shdr->sh_addr; + *rsc_size = (ulong)shdr->sh_size; + + src = (void *)fw_addr + shdr->sh_offset; + if (ops->device_to_virt) + dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size); + else + dst = (void *)rsc_addr; + + dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n", + (ulong)dst, *rsc_size); + + memcpy(dst, src, *rsc_size); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + *rsc_size, + ARCH_DMA_MINALIGN) - + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); + + return 0; +} + +/* Load the resource table from an ELF32 or ELF64 image */ +int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr, + ulong fw_size, ulong *rsc_addr, ulong *rsc_size) + +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr; + + if (!fw_addr) + return -EFAULT; + + if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) + return rproc_elf64_load_rsc_table(dev, fw_addr, fw_size, + rsc_addr, rsc_size); + else + return rproc_elf32_load_rsc_table(dev, fw_addr, fw_size, + rsc_addr, rsc_size); +} diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c index 40bba372119..c25488f54d5 100644 --- a/drivers/remoteproc/stm32_copro.c +++ b/drivers/remoteproc/stm32_copro.c @@ -22,14 +22,14 @@ * @hold_boot_regmap: regmap for remote processor reset hold boot * @hold_boot_offset: offset of the register controlling the hold boot setting * @hold_boot_mask: bitmask of the register for the hold boot field - * @is_running: is the remote processor running + * @rsc_table_addr: resource table address */ struct stm32_copro_privdata { struct reset_ctl reset_ctl; struct regmap *hold_boot_regmap; uint hold_boot_offset; uint hold_boot_mask; - bool is_running; + ulong rsc_table_addr; }; /** @@ -141,6 +141,7 @@ static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da, static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) { struct stm32_copro_privdata *priv; + ulong rsc_table_size; int ret; priv = dev_get_priv(dev); @@ -155,6 +156,12 @@ static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size) return ret; } + if (rproc_elf32_load_rsc_table(dev, addr, size, &priv->rsc_table_addr, + &rsc_table_size)) { + priv->rsc_table_addr = 0; + dev_warn(dev, "No valid resource table for this firmware\n"); + } + return rproc_elf32_load_image(dev, addr, size); } @@ -180,7 +187,12 @@ static int stm32_copro_start(struct udevice *dev) * rebooting autonomously */ ret = stm32_copro_set_hold_boot(dev, true); - priv->is_running = !ret; + writel(ret ? TAMP_COPRO_STATE_OFF : TAMP_COPRO_STATE_CRUN, + TAMP_COPRO_STATE); + if (!ret) + /* Store rsc_address in bkp register */ + writel(priv->rsc_table_addr, TAMP_COPRO_RSC_TBL_ADDRESS); + return ret; } @@ -206,7 +218,7 @@ static int stm32_copro_reset(struct udevice *dev) return ret; } - priv->is_running = false; + writel(TAMP_COPRO_STATE_OFF, TAMP_COPRO_STATE); return 0; } @@ -224,14 +236,11 @@ static int stm32_copro_stop(struct udevice *dev) /** * stm32_copro_is_running() - Is the STM32 remote processor running * @dev: corresponding STM32 remote processor device - * @return 1 if the remote processor is running, 0 otherwise + * @return 0 if the remote processor is running, 1 otherwise */ static int stm32_copro_is_running(struct udevice *dev) { - struct stm32_copro_privdata *priv; - - priv = dev_get_priv(dev); - return priv->is_running; + return (readl(TAMP_COPRO_STATE) == TAMP_COPRO_STATE_OFF); } static const struct dm_rproc_ops stm32_copro_ops = { diff --git a/drivers/sysreset/sysreset_socfpga.c b/drivers/sysreset/sysreset_socfpga.c index d6c26a5b235..3390b7bdc2c 100644 --- a/drivers/sysreset/sysreset_socfpga.c +++ b/drivers/sysreset/sysreset_socfpga.c @@ -12,7 +12,7 @@ #include <asm/arch/reset_manager.h> struct socfpga_sysreset_data { - struct socfpga_reset_manager *rstmgr_base; + void __iomem *rstmgr_base; }; static int socfpga_sysreset_request(struct udevice *dev, @@ -23,11 +23,11 @@ static int socfpga_sysreset_request(struct udevice *dev, switch (type) { case SYSRESET_WARM: writel(BIT(RSTMGR_CTRL_SWWARMRSTREQ_LSB), - &data->rstmgr_base->ctrl); + data->rstmgr_base + RSTMGR_CTRL); break; case SYSRESET_COLD: writel(BIT(RSTMGR_CTRL_SWCOLDRSTREQ_LSB), - &data->rstmgr_base->ctrl); + data->rstmgr_base + RSTMGR_CTRL); break; default: return -EPROTONOSUPPORT; diff --git a/drivers/video/lg4573.c b/drivers/video/lg4573.c index 46d9ec83ce4..997e854ef8f 100644 --- a/drivers/video/lg4573.c +++ b/drivers/video/lg4573.c @@ -5,36 +5,40 @@ * */ #include <common.h> +#include <backlight.h> +#include <display.h> +#include <dm.h> +#include <dm/read.h> +#include <dm/uclass-internal.h> #include <errno.h> #include <spi.h> +#include <asm/gpio.h> #define PWR_ON_DELAY_MSECS 120 -static int lb043wv_spi_write_u16(struct spi_slave *spi, u16 val) +static int lb043wv_spi_write_u16(struct spi_slave *slave, u16 val) { - unsigned long flags = SPI_XFER_BEGIN; unsigned short buf16 = htons(val); int ret = 0; - flags |= SPI_XFER_END; - - ret = spi_xfer(spi, 16, &buf16, NULL, flags); + ret = spi_xfer(slave, 16, &buf16, NULL, + SPI_XFER_BEGIN | SPI_XFER_END); if (ret) debug("%s: Failed to send: %d\n", __func__, ret); return ret; } -static void lb043wv_spi_write_u16_array(struct spi_slave *spi, u16 *buff, +static void lb043wv_spi_write_u16_array(struct spi_slave *slave, u16 *buff, int size) { int i; for (i = 0; i < size; i++) - lb043wv_spi_write_u16(spi, buff[i]); + lb043wv_spi_write_u16(slave, buff[i]); } -static void lb043wv_display_mode_settings(struct spi_slave *spi) +static void lb043wv_display_mode_settings(struct spi_slave *slave) { static u16 display_mode_settings[] = { 0x703A, @@ -72,11 +76,11 @@ static void lb043wv_display_mode_settings(struct spi_slave *spi) }; debug("transfer display mode settings\n"); - lb043wv_spi_write_u16_array(spi, display_mode_settings, + lb043wv_spi_write_u16_array(slave, display_mode_settings, ARRAY_SIZE(display_mode_settings)); } -static void lb043wv_power_settings(struct spi_slave *spi) +static void lb043wv_power_settings(struct spi_slave *slave) { static u16 power_settings[] = { 0x70C0, @@ -103,11 +107,11 @@ static void lb043wv_power_settings(struct spi_slave *spi) }; debug("transfer power settings\n"); - lb043wv_spi_write_u16_array(spi, power_settings, + lb043wv_spi_write_u16_array(slave, power_settings, ARRAY_SIZE(power_settings)); } -static void lb043wv_gamma_settings(struct spi_slave *spi) +static void lb043wv_gamma_settings(struct spi_slave *slave) { static u16 gamma_settings[] = { 0x70D0, @@ -173,54 +177,57 @@ static void lb043wv_gamma_settings(struct spi_slave *spi) }; debug("transfer gamma settings\n"); - lb043wv_spi_write_u16_array(spi, gamma_settings, + lb043wv_spi_write_u16_array(slave, gamma_settings, ARRAY_SIZE(gamma_settings)); } -static void lb043wv_display_on(struct spi_slave *spi) +static void lb043wv_display_on(struct spi_slave *slave) { static u16 sleep_out = 0x7011; static u16 display_on = 0x7029; - lb043wv_spi_write_u16(spi, sleep_out); + lb043wv_spi_write_u16(slave, sleep_out); mdelay(PWR_ON_DELAY_MSECS); - lb043wv_spi_write_u16(spi, display_on); + lb043wv_spi_write_u16(slave, display_on); } -int lg4573_spi_startup(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int spi_mode) +static int lg4573_spi_startup(struct spi_slave *slave) { - struct spi_slave *spi; int ret; - spi = spi_setup_slave(bus, cs, max_hz, spi_mode); - if (!spi) { - debug("%s: Failed to set up slave\n", __func__); - return -1; - } - - ret = spi_claim_bus(spi); - if (ret) { - debug("%s: Failed to claim SPI bus: %d\n", __func__, ret); - goto err_claim_bus; - } + ret = spi_claim_bus(slave); + if (ret) + return ret; - lb043wv_display_mode_settings(spi); - lb043wv_power_settings(spi); - lb043wv_gamma_settings(spi); + lb043wv_display_mode_settings(slave); + lb043wv_power_settings(slave); + lb043wv_gamma_settings(slave); + lb043wv_display_on(slave); - lb043wv_display_on(spi); + spi_release_bus(slave); return 0; -err_claim_bus: - spi_free_slave(spi); - return -1; } static int do_lgset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - lg4573_spi_startup(CONFIG_LG4573_BUS, CONFIG_LG4573_CS, 10000000, - SPI_MODE_0); + struct spi_slave *slave; + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_DISPLAY, + DM_GET_DRIVER(lg4573_lcd), &dev); + if (ret) { + printf("%s: Could not get lg4573 device\n", __func__); + return ret; + } + slave = dev_get_parent_priv(dev); + if (!slave) { + printf("%s: No slave data\n", __func__); + return -ENODEV; + } + lg4573_spi_startup(slave); + return 0; } @@ -229,3 +236,93 @@ U_BOOT_CMD( "set lgdisplay", "" ); + +static int lg4573_bind(struct udevice *dev) +{ + return 0; +} + +static int lg4573_probe(struct udevice *dev) +{ + return 0; +} + +static const struct udevice_id lg4573_ids[] = { + { .compatible = "lg,lg4573" }, + { } +}; + +struct lg4573_lcd_priv { + struct display_timing timing; + struct udevice *backlight; + struct gpio_desc enable; + int panel_bpp; + u32 power_on_delay; +}; + +static int lg4573_lcd_read_timing(struct udevice *dev, + struct display_timing *timing) +{ + struct lg4573_lcd_priv *priv = dev_get_priv(dev); + + memcpy(timing, &priv->timing, sizeof(struct display_timing)); + + return 0; +} + +static int lg4573_lcd_enable(struct udevice *dev, int bpp, + const struct display_timing *edid) +{ + struct spi_slave *slave = dev_get_parent_priv(dev); + struct lg4573_lcd_priv *priv = dev_get_priv(dev); + int ret = 0; + + dm_gpio_set_value(&priv->enable, 1); + ret = backlight_enable(priv->backlight); + + mdelay(priv->power_on_delay); + lg4573_spi_startup(slave); + + return ret; +}; + +static const struct dm_display_ops lg4573_lcd_ops = { + .read_timing = lg4573_lcd_read_timing, + .enable = lg4573_lcd_enable, +}; + +static int lg4573_ofdata_to_platdata(struct udevice *dev) +{ + struct lg4573_lcd_priv *priv = dev_get_priv(dev); + int ret; + + ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, + "backlight", &priv->backlight); + if (ret) { + debug("%s: Cannot get backlight: ret=%d\n", __func__, ret); + return log_ret(ret); + } + ret = gpio_request_by_name(dev, "enable-gpios", 0, &priv->enable, + GPIOD_IS_OUT); + if (ret) { + debug("%s: Warning: cannot get enable GPIO: ret=%d\n", + __func__, ret); + if (ret != -ENOENT) + return log_ret(ret); + } + + priv->power_on_delay = dev_read_u32_default(dev, "power-on-delay", 10); + + return 0; +} + +U_BOOT_DRIVER(lg4573_lcd) = { + .name = "lg4573", + .id = UCLASS_DISPLAY, + .ops = &lg4573_lcd_ops, + .ofdata_to_platdata = lg4573_ofdata_to_platdata, + .of_match = lg4573_ids, + .bind = lg4573_bind, + .probe = lg4573_probe, + .priv_auto_alloc_size = sizeof(struct lg4573_lcd_priv), +}; diff --git a/drivers/video/meson/meson_canvas.c b/drivers/video/meson/meson_canvas.c index b71cbfcc0b0..eccac2f8f24 100644 --- a/drivers/video/meson/meson_canvas.c +++ b/drivers/video/meson/meson_canvas.c @@ -6,6 +6,10 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ +#include <common.h> +#include <dm.h> +#include <asm/io.h> + #include "meson_vpu.h" /* DMC Registers */ diff --git a/drivers/video/meson/meson_plane.c b/drivers/video/meson/meson_plane.c index 2bc9327e1e2..8edf451f13f 100644 --- a/drivers/video/meson/meson_plane.c +++ b/drivers/video/meson/meson_plane.c @@ -6,6 +6,11 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <linux/bitfield.h> + #include "meson_vpu.h" /* OSDx_BLKx_CFG */ diff --git a/drivers/video/meson/meson_vclk.c b/drivers/video/meson/meson_vclk.c index 0f628e920ba..01bfa4bcb8d 100644 --- a/drivers/video/meson/meson_vclk.c +++ b/drivers/video/meson/meson_vclk.c @@ -6,6 +6,8 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ +#include <common.h> +#include <dm.h> #include <edid.h> #include "meson_vpu.h" #include <linux/iopoll.h> diff --git a/drivers/video/meson/meson_venc.c b/drivers/video/meson/meson_venc.c index 5da4b3f0963..89e859b02a7 100644 --- a/drivers/video/meson/meson_venc.c +++ b/drivers/video/meson/meson_venc.c @@ -6,7 +6,11 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ +#include <common.h> +#include <dm.h> #include <edid.h> +#include <fdtdec.h> +#include <asm/io.h> #include "meson_vpu.h" enum { diff --git a/drivers/video/meson/meson_vpu.c b/drivers/video/meson/meson_vpu.c index c3af9b013c6..4eb66398d09 100644 --- a/drivers/video/meson/meson_vpu.c +++ b/drivers/video/meson/meson_vpu.c @@ -6,13 +6,17 @@ * Author: Neil Armstrong <narmstrong@baylibre.com> */ -#include "meson_vpu.h" +#include <common.h> +#include <display.h> +#include <dm.h> #include <efi_loader.h> -#include <dm/device-internal.h> -#include <dm/uclass-internal.h> #include <fdt_support.h> #include <linux/sizes.h> #include <asm/arch/mem.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> + +#include "meson_vpu.h" #include "meson_registers.h" #include "simplefb_common.h" @@ -27,6 +31,14 @@ static struct meson_framebuffer { bool is_cvbs; } meson_fb = { 0 }; +bool meson_vpu_is_compatible(struct meson_vpu_priv *priv, + enum vpu_compatible family) +{ + enum vpu_compatible compat = dev_get_driver_data(priv->dev); + + return compat == family; +} + static int meson_vpu_setup_mode(struct udevice *dev, struct udevice *disp) { struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); diff --git a/drivers/video/meson/meson_vpu.h b/drivers/video/meson/meson_vpu.h index 0d9fddad2e7..d9588c3775c 100644 --- a/drivers/video/meson/meson_vpu.h +++ b/drivers/video/meson/meson_vpu.h @@ -9,14 +9,12 @@ #ifndef __MESON_VPU_H__ #define __MESON_VPU_H__ -#include <common.h> -#include <dm.h> #include <video.h> -#include <display.h> -#include <linux/io.h> -#include <linux/bitfield.h> #include "meson_registers.h" +struct display_timing; +struct udevice; + enum { /* Maximum size we support */ VPU_MAX_WIDTH = 3840, @@ -38,13 +36,8 @@ struct meson_vpu_priv { void __iomem *dmc_base; }; -static inline bool meson_vpu_is_compatible(struct meson_vpu_priv *priv, - enum vpu_compatible family) -{ - enum vpu_compatible compat = dev_get_driver_data(priv->dev); - - return compat == family; -} +bool meson_vpu_is_compatible(struct meson_vpu_priv *priv, + enum vpu_compatible family); #define hhi_update_bits(offset, mask, value) \ writel_bits(mask, value, priv->hhi_base + offset) diff --git a/drivers/video/meson/meson_vpu_init.c b/drivers/video/meson/meson_vpu_init.c index 12f8c4194ad..8408c59eaa1 100644 --- a/drivers/video/meson/meson_vpu_init.c +++ b/drivers/video/meson/meson_vpu_init.c @@ -8,6 +8,10 @@ #define DEBUG +#include <common.h> +#include <dm.h> +#include <asm/io.h> + #include "meson_vpu.h" /* HHI Registers */ |