diff options
Diffstat (limited to 'drivers/memory')
47 files changed, 4447 insertions, 1837 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index fac290e48e0b..79df0d22e218 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -30,20 +30,9 @@ config ARM_PL172_MPMC If you have an embedded system with an AMBA bus and a PL172 controller, say Y or M here. -config ATMEL_SDRAMC - bool "Atmel (Multi-port DDR-)SDRAM Controller" - default y if ARCH_AT91 - depends on ARCH_AT91 || COMPILE_TEST - depends on OF - help - This driver is for Atmel SDRAM Controller or Atmel Multi-port - DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs. - Starting with the at91sam9g45, this controller supports SDR, DDR and - LP-DDR memories. - config ATMEL_EBI bool "Atmel EBI driver" - default y if ARCH_AT91 + default ARCH_AT91 depends on ARCH_AT91 || COMPILE_TEST depends on OF select MFD_SYSCON @@ -158,7 +147,7 @@ config FPGA_DFL_EMIF config MVEBU_DEVBUS bool "Marvell EBU Device Bus Controller" - default y if PLAT_ORION + default PLAT_ORION depends on PLAT_ORION || COMPILE_TEST depends on OF help @@ -178,7 +167,7 @@ config FSL_CORENET_CF represents a coherency violation. config FSL_IFC - bool "Freescale IFC driver" if COMPILE_TEST + bool "Freescale IFC driver" depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST depends on HAS_IOMEM @@ -209,7 +198,7 @@ config DA8XX_DDRCTL config PL353_SMC tristate "ARM PL35X Static Memory Controller(SMC) driver" - default y if ARM + default ARM depends on ARM || COMPILE_TEST depends on ARM_AMBA help @@ -228,7 +217,7 @@ config RENESAS_RPCIF config STM32_FMC2_EBI tristate "Support for FMC2 External Bus Interface on STM32MP SoCs" - depends on MACH_STM32MP157 || COMPILE_TEST + depends on ARCH_STM32 || COMPILE_TEST select MFD_SYSCON help Select this option to enable the STM32 FMC2 External Bus Interface @@ -236,6 +225,23 @@ config STM32_FMC2_EBI devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on SOCs containing the FMC2 External Bus Interface. +config STM32_OMM + tristate "STM32 Octo Memory Manager" + depends on SPI_STM32_OSPI || COMPILE_TEST + help + This driver manages the muxing between the 2 OSPI busses and + the 2 output ports. There are 4 possible muxing configurations: + - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2 + output is on port 2 + - OSPI1 and OSPI2 are multiplexed over the same output port 1 + - swapped mode (no multiplexing), OSPI1 output is on port 2, + OSPI2 output is on port 1 + - OSPI1 and OSPI2 are multiplexed over the same output port 2 + It also manages : + - the split of the memory area shared between the 2 OSPI instances. + - chip select selection override. + - the time between 2 transactions in multiplexed mode. + source "drivers/memory/samsung/Kconfig" source "drivers/memory/tegra/Kconfig" diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index ae14ded464a8..c1959661bf63 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -8,7 +8,6 @@ ifeq ($(CONFIG_DDR),y) obj-$(CONFIG_OF) += of_memory.o endif obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o -obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.o obj-$(CONFIG_BRCMSTB_MEMC) += brcmstb_memc.o @@ -25,6 +24,7 @@ obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o obj-$(CONFIG_PL353_SMC) += pl353-smc.o obj-$(CONFIG_RENESAS_RPCIF) += renesas-rpc-if.o obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o +obj-$(CONFIG_STM32_OMM) += stm32_omm.o obj-$(CONFIG_SAMSUNG_MC) += samsung/ obj-$(CONFIG_TEGRA_MC) += tegra/ diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index e749dcb3ddea..8db970da9af9 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -6,13 +6,17 @@ * Copyright (C) 2013 Jean-Jacques Hiblot <jjhiblot@traphandler.com> */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/atmel-matrix.h> #include <linux/mfd/syscon/atmel-smc.h> #include <linux/init.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/property.h> #include <linux/regmap.h> #include <soc/at91/atmel-sfr.h> @@ -30,7 +34,7 @@ struct atmel_ebi_dev { struct atmel_ebi *ebi; u32 mode; int numcs; - struct atmel_ebi_dev_config configs[]; + struct atmel_ebi_dev_config configs[] __counted_by(numcs); }; struct atmel_ebi_caps { @@ -514,17 +518,12 @@ static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np) static int atmel_ebi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *child, *np = dev->of_node, *smc_np; - const struct of_device_id *match; + struct device_node *np = dev->of_node; struct atmel_ebi *ebi; int ret, reg_cells; struct clk *clk; u32 val; - match = of_match_device(atmel_ebi_id_table, dev); - if (!match || !match->data) - return -EINVAL; - ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL); if (!ebi) return -ENOMEM; @@ -532,7 +531,9 @@ static int atmel_ebi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ebi); INIT_LIST_HEAD(&ebi->devs); - ebi->caps = match->data; + ebi->caps = device_get_match_data(dev); + if (!ebi->caps) + return -EINVAL; ebi->dev = dev; clk = devm_clk_get(dev, NULL); @@ -541,30 +542,24 @@ static int atmel_ebi_probe(struct platform_device *pdev) ebi->clk = clk; - smc_np = of_parse_phandle(dev->of_node, "atmel,smc", 0); + struct device_node *smc_np __free(device_node) = + of_parse_phandle(dev->of_node, "atmel,smc", 0); ebi->smc.regmap = syscon_node_to_regmap(smc_np); - if (IS_ERR(ebi->smc.regmap)) { - ret = PTR_ERR(ebi->smc.regmap); - goto put_node; - } + if (IS_ERR(ebi->smc.regmap)) + return PTR_ERR(ebi->smc.regmap); ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np); - if (IS_ERR(ebi->smc.layout)) { - ret = PTR_ERR(ebi->smc.layout); - goto put_node; - } + if (IS_ERR(ebi->smc.layout)) + return PTR_ERR(ebi->smc.layout); ebi->smc.clk = of_clk_get(smc_np, 0); if (IS_ERR(ebi->smc.clk)) { - if (PTR_ERR(ebi->smc.clk) != -ENOENT) { - ret = PTR_ERR(ebi->smc.clk); - goto put_node; - } + if (PTR_ERR(ebi->smc.clk) != -ENOENT) + return PTR_ERR(ebi->smc.clk); ebi->smc.clk = NULL; } - of_node_put(smc_np); ret = clk_prepare_enable(ebi->smc.clk); if (ret) return ret; @@ -597,8 +592,8 @@ static int atmel_ebi_probe(struct platform_device *pdev) reg_cells += val; - for_each_available_child_of_node(np, child) { - if (!of_find_property(child, "reg", NULL)) + for_each_available_child_of_node_scoped(np, child) { + if (!of_property_present(child, "reg")) continue; ret = atmel_ebi_dev_setup(ebi, child, reg_cells); @@ -607,18 +602,12 @@ static int atmel_ebi_probe(struct platform_device *pdev) child); ret = atmel_ebi_dev_disable(ebi, child); - if (ret) { - of_node_put(child); + if (ret) return ret; - } } } return of_platform_populate(np, NULL, NULL, dev); - -put_node: - of_node_put(smc_np); - return ret; } static __maybe_unused int atmel_ebi_resume(struct device *dev) diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c deleted file mode 100644 index ea6e9e1eaf04..000000000000 --- a/drivers/memory/atmel-sdramc.c +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Atmel (Multi-port DDR-)SDRAM Controller driver - * - * Author: Alexandre Belloni <alexandre.belloni@free-electrons.com> - * - * Copyright (C) 2014 Atmel - */ - -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> - -struct at91_ramc_caps { - bool has_ddrck; - bool has_mpddr_clk; -}; - -static const struct at91_ramc_caps at91rm9200_caps = { }; - -static const struct at91_ramc_caps at91sam9g45_caps = { - .has_ddrck = 1, - .has_mpddr_clk = 0, -}; - -static const struct at91_ramc_caps sama5d3_caps = { - .has_ddrck = 1, - .has_mpddr_clk = 1, -}; - -static const struct of_device_id atmel_ramc_of_match[] = { - { .compatible = "atmel,at91rm9200-sdramc", .data = &at91rm9200_caps, }, - { .compatible = "atmel,at91sam9260-sdramc", .data = &at91rm9200_caps, }, - { .compatible = "atmel,at91sam9g45-ddramc", .data = &at91sam9g45_caps, }, - { .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, }, - {}, -}; - -static int atmel_ramc_probe(struct platform_device *pdev) -{ - const struct at91_ramc_caps *caps; - struct clk *clk; - - caps = of_device_get_match_data(&pdev->dev); - - if (caps->has_ddrck) { - clk = devm_clk_get_enabled(&pdev->dev, "ddrck"); - if (IS_ERR(clk)) - return PTR_ERR(clk); - } - - if (caps->has_mpddr_clk) { - clk = devm_clk_get_enabled(&pdev->dev, "mpddr"); - if (IS_ERR(clk)) { - pr_err("AT91 RAMC: couldn't get mpddr clock\n"); - return PTR_ERR(clk); - } - } - - return 0; -} - -static struct platform_driver atmel_ramc_driver = { - .probe = atmel_ramc_probe, - .driver = { - .name = "atmel-ramc", - .of_match_table = atmel_ramc_of_match, - }, -}; - -builtin_platform_driver(atmel_ramc_driver); diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 76c82e9c8fce..08d9e05b1b33 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -32,8 +32,7 @@ #include <linux/firmware.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #define DRVNAME "brcmstb-dpfe" @@ -434,15 +433,17 @@ static void __finalize_command(struct brcmstb_dpfe_priv *priv) static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd, u32 result[]) { - const u32 *msg = priv->dpfe_api->command[cmd]; void __iomem *regs = priv->regs; unsigned int i, chksum, chksum_idx; + const u32 *msg; int ret = 0; u32 resp; if (cmd >= DPFE_CMD_MAX) return -1; + msg = priv->dpfe_api->command[cmd]; + mutex_lock(&priv->lock); /* Wait for DCPU to become ready */ @@ -908,13 +909,11 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev) return ret; } -static int brcmstb_dpfe_remove(struct platform_device *pdev) +static void brcmstb_dpfe_remove(struct platform_device *pdev) { struct brcmstb_dpfe_priv *priv = dev_get_drvdata(&pdev->dev); sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs); - - return 0; } static const struct of_device_id brcmstb_dpfe_of_match[] = { @@ -935,7 +934,7 @@ static struct platform_driver brcmstb_dpfe_driver = { .of_match_table = brcmstb_dpfe_of_match, }, .probe = brcmstb_dpfe_probe, - .remove = brcmstb_dpfe_remove, + .remove = brcmstb_dpfe_remove, .resume = brcmstb_dpfe_resume, }; diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c index 233a53f5bce1..ba73470b1b13 100644 --- a/drivers/memory/brcmstb_memc.c +++ b/drivers/memory/brcmstb_memc.c @@ -8,8 +8,9 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/property.h> #define REG_MEMC_CNTRLR_CONFIG 0x00 #define CNTRLR_CONFIG_LPDDR4_SHIFT 5 @@ -121,12 +122,9 @@ static struct attribute_group dev_attr_group = { .attrs = dev_attrs, }; -static const struct of_device_id brcmstb_memc_of_match[]; - static int brcmstb_memc_probe(struct platform_device *pdev) { const struct brcmstb_memc_data *memc_data; - const struct of_device_id *of_id; struct device *dev = &pdev->dev; struct brcmstb_memc *memc; int ret; @@ -137,8 +135,7 @@ static int brcmstb_memc_probe(struct platform_device *pdev) dev_set_drvdata(dev, memc); - of_id = of_match_device(brcmstb_memc_of_match, dev); - memc_data = of_id->data; + memc_data = device_get_match_data(dev); memc->srpd_offset = memc_data->srpd_offset; memc->ddr_ctrl = devm_platform_ioremap_resource(pdev, 0); @@ -155,13 +152,11 @@ static int brcmstb_memc_probe(struct platform_device *pdev) return 0; } -static int brcmstb_memc_remove(struct platform_device *pdev) +static void brcmstb_memc_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; sysfs_remove_group(&dev->kobj, &dev_attr_group); - - return 0; } enum brcmstb_memc_hwtype { @@ -189,65 +184,14 @@ static const struct of_device_id brcmstb_memc_of_match[] = { .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1", .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.5", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.6", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.7", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.8", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-c.1.0", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-c.1.1", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-c.1.2", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-c.1.3", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - { - .compatible = "brcm,brcmstb-memc-ddr-rev-c.1.4", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] - }, - /* default to the original offset */ + /* default to the V21 offset */ { .compatible = "brcm,brcmstb-memc-ddr", - .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V1X] + .data = &brcmstb_memc_versions[BRCMSTB_MEMC_V21] }, {} }; +MODULE_DEVICE_TABLE(of, brcmstb_memc_of_match); static int brcmstb_memc_suspend(struct device *dev) { diff --git a/drivers/memory/bt1-l2-ctl.c b/drivers/memory/bt1-l2-ctl.c index 85965fa26e0b..0fd96abc172a 100644 --- a/drivers/memory/bt1-l2-ctl.c +++ b/drivers/memory/bt1-l2-ctl.c @@ -222,7 +222,7 @@ static ssize_t l2_ctl_latency_show(struct device *dev, if (ret) return ret; - return scnprintf(buf, PAGE_SIZE, "%u\n", data); + return sysfs_emit(buf, "%u\n", data); } static ssize_t l2_ctl_latency_store(struct device *dev, @@ -321,4 +321,3 @@ module_platform_driver(l2_ctl_driver); MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>"); MODULE_DESCRIPTION("Baikal-T1 L2-cache driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c index b32005bf269c..2bf34da85d22 100644 --- a/drivers/memory/da8xx-ddrctl.c +++ b/drivers/memory/da8xx-ddrctl.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/io.h> @@ -164,4 +163,3 @@ module_platform_driver(da8xx_ddrctl_driver); MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); MODULE_DESCRIPTION("TI da8xx DDR2/mDDR controller driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index f305643209f0..2fadad0666b1 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -7,6 +7,7 @@ * Aneesh V <aneesh@ti.com> * Santosh Shilimkar <santosh.shilimkar@ti.com> */ +#include <linux/cleanup.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/reboot.h> @@ -38,6 +39,7 @@ * are two devices attached to this EMIF, this * value is the maximum of the two temperature * levels. + * @lpmode: Chosen low power mode * @node: node in the device list * @base: base address of memory-mapped IO registers. * @dev: device pointer. @@ -57,7 +59,6 @@ struct emif_data { u8 temperature_level; u8 lpmode; struct list_head node; - unsigned long irq_state; void __iomem *base; struct device *dev; struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES]; @@ -69,10 +70,8 @@ struct emif_data { static struct emif_data *emif1; static DEFINE_SPINLOCK(emif_lock); -static unsigned long irq_state; static LIST_HEAD(device_list); -#ifdef CONFIG_DEBUG_FS static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif, struct emif_regs *regs) { @@ -140,31 +139,24 @@ static int emif_mr4_show(struct seq_file *s, void *unused) DEFINE_SHOW_ATTRIBUTE(emif_mr4); -static int __init_or_module emif_debugfs_init(struct emif_data *emif) +static void emif_debugfs_init(struct emif_data *emif) { - emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL); - debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif, - &emif_regdump_fops); - debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif, - &emif_mr4_fops); - return 0; -} - -static void __exit emif_debugfs_exit(struct emif_data *emif) -{ - debugfs_remove_recursive(emif->debugfs_root); - emif->debugfs_root = NULL; -} -#else -static inline int __init_or_module emif_debugfs_init(struct emif_data *emif) -{ - return 0; + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL); + debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif, + &emif_regdump_fops); + debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif, + &emif_mr4_fops); + } } -static inline void __exit emif_debugfs_exit(struct emif_data *emif) +static void emif_debugfs_exit(struct emif_data *emif) { + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + debugfs_remove_recursive(emif->debugfs_root); + emif->debugfs_root = NULL; + } } -#endif /* * Get bus width used by EMIF. Note that this may be different from the @@ -531,18 +523,18 @@ out: static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) { u32 old_temp_level; - irqreturn_t ret = IRQ_HANDLED; + irqreturn_t ret; struct emif_custom_configs *custom_configs; - spin_lock_irqsave(&emif_lock, irq_state); + guard(spinlock_irqsave)(&emif_lock); old_temp_level = emif->temperature_level; get_temperature_level(emif); if (unlikely(emif->temperature_level == old_temp_level)) { - goto out; + return IRQ_HANDLED; } else if (!emif->curr_regs) { dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n"); - goto out; + return IRQ_HANDLED; } custom_configs = emif->plat_data->custom_configs; @@ -562,8 +554,7 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) * from thread context */ emif->temperature_level = SDRAM_TEMP_VERY_HIGH_SHUTDOWN; - ret = IRQ_WAKE_THREAD; - goto out; + return IRQ_WAKE_THREAD; } } @@ -579,10 +570,9 @@ static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) /* Temperature is going up - handle immediately */ setup_temperature_sensitive_regs(emif, emif->curr_regs); do_freq_update(); + ret = IRQ_HANDLED; } -out: - spin_unlock_irqrestore(&emif_lock, irq_state); return ret; } @@ -625,6 +615,7 @@ static irqreturn_t emif_interrupt_handler(int irq, void *dev_id) static irqreturn_t emif_threaded_isr(int irq, void *dev_id) { struct emif_data *emif = dev_id; + unsigned long irq_state; if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n"); @@ -679,7 +670,7 @@ static void disable_and_clear_all_interrupts(struct emif_data *emif) clear_all_interrupts(emif); } -static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq) +static int setup_interrupts(struct emif_data *emif, u32 irq) { u32 interrupts, type; void __iomem *base = emif->base; @@ -710,7 +701,7 @@ static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq) } -static void __init_or_module emif_onetime_settings(struct emif_data *emif) +static void emif_onetime_settings(struct emif_data *emif) { u32 pwr_mgmt_ctrl, zq, temp_alert_cfg; void __iomem *base = emif->base; @@ -834,8 +825,7 @@ static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs, return valid; } -#if defined(CONFIG_OF) -static void __init_or_module of_get_custom_configs(struct device_node *np_emif, +static void of_get_custom_configs(struct device_node *np_emif, struct emif_data *emif) { struct emif_custom_configs *cust_cfgs = NULL; @@ -873,7 +863,7 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif, be32_to_cpup(poll_intvl); } - if (of_find_property(np_emif, "extended-temp-part", &len)) + if (of_property_read_bool(np_emif, "extended-temp-part")) cust_cfgs->mask |= EMIF_CUSTOM_CONFIG_EXTENDED_TEMP_PART; if (!is_custom_config_valid(cust_cfgs, emif->dev)) { @@ -884,18 +874,14 @@ static void __init_or_module of_get_custom_configs(struct device_node *np_emif, emif->plat_data->custom_configs = cust_cfgs; } -static void __init_or_module of_get_ddr_info(struct device_node *np_emif, +static void of_get_ddr_info(struct device_node *np_emif, struct device_node *np_ddr, struct ddr_device_info *dev_info) { u32 density = 0, io_width = 0; - int len; - - if (of_find_property(np_emif, "cs1-used", &len)) - dev_info->cs1_used = true; - if (of_find_property(np_emif, "cal-resistor-per-cs", &len)) - dev_info->cal_resistors_per_cs = true; + dev_info->cs1_used = of_property_read_bool(np_emif, "cs1-used"); + dev_info->cal_resistors_per_cs = of_property_read_bool(np_emif, "cal-resistor-per-cs"); if (of_device_is_compatible(np_ddr, "jedec,lpddr2-s4")) dev_info->type = DDR_TYPE_LPDDR2_S4; @@ -918,14 +904,13 @@ static void __init_or_module of_get_ddr_info(struct device_node *np_emif, dev_info->io_width = __fls(io_width) - 1; } -static struct emif_data * __init_or_module of_get_memory_device_details( +static struct emif_data *of_get_memory_device_details( struct device_node *np_emif, struct device *dev) { struct emif_data *emif = NULL; struct ddr_device_info *dev_info = NULL; struct emif_platform_data *pd = NULL; struct device_node *np_ddr; - int len; np_ddr = of_parse_phandle(np_emif, "device-handle", 0); if (!np_ddr) @@ -953,7 +938,7 @@ static struct emif_data * __init_or_module of_get_memory_device_details( of_property_read_u32(np_emif, "phy-type", &pd->phy_type); - if (of_find_property(np_emif, "hw-caps-ll-interface", &len)) + if (of_property_read_bool(np_emif, "hw-caps-ll-interface")) pd->hw_caps |= EMIF_HW_CAPS_LL_INTERFACE; of_get_ddr_info(np_emif, np_ddr, dev_info); @@ -991,16 +976,7 @@ out: return emif; } -#else - -static struct emif_data * __init_or_module of_get_memory_device_details( - struct device_node *np_emif, struct device *dev) -{ - return NULL; -} -#endif - -static struct emif_data *__init_or_module get_device_details( +static struct emif_data *get_device_details( struct platform_device *pdev) { u32 size; @@ -1104,7 +1080,7 @@ error: return NULL; } -static int __init_or_module emif_probe(struct platform_device *pdev) +static int emif_probe(struct platform_device *pdev) { struct emif_data *emif; int irq, ret; @@ -1159,13 +1135,11 @@ error: return -ENODEV; } -static int __exit emif_remove(struct platform_device *pdev) +static void emif_remove(struct platform_device *pdev) { struct emif_data *emif = platform_get_drvdata(pdev); emif_debugfs_exit(emif); - - return 0; } static void emif_shutdown(struct platform_device *pdev) @@ -1185,7 +1159,8 @@ MODULE_DEVICE_TABLE(of, emif_of_match); #endif static struct platform_driver emif_driver = { - .remove = __exit_p(emif_remove), + .probe = emif_probe, + .remove = emif_remove, .shutdown = emif_shutdown, .driver = { .name = "emif", @@ -1193,7 +1168,7 @@ static struct platform_driver emif_driver = { }, }; -module_platform_driver_probe(emif_driver, emif_probe); +module_platform_driver(emif_driver); MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c index 7fc9f57ae278..ecd6c1955153 100644 --- a/drivers/memory/fsl-corenet-cf.c +++ b/drivers/memory/fsl-corenet-cf.c @@ -10,10 +10,8 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/of_irq.h> #include <linux/platform_device.h> +#include <linux/property.h> enum ccf_version { CCF1, @@ -172,14 +170,9 @@ out: static int ccf_probe(struct platform_device *pdev) { struct ccf_private *ccf; - const struct of_device_id *match; u32 errinten; int ret, irq; - match = of_match_device(ccf_matches, &pdev->dev); - if (WARN_ON(!match)) - return -ENODEV; - ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL); if (!ccf) return -ENOMEM; @@ -189,7 +182,7 @@ static int ccf_probe(struct platform_device *pdev) return PTR_ERR(ccf->regs); ccf->dev = &pdev->dev; - ccf->info = match->data; + ccf->info = device_get_match_data(&pdev->dev); ccf->err_regs = ccf->regs + ccf->info->err_reg_offs; if (ccf->info->has_brr) { @@ -230,7 +223,7 @@ static int ccf_probe(struct platform_device *pdev) return 0; } -static int ccf_remove(struct platform_device *pdev) +static void ccf_remove(struct platform_device *pdev) { struct ccf_private *ccf = dev_get_drvdata(&pdev->dev); @@ -248,8 +241,6 @@ static int ccf_remove(struct platform_device *pdev) iowrite32be(0, &ccf->err_regs->errinten); break; } - - return 0; } static struct platform_driver ccf_driver = { diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c index e83b61c925a4..e89e0c6cc4bc 100644 --- a/drivers/memory/fsl_ifc.c +++ b/drivers/memory/fsl_ifc.c @@ -15,7 +15,7 @@ #include <linux/slab.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/fsl_ifc.h> #include <linux/irqdomain.h> @@ -84,7 +84,7 @@ static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl) return 0; } -static int fsl_ifc_ctrl_remove(struct platform_device *dev) +static void fsl_ifc_ctrl_remove(struct platform_device *dev) { struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev); @@ -98,8 +98,6 @@ static int fsl_ifc_ctrl_remove(struct platform_device *dev) iounmap(ctrl->gregs); dev_set_drvdata(&dev->dev, NULL); - - return 0; } /* @@ -318,7 +316,7 @@ static struct platform_driver fsl_ifc_ctrl_driver = { .of_match_table = fsl_ifc_match, }, .probe = fsl_ifc_ctrl_probe, - .remove = fsl_ifc_ctrl_remove, + .remove = fsl_ifc_ctrl_remove, }; static int __init fsl_ifc_init(void) @@ -327,6 +325,5 @@ static int __init fsl_ifc_init(void) } subsys_initcall(fsl_ifc_init); -MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale Semiconductor"); MODULE_DESCRIPTION("Freescale Integrated Flash Controller driver"); diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c index 555f7ac3b7dd..1a8161514d03 100644 --- a/drivers/memory/jz4780-nemc.c +++ b/drivers/memory/jz4780-nemc.c @@ -12,7 +12,6 @@ #include <linux/math64.h> #include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -385,12 +384,11 @@ static int jz4780_nemc_probe(struct platform_device *pdev) return 0; } -static int jz4780_nemc_remove(struct platform_device *pdev) +static void jz4780_nemc_remove(struct platform_device *pdev) { struct jz4780_nemc *nemc = platform_get_drvdata(pdev); clk_disable_unprepare(nemc->clk); - return 0; } static const struct jz_soc_info jz4740_soc_info = { diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c index 5a9754442bc7..733e22f695ab 100644 --- a/drivers/memory/mtk-smi.c +++ b/drivers/memory/mtk-smi.c @@ -283,6 +283,75 @@ static int mtk_smi_larb_config_port_gen2_general(struct device *dev) return 0; } +static const u8 mtk_smi_larb_mt6893_ostd[][SMI_LARB_PORT_NR_MAX] = { + [0] = {0x2, 0x6, 0x2, 0x2, 0x2, 0x28, 0x18, 0x18, 0x1, 0x1, 0x1, 0x8, + 0x8, 0x1, 0x3f}, + [1] = {0x2, 0x6, 0x2, 0x2, 0x2, 0x28, 0x18, 0x18, 0x1, 0x1, 0x1, 0x8, + 0x8, 0x1, 0x3f}, + [2] = {0x5, 0x5, 0x5, 0x5, 0x1, 0x3f}, + [3] = {0x5, 0x5, 0x5, 0x5, 0x1, 0x3f}, + [4] = {0x28, 0x19, 0xb, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1}, + [5] = {0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x16}, + [6] = {}, + [7] = {0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x4, 0x1, + 0x4, 0x1, 0xa, 0x6, 0x1, 0xa, 0x6, 0x1, 0x1, 0x1, 0x1, 0x5, + 0x3, 0x3, 0x4}, + [8] = {0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x4, 0x1, + 0x4, 0x1, 0xa, 0x6, 0x1, 0xa, 0x6, 0x1, 0x1, 0x1, 0x1, 0x5, + 0x3, 0x3, 0x4}, + [9] = {0x9, 0x7, 0xf, 0x8, 0x1, 0x8, 0x9, 0x3, 0x3, 0x6, 0x7, 0x4, + 0x9, 0x3, 0x4, 0xe, 0x1, 0x7, 0x8, 0x7, 0x7, 0x1, 0x6, 0x2, + 0xf, 0x8, 0x1, 0x1, 0x1}, + [10] = {}, + [11] = {0x9, 0x7, 0xf, 0x8, 0x1, 0x8, 0x9, 0x3, 0x3, 0x6, 0x7, 0x4, + 0x9, 0x3, 0x4, 0xe, 0x1, 0x7, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1}, + [12] = {}, + [13] = {0x2, 0xc, 0xc, 0xe, 0x6, 0x6, 0x6, 0x6, 0x6, 0x12, 0x6, 0x1}, + [14] = {0x2, 0xc, 0xc, 0x28, 0x12, 0x6}, + [15] = {0x28, 0x1, 0x2, 0x28, 0x1}, + [16] = {0x28, 0x14, 0x2, 0xc, 0x18, 0x2, 0x14, 0x14, 0x4, 0x4, 0x4, 0x2, + 0x4, 0x2, 0x8, 0x4, 0x4}, + [17] = {0x28, 0x14, 0x2, 0xc, 0x18, 0x2, 0x14, 0x14, 0x4, 0x4, 0x4, 0x2, + 0x4, 0x2, 0x8, 0x4, 0x4}, + [18] = {0x28, 0x14, 0x2, 0xc, 0x18, 0x2, 0x14, 0x14, 0x4, 0x4, 0x4, 0x2, + 0x4, 0x2, 0x8, 0x4, 0x4}, + [19] = {0x2, 0x2, 0x4, 0x2}, + [20] = {0x9, 0x9, 0x5, 0x5, 0x1, 0x1}, +}; + +static const u8 mtk_smi_larb_mt8186_ostd[][SMI_LARB_PORT_NR_MAX] = { + [0] = {0x2, 0x1, 0x8, 0x1,}, + [1] = {0x1, 0x3, 0x1, 0x1,}, + [2] = {0x6, 0x1, 0x4, 0x1,}, + [3] = {}, + [4] = {0xf, 0x1, 0x5, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1,}, + [5] = {}, + [6] = {}, + [7] = {0x1, 0x3, 0x1, 0x1, 0x1, 0x3, 0x2, 0xd, 0x7, 0x5, 0x3, + 0x1, 0x5,}, + [8] = {0x1, 0x2, 0x2,}, + [9] = {0x9, 0x7, 0xf, 0x8, 0x1, 0x8, 0x9, 0x3, 0x3, 0xb, 0x7, 0x4, + 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1,}, + [10] = {}, + [11] = {0x9, 0x7, 0xf, 0x8, 0x1, 0x8, 0x9, 0x3, 0x3, 0xb, 0x7, 0x4, + 0x9, 0x1, 0x1, 0x1, 0x1, 0x1, 0x8, 0x7, 0x7, 0x1, 0x6, 0x2, + 0xf, 0x8, 0x1, 0x1, 0x1,}, + [12] = {}, + [13] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x6, 0x6, 0x6, 0x1, 0x1, 0x1,}, + [14] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1,}, + [15] = {}, + [16] = {0x28, 0x14, 0x2, 0xc, 0x18, 0x1, 0x14, 0x1, 0x4, 0x4, 0x4, + 0x2, 0x4, 0x2, 0x8, 0x4, 0x4,}, + [17] = {0x28, 0x14, 0x2, 0xc, 0x18, 0x1, 0x14, 0x1, 0x4, 0x4, 0x4, + 0x2, 0x4, 0x2, 0x8, 0x4, 0x4,}, + [18] = {}, + [19] = {0x1, 0x1, 0x1, 0x1,}, + [20] = {0x2, 0x2, 0x2, 0x2, 0x1, 0x1,}, +}; + static const u8 mtk_smi_larb_mt8188_ostd[][SMI_LARB_PORT_NR_MAX] = { [0] = {0x02, 0x18, 0x22, 0x22, 0x01, 0x02, 0x0a,}, [1] = {0x12, 0x02, 0x14, 0x14, 0x01, 0x18, 0x0a,}, @@ -332,6 +401,38 @@ static const u8 mtk_smi_larb_mt8188_ostd[][SMI_LARB_PORT_NR_MAX] = { [25] = {0x01}, }; +static const u8 mtk_smi_larb_mt8192_ostd[][SMI_LARB_PORT_NR_MAX] = { + [0] = {0x2, 0x2, 0x28, 0xa, 0xc, 0x28,}, + [1] = {0x2, 0x2, 0x18, 0x18, 0x18, 0xa, 0xc, 0x28,}, + [2] = {0x5, 0x5, 0x5, 0x5, 0x1,}, + [3] = {}, + [4] = {0x28, 0x19, 0xb, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x4, 0x1,}, + [5] = {0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 0x16,}, + [6] = {}, + [7] = {0x1, 0x3, 0x2, 0x1, 0x1, 0x5, 0x2, 0x12, 0x13, 0x4, 0x4, 0x1, + 0x4, 0x2, 0x1,}, + [8] = {}, + [9] = {0xa, 0x7, 0xf, 0x8, 0x1, 0x8, 0x9, 0x3, 0x3, 0x6, 0x7, 0x4, + 0xa, 0x3, 0x4, 0xe, 0x1, 0x7, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1,}, + [10] = {}, + [11] = {0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0xe, 0x1, 0x7, 0x8, 0x7, 0x7, 0x1, 0x6, 0x2, + 0xf, 0x8, 0x1, 0x1, 0x1,}, + [12] = {}, + [13] = {0x2, 0xc, 0xc, 0xe, 0x6, 0x6, 0x6, 0x6, 0x6, 0x12, 0x6, 0x28, + 0x2, 0xc, 0xc, 0x28, 0x12, 0x6,}, + [14] = {}, + [15] = {0x28, 0x14, 0x2, 0xc, 0x18, 0x4, 0x28, 0x14, 0x4, 0x4, 0x4, 0x2, + 0x4, 0x2, 0x8, 0x4, 0x4,}, + [16] = {0x28, 0x14, 0x2, 0xc, 0x18, 0x4, 0x28, 0x14, 0x4, 0x4, 0x4, 0x2, + 0x4, 0x2, 0x8, 0x4, 0x4,}, + [17] = {0x28, 0x14, 0x2, 0xc, 0x18, 0x4, 0x28, 0x14, 0x4, 0x4, 0x4, 0x2, + 0x4, 0x2, 0x8, 0x4, 0x4,}, + [18] = {0x2, 0x2, 0x4, 0x2,}, + [19] = {0x9, 0x9, 0x5, 0x5, 0x1, 0x1,}, +}; + static const u8 mtk_smi_larb_mt8195_ostd[][SMI_LARB_PORT_NR_MAX] = { [0] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb0 */ [1] = {0x0a, 0xc, 0x22, 0x22, 0x01, 0x0a,}, /* larb1 */ @@ -397,6 +498,12 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt6779 = { /* DUMMY | IPU0 | IPU1 | CCU | MDLA */ }; +static const struct mtk_smi_larb_gen mtk_smi_larb_mt6893 = { + .config_port = mtk_smi_larb_config_port_gen2_general, + .flags_general = MTK_SMI_FLAG_THRT_UPDATE | MTK_SMI_FLAG_SW_FLAG, + .ostd = mtk_smi_larb_mt6893_ostd, +}; + static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = { /* mt8167 do not need the port in larb */ .config_port = mtk_smi_larb_config_port_mt8167, @@ -416,6 +523,7 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = { static const struct mtk_smi_larb_gen mtk_smi_larb_mt8186 = { .config_port = mtk_smi_larb_config_port_gen2_general, .flags_general = MTK_SMI_FLAG_SLEEP_CTL, + .ostd = mtk_smi_larb_mt8186_ostd, }; static const struct mtk_smi_larb_gen mtk_smi_larb_mt8188 = { @@ -427,6 +535,7 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8188 = { static const struct mtk_smi_larb_gen mtk_smi_larb_mt8192 = { .config_port = mtk_smi_larb_config_port_gen2_general, + .ostd = mtk_smi_larb_mt8192_ostd, }; static const struct mtk_smi_larb_gen mtk_smi_larb_mt8195 = { @@ -441,6 +550,7 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = { {.compatible = "mediatek,mt2712-smi-larb", .data = &mtk_smi_larb_mt2712}, {.compatible = "mediatek,mt6779-smi-larb", .data = &mtk_smi_larb_mt6779}, {.compatible = "mediatek,mt6795-smi-larb", .data = &mtk_smi_larb_mt8173}, + {.compatible = "mediatek,mt6893-smi-larb", .data = &mtk_smi_larb_mt6893}, {.compatible = "mediatek,mt8167-smi-larb", .data = &mtk_smi_larb_mt8167}, {.compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173}, {.compatible = "mediatek,mt8183-smi-larb", .data = &mtk_smi_larb_mt8183}, @@ -450,6 +560,7 @@ static const struct of_device_id mtk_smi_larb_of_ids[] = { {.compatible = "mediatek,mt8195-smi-larb", .data = &mtk_smi_larb_mt8195}, {} }; +MODULE_DEVICE_TABLE(of, mtk_smi_larb_of_ids); static int mtk_smi_larb_sleep_ctrl_enable(struct mtk_smi_larb *larb) { @@ -566,14 +677,13 @@ err_pm_disable: return ret; } -static int mtk_smi_larb_remove(struct platform_device *pdev) +static void mtk_smi_larb_remove(struct platform_device *pdev) { struct mtk_smi_larb *larb = platform_get_drvdata(pdev); device_link_remove(&pdev->dev, larb->smi_common_dev); pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &mtk_smi_larb_component_ops); - return 0; } static int __maybe_unused mtk_smi_larb_resume(struct device *dev) @@ -616,7 +726,7 @@ static const struct dev_pm_ops smi_larb_pm_ops = { static struct platform_driver mtk_smi_larb_driver = { .probe = mtk_smi_larb_probe, - .remove = mtk_smi_larb_remove, + .remove = mtk_smi_larb_remove, .driver = { .name = "mtk-smi-larb", .of_match_table = mtk_smi_larb_of_ids, @@ -661,6 +771,13 @@ static const struct mtk_smi_common_plat mtk_smi_common_mt6795 = { .init = mtk_smi_common_mt6795_init, }; +static const struct mtk_smi_common_plat mtk_smi_common_mt6893 = { + .type = MTK_SMI_GEN2, + .has_gals = true, + .bus_sel = F_MMU1_LARB(1) | F_MMU1_LARB(2) | F_MMU1_LARB(4) | + F_MMU1_LARB(5) | F_MMU1_LARB(7), +}; + static const struct mtk_smi_common_plat mtk_smi_common_mt8183 = { .type = MTK_SMI_GEN2, .has_gals = true, @@ -713,11 +830,17 @@ static const struct mtk_smi_common_plat mtk_smi_sub_common_mt8195 = { .has_gals = true, }; +static const struct mtk_smi_common_plat mtk_smi_common_mt8365 = { + .type = MTK_SMI_GEN2, + .bus_sel = F_MMU1_LARB(2) | F_MMU1_LARB(4), +}; + static const struct of_device_id mtk_smi_common_of_ids[] = { {.compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1}, {.compatible = "mediatek,mt2712-smi-common", .data = &mtk_smi_common_gen2}, {.compatible = "mediatek,mt6779-smi-common", .data = &mtk_smi_common_mt6779}, {.compatible = "mediatek,mt6795-smi-common", .data = &mtk_smi_common_mt6795}, + {.compatible = "mediatek,mt6893-smi-common", .data = &mtk_smi_common_mt6893}, {.compatible = "mediatek,mt8167-smi-common", .data = &mtk_smi_common_gen2}, {.compatible = "mediatek,mt8173-smi-common", .data = &mtk_smi_common_gen2}, {.compatible = "mediatek,mt8183-smi-common", .data = &mtk_smi_common_mt8183}, @@ -728,8 +851,10 @@ static const struct of_device_id mtk_smi_common_of_ids[] = { {.compatible = "mediatek,mt8195-smi-common-vdo", .data = &mtk_smi_common_mt8195_vdo}, {.compatible = "mediatek,mt8195-smi-common-vpp", .data = &mtk_smi_common_mt8195_vpp}, {.compatible = "mediatek,mt8195-smi-sub-common", .data = &mtk_smi_sub_common_mt8195}, + {.compatible = "mediatek,mt8365-smi-common", .data = &mtk_smi_common_mt8365}, {} }; +MODULE_DEVICE_TABLE(of, mtk_smi_common_of_ids); static int mtk_smi_common_probe(struct platform_device *pdev) { @@ -764,13 +889,9 @@ static int mtk_smi_common_probe(struct platform_device *pdev) if (IS_ERR(common->smi_ao_base)) return PTR_ERR(common->smi_ao_base); - common->clk_async = devm_clk_get(dev, "async"); + common->clk_async = devm_clk_get_enabled(dev, "async"); if (IS_ERR(common->clk_async)) return PTR_ERR(common->clk_async); - - ret = clk_prepare_enable(common->clk_async); - if (ret) - return ret; } else { common->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(common->base)) @@ -789,14 +910,13 @@ static int mtk_smi_common_probe(struct platform_device *pdev) return 0; } -static int mtk_smi_common_remove(struct platform_device *pdev) +static void mtk_smi_common_remove(struct platform_device *pdev) { struct mtk_smi *common = dev_get_drvdata(&pdev->dev); if (common->plat->type == MTK_SMI_GEN2_SUB_COMM) device_link_remove(&pdev->dev, common->smi_common_dev); pm_runtime_disable(&pdev->dev); - return 0; } static int __maybe_unused mtk_smi_common_resume(struct device *dev) diff --git a/drivers/memory/mvebu-devbus.c b/drivers/memory/mvebu-devbus.c index efc6c08db2b7..406fddcdba02 100644 --- a/drivers/memory/mvebu-devbus.c +++ b/drivers/memory/mvebu-devbus.c @@ -341,6 +341,5 @@ static int __init mvebu_devbus_init(void) } module_init(mvebu_devbus_init); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>"); MODULE_DESCRIPTION("Marvell EBU SoC Device Bus controller"); diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index d78f73db37c8..d9e13c1f9b13 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -9,6 +9,7 @@ * Copyright (C) 2009 Texas Instruments * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> */ +#include <linux/cleanup.h> #include <linux/cpu_pm.h> #include <linux/irq.h> #include <linux/kernel.h> @@ -357,17 +358,6 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps) return (time_ps + tick_ps - 1) / tick_ps; } -static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs, - enum gpmc_clk_domain cd) -{ - return ticks * gpmc_get_clk_period(cs, cd) / 1000; -} - -unsigned int gpmc_ticks_to_ns(unsigned int ticks) -{ - return gpmc_clk_ticks_to_ns(ticks, /* any CS */ 0, GPMC_CD_FCLK); -} - static unsigned int gpmc_ticks_to_ps(unsigned int ticks) { return ticks * gpmc_get_fclk_period(); @@ -414,6 +404,13 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p) } #ifdef CONFIG_OMAP_GPMC_DEBUG + +static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs, + enum gpmc_clk_domain cd) +{ + return ticks * gpmc_get_clk_period(cs, cd) / 1000; +} + /** * get_gpmc_timing_reg - read a timing parameter and print DTS settings for it. * @cs: Chip Select Region @@ -989,18 +986,18 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) if (size > (1 << GPMC_SECTION_SHIFT)) return -ENOMEM; - spin_lock(&gpmc_mem_lock); - if (gpmc_cs_reserved(cs)) { - r = -EBUSY; - goto out; - } + guard(spinlock)(&gpmc_mem_lock); + + if (gpmc_cs_reserved(cs)) + return -EBUSY; + if (gpmc_cs_mem_enabled(cs)) r = adjust_resource(res, res->start & ~(size - 1), size); if (r < 0) r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0, size, NULL, NULL); if (r < 0) - goto out; + return r; /* Disable CS while changing base address and size mask */ gpmc_cs_disable_mem(cs); @@ -1008,16 +1005,15 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) r = gpmc_cs_set_memconf(cs, res->start, resource_size(res)); if (r < 0) { release_resource(res); - goto out; + return r; } /* Enable CS */ gpmc_cs_enable_mem(cs); *base = res->start; gpmc_cs_set_reserved(cs, 1); -out: - spin_unlock(&gpmc_mem_lock); - return r; + + return 0; } EXPORT_SYMBOL(gpmc_cs_request); @@ -1026,10 +1022,9 @@ void gpmc_cs_free(int cs) struct gpmc_cs_data *gpmc; struct resource *res; - spin_lock(&gpmc_mem_lock); + guard(spinlock)(&gpmc_mem_lock); if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) { WARN(1, "Trying to free non-reserved GPMC CS%d\n", cs); - spin_unlock(&gpmc_mem_lock); return; } gpmc = &gpmc_cs[cs]; @@ -1039,7 +1034,6 @@ void gpmc_cs_free(int cs) if (res->flags) release_resource(res); gpmc_cs_set_reserved(cs, 0); - spin_unlock(&gpmc_mem_lock); } EXPORT_SYMBOL(gpmc_cs_free); @@ -1297,21 +1291,6 @@ int gpmc_omap_onenand_set_timings(struct device *dev, int cs, int freq, } EXPORT_SYMBOL_GPL(gpmc_omap_onenand_set_timings); -int gpmc_get_client_irq(unsigned int irq_config) -{ - if (!gpmc_irq_domain) { - pr_warn("%s called before GPMC IRQ domain available\n", - __func__); - return 0; - } - - /* we restrict this to NAND IRQs only */ - if (irq_config >= GPMC_NR_NAND_IRQS) - return 0; - - return irq_create_mapping(gpmc_irq_domain, irq_config); -} - static int gpmc_irq_endis(unsigned long hwirq, bool endis) { u32 regval; @@ -1476,10 +1455,8 @@ static int gpmc_setup_irq(struct gpmc_device *gpmc) gpmc->irq_chip.irq_unmask = gpmc_irq_unmask; gpmc->irq_chip.irq_set_type = gpmc_irq_set_type; - gpmc_irq_domain = irq_domain_add_linear(gpmc->dev->of_node, - gpmc->nirqs, - &gpmc_irq_domain_ops, - gpmc); + gpmc_irq_domain = irq_domain_create_linear(dev_fwnode(gpmc->dev), gpmc->nirqs, + &gpmc_irq_domain_ops, gpmc); if (!gpmc_irq_domain) { dev_err(gpmc->dev, "IRQ domain add failed\n"); return -ENODEV; @@ -2247,26 +2224,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, goto err; } - if (of_node_name_eq(child, "nand")) { - /* Warn about older DT blobs with no compatible property */ - if (!of_property_read_bool(child, "compatible")) { - dev_warn(&pdev->dev, - "Incompatible NAND node: missing compatible"); - ret = -EINVAL; - goto err; - } - } - - if (of_node_name_eq(child, "onenand")) { - /* Warn about older DT blobs with no compatible property */ - if (!of_property_read_bool(child, "compatible")) { - dev_warn(&pdev->dev, - "Incompatible OneNAND node: missing compatible"); - ret = -EINVAL; - goto err; - } - } - if (of_match_node(omap_nand_ids, child)) { /* NAND specific setup */ val = 8; @@ -2417,7 +2374,7 @@ static void gpmc_probe_dt_children(struct platform_device *pdev) static int gpmc_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { - return 1; /* we're input only */ + return GPIO_LINE_DIRECTION_IN; /* we're input only */ } static int gpmc_gpio_direction_input(struct gpio_chip *chip, @@ -2426,17 +2383,6 @@ static int gpmc_gpio_direction_input(struct gpio_chip *chip, return 0; /* we're input only */ } -static int gpmc_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - return -EINVAL; /* we're input only */ -} - -static void gpmc_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) -{ -} - static int gpmc_gpio_get(struct gpio_chip *chip, unsigned int offset) { u32 reg; @@ -2458,8 +2404,6 @@ static int gpmc_gpio_init(struct gpmc_device *gpmc) gpmc->gpio_chip.ngpio = gpmc_nr_waitpins; gpmc->gpio_chip.get_direction = gpmc_gpio_get_direction; gpmc->gpio_chip.direction_input = gpmc_gpio_direction_input; - gpmc->gpio_chip.direction_output = gpmc_gpio_direction_output; - gpmc->gpio_chip.set = gpmc_gpio_set; gpmc->gpio_chip.get = gpmc_gpio_get; gpmc->gpio_chip.base = -1; @@ -2690,7 +2634,7 @@ gpio_init_failed: return rc; } -static int gpmc_remove(struct platform_device *pdev) +static void gpmc_remove(struct platform_device *pdev) { int i; struct gpmc_device *gpmc = platform_get_drvdata(pdev); @@ -2702,8 +2646,6 @@ static int gpmc_remove(struct platform_device *pdev) gpmc_mem_exit(); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/memory/pl172.c b/drivers/memory/pl172.c index 9eb8cc7de494..be7ba599cccf 100644 --- a/drivers/memory/pl172.c +++ b/drivers/memory/pl172.c @@ -187,6 +187,13 @@ static int pl172_parse_cs_config(struct amba_device *adev, return -EINVAL; } +static void pl172_amba_release_regions(void *data) +{ + struct amba_device *adev = data; + + amba_release_regions(adev); +} + static const char * const pl172_revisions[] = {"r1", "r2", "r2p3", "r2p4"}; static const char * const pl175_revisions[] = {"r1"}; static const char * const pl176_revisions[] = {"r0"}; @@ -216,38 +223,30 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id) if (!pl172) return -ENOMEM; - pl172->clk = devm_clk_get(dev, "mpmcclk"); - if (IS_ERR(pl172->clk)) { - dev_err(dev, "no mpmcclk provided clock\n"); - return PTR_ERR(pl172->clk); - } - - ret = clk_prepare_enable(pl172->clk); - if (ret) { - dev_err(dev, "unable to mpmcclk enable clock\n"); - return ret; - } + pl172->clk = devm_clk_get_enabled(dev, "mpmcclk"); + if (IS_ERR(pl172->clk)) + return dev_err_probe(dev, PTR_ERR(pl172->clk), + "no mpmcclk provided clock\n"); pl172->rate = clk_get_rate(pl172->clk) / MSEC_PER_SEC; - if (!pl172->rate) { - dev_err(dev, "unable to get mpmcclk clock rate\n"); - ret = -EINVAL; - goto err_clk_enable; - } + if (!pl172->rate) + return dev_err_probe(dev, -EINVAL, + "unable to get mpmcclk clock rate\n"); ret = amba_request_regions(adev, NULL); if (ret) { dev_err(dev, "unable to request AMBA regions\n"); - goto err_clk_enable; + return ret; } + ret = devm_add_action_or_reset(dev, pl172_amba_release_regions, adev); + if (ret) + return ret; + pl172->base = devm_ioremap(dev, adev->res.start, resource_size(&adev->res)); - if (!pl172->base) { - dev_err(dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_no_ioremap; - } + if (!pl172->base) + return dev_err_probe(dev, -ENOMEM, "ioremap failed\n"); amba_set_drvdata(adev, pl172); @@ -265,20 +264,6 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id) } return 0; - -err_no_ioremap: - amba_release_regions(adev); -err_clk_enable: - clk_disable_unprepare(pl172->clk); - return ret; -} - -static void pl172_remove(struct amba_device *adev) -{ - struct pl172_data *pl172 = amba_get_drvdata(adev); - - clk_disable_unprepare(pl172->clk); - amba_release_regions(adev); } static const struct amba_id pl172_ids[] = { @@ -306,7 +291,6 @@ static struct amba_driver pl172_driver = { .name = "memory-pl172", }, .probe = pl172_probe, - .remove = pl172_remove, .id_table = pl172_ids, }; module_amba_driver(pl172_driver); diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c index d39ee7d06665..28a8cc56003c 100644 --- a/drivers/memory/pl353-smc.c +++ b/drivers/memory/pl353-smc.c @@ -10,6 +10,7 @@ #include <linux/clk.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/amba/bus.h> @@ -73,73 +74,39 @@ static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) struct device_node *of_node = adev->dev.of_node; const struct of_device_id *match = NULL; struct pl353_smc_data *pl353_smc; - struct device_node *child; - int err; pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL); if (!pl353_smc) return -ENOMEM; - pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk"); - if (IS_ERR(pl353_smc->aclk)) { - dev_err(&adev->dev, "aclk clock not found.\n"); - return PTR_ERR(pl353_smc->aclk); - } - - pl353_smc->memclk = devm_clk_get(&adev->dev, "memclk"); - if (IS_ERR(pl353_smc->memclk)) { - dev_err(&adev->dev, "memclk clock not found.\n"); - return PTR_ERR(pl353_smc->memclk); - } + pl353_smc->aclk = devm_clk_get_enabled(&adev->dev, "apb_pclk"); + if (IS_ERR(pl353_smc->aclk)) + return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->aclk), + "aclk clock not found.\n"); - err = clk_prepare_enable(pl353_smc->aclk); - if (err) { - dev_err(&adev->dev, "Unable to enable AXI clock.\n"); - return err; - } - - err = clk_prepare_enable(pl353_smc->memclk); - if (err) { - dev_err(&adev->dev, "Unable to enable memory clock.\n"); - goto disable_axi_clk; - } + pl353_smc->memclk = devm_clk_get_enabled(&adev->dev, "memclk"); + if (IS_ERR(pl353_smc->memclk)) + return dev_err_probe(&adev->dev, PTR_ERR(pl353_smc->memclk), + "memclk clock not found.\n"); amba_set_drvdata(adev, pl353_smc); /* Find compatible children. Only a single child is supported */ - for_each_available_child_of_node(of_node, child) { + for_each_available_child_of_node_scoped(of_node, child) { match = of_match_node(pl353_smc_supported_children, child); if (!match) { dev_warn(&adev->dev, "unsupported child node\n"); continue; } + of_platform_device_create(child, NULL, &adev->dev); break; } if (!match) { - err = -ENODEV; dev_err(&adev->dev, "no matching children\n"); - goto disable_mem_clk; + return -ENODEV; } - of_platform_device_create(child, NULL, &adev->dev); - of_node_put(child); - return 0; - -disable_mem_clk: - clk_disable_unprepare(pl353_smc->memclk); -disable_axi_clk: - clk_disable_unprepare(pl353_smc->aclk); - - return err; -} - -static void pl353_smc_remove(struct amba_device *adev) -{ - struct pl353_smc_data *pl353_smc = amba_get_drvdata(adev); - - clk_disable_unprepare(pl353_smc->memclk); - clk_disable_unprepare(pl353_smc->aclk); } static const struct amba_id pl353_ids[] = { @@ -153,13 +120,11 @@ MODULE_DEVICE_TABLE(amba, pl353_ids); static struct amba_driver pl353_smc_driver = { .drv = { - .owner = THIS_MODULE, .name = "pl353-smc", .pm = &pl353_smc_dev_pm_ops, }, .id_table = pl353_ids, .probe = pl353_smc_probe, - .remove = pl353_smc_remove, }; module_amba_driver(pl353_smc_driver); diff --git a/drivers/memory/renesas-rpc-if-regs.h b/drivers/memory/renesas-rpc-if-regs.h new file mode 100644 index 000000000000..e6b33f7c40a8 --- /dev/null +++ b/drivers/memory/renesas-rpc-if-regs.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * R-Car RPC Interface Registers Definitions + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#ifndef __RENESAS_RPC_IF_REGS_H__ +#define __RENESAS_RPC_IF_REGS_H__ + +#include <linux/bits.h> + +#define RPCIF_CMNCR 0x0000 /* R/W */ +#define RPCIF_CMNCR_MD BIT(31) +#define RPCIF_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) +#define RPCIF_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) +#define RPCIF_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) +#define RPCIF_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) +#define RPCIF_CMNCR_MOIIO(val) (RPCIF_CMNCR_MOIIO0(val) | RPCIF_CMNCR_MOIIO1(val) | \ + RPCIF_CMNCR_MOIIO2(val) | RPCIF_CMNCR_MOIIO3(val)) +#define RPCIF_CMNCR_IO3FV(val) (((val) & 0x3) << 14) /* documented for RZ/G2L */ +#define RPCIF_CMNCR_IO2FV(val) (((val) & 0x3) << 12) /* documented for RZ/G2L */ +#define RPCIF_CMNCR_IO0FV(val) (((val) & 0x3) << 8) +#define RPCIF_CMNCR_IOFV(val) (RPCIF_CMNCR_IO0FV(val) | RPCIF_CMNCR_IO2FV(val) | \ + RPCIF_CMNCR_IO3FV(val)) +#define RPCIF_CMNCR_BSZ(val) (((val) & 0x3) << 0) + +#define RPCIF_SSLDR 0x0004 /* R/W */ +#define RPCIF_SSLDR_SPNDL(d) (((d) & 0x7) << 16) +#define RPCIF_SSLDR_SLNDL(d) (((d) & 0x7) << 8) +#define RPCIF_SSLDR_SCKDL(d) (((d) & 0x7) << 0) + +#define RPCIF_DRCR 0x000C /* R/W */ +#define RPCIF_DRCR_SSLN BIT(24) +#define RPCIF_DRCR_RBURST(v) ((((v) - 1) & 0x1F) << 16) +#define RPCIF_DRCR_RCF BIT(9) +#define RPCIF_DRCR_RBE BIT(8) +#define RPCIF_DRCR_SSLE BIT(0) + +#define RPCIF_DRCMR 0x0010 /* R/W */ +#define RPCIF_DRCMR_CMD(c) (((c) & 0xFF) << 16) +#define RPCIF_DRCMR_OCMD(c) (((c) & 0xFF) << 0) + +#define RPCIF_DREAR 0x0014 /* R/W */ +#define RPCIF_DREAR_EAV(c) (((c) & 0xF) << 16) +#define RPCIF_DREAR_EAC(c) (((c) & 0x7) << 0) + +#define RPCIF_DROPR 0x0018 /* R/W */ + +#define RPCIF_DRENR 0x001C /* R/W */ +#define RPCIF_DRENR_CDB(o) (((u32)((o) & 0x3)) << 30) +#define RPCIF_DRENR_OCDB(o) (((o) & 0x3) << 28) +#define RPCIF_DRENR_ADB(o) (((o) & 0x3) << 24) +#define RPCIF_DRENR_OPDB(o) (((o) & 0x3) << 20) +#define RPCIF_DRENR_DRDB(o) (((o) & 0x3) << 16) +#define RPCIF_DRENR_DME BIT(15) +#define RPCIF_DRENR_CDE BIT(14) +#define RPCIF_DRENR_OCDE BIT(12) +#define RPCIF_DRENR_ADE(v) (((v) & 0xF) << 8) +#define RPCIF_DRENR_OPDE(v) (((v) & 0xF) << 4) + +#define RPCIF_SMCR 0x0020 /* R/W */ +#define RPCIF_SMCR_SSLKP BIT(8) +#define RPCIF_SMCR_SPIRE BIT(2) +#define RPCIF_SMCR_SPIWE BIT(1) +#define RPCIF_SMCR_SPIE BIT(0) + +#define RPCIF_SMCMR 0x0024 /* R/W */ +#define RPCIF_SMCMR_CMD(c) (((c) & 0xFF) << 16) +#define RPCIF_SMCMR_OCMD(c) (((c) & 0xFF) << 0) + +#define RPCIF_SMADR 0x0028 /* R/W */ + +#define RPCIF_SMOPR 0x002C /* R/W */ +#define RPCIF_SMOPR_OPD3(o) (((o) & 0xFF) << 24) +#define RPCIF_SMOPR_OPD2(o) (((o) & 0xFF) << 16) +#define RPCIF_SMOPR_OPD1(o) (((o) & 0xFF) << 8) +#define RPCIF_SMOPR_OPD0(o) (((o) & 0xFF) << 0) + +#define RPCIF_SMENR 0x0030 /* R/W */ +#define RPCIF_SMENR_CDB(o) (((o) & 0x3) << 30) +#define RPCIF_SMENR_OCDB(o) (((o) & 0x3) << 28) +#define RPCIF_SMENR_ADB(o) (((o) & 0x3) << 24) +#define RPCIF_SMENR_OPDB(o) (((o) & 0x3) << 20) +#define RPCIF_SMENR_SPIDB(o) (((o) & 0x3) << 16) +#define RPCIF_SMENR_DME BIT(15) +#define RPCIF_SMENR_CDE BIT(14) +#define RPCIF_SMENR_OCDE BIT(12) +#define RPCIF_SMENR_ADE(v) (((v) & 0xF) << 8) +#define RPCIF_SMENR_OPDE(v) (((v) & 0xF) << 4) +#define RPCIF_SMENR_SPIDE(v) (((v) & 0xF) << 0) + +#define RPCIF_SMRDR0 0x0038 /* R */ +#define RPCIF_SMRDR1 0x003C /* R */ +#define RPCIF_SMWDR0 0x0040 /* W */ +#define RPCIF_SMWDR1 0x0044 /* W */ + +#define RPCIF_CMNSR 0x0048 /* R */ +#define RPCIF_CMNSR_SSLF BIT(1) +#define RPCIF_CMNSR_TEND BIT(0) + +#define RPCIF_DRDMCR 0x0058 /* R/W */ +#define RPCIF_DMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) + +#define RPCIF_DRDRENR 0x005C /* R/W */ +#define RPCIF_DRDRENR_HYPE(v) (((v) & 0x7) << 12) +#define RPCIF_DRDRENR_ADDRE BIT(8) +#define RPCIF_DRDRENR_OPDRE BIT(4) +#define RPCIF_DRDRENR_DRDRE BIT(0) + +#define RPCIF_SMDMCR 0x0060 /* R/W */ +#define RPCIF_SMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) + +#define RPCIF_SMDRENR 0x0064 /* R/W */ +#define RPCIF_SMDRENR_HYPE(v) (((v) & 0x7) << 12) +#define RPCIF_SMDRENR_ADDRE BIT(8) +#define RPCIF_SMDRENR_OPDRE BIT(4) +#define RPCIF_SMDRENR_SPIDRE BIT(0) + +#define RPCIF_PHYADD 0x0070 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ +#define RPCIF_PHYWR 0x0074 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ + +#define RPCIF_PHYCNT 0x007C /* R/W */ +#define RPCIF_PHYCNT_CAL BIT(31) +#define RPCIF_PHYCNT_OCTA(v) (((v) & 0x3) << 22) +#define RPCIF_PHYCNT_EXDS BIT(21) +#define RPCIF_PHYCNT_OCT BIT(20) +#define RPCIF_PHYCNT_DDRCAL BIT(19) +#define RPCIF_PHYCNT_HS BIT(18) +#define RPCIF_PHYCNT_CKSEL(v) (((v) & 0x3) << 16) /* valid only for RZ/G2L */ +#define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15 | ((v) & 0x8) << 24) /* valid for R-Car and RZ/G2{E,H,M,N} */ + +#define RPCIF_PHYCNT_WBUF2 BIT(4) +#define RPCIF_PHYCNT_WBUF BIT(2) +#define RPCIF_PHYCNT_PHYMEM(v) (((v) & 0x3) << 0) +#define RPCIF_PHYCNT_PHYMEM_MASK GENMASK(1, 0) + +#define RPCIF_PHYOFFSET1 0x0080 /* R/W */ +#define RPCIF_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28) + +#define RPCIF_PHYOFFSET2 0x0084 /* R/W */ +#define RPCIF_PHYOFFSET2_OCTTMG(v) (((v) & 0x7) << 8) + +#define RPCIF_PHYINT 0x0088 /* R/W */ +#define RPCIF_PHYINT_WPVAL BIT(1) + +#endif /* __RENESAS_RPC_IF_REGS_H__ */ diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 09cd4318a83d..58ccc1c02e90 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -7,150 +7,19 @@ * Copyright (C) 2019-2020 Cogent Embedded, Inc. */ +#include <linux/bitops.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/regmap.h> #include <linux/reset.h> #include <memory/renesas-rpc-if.h> -#define RPCIF_CMNCR 0x0000 /* R/W */ -#define RPCIF_CMNCR_MD BIT(31) -#define RPCIF_CMNCR_MOIIO3(val) (((val) & 0x3) << 22) -#define RPCIF_CMNCR_MOIIO2(val) (((val) & 0x3) << 20) -#define RPCIF_CMNCR_MOIIO1(val) (((val) & 0x3) << 18) -#define RPCIF_CMNCR_MOIIO0(val) (((val) & 0x3) << 16) -#define RPCIF_CMNCR_MOIIO(val) (RPCIF_CMNCR_MOIIO0(val) | RPCIF_CMNCR_MOIIO1(val) | \ - RPCIF_CMNCR_MOIIO2(val) | RPCIF_CMNCR_MOIIO3(val)) -#define RPCIF_CMNCR_IO3FV(val) (((val) & 0x3) << 14) /* documented for RZ/G2L */ -#define RPCIF_CMNCR_IO2FV(val) (((val) & 0x3) << 12) /* documented for RZ/G2L */ -#define RPCIF_CMNCR_IO0FV(val) (((val) & 0x3) << 8) -#define RPCIF_CMNCR_IOFV(val) (RPCIF_CMNCR_IO0FV(val) | RPCIF_CMNCR_IO2FV(val) | \ - RPCIF_CMNCR_IO3FV(val)) -#define RPCIF_CMNCR_BSZ(val) (((val) & 0x3) << 0) - -#define RPCIF_SSLDR 0x0004 /* R/W */ -#define RPCIF_SSLDR_SPNDL(d) (((d) & 0x7) << 16) -#define RPCIF_SSLDR_SLNDL(d) (((d) & 0x7) << 8) -#define RPCIF_SSLDR_SCKDL(d) (((d) & 0x7) << 0) - -#define RPCIF_DRCR 0x000C /* R/W */ -#define RPCIF_DRCR_SSLN BIT(24) -#define RPCIF_DRCR_RBURST(v) ((((v) - 1) & 0x1F) << 16) -#define RPCIF_DRCR_RCF BIT(9) -#define RPCIF_DRCR_RBE BIT(8) -#define RPCIF_DRCR_SSLE BIT(0) - -#define RPCIF_DRCMR 0x0010 /* R/W */ -#define RPCIF_DRCMR_CMD(c) (((c) & 0xFF) << 16) -#define RPCIF_DRCMR_OCMD(c) (((c) & 0xFF) << 0) - -#define RPCIF_DREAR 0x0014 /* R/W */ -#define RPCIF_DREAR_EAV(c) (((c) & 0xF) << 16) -#define RPCIF_DREAR_EAC(c) (((c) & 0x7) << 0) - -#define RPCIF_DROPR 0x0018 /* R/W */ - -#define RPCIF_DRENR 0x001C /* R/W */ -#define RPCIF_DRENR_CDB(o) (u32)((((o) & 0x3) << 30)) -#define RPCIF_DRENR_OCDB(o) (((o) & 0x3) << 28) -#define RPCIF_DRENR_ADB(o) (((o) & 0x3) << 24) -#define RPCIF_DRENR_OPDB(o) (((o) & 0x3) << 20) -#define RPCIF_DRENR_DRDB(o) (((o) & 0x3) << 16) -#define RPCIF_DRENR_DME BIT(15) -#define RPCIF_DRENR_CDE BIT(14) -#define RPCIF_DRENR_OCDE BIT(12) -#define RPCIF_DRENR_ADE(v) (((v) & 0xF) << 8) -#define RPCIF_DRENR_OPDE(v) (((v) & 0xF) << 4) - -#define RPCIF_SMCR 0x0020 /* R/W */ -#define RPCIF_SMCR_SSLKP BIT(8) -#define RPCIF_SMCR_SPIRE BIT(2) -#define RPCIF_SMCR_SPIWE BIT(1) -#define RPCIF_SMCR_SPIE BIT(0) - -#define RPCIF_SMCMR 0x0024 /* R/W */ -#define RPCIF_SMCMR_CMD(c) (((c) & 0xFF) << 16) -#define RPCIF_SMCMR_OCMD(c) (((c) & 0xFF) << 0) - -#define RPCIF_SMADR 0x0028 /* R/W */ - -#define RPCIF_SMOPR 0x002C /* R/W */ -#define RPCIF_SMOPR_OPD3(o) (((o) & 0xFF) << 24) -#define RPCIF_SMOPR_OPD2(o) (((o) & 0xFF) << 16) -#define RPCIF_SMOPR_OPD1(o) (((o) & 0xFF) << 8) -#define RPCIF_SMOPR_OPD0(o) (((o) & 0xFF) << 0) - -#define RPCIF_SMENR 0x0030 /* R/W */ -#define RPCIF_SMENR_CDB(o) (((o) & 0x3) << 30) -#define RPCIF_SMENR_OCDB(o) (((o) & 0x3) << 28) -#define RPCIF_SMENR_ADB(o) (((o) & 0x3) << 24) -#define RPCIF_SMENR_OPDB(o) (((o) & 0x3) << 20) -#define RPCIF_SMENR_SPIDB(o) (((o) & 0x3) << 16) -#define RPCIF_SMENR_DME BIT(15) -#define RPCIF_SMENR_CDE BIT(14) -#define RPCIF_SMENR_OCDE BIT(12) -#define RPCIF_SMENR_ADE(v) (((v) & 0xF) << 8) -#define RPCIF_SMENR_OPDE(v) (((v) & 0xF) << 4) -#define RPCIF_SMENR_SPIDE(v) (((v) & 0xF) << 0) - -#define RPCIF_SMRDR0 0x0038 /* R */ -#define RPCIF_SMRDR1 0x003C /* R */ -#define RPCIF_SMWDR0 0x0040 /* W */ -#define RPCIF_SMWDR1 0x0044 /* W */ - -#define RPCIF_CMNSR 0x0048 /* R */ -#define RPCIF_CMNSR_SSLF BIT(1) -#define RPCIF_CMNSR_TEND BIT(0) - -#define RPCIF_DRDMCR 0x0058 /* R/W */ -#define RPCIF_DMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) - -#define RPCIF_DRDRENR 0x005C /* R/W */ -#define RPCIF_DRDRENR_HYPE(v) (((v) & 0x7) << 12) -#define RPCIF_DRDRENR_ADDRE BIT(8) -#define RPCIF_DRDRENR_OPDRE BIT(4) -#define RPCIF_DRDRENR_DRDRE BIT(0) - -#define RPCIF_SMDMCR 0x0060 /* R/W */ -#define RPCIF_SMDMCR_DMCYC(v) ((((v) - 1) & 0x1F) << 0) - -#define RPCIF_SMDRENR 0x0064 /* R/W */ -#define RPCIF_SMDRENR_HYPE(v) (((v) & 0x7) << 12) -#define RPCIF_SMDRENR_ADDRE BIT(8) -#define RPCIF_SMDRENR_OPDRE BIT(4) -#define RPCIF_SMDRENR_SPIDRE BIT(0) - -#define RPCIF_PHYADD 0x0070 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ -#define RPCIF_PHYWR 0x0074 /* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */ - -#define RPCIF_PHYCNT 0x007C /* R/W */ -#define RPCIF_PHYCNT_CAL BIT(31) -#define RPCIF_PHYCNT_OCTA(v) (((v) & 0x3) << 22) -#define RPCIF_PHYCNT_EXDS BIT(21) -#define RPCIF_PHYCNT_OCT BIT(20) -#define RPCIF_PHYCNT_DDRCAL BIT(19) -#define RPCIF_PHYCNT_HS BIT(18) -#define RPCIF_PHYCNT_CKSEL(v) (((v) & 0x3) << 16) /* valid only for RZ/G2L */ -#define RPCIF_PHYCNT_STRTIM(v) (((v) & 0x7) << 15 | ((v) & 0x8) << 24) /* valid for R-Car and RZ/G2{E,H,M,N} */ - -#define RPCIF_PHYCNT_WBUF2 BIT(4) -#define RPCIF_PHYCNT_WBUF BIT(2) -#define RPCIF_PHYCNT_PHYMEM(v) (((v) & 0x3) << 0) -#define RPCIF_PHYCNT_PHYMEM_MASK GENMASK(1, 0) - -#define RPCIF_PHYOFFSET1 0x0080 /* R/W */ -#define RPCIF_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28) - -#define RPCIF_PHYOFFSET2 0x0084 /* R/W */ -#define RPCIF_PHYOFFSET2_OCTTMG(v) (((v) & 0x7) << 8) - -#define RPCIF_PHYINT 0x0088 /* R/W */ -#define RPCIF_PHYINT_WPVAL BIT(1) +#include "renesas-rpc-if-regs.h" +#include "renesas-xspi-if-regs.h" static const struct regmap_range rpcif_volatile_ranges[] = { regmap_reg_range(RPCIF_SMRDR0, RPCIF_SMRDR1), @@ -163,14 +32,69 @@ static const struct regmap_access_table rpcif_volatile_table = { .n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges), }; +static const struct regmap_range xspi_volatile_ranges[] = { + regmap_reg_range(XSPI_CDD0BUF0, XSPI_CDD0BUF0), +}; + +static const struct regmap_access_table xspi_volatile_table = { + .yes_ranges = xspi_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(xspi_volatile_ranges), +}; + +struct rpcif_priv; + +struct rpcif_impl { + int (*hw_init)(struct rpcif_priv *rpc, bool hyperflash); + void (*prepare)(struct rpcif_priv *rpc, const struct rpcif_op *op, + u64 *offs, size_t *len); + int (*manual_xfer)(struct rpcif_priv *rpc); + size_t (*dirmap_read)(struct rpcif_priv *rpc, u64 offs, size_t len, + void *buf); + u32 status_reg; + u32 status_mask; +}; + +struct rpcif_info { + const struct regmap_config *regmap_config; + const struct rpcif_impl *impl; + enum rpcif_type type; + u8 strtim; +}; + +struct rpcif_priv { + struct device *dev; + void __iomem *base; + void __iomem *dirmap; + struct regmap *regmap; + struct reset_control *rstc; + struct clk *spi_clk; + struct clk *spix2_clk; + struct platform_device *vdev; + size_t size; + const struct rpcif_info *info; + enum rpcif_data_dir dir; + u8 bus_size; + u8 xfer_size; + u8 addr_nbytes; /* Specified for xSPI */ + u32 proto; /* Specified for xSPI */ + void *buffer; + u32 xferlen; + u32 smcr; + u32 smadr; + u32 command; /* DRCMR or SMCMR */ + u32 option; /* DROPR or SMOPR */ + u32 enable; /* DRENR or SMENR */ + u32 dummy; /* DRDMCR or SMDMCR */ + u32 ddr; /* DRDRENR or SMDRENR */ +}; /* * Custom accessor functions to ensure SM[RW]DR[01] are always accessed with - * proper width. Requires rpcif.xfer_size to be correctly set before! + * proper width. Requires rpcif_priv.xfer_size to be correctly set before! */ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val) { - struct rpcif *rpc = context; + struct rpcif_priv *rpc = context; switch (reg) { case RPCIF_SMRDR0: @@ -206,7 +130,7 @@ static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val) static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val) { - struct rpcif *rpc = context; + struct rpcif_priv *rpc = context; switch (reg) { case RPCIF_SMWDR0: @@ -253,39 +177,46 @@ static const struct regmap_config rpcif_regmap_config = { .volatile_table = &rpcif_volatile_table, }; -int rpcif_sw_init(struct rpcif *rpc, struct device *dev) +static int xspi_reg_read(void *context, unsigned int reg, unsigned int *val) { - struct platform_device *pdev = to_platform_device(dev); - struct resource *res; + struct rpcif_priv *xspi = context; - rpc->dev = dev; + *val = readl(xspi->base + reg); + return 0; +} - rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs"); - if (IS_ERR(rpc->base)) - return PTR_ERR(rpc->base); +static int xspi_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct rpcif_priv *xspi = context; - rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config); - if (IS_ERR(rpc->regmap)) { - dev_err(&pdev->dev, - "failed to init regmap for rpcif, error %ld\n", - PTR_ERR(rpc->regmap)); - return PTR_ERR(rpc->regmap); - } + writel(val, xspi->base + reg); + return 0; +} - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap"); - rpc->dirmap = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(rpc->dirmap)) - return PTR_ERR(rpc->dirmap); - rpc->size = resource_size(res); +static const struct regmap_config xspi_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .reg_read = xspi_reg_read, + .reg_write = xspi_reg_write, + .fast_io = true, + .max_register = XSPI_INTE, + .volatile_table = &xspi_volatile_table, +}; - rpc->type = (uintptr_t)of_device_get_match_data(dev); - rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); +int rpcif_sw_init(struct rpcif *rpcif, struct device *dev) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); - return PTR_ERR_OR_ZERO(rpc->rstc); + rpcif->dev = dev; + rpcif->dirmap = rpc->dirmap; + rpcif->size = rpc->size; + rpcif->xspi = rpc->info->type == XSPI_RZ_G3E; + return 0; } EXPORT_SYMBOL(rpcif_sw_init); -static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc) +static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif_priv *rpc) { regmap_write(rpc->regmap, RPCIF_PHYWR, 0xa5390000); regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000000); @@ -299,15 +230,12 @@ static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc) regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032); } -int rpcif_hw_init(struct rpcif *rpc, bool hyperflash) +static int rpcif_hw_init_impl(struct rpcif_priv *rpc, bool hyperflash) { u32 dummy; + int ret; - pm_runtime_get_sync(rpc->dev); - - if (rpc->type == RPCIF_RZ_G2L) { - int ret; - + if (rpc->info->type == RPCIF_RZ_G2L) { ret = reset_control_reset(rpc->rstc); if (ret) return ret; @@ -321,12 +249,10 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash) /* DMA Transfer is not supported */ regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_HS, 0); - if (rpc->type == RPCIF_RCAR_GEN3) - regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, - RPCIF_PHYCNT_STRTIM(7), RPCIF_PHYCNT_STRTIM(7)); - else if (rpc->type == RPCIF_RCAR_GEN4) - regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, - RPCIF_PHYCNT_STRTIM(15), RPCIF_PHYCNT_STRTIM(15)); + regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, + /* create mask with all affected bits set */ + RPCIF_PHYCNT_STRTIM(BIT(fls(rpc->info->strtim)) - 1), + RPCIF_PHYCNT_STRTIM(rpc->info->strtim)); regmap_update_bits(rpc->regmap, RPCIF_PHYOFFSET1, RPCIF_PHYOFFSET1_DDRTMG(3), RPCIF_PHYOFFSET1_DDRTMG(3)); @@ -337,11 +263,11 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash) regmap_update_bits(rpc->regmap, RPCIF_PHYINT, RPCIF_PHYINT_WPVAL, 0); - if (rpc->type == RPCIF_RZ_G2L) + if (rpc->info->type == RPCIF_RZ_G2L) regmap_update_bits(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_IOFV(3) | RPCIF_CMNCR_BSZ(3), - RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(2) | + RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(3) | RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0)); else regmap_update_bits(rpc->regmap, RPCIF_CMNCR, @@ -356,24 +282,65 @@ int rpcif_hw_init(struct rpcif *rpc, bool hyperflash) regmap_write(rpc->regmap, RPCIF_SSLDR, RPCIF_SSLDR_SPNDL(7) | RPCIF_SSLDR_SLNDL(7) | RPCIF_SSLDR_SCKDL(7)); - pm_runtime_put(rpc->dev); - rpc->bus_size = hyperflash ? 2 : 1; return 0; } + +static int xspi_hw_init_impl(struct rpcif_priv *xspi, bool hyperflash) +{ + int ret; + + ret = reset_control_reset(xspi->rstc); + if (ret) + return ret; + + regmap_write(xspi->regmap, XSPI_WRAPCFG, 0x0); + + regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, + XSPI_LIOCFG_PRTMD(0x3ff) | XSPI_LIOCFG_CSMIN(0xf) | + XSPI_LIOCFG_CSASTEX | XSPI_LIOCFG_CSNEGEX, + XSPI_LIOCFG_PRTMD(0) | XSPI_LIOCFG_CSMIN(0) | + XSPI_LIOCFG_CSASTEX | XSPI_LIOCFG_CSNEGEX); + + regmap_update_bits(xspi->regmap, XSPI_CCCTL0CS0, XSPI_CCCTL0_CAEN, 0); + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ | XSPI_CDCTL0_CSSEL, 0); + + regmap_update_bits(xspi->regmap, XSPI_INTE, XSPI_INTE_CMDCMPE, + XSPI_INTE_CMDCMPE); + + return 0; +} + +int rpcif_hw_init(struct device *dev, bool hyperflash) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = rpc->info->impl->hw_init(rpc, hyperflash); + + pm_runtime_put(dev); + + return ret; +} EXPORT_SYMBOL(rpcif_hw_init); -static int wait_msg_xfer_end(struct rpcif *rpc) +static int wait_msg_xfer_end(struct rpcif_priv *rpc) { u32 sts; - return regmap_read_poll_timeout(rpc->regmap, RPCIF_CMNSR, sts, - sts & RPCIF_CMNSR_TEND, 0, - USEC_PER_SEC); + return regmap_read_poll_timeout(rpc->regmap, rpc->info->impl->status_reg, + sts, sts & rpc->info->impl->status_mask, + 0, USEC_PER_SEC); } -static u8 rpcif_bits_set(struct rpcif *rpc, u32 nbytes) +static u8 rpcif_bits_set(struct rpcif_priv *rpc, u32 nbytes) { if (rpc->bus_size == 2) nbytes /= 2; @@ -386,8 +353,8 @@ static u8 rpcif_bit_size(u8 buswidth) return buswidth > 4 ? 2 : ilog2(buswidth); } -void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs, - size_t *len) +static void rpcif_prepare_impl(struct rpcif_priv *rpc, const struct rpcif_op *op, + u64 *offs, size_t *len) { rpc->smcr = 0; rpc->smadr = 0; @@ -430,8 +397,7 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs, if (op->dummy.buswidth) { rpc->enable |= RPCIF_SMENR_DME; - rpc->dummy = RPCIF_SMDMCR_DMCYC(op->dummy.ncycles / - op->dummy.buswidth); + rpc->dummy = RPCIF_SMDMCR_DMCYC(op->dummy.ncycles); } if (op->option.buswidth) { @@ -470,15 +436,76 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs, rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth)); } } + +static void xspi_prepare_impl(struct rpcif_priv *xspi, const struct rpcif_op *op, + u64 *offs, size_t *len) +{ + xspi->smadr = 0; + xspi->addr_nbytes = 0; + xspi->command = 0; + xspi->option = 0; + xspi->dummy = 0; + xspi->xferlen = 0; + xspi->proto = 0; + + if (op->cmd.buswidth) + xspi->command = op->cmd.opcode; + + if (op->ocmd.buswidth) + xspi->command = (xspi->command << 8) | op->ocmd.opcode; + + if (op->addr.buswidth) { + xspi->addr_nbytes = op->addr.nbytes; + if (offs && len) + xspi->smadr = *offs; + else + xspi->smadr = op->addr.val; + } + + if (op->dummy.buswidth) + xspi->dummy = op->dummy.ncycles; + + xspi->dir = op->data.dir; + if (op->data.buswidth) { + u32 nbytes; + + xspi->buffer = op->data.buf.in; + + if (offs && len) + nbytes = *len; + else + nbytes = op->data.nbytes; + xspi->xferlen = nbytes; + } + + if (op->cmd.buswidth == 1) { + if (op->addr.buswidth == 2 || op->data.buswidth == 2) + xspi->proto = PROTO_1S_2S_2S; + else if (op->addr.buswidth == 4 || op->data.buswidth == 4) + xspi->proto = PROTO_1S_4S_4S; + } else if (op->cmd.buswidth == 2 && + (op->addr.buswidth == 2 || op->data.buswidth == 2)) { + xspi->proto = PROTO_2S_2S_2S; + } else if (op->cmd.buswidth == 4 && + (op->addr.buswidth == 4 || op->data.buswidth == 4)) { + xspi->proto = PROTO_4S_4S_4S; + } +} + +void rpcif_prepare(struct device *dev, const struct rpcif_op *op, u64 *offs, + size_t *len) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + + rpc->info->impl->prepare(rpc, op, offs, len); +} EXPORT_SYMBOL(rpcif_prepare); -int rpcif_manual_xfer(struct rpcif *rpc) +static int rpcif_manual_xfer_impl(struct rpcif_priv *rpc) { u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4; int ret = 0; - pm_runtime_get_sync(rpc->dev); - regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_CAL, RPCIF_PHYCNT_CAL); regmap_update_bits(rpc->regmap, RPCIF_CMNCR, @@ -586,15 +613,169 @@ int rpcif_manual_xfer(struct rpcif *rpc) goto err_out; } -exit: - pm_runtime_put(rpc->dev); return ret; err_out: if (reset_control_reset(rpc->rstc)) dev_err(rpc->dev, "Failed to reset HW\n"); - rpcif_hw_init(rpc, rpc->bus_size == 2); - goto exit; + rpcif_hw_init_impl(rpc, rpc->bus_size == 2); + return ret; +} + +static int xspi_manual_xfer_impl(struct rpcif_priv *xspi) +{ + u32 pos = 0, max = 8; + int ret = 0; + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, XSPI_CDCTL0_TRNUM(0x3), + XSPI_CDCTL0_TRNUM(0)); + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, XSPI_CDCTL0_TRREQ, 0); + + regmap_write(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_CMDSIZE(0x1) | XSPI_CDTBUF_CMD_FIELD(xspi->command)); + + regmap_write(xspi->regmap, XSPI_CDABUF0, 0); + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, XSPI_CDTBUF_ADDSIZE(0x7), + XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes)); + + regmap_write(xspi->regmap, XSPI_CDABUF0, xspi->smadr); + + regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, XSPI_LIOCFG_PRTMD(0x3ff), + XSPI_LIOCFG_PRTMD(xspi->proto)); + + switch (xspi->dir) { + case RPCIF_DATA_OUT: + while (pos < xspi->xferlen) { + u32 bytes_left = xspi->xferlen - pos; + u32 nbytes, data[2], *p = data; + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_TRTYPE, XSPI_CDTBUF_TRTYPE); + + nbytes = bytes_left >= max ? max : bytes_left; + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_DATASIZE(0xf), + XSPI_CDTBUF_DATASIZE(nbytes)); + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_ADDSIZE(0x7), + XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes)); + + memcpy(data, xspi->buffer + pos, nbytes); + + if (nbytes > 4) { + regmap_write(xspi->regmap, XSPI_CDD0BUF0, *p++); + regmap_write(xspi->regmap, XSPI_CDD1BUF0, *p); + } else { + regmap_write(xspi->regmap, XSPI_CDD0BUF0, *p); + } + + regmap_write(xspi->regmap, XSPI_CDABUF0, xspi->smadr + pos); + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ, XSPI_CDCTL0_TRREQ); + + ret = wait_msg_xfer_end(xspi); + if (ret) + goto err_out; + + regmap_update_bits(xspi->regmap, XSPI_INTC, + XSPI_INTC_CMDCMPC, XSPI_INTC_CMDCMPC); + + pos += nbytes; + } + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, XSPI_CDCTL0_TRREQ, 0); + break; + case RPCIF_DATA_IN: + while (pos < xspi->xferlen) { + u32 bytes_left = xspi->xferlen - pos; + u32 nbytes, data[2], *p = data; + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_TRTYPE, + ~(u32)XSPI_CDTBUF_TRTYPE); + + /* nbytes can be up to 8 bytes */ + nbytes = bytes_left >= max ? max : bytes_left; + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_DATASIZE(0xf), + XSPI_CDTBUF_DATASIZE(nbytes)); + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_ADDSIZE(0x7), + XSPI_CDTBUF_ADDSIZE(xspi->addr_nbytes)); + + if (xspi->addr_nbytes) + regmap_write(xspi->regmap, XSPI_CDABUF0, + xspi->smadr + pos); + + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_LATE(0x1f), + XSPI_CDTBUF_LATE(xspi->dummy)); + + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ, XSPI_CDCTL0_TRREQ); + + ret = wait_msg_xfer_end(xspi); + if (ret) + goto err_out; + + if (nbytes > 4) { + regmap_read(xspi->regmap, XSPI_CDD0BUF0, p++); + regmap_read(xspi->regmap, XSPI_CDD1BUF0, p); + } else { + regmap_read(xspi->regmap, XSPI_CDD0BUF0, p); + } + + memcpy(xspi->buffer + pos, data, nbytes); + + regmap_update_bits(xspi->regmap, XSPI_INTC, + XSPI_INTC_CMDCMPC, XSPI_INTC_CMDCMPC); + + pos += nbytes; + } + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ, 0); + break; + default: + regmap_update_bits(xspi->regmap, XSPI_CDTBUF0, + XSPI_CDTBUF_TRTYPE, XSPI_CDTBUF_TRTYPE); + regmap_update_bits(xspi->regmap, XSPI_CDCTL0, + XSPI_CDCTL0_TRREQ, XSPI_CDCTL0_TRREQ); + + ret = wait_msg_xfer_end(xspi); + if (ret) + goto err_out; + + regmap_update_bits(xspi->regmap, XSPI_INTC, + XSPI_INTC_CMDCMPC, XSPI_INTC_CMDCMPC); + } + + return ret; + +err_out: + xspi_hw_init_impl(xspi, false); + return ret; +} + +int rpcif_manual_xfer(struct device *dev) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = rpc->info->impl->manual_xfer(rpc); + + pm_runtime_put(dev); + + return ret; } EXPORT_SYMBOL(rpcif_manual_xfer); @@ -640,7 +821,8 @@ static void memcpy_fromio_readw(void *to, } } -ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf) +static size_t rpcif_dirmap_read_impl(struct rpcif_priv *rpc, u64 offs, + size_t len, void *buf) { loff_t from = offs & (rpc->size - 1); size_t size = rpc->size - from; @@ -648,8 +830,6 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf) if (len > size) len = size; - pm_runtime_get_sync(rpc->dev); - regmap_update_bits(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_MD, 0); regmap_write(rpc->regmap, RPCIF_DRCR, 0); regmap_write(rpc->regmap, RPCIF_DRCMR, rpc->command); @@ -666,22 +846,142 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf) else memcpy_fromio(buf, rpc->dirmap + from, len); - pm_runtime_put(rpc->dev); + return len; +} + +static size_t xspi_dirmap_read_impl(struct rpcif_priv *xspi, u64 offs, + size_t len, void *buf) +{ + loff_t from = offs & (xspi->size - 1); + size_t size = xspi->size - from; + u8 addsize = xspi->addr_nbytes - 1; + + if (len > size) + len = size; + + regmap_update_bits(xspi->regmap, XSPI_CMCFG0CS0, + XSPI_CMCFG0_FFMT(0x3) | XSPI_CMCFG0_ADDSIZE(0x3), + XSPI_CMCFG0_FFMT(0) | XSPI_CMCFG0_ADDSIZE(addsize)); + + regmap_update_bits(xspi->regmap, XSPI_CMCFG1CS0, + XSPI_CMCFG1_RDCMD(0xffff) | XSPI_CMCFG1_RDLATE(0x1f), + XSPI_CMCFG1_RDCMD_UPPER_BYTE(xspi->command) | + XSPI_CMCFG1_RDLATE(xspi->dummy)); + + regmap_update_bits(xspi->regmap, XSPI_BMCTL0, XSPI_BMCTL0_CS0ACC(0xff), + XSPI_BMCTL0_CS0ACC(0x01)); + + regmap_update_bits(xspi->regmap, XSPI_BMCFG, + XSPI_BMCFG_WRMD | XSPI_BMCFG_MWRCOMB | + XSPI_BMCFG_MWRSIZE(0xff) | XSPI_BMCFG_PREEN, + 0 | XSPI_BMCFG_MWRCOMB | XSPI_BMCFG_MWRSIZE(0x0f) | + XSPI_BMCFG_PREEN); + + regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, XSPI_LIOCFG_PRTMD(0x3ff), + XSPI_LIOCFG_PRTMD(xspi->proto)); + + memcpy_fromio(buf, xspi->dirmap + from, len); return len; } + +ssize_t rpcif_dirmap_read(struct device *dev, u64 offs, size_t len, void *buf) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + size_t read; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + read = rpc->info->impl->dirmap_read(rpc, offs, len, buf); + + pm_runtime_put(dev); + + return read; +} EXPORT_SYMBOL(rpcif_dirmap_read); +/** + * xspi_dirmap_write - Write data to xspi memory. + * @dev: xspi device + * @offs: offset + * @len: Number of bytes to be written. + * @buf: Buffer holding write data. + * + * This function writes data into xspi memory. + * + * Returns number of bytes written on success, else negative errno. + */ +ssize_t xspi_dirmap_write(struct device *dev, u64 offs, size_t len, const void *buf) +{ + struct rpcif_priv *xspi = dev_get_drvdata(dev); + loff_t from = offs & (xspi->size - 1); + u8 addsize = xspi->addr_nbytes - 1; + size_t size = xspi->size - from; + ssize_t writebytes; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + if (len > size) + len = size; + + if (len > MWRSIZE_MAX) + writebytes = MWRSIZE_MAX; + else + writebytes = len; + + regmap_update_bits(xspi->regmap, XSPI_CMCFG0CS0, + XSPI_CMCFG0_FFMT(0x3) | XSPI_CMCFG0_ADDSIZE(0x3), + XSPI_CMCFG0_FFMT(0) | XSPI_CMCFG0_ADDSIZE(addsize)); + + regmap_update_bits(xspi->regmap, XSPI_CMCFG2CS0, + XSPI_CMCFG2_WRCMD_UPPER(0xff) | XSPI_CMCFG2_WRLATE(0x1f), + XSPI_CMCFG2_WRCMD_UPPER(xspi->command) | + XSPI_CMCFG2_WRLATE(xspi->dummy)); + + regmap_update_bits(xspi->regmap, XSPI_BMCTL0, + XSPI_BMCTL0_CS0ACC(0xff), XSPI_BMCTL0_CS0ACC(0x03)); + + regmap_update_bits(xspi->regmap, XSPI_BMCFG, + XSPI_BMCFG_WRMD | XSPI_BMCFG_MWRCOMB | + XSPI_BMCFG_MWRSIZE(0xff) | XSPI_BMCFG_PREEN, + 0 | XSPI_BMCFG_MWRCOMB | XSPI_BMCFG_MWRSIZE(0x0f) | + XSPI_BMCFG_PREEN); + + regmap_update_bits(xspi->regmap, XSPI_LIOCFGCS0, XSPI_LIOCFG_PRTMD(0x3ff), + XSPI_LIOCFG_PRTMD(xspi->proto)); + + memcpy_toio(xspi->dirmap + from, buf, writebytes); + + /* Request to push the pending data */ + if (writebytes < MWRSIZE_MAX) + regmap_update_bits(xspi->regmap, XSPI_BMCTL1, + XSPI_BMCTL1_MWRPUSH, XSPI_BMCTL1_MWRPUSH); + + pm_runtime_put(dev); + + return writebytes; +} +EXPORT_SYMBOL_GPL(xspi_dirmap_write); + static int rpcif_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct platform_device *vdev; struct device_node *flash; + struct rpcif_priv *rpc; + struct resource *res; const char *name; int ret; - flash = of_get_next_child(pdev->dev.of_node, NULL); + flash = of_get_next_child(dev->of_node, NULL); if (!flash) { - dev_warn(&pdev->dev, "no flash node found\n"); + dev_warn(dev, "no flash node found\n"); return -ENODEV; } @@ -691,16 +991,59 @@ static int rpcif_probe(struct platform_device *pdev) name = "rpc-if-hyperflash"; } else { of_node_put(flash); - dev_warn(&pdev->dev, "unknown flash type\n"); + dev_warn(dev, "unknown flash type\n"); return -ENODEV; } of_node_put(flash); + rpc = devm_kzalloc(dev, sizeof(*rpc), GFP_KERNEL); + if (!rpc) + return -ENOMEM; + + rpc->base = devm_platform_ioremap_resource_byname(pdev, "regs"); + if (IS_ERR(rpc->base)) + return PTR_ERR(rpc->base); + rpc->info = of_device_get_match_data(dev); + rpc->regmap = devm_regmap_init(dev, NULL, rpc, rpc->info->regmap_config); + if (IS_ERR(rpc->regmap)) { + dev_err(dev, "failed to init regmap for rpcif, error %ld\n", + PTR_ERR(rpc->regmap)); + return PTR_ERR(rpc->regmap); + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap"); + rpc->dirmap = devm_ioremap_resource(dev, res); + if (IS_ERR(rpc->dirmap)) + return PTR_ERR(rpc->dirmap); + + rpc->size = resource_size(res); + rpc->rstc = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(rpc->rstc)) + return PTR_ERR(rpc->rstc); + + /* + * The enabling/disabling of spi/spix2 clocks at runtime leading to + * flash write failure. So, enable these clocks during probe() and + * disable it in remove(). + */ + rpc->spix2_clk = devm_clk_get_optional_enabled(dev, "spix2"); + if (IS_ERR(rpc->spix2_clk)) + return dev_err_probe(dev, PTR_ERR(rpc->spix2_clk), + "cannot get enabled spix2 clk\n"); + + rpc->spi_clk = devm_clk_get_optional_enabled(dev, "spi"); + if (IS_ERR(rpc->spi_clk)) + return dev_err_probe(dev, PTR_ERR(rpc->spi_clk), + "cannot get enabled spi clk\n"); + vdev = platform_device_alloc(name, pdev->id); if (!vdev) return -ENOMEM; - vdev->dev.parent = &pdev->dev; - platform_set_drvdata(pdev, vdev); + vdev->dev.parent = dev; + + rpc->dev = dev; + rpc->vdev = vdev; + platform_set_drvdata(pdev, rpc); ret = platform_device_add(vdev); if (ret) { @@ -711,29 +1054,115 @@ static int rpcif_probe(struct platform_device *pdev) return 0; } -static int rpcif_remove(struct platform_device *pdev) +static void rpcif_remove(struct platform_device *pdev) { - struct platform_device *vdev = platform_get_drvdata(pdev); + struct rpcif_priv *rpc = platform_get_drvdata(pdev); - platform_device_unregister(vdev); + platform_device_unregister(rpc->vdev); +} + +static int rpcif_suspend(struct device *dev) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + + clk_disable_unprepare(rpc->spi_clk); + clk_disable_unprepare(rpc->spix2_clk); + + return 0; +} + +static int rpcif_resume(struct device *dev) +{ + struct rpcif_priv *rpc = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(rpc->spix2_clk); + if (ret) { + dev_err(dev, "failed to enable spix2 clock: %pe\n", ERR_PTR(ret)); + return ret; + } + + ret = clk_prepare_enable(rpc->spi_clk); + if (ret) { + clk_disable_unprepare(rpc->spix2_clk); + dev_err(dev, "failed to enable spi clock: %pe\n", ERR_PTR(ret)); + return ret; + } return 0; } +static const struct rpcif_impl rpcif_impl = { + .hw_init = rpcif_hw_init_impl, + .prepare = rpcif_prepare_impl, + .manual_xfer = rpcif_manual_xfer_impl, + .dirmap_read = rpcif_dirmap_read_impl, + .status_reg = RPCIF_CMNSR, + .status_mask = RPCIF_CMNSR_TEND, +}; + +static const struct rpcif_impl xspi_impl = { + .hw_init = xspi_hw_init_impl, + .prepare = xspi_prepare_impl, + .manual_xfer = xspi_manual_xfer_impl, + .dirmap_read = xspi_dirmap_read_impl, + .status_reg = XSPI_INTS, + .status_mask = XSPI_INTS_CMDCMP, +}; + +static const struct rpcif_info rpcif_info_r8a7796 = { + .regmap_config = &rpcif_regmap_config, + .impl = &rpcif_impl, + .type = RPCIF_RCAR_GEN3, + .strtim = 6, +}; + +static const struct rpcif_info rpcif_info_gen3 = { + .regmap_config = &rpcif_regmap_config, + .impl = &rpcif_impl, + .type = RPCIF_RCAR_GEN3, + .strtim = 7, +}; + +static const struct rpcif_info rpcif_info_rz_g2l = { + .regmap_config = &rpcif_regmap_config, + .impl = &rpcif_impl, + .type = RPCIF_RZ_G2L, + .strtim = 7, +}; + +static const struct rpcif_info rpcif_info_gen4 = { + .regmap_config = &rpcif_regmap_config, + .impl = &rpcif_impl, + .type = RPCIF_RCAR_GEN4, + .strtim = 15, +}; + +static const struct rpcif_info xspi_info_r9a09g047 = { + .regmap_config = &xspi_regmap_config, + .impl = &xspi_impl, + .type = XSPI_RZ_G3E, +}; + static const struct of_device_id rpcif_of_match[] = { - { .compatible = "renesas,rcar-gen3-rpc-if", .data = (void *)RPCIF_RCAR_GEN3 }, - { .compatible = "renesas,rcar-gen4-rpc-if", .data = (void *)RPCIF_RCAR_GEN4 }, - { .compatible = "renesas,rzg2l-rpc-if", .data = (void *)RPCIF_RZ_G2L }, + { .compatible = "renesas,r8a7796-rpc-if", .data = &rpcif_info_r8a7796 }, + { .compatible = "renesas,r9a09g047-xspi", .data = &xspi_info_r9a09g047 }, + { .compatible = "renesas,rcar-gen3-rpc-if", .data = &rpcif_info_gen3 }, + { .compatible = "renesas,rcar-gen4-rpc-if", .data = &rpcif_info_gen4 }, + { .compatible = "renesas,rzg2l-rpc-if", .data = &rpcif_info_rz_g2l }, {}, }; MODULE_DEVICE_TABLE(of, rpcif_of_match); +static DEFINE_SIMPLE_DEV_PM_OPS(rpcif_pm_ops, rpcif_suspend, rpcif_resume); + static struct platform_driver rpcif_driver = { .probe = rpcif_probe, - .remove = rpcif_remove, + .remove = rpcif_remove, .driver = { .name = "rpc-if", .of_match_table = rpcif_of_match, + .pm = pm_sleep_ptr(&rpcif_pm_ops), }, }; module_platform_driver(rpcif_driver); diff --git a/drivers/memory/renesas-xspi-if-regs.h b/drivers/memory/renesas-xspi-if-regs.h new file mode 100644 index 000000000000..53f801d591f2 --- /dev/null +++ b/drivers/memory/renesas-xspi-if-regs.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * RZ xSPI Interface Registers Definitions + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#ifndef __RENESAS_XSPI_IF_REGS_H__ +#define __RENESAS_XSPI_IF_REGS_H__ + +#include <linux/bits.h> + +/* xSPI Wrapper Configuration Register */ +#define XSPI_WRAPCFG 0x0000 + +/* xSPI Bridge Configuration Register */ +#define XSPI_BMCFG 0x0008 +#define XSPI_BMCFG_WRMD BIT(0) +#define XSPI_BMCFG_MWRCOMB BIT(7) +#define XSPI_BMCFG_MWRSIZE(val) (((val) & 0xff) << 8) +#define XSPI_BMCFG_PREEN BIT(16) + +/* xSPI Command Map Configuration Register 0 CS0 */ +#define XSPI_CMCFG0CS0 0x0010 +#define XSPI_CMCFG0_FFMT(val) (((val) & 0x03) << 0) +#define XSPI_CMCFG0_ADDSIZE(val) (((val) & 0x03) << 2) + +/* xSPI Command Map Configuration Register 1 CS0 */ +#define XSPI_CMCFG1CS0 0x0014 +#define XSPI_CMCFG1_RDCMD(val) (((val) & 0xffff) << 0) +#define XSPI_CMCFG1_RDCMD_UPPER_BYTE(val) (((val) & 0xff) << 8) +#define XSPI_CMCFG1_RDLATE(val) (((val) & 0x1f) << 16) + +/* xSPI Command Map Configuration Register 2 CS0 */ +#define XSPI_CMCFG2CS0 0x0018 +#define XSPI_CMCFG2_WRCMD(val) (((val) & 0xffff) << 0) +#define XSPI_CMCFG2_WRCMD_UPPER(val) (((val) & 0xff) << 8) +#define XSPI_CMCFG2_WRLATE(val) (((val) & 0x1f) << 16) + +/* xSPI Link I/O Configuration Register CS0 */ +#define XSPI_LIOCFGCS0 0x0050 +#define XSPI_LIOCFG_PRTMD(val) (((val) & 0x3ff) << 0) +#define XSPI_LIOCFG_CSMIN(val) (((val) & 0x0f) << 16) +#define XSPI_LIOCFG_CSASTEX BIT(20) +#define XSPI_LIOCFG_CSNEGEX BIT(21) + +/* xSPI Bridge Map Control Register 0 */ +#define XSPI_BMCTL0 0x0060 +#define XSPI_BMCTL0_CS0ACC(val) (((val) & 0x03) << 0) + +/* xSPI Bridge Map Control Register 1 */ +#define XSPI_BMCTL1 0x0064 +#define XSPI_BMCTL1_MWRPUSH BIT(8) + +/* xSPI Command Manual Control Register 0 */ +#define XSPI_CDCTL0 0x0070 +#define XSPI_CDCTL0_TRREQ BIT(0) +#define XSPI_CDCTL0_CSSEL BIT(3) +#define XSPI_CDCTL0_TRNUM(val) (((val) & 0x03) << 4) + +/* xSPI Command Manual Type Buf */ +#define XSPI_CDTBUF0 0x0080 +#define XSPI_CDTBUF_CMDSIZE(val) (((val) & 0x03) << 0) +#define XSPI_CDTBUF_ADDSIZE(val) (((val) & 0x07) << 2) +#define XSPI_CDTBUF_DATASIZE(val) (((val) & 0x0f) << 5) +#define XSPI_CDTBUF_LATE(val) (((val) & 0x1f) << 9) +#define XSPI_CDTBUF_TRTYPE BIT(15) +#define XSPI_CDTBUF_CMD(val) (((val) & 0xffff) << 16) +#define XSPI_CDTBUF_CMD_FIELD(val) (((val) & 0xff) << 24) + +/* xSPI Command Manual Address Buff */ +#define XSPI_CDABUF0 0x0084 + +/* xSPI Command Manual Data 0 Buf */ +#define XSPI_CDD0BUF0 0x0088 + +/* xSPI Command Manual Data 1 Buf */ +#define XSPI_CDD1BUF0 0x008c + +/* xSPI Command Calibration Control Register 0 CS0 */ +#define XSPI_CCCTL0CS0 0x0130 +#define XSPI_CCCTL0_CAEN BIT(0) + +/* xSPI Interrupt Status Register */ +#define XSPI_INTS 0x0190 +#define XSPI_INTS_CMDCMP BIT(0) + +/* xSPI Interrupt Clear Register */ +#define XSPI_INTC 0x0194 +#define XSPI_INTC_CMDCMPC BIT(0) + +/* xSPI Interrupt Enable Register */ +#define XSPI_INTE 0x0198 +#define XSPI_INTE_CMDCMPE BIT(0) + +/* Maximum data size of MWRSIZE*/ +#define MWRSIZE_MAX 64 + +/* xSPI Protocol mode */ +#define PROTO_1S_2S_2S 0x48 +#define PROTO_2S_2S_2S 0x49 +#define PROTO_1S_4S_4S 0x090 +#define PROTO_4S_4S_4S 0x092 + +#endif /* __RENESAS_XSPI_IF_REGS_H__ */ diff --git a/drivers/memory/samsung/exynos-srom.c b/drivers/memory/samsung/exynos-srom.c index e73dd330af47..d913fb901973 100644 --- a/drivers/memory/samsung/exynos-srom.c +++ b/drivers/memory/samsung/exynos-srom.c @@ -121,20 +121,18 @@ static int exynos_srom_probe(struct platform_device *pdev) return -ENOMEM; srom->dev = dev; - srom->reg_base = of_iomap(np, 0); - if (!srom->reg_base) { + srom->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(srom->reg_base)) { dev_err(&pdev->dev, "iomap of exynos srom controller failed\n"); - return -ENOMEM; + return PTR_ERR(srom->reg_base); } platform_set_drvdata(pdev, srom); srom->reg_offset = exynos_srom_alloc_reg_dump(exynos_srom_offsets, ARRAY_SIZE(exynos_srom_offsets)); - if (!srom->reg_offset) { - iounmap(srom->reg_base); + if (!srom->reg_offset) return -ENOMEM; - } for_each_child_of_node(np, child) { if (exynos_srom_configure_bank(srom, child)) { diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c index c491cd549644..788d49c688b1 100644 --- a/drivers/memory/samsung/exynos5422-dmc.c +++ b/drivers/memory/samsung/exynos5422-dmc.c @@ -4,6 +4,7 @@ * Author: Lukasz Luba <l.luba@partner.samsung.com> */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/devfreq.h> #include <linux/devfreq-event.h> @@ -13,7 +14,7 @@ #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/pm_opp.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -339,19 +340,20 @@ static int exynos5_switch_timing_regs(struct exynos5_dmc *dmc, bool set) static int exynos5_init_freq_table(struct exynos5_dmc *dmc, struct devfreq_dev_profile *profile) { + struct device *dev = dmc->dev; int i, ret; int idx; unsigned long freq; - ret = devm_pm_opp_of_add_table(dmc->dev); + ret = devm_pm_opp_of_add_table(dev); if (ret < 0) { - dev_err(dmc->dev, "Failed to get OPP table\n"); + dev_err(dev, "Failed to get OPP table\n"); return ret; } - dmc->opp_count = dev_pm_opp_get_opp_count(dmc->dev); + dmc->opp_count = dev_pm_opp_get_opp_count(dev); - dmc->opp = devm_kmalloc_array(dmc->dev, dmc->opp_count, + dmc->opp = devm_kmalloc_array(dev, dmc->opp_count, sizeof(struct dmc_opp_table), GFP_KERNEL); if (!dmc->opp) return -ENOMEM; @@ -360,7 +362,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc, for (i = 0, freq = ULONG_MAX; i < dmc->opp_count; i++, freq--) { struct dev_pm_opp *opp; - opp = dev_pm_opp_find_freq_floor(dmc->dev, &freq); + opp = dev_pm_opp_find_freq_floor(dev, &freq); if (IS_ERR(opp)) return PTR_ERR(opp); @@ -1175,51 +1177,44 @@ static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row, static int of_get_dram_timings(struct exynos5_dmc *dmc) { int ret = 0; + struct device *dev = dmc->dev; int idx; - struct device_node *np_ddr; u32 freq_mhz, clk_period_ps; - np_ddr = of_parse_phandle(dmc->dev->of_node, "device-handle", 0); + struct device_node *np_ddr __free(device_node) = + of_parse_phandle(dev->of_node, "device-handle", 0); if (!np_ddr) { - dev_warn(dmc->dev, "could not find 'device-handle' in DT\n"); + dev_warn(dev, "could not find 'device-handle' in DT\n"); return -EINVAL; } - dmc->timing_row = devm_kmalloc_array(dmc->dev, TIMING_COUNT, + dmc->timing_row = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); - if (!dmc->timing_row) { - ret = -ENOMEM; - goto put_node; - } + if (!dmc->timing_row) + return -ENOMEM; - dmc->timing_data = devm_kmalloc_array(dmc->dev, TIMING_COUNT, + dmc->timing_data = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); - if (!dmc->timing_data) { - ret = -ENOMEM; - goto put_node; - } + if (!dmc->timing_data) + return -ENOMEM; - dmc->timing_power = devm_kmalloc_array(dmc->dev, TIMING_COUNT, + dmc->timing_power = devm_kmalloc_array(dev, TIMING_COUNT, sizeof(u32), GFP_KERNEL); - if (!dmc->timing_power) { - ret = -ENOMEM; - goto put_node; - } + if (!dmc->timing_power) + return -ENOMEM; - dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dmc->dev, + dmc->timings = of_lpddr3_get_ddr_timings(np_ddr, dev, DDR_TYPE_LPDDR3, &dmc->timings_arr_size); if (!dmc->timings) { - dev_warn(dmc->dev, "could not get timings from DT\n"); - ret = -EINVAL; - goto put_node; + dev_warn(dev, "could not get timings from DT\n"); + return -EINVAL; } - dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dmc->dev); + dmc->min_tck = of_lpddr3_get_min_tck(np_ddr, dev); if (!dmc->min_tck) { - dev_warn(dmc->dev, "could not get tck from DT\n"); - ret = -EINVAL; - goto put_node; + dev_warn(dev, "could not get tck from DT\n"); + return -EINVAL; } /* Sorted array of OPPs with frequency ascending */ @@ -1239,8 +1234,6 @@ static int of_get_dram_timings(struct exynos5_dmc *dmc) dmc->bypass_timing_data = dmc->timing_data[idx - 1]; dmc->bypass_timing_power = dmc->timing_power[idx - 1]; -put_node: - of_node_put(np_ddr); return ret; } @@ -1254,34 +1247,34 @@ put_node: static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc) { int ret; + struct device *dev = dmc->dev; unsigned long target_volt = 0; unsigned long target_rate = 0; unsigned int tmp; - dmc->fout_spll = devm_clk_get(dmc->dev, "fout_spll"); + dmc->fout_spll = devm_clk_get(dev, "fout_spll"); if (IS_ERR(dmc->fout_spll)) return PTR_ERR(dmc->fout_spll); - dmc->fout_bpll = devm_clk_get(dmc->dev, "fout_bpll"); + dmc->fout_bpll = devm_clk_get(dev, "fout_bpll"); if (IS_ERR(dmc->fout_bpll)) return PTR_ERR(dmc->fout_bpll); - dmc->mout_mclk_cdrex = devm_clk_get(dmc->dev, "mout_mclk_cdrex"); + dmc->mout_mclk_cdrex = devm_clk_get(dev, "mout_mclk_cdrex"); if (IS_ERR(dmc->mout_mclk_cdrex)) return PTR_ERR(dmc->mout_mclk_cdrex); - dmc->mout_bpll = devm_clk_get(dmc->dev, "mout_bpll"); + dmc->mout_bpll = devm_clk_get(dev, "mout_bpll"); if (IS_ERR(dmc->mout_bpll)) return PTR_ERR(dmc->mout_bpll); - dmc->mout_mx_mspll_ccore = devm_clk_get(dmc->dev, - "mout_mx_mspll_ccore"); + dmc->mout_mx_mspll_ccore = devm_clk_get(dev, "mout_mx_mspll_ccore"); if (IS_ERR(dmc->mout_mx_mspll_ccore)) return PTR_ERR(dmc->mout_mx_mspll_ccore); - dmc->mout_spll = devm_clk_get(dmc->dev, "ff_dout_spll2"); + dmc->mout_spll = devm_clk_get(dev, "ff_dout_spll2"); if (IS_ERR(dmc->mout_spll)) { - dmc->mout_spll = devm_clk_get(dmc->dev, "mout_sclk_spll"); + dmc->mout_spll = devm_clk_get(dev, "mout_sclk_spll"); if (IS_ERR(dmc->mout_spll)) return PTR_ERR(dmc->mout_spll); } @@ -1329,38 +1322,37 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc) */ static int exynos5_performance_counters_init(struct exynos5_dmc *dmc) { + struct device *dev = dmc->dev; int ret, i; - dmc->num_counters = devfreq_event_get_edev_count(dmc->dev, - "devfreq-events"); + dmc->num_counters = devfreq_event_get_edev_count(dev, "devfreq-events"); if (dmc->num_counters < 0) { - dev_err(dmc->dev, "could not get devfreq-event counters\n"); + dev_err(dev, "could not get devfreq-event counters\n"); return dmc->num_counters; } - dmc->counter = devm_kcalloc(dmc->dev, dmc->num_counters, + dmc->counter = devm_kcalloc(dev, dmc->num_counters, sizeof(*dmc->counter), GFP_KERNEL); if (!dmc->counter) return -ENOMEM; for (i = 0; i < dmc->num_counters; i++) { dmc->counter[i] = - devfreq_event_get_edev_by_phandle(dmc->dev, - "devfreq-events", i); + devfreq_event_get_edev_by_phandle(dev, "devfreq-events", i); if (IS_ERR_OR_NULL(dmc->counter[i])) return -EPROBE_DEFER; } ret = exynos5_counters_enable_edev(dmc); if (ret < 0) { - dev_err(dmc->dev, "could not enable event counter\n"); + dev_err(dev, "could not enable event counter\n"); return ret; } ret = exynos5_counters_set_event(dmc); if (ret < 0) { exynos5_counters_disable_edev(dmc); - dev_err(dmc->dev, "could not set event counter\n"); + dev_err(dev, "could not set event counter\n"); return ret; } @@ -1558,7 +1550,7 @@ remove_clocks: * clean the device's resources. It just calls explicitly disable function for * the performance counters. */ -static int exynos5_dmc_remove(struct platform_device *pdev) +static void exynos5_dmc_remove(struct platform_device *pdev) { struct exynos5_dmc *dmc = dev_get_drvdata(&pdev->dev); @@ -1569,8 +1561,6 @@ static int exynos5_dmc_remove(struct platform_device *pdev) clk_disable_unprepare(dmc->mout_bpll); clk_disable_unprepare(dmc->fout_bpll); - - return 0; } static const struct of_device_id exynos5_dmc_of_match[] = { diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c index ffec26a99313..6e386ab54091 100644 --- a/drivers/memory/stm32-fmc2-ebi.c +++ b/drivers/memory/stm32-fmc2-ebi.c @@ -7,8 +7,11 @@ #include <linux/clk.h> #include <linux/mfd/syscon.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_platform.h> #include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/reset.h> @@ -18,8 +21,15 @@ #define FMC2_BCR(x) ((x) * 0x8 + FMC2_BCR1) #define FMC2_BTR(x) ((x) * 0x8 + FMC2_BTR1) #define FMC2_PCSCNTR 0x20 +#define FMC2_CFGR 0x20 +#define FMC2_SR 0x84 #define FMC2_BWTR1 0x104 #define FMC2_BWTR(x) ((x) * 0x8 + FMC2_BWTR1) +#define FMC2_SECCFGR 0x300 +#define FMC2_CIDCFGR0 0x30c +#define FMC2_CIDCFGR(x) ((x) * 0x8 + FMC2_CIDCFGR0) +#define FMC2_SEMCR0 0x310 +#define FMC2_SEMCR(x) ((x) * 0x8 + FMC2_SEMCR0) /* Register: FMC2_BCR1 */ #define FMC2_BCR1_CCLKEN BIT(20) @@ -40,6 +50,7 @@ #define FMC2_BCR_ASYNCWAIT BIT(15) #define FMC2_BCR_CPSIZE GENMASK(18, 16) #define FMC2_BCR_CBURSTRW BIT(19) +#define FMC2_BCR_CSCOUNT GENMASK(21, 20) #define FMC2_BCR_NBLSET GENMASK(23, 22) /* Register: FMC2_BTRx/FMC2_BWTRx */ @@ -56,8 +67,28 @@ #define FMC2_PCSCNTR_CSCOUNT GENMASK(15, 0) #define FMC2_PCSCNTR_CNTBEN(x) BIT((x) + 16) +/* Register: FMC2_CFGR */ +#define FMC2_CFGR_CLKDIV GENMASK(19, 16) +#define FMC2_CFGR_CCLKEN BIT(20) +#define FMC2_CFGR_FMC2EN BIT(31) + +/* Register: FMC2_SR */ +#define FMC2_SR_ISOST GENMASK(1, 0) + +/* Register: FMC2_CIDCFGR */ +#define FMC2_CIDCFGR_CFEN BIT(0) +#define FMC2_CIDCFGR_SEMEN BIT(1) +#define FMC2_CIDCFGR_SCID GENMASK(6, 4) +#define FMC2_CIDCFGR_SEMWLC1 BIT(17) + +/* Register: FMC2_SEMCR */ +#define FMC2_SEMCR_SEM_MUTEX BIT(0) +#define FMC2_SEMCR_SEMCID GENMASK(6, 4) + #define FMC2_MAX_EBI_CE 4 #define FMC2_MAX_BANKS 5 +#define FMC2_MAX_RESOURCES 6 +#define FMC2_CID1 1 #define FMC2_BCR_CPSIZE_0 0x0 #define FMC2_BCR_CPSIZE_128 0x1 @@ -72,6 +103,11 @@ #define FMC2_BCR_MTYP_PSRAM 0x1 #define FMC2_BCR_MTYP_NOR 0x2 +#define FMC2_BCR_CSCOUNT_0 0x0 +#define FMC2_BCR_CSCOUNT_1 0x1 +#define FMC2_BCR_CSCOUNT_64 0x2 +#define FMC2_BCR_CSCOUNT_256 0x3 + #define FMC2_BXTR_EXTMOD_A 0x0 #define FMC2_BXTR_EXTMOD_B 0x1 #define FMC2_BXTR_EXTMOD_C 0x2 @@ -86,6 +122,7 @@ #define FMC2_BTR_CLKDIV_MAX 0xf #define FMC2_BTR_DATLAT_MAX 0xf #define FMC2_PCSCNTR_CSCOUNT_MAX 0xff +#define FMC2_CFGR_CLKDIV_MAX 0xf enum stm32_fmc2_ebi_bank { FMC2_EBI1 = 0, @@ -99,7 +136,8 @@ enum stm32_fmc2_ebi_register_type { FMC2_REG_BCR = 1, FMC2_REG_BTR, FMC2_REG_BWTR, - FMC2_REG_PCSCNTR + FMC2_REG_PCSCNTR, + FMC2_REG_CFGR }; enum stm32_fmc2_ebi_transaction_type { @@ -130,16 +168,42 @@ enum stm32_fmc2_ebi_cpsize { FMC2_CPSIZE_1024 = 1024 }; +enum stm32_fmc2_ebi_cscount { + FMC2_CSCOUNT_0 = 0, + FMC2_CSCOUNT_1 = 1, + FMC2_CSCOUNT_64 = 64, + FMC2_CSCOUNT_256 = 256 +}; + +struct stm32_fmc2_ebi; + +struct stm32_fmc2_ebi_data { + const struct stm32_fmc2_prop *child_props; + unsigned int nb_child_props; + u32 fmc2_enable_reg; + u32 fmc2_enable_bit; + int (*nwait_used_by_ctrls)(struct stm32_fmc2_ebi *ebi); + void (*set_setup)(struct stm32_fmc2_ebi *ebi); + int (*save_setup)(struct stm32_fmc2_ebi *ebi); + int (*check_rif)(struct stm32_fmc2_ebi *ebi, u32 resource); + void (*put_sems)(struct stm32_fmc2_ebi *ebi); + void (*get_sems)(struct stm32_fmc2_ebi *ebi); +}; + struct stm32_fmc2_ebi { struct device *dev; struct clk *clk; struct regmap *regmap; + const struct stm32_fmc2_ebi_data *data; u8 bank_assigned; + u8 sem_taken; + bool access_granted; u32 bcr[FMC2_MAX_EBI_CE]; u32 btr[FMC2_MAX_EBI_CE]; u32 bwtr[FMC2_MAX_EBI_CE]; u32 pcscntr; + u32 cfgr; }; /* @@ -179,8 +243,11 @@ static int stm32_fmc2_ebi_check_mux(struct stm32_fmc2_ebi *ebi, int cs) { u32 bcr; + int ret; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; if (bcr & FMC2_BCR_MTYP) return 0; @@ -193,8 +260,11 @@ static int stm32_fmc2_ebi_check_waitcfg(struct stm32_fmc2_ebi *ebi, int cs) { u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); + int ret; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN) return 0; @@ -207,8 +277,11 @@ static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi, int cs) { u32 bcr; + int ret; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; if (bcr & FMC2_BCR_BURSTEN) return 0; @@ -216,13 +289,43 @@ static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi, return -EINVAL; } +static int stm32_fmc2_ebi_mp25_check_cclk(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + if (!ebi->access_granted) + return -EACCES; + + return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs); +} + +static int stm32_fmc2_ebi_mp25_check_clk_period(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs) +{ + u32 cfgr; + int ret; + + ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr); + if (ret) + return ret; + + if (cfgr & FMC2_CFGR_CCLKEN && !ebi->access_granted) + return -EACCES; + + return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs); +} + static int stm32_fmc2_ebi_check_async_trans(struct stm32_fmc2_ebi *ebi, const struct stm32_fmc2_prop *prop, int cs) { u32 bcr; + int ret; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; if (!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW)) return 0; @@ -235,8 +338,11 @@ static int stm32_fmc2_ebi_check_cpsize(struct stm32_fmc2_ebi *ebi, int cs) { u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); + int ret; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN) return 0; @@ -249,12 +355,18 @@ static int stm32_fmc2_ebi_check_address_hold(struct stm32_fmc2_ebi *ebi, int cs) { u32 bcr, bxtr, val = FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); + int ret; + + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); if (prop->reg_type == FMC2_REG_BWTR) - regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr); + ret = regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr); else - regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr); + ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr); + if (ret) + return ret; if ((!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW)) && ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN)) @@ -268,12 +380,19 @@ static int stm32_fmc2_ebi_check_clk_period(struct stm32_fmc2_ebi *ebi, int cs) { u32 bcr, bcr1; + int ret; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); - if (cs) - regmap_read(ebi->regmap, FMC2_BCR1, &bcr1); - else + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; + + if (cs) { + ret = regmap_read(ebi->regmap, FMC2_BCR1, &bcr1); + if (ret) + return ret; + } else { bcr1 = bcr; + } if (bcr & FMC2_BCR_BURSTEN && (!cs || !(bcr1 & FMC2_BCR1_CCLKEN))) return 0; @@ -305,18 +424,48 @@ static u32 stm32_fmc2_ebi_ns_to_clk_period(struct stm32_fmc2_ebi *ebi, { u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup); u32 bcr, btr, clk_period; + int ret; + + ret = regmap_read(ebi->regmap, FMC2_BCR1, &bcr); + if (ret) + return ret; - regmap_read(ebi->regmap, FMC2_BCR1, &bcr); if (bcr & FMC2_BCR1_CCLKEN || !cs) - regmap_read(ebi->regmap, FMC2_BTR1, &btr); + ret = regmap_read(ebi->regmap, FMC2_BTR1, &btr); else - regmap_read(ebi->regmap, FMC2_BTR(cs), &btr); + ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &btr); + if (ret) + return ret; clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1; return DIV_ROUND_UP(nb_clk_cycles, clk_period); } +static u32 stm32_fmc2_ebi_mp25_ns_to_clk_period(struct stm32_fmc2_ebi *ebi, + int cs, u32 setup) +{ + u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup); + u32 cfgr, btr, clk_period; + int ret; + + ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr); + if (ret) + return ret; + + if (cfgr & FMC2_CFGR_CCLKEN) { + clk_period = FIELD_GET(FMC2_CFGR_CLKDIV, cfgr) + 1; + } else { + ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &btr); + if (ret) + return ret; + + clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1; + } + + return DIV_ROUND_UP(nb_clk_cycles, clk_period); +} + static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg) { switch (reg_type) { @@ -332,6 +481,9 @@ static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg) case FMC2_REG_PCSCNTR: *reg = FMC2_PCSCNTR; break; + case FMC2_REG_CFGR: + *reg = FMC2_CFGR; + break; default: return -EINVAL; } @@ -569,11 +721,16 @@ static int stm32_fmc2_ebi_set_address_setup(struct stm32_fmc2_ebi *ebi, if (ret) return ret; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; + if (prop->reg_type == FMC2_REG_BWTR) - regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr); + ret = regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr); else - regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr); + ret = regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr); + if (ret) + return ret; if ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN) val = clamp_val(setup, 1, FMC2_BXTR_ADDSET_MAX); @@ -673,6 +830,30 @@ static int stm32_fmc2_ebi_set_clk_period(struct stm32_fmc2_ebi *ebi, return 0; } +static int stm32_fmc2_ebi_mp25_set_clk_period(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val, cfgr; + int ret; + + ret = regmap_read(ebi->regmap, FMC2_CFGR, &cfgr); + if (ret) + return ret; + + if (cfgr & FMC2_CFGR_CCLKEN) { + val = setup ? clamp_val(setup - 1, 1, FMC2_CFGR_CLKDIV_MAX) : 1; + val = FIELD_PREP(FMC2_CFGR_CLKDIV, val); + regmap_update_bits(ebi->regmap, FMC2_CFGR, FMC2_CFGR_CLKDIV, val); + } else { + val = setup ? clamp_val(setup - 1, 1, FMC2_BTR_CLKDIV_MAX) : 1; + val = FIELD_PREP(FMC2_BTR_CLKDIV, val); + regmap_update_bits(ebi->regmap, FMC2_BTR(cs), FMC2_BTR_CLKDIV, val); + } + + return 0; +} + static int stm32_fmc2_ebi_set_data_latency(struct stm32_fmc2_ebi *ebi, const struct stm32_fmc2_prop *prop, int cs, u32 setup) @@ -691,11 +872,14 @@ static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi, int cs, u32 setup) { u32 old_val, new_val, pcscntr; + int ret; if (setup < 1) return 0; - regmap_read(ebi->regmap, FMC2_PCSCNTR, &pcscntr); + ret = regmap_read(ebi->regmap, FMC2_PCSCNTR, &pcscntr); + if (ret) + return ret; /* Enable counter for the bank */ regmap_update_bits(ebi->regmap, FMC2_PCSCNTR, @@ -715,6 +899,27 @@ static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi, return 0; } +static int stm32_fmc2_ebi_mp25_set_max_low_pulse(struct stm32_fmc2_ebi *ebi, + const struct stm32_fmc2_prop *prop, + int cs, u32 setup) +{ + u32 val; + + if (setup == FMC2_CSCOUNT_0) + val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_0); + else if (setup == FMC2_CSCOUNT_1) + val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_1); + else if (setup <= FMC2_CSCOUNT_64) + val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_64); + else + val = FIELD_PREP(FMC2_BCR_CSCOUNT, FMC2_BCR_CSCOUNT_256); + + regmap_update_bits(ebi->regmap, FMC2_BCR(cs), + FMC2_BCR_CSCOUNT, val); + + return 0; +} + static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = { /* st,fmc2-ebi-cs-trans-type must be the first property */ { @@ -880,6 +1085,275 @@ static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = { }, }; +static const struct stm32_fmc2_prop stm32_fmc2_mp25_child_props[] = { + /* st,fmc2-ebi-cs-trans-type must be the first property */ + { + .name = "st,fmc2-ebi-cs-transaction-type", + .mprop = true, + .set = stm32_fmc2_ebi_set_trans_type, + }, + { + .name = "st,fmc2-ebi-cs-cclk-enable", + .bprop = true, + .reg_type = FMC2_REG_CFGR, + .reg_mask = FMC2_CFGR_CCLKEN, + .check = stm32_fmc2_ebi_mp25_check_cclk, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-mux-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_MUXEN, + .check = stm32_fmc2_ebi_check_mux, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-buswidth", + .reset_val = FMC2_BUSWIDTH_16, + .set = stm32_fmc2_ebi_set_buswidth, + }, + { + .name = "st,fmc2-ebi-cs-waitpol-high", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_WAITPOL, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-waitcfg-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_WAITCFG, + .check = stm32_fmc2_ebi_check_waitcfg, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-wait-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_WAITEN, + .check = stm32_fmc2_ebi_check_sync_trans, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-asyncwait-enable", + .bprop = true, + .reg_type = FMC2_REG_BCR, + .reg_mask = FMC2_BCR_ASYNCWAIT, + .check = stm32_fmc2_ebi_check_async_trans, + .set = stm32_fmc2_ebi_set_bit_field, + }, + { + .name = "st,fmc2-ebi-cs-cpsize", + .check = stm32_fmc2_ebi_check_cpsize, + .set = stm32_fmc2_ebi_set_cpsize, + }, + { + .name = "st,fmc2-ebi-cs-byte-lane-setup-ns", + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_bl_setup, + }, + { + .name = "st,fmc2-ebi-cs-address-setup-ns", + .reg_type = FMC2_REG_BTR, + .reset_val = FMC2_BXTR_ADDSET_MAX, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_address_setup, + }, + { + .name = "st,fmc2-ebi-cs-address-hold-ns", + .reg_type = FMC2_REG_BTR, + .reset_val = FMC2_BXTR_ADDHLD_MAX, + .check = stm32_fmc2_ebi_check_address_hold, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_address_hold, + }, + { + .name = "st,fmc2-ebi-cs-data-setup-ns", + .reg_type = FMC2_REG_BTR, + .reset_val = FMC2_BXTR_DATAST_MAX, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_data_setup, + }, + { + .name = "st,fmc2-ebi-cs-bus-turnaround-ns", + .reg_type = FMC2_REG_BTR, + .reset_val = FMC2_BXTR_BUSTURN_MAX + 1, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_bus_turnaround, + }, + { + .name = "st,fmc2-ebi-cs-data-hold-ns", + .reg_type = FMC2_REG_BTR, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_data_hold, + }, + { + .name = "st,fmc2-ebi-cs-clk-period-ns", + .reset_val = FMC2_CFGR_CLKDIV_MAX + 1, + .check = stm32_fmc2_ebi_mp25_check_clk_period, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_mp25_set_clk_period, + }, + { + .name = "st,fmc2-ebi-cs-data-latency-ns", + .check = stm32_fmc2_ebi_check_sync_trans, + .calculate = stm32_fmc2_ebi_mp25_ns_to_clk_period, + .set = stm32_fmc2_ebi_set_data_latency, + }, + { + .name = "st,fmc2-ebi-cs-write-address-setup-ns", + .reg_type = FMC2_REG_BWTR, + .reset_val = FMC2_BXTR_ADDSET_MAX, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_address_setup, + }, + { + .name = "st,fmc2-ebi-cs-write-address-hold-ns", + .reg_type = FMC2_REG_BWTR, + .reset_val = FMC2_BXTR_ADDHLD_MAX, + .check = stm32_fmc2_ebi_check_address_hold, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_address_hold, + }, + { + .name = "st,fmc2-ebi-cs-write-data-setup-ns", + .reg_type = FMC2_REG_BWTR, + .reset_val = FMC2_BXTR_DATAST_MAX, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_data_setup, + }, + { + .name = "st,fmc2-ebi-cs-write-bus-turnaround-ns", + .reg_type = FMC2_REG_BWTR, + .reset_val = FMC2_BXTR_BUSTURN_MAX + 1, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_bus_turnaround, + }, + { + .name = "st,fmc2-ebi-cs-write-data-hold-ns", + .reg_type = FMC2_REG_BWTR, + .check = stm32_fmc2_ebi_check_async_trans, + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_set_data_hold, + }, + { + .name = "st,fmc2-ebi-cs-max-low-pulse-ns", + .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, + .set = stm32_fmc2_ebi_mp25_set_max_low_pulse, + }, +}; + +static int stm32_fmc2_ebi_mp25_check_rif(struct stm32_fmc2_ebi *ebi, u32 resource) +{ + u32 seccfgr, cidcfgr, semcr; + int cid, ret; + + if (resource >= FMC2_MAX_RESOURCES) + return -EINVAL; + + ret = regmap_read(ebi->regmap, FMC2_SECCFGR, &seccfgr); + if (ret) + return ret; + + if (seccfgr & BIT(resource)) { + if (resource) + dev_err(ebi->dev, "resource %d is configured as secure\n", + resource); + + return -EACCES; + } + + ret = regmap_read(ebi->regmap, FMC2_CIDCFGR(resource), &cidcfgr); + if (ret) + return ret; + + if (!(cidcfgr & FMC2_CIDCFGR_CFEN)) + /* CID filtering is turned off: access granted */ + return 0; + + if (!(cidcfgr & FMC2_CIDCFGR_SEMEN)) { + /* Static CID mode */ + cid = FIELD_GET(FMC2_CIDCFGR_SCID, cidcfgr); + if (cid != FMC2_CID1) { + if (resource) + dev_err(ebi->dev, "static CID%d set for resource %d\n", + cid, resource); + + return -EACCES; + } + + return 0; + } + + /* Pass-list with semaphore mode */ + if (!(cidcfgr & FMC2_CIDCFGR_SEMWLC1)) { + if (resource) + dev_err(ebi->dev, "CID1 is block-listed for resource %d\n", + resource); + + return -EACCES; + } + + ret = regmap_read(ebi->regmap, FMC2_SEMCR(resource), &semcr); + if (ret) + return ret; + + if (!(semcr & FMC2_SEMCR_SEM_MUTEX)) { + regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource), + FMC2_SEMCR_SEM_MUTEX, FMC2_SEMCR_SEM_MUTEX); + + ret = regmap_read(ebi->regmap, FMC2_SEMCR(resource), &semcr); + if (ret) + return ret; + } + + cid = FIELD_GET(FMC2_SEMCR_SEMCID, semcr); + if (cid != FMC2_CID1) { + if (resource) + dev_err(ebi->dev, "resource %d is already used by CID%d\n", + resource, cid); + + return -EACCES; + } + + ebi->sem_taken |= BIT(resource); + + return 0; +} + +static void stm32_fmc2_ebi_mp25_put_sems(struct stm32_fmc2_ebi *ebi) +{ + unsigned int resource; + + for (resource = 0; resource < FMC2_MAX_RESOURCES; resource++) { + if (!(ebi->sem_taken & BIT(resource))) + continue; + + regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource), + FMC2_SEMCR_SEM_MUTEX, 0); + } +} + +static void stm32_fmc2_ebi_mp25_get_sems(struct stm32_fmc2_ebi *ebi) +{ + unsigned int resource; + + for (resource = 0; resource < FMC2_MAX_RESOURCES; resource++) { + if (!(ebi->sem_taken & BIT(resource))) + continue; + + regmap_update_bits(ebi->regmap, FMC2_SEMCR(resource), + FMC2_SEMCR_SEM_MUTEX, FMC2_SEMCR_SEM_MUTEX); + } +} + static int stm32_fmc2_ebi_parse_prop(struct stm32_fmc2_ebi *ebi, struct device_node *dev_node, const struct stm32_fmc2_prop *prop, @@ -942,17 +1416,48 @@ static void stm32_fmc2_ebi_disable_bank(struct stm32_fmc2_ebi *ebi, int cs) regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_MBKEN, 0); } -static void stm32_fmc2_ebi_save_setup(struct stm32_fmc2_ebi *ebi) +static int stm32_fmc2_ebi_save_setup(struct stm32_fmc2_ebi *ebi) { unsigned int cs; + int ret; for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { - regmap_read(ebi->regmap, FMC2_BCR(cs), &ebi->bcr[cs]); - regmap_read(ebi->regmap, FMC2_BTR(cs), &ebi->btr[cs]); - regmap_read(ebi->regmap, FMC2_BWTR(cs), &ebi->bwtr[cs]); + if (!(ebi->bank_assigned & BIT(cs))) + continue; + + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &ebi->bcr[cs]); + ret |= regmap_read(ebi->regmap, FMC2_BTR(cs), &ebi->btr[cs]); + ret |= regmap_read(ebi->regmap, FMC2_BWTR(cs), &ebi->bwtr[cs]); + if (ret) + return ret; } - regmap_read(ebi->regmap, FMC2_PCSCNTR, &ebi->pcscntr); + return 0; +} + +static int stm32_fmc2_ebi_mp1_save_setup(struct stm32_fmc2_ebi *ebi) +{ + int ret; + + ret = stm32_fmc2_ebi_save_setup(ebi); + if (ret) + return ret; + + return regmap_read(ebi->regmap, FMC2_PCSCNTR, &ebi->pcscntr); +} + +static int stm32_fmc2_ebi_mp25_save_setup(struct stm32_fmc2_ebi *ebi) +{ + int ret; + + ret = stm32_fmc2_ebi_save_setup(ebi); + if (ret) + return ret; + + if (ebi->access_granted) + ret = regmap_read(ebi->regmap, FMC2_CFGR, &ebi->cfgr); + + return ret; } static void stm32_fmc2_ebi_set_setup(struct stm32_fmc2_ebi *ebi) @@ -960,14 +1465,29 @@ static void stm32_fmc2_ebi_set_setup(struct stm32_fmc2_ebi *ebi) unsigned int cs; for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { + if (!(ebi->bank_assigned & BIT(cs))) + continue; + regmap_write(ebi->regmap, FMC2_BCR(cs), ebi->bcr[cs]); regmap_write(ebi->regmap, FMC2_BTR(cs), ebi->btr[cs]); regmap_write(ebi->regmap, FMC2_BWTR(cs), ebi->bwtr[cs]); } +} +static void stm32_fmc2_ebi_mp1_set_setup(struct stm32_fmc2_ebi *ebi) +{ + stm32_fmc2_ebi_set_setup(ebi); regmap_write(ebi->regmap, FMC2_PCSCNTR, ebi->pcscntr); } +static void stm32_fmc2_ebi_mp25_set_setup(struct stm32_fmc2_ebi *ebi) +{ + stm32_fmc2_ebi_set_setup(ebi); + + if (ebi->access_granted) + regmap_write(ebi->regmap, FMC2_CFGR, ebi->cfgr); +} + static void stm32_fmc2_ebi_disable_banks(struct stm32_fmc2_ebi *ebi) { unsigned int cs; @@ -981,33 +1501,48 @@ static void stm32_fmc2_ebi_disable_banks(struct stm32_fmc2_ebi *ebi) } /* NWAIT signal can not be connected to EBI controller and NAND controller */ -static bool stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi) +static int stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi) { + struct device *dev = ebi->dev; unsigned int cs; u32 bcr; + int ret; for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { if (!(ebi->bank_assigned & BIT(cs))) continue; - regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + ret = regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); + if (ret) + return ret; + if ((bcr & FMC2_BCR_WAITEN || bcr & FMC2_BCR_ASYNCWAIT) && - ebi->bank_assigned & BIT(FMC2_NAND)) - return true; + ebi->bank_assigned & BIT(FMC2_NAND)) { + dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n"); + return -EINVAL; + } } - return false; + return 0; } static void stm32_fmc2_ebi_enable(struct stm32_fmc2_ebi *ebi) { - regmap_update_bits(ebi->regmap, FMC2_BCR1, - FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); + if (!ebi->access_granted) + return; + + regmap_update_bits(ebi->regmap, ebi->data->fmc2_enable_reg, + ebi->data->fmc2_enable_bit, + ebi->data->fmc2_enable_bit); } static void stm32_fmc2_ebi_disable(struct stm32_fmc2_ebi *ebi) { - regmap_update_bits(ebi->regmap, FMC2_BCR1, FMC2_BCR1_FMC2EN, 0); + if (!ebi->access_granted) + return; + + regmap_update_bits(ebi->regmap, ebi->data->fmc2_enable_reg, + ebi->data->fmc2_enable_bit, 0); } static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi, @@ -1019,8 +1554,8 @@ static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi, stm32_fmc2_ebi_disable_bank(ebi, cs); - for (i = 0; i < ARRAY_SIZE(stm32_fmc2_child_props); i++) { - const struct stm32_fmc2_prop *p = &stm32_fmc2_child_props[i]; + for (i = 0; i < ebi->data->nb_child_props; i++) { + const struct stm32_fmc2_prop *p = &ebi->data->child_props[i]; ret = stm32_fmc2_ebi_parse_prop(ebi, dev_node, p, cs); if (ret) { @@ -1038,42 +1573,40 @@ static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi, static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) { struct device *dev = ebi->dev; - struct device_node *child; bool child_found = false; u32 bank; int ret; - for_each_available_child_of_node(dev->of_node, child) { + for_each_available_child_of_node_scoped(dev->of_node, child) { ret = of_property_read_u32(child, "reg", &bank); - if (ret) { - dev_err(dev, "could not retrieve reg property: %d\n", - ret); - of_node_put(child); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "could not retrieve reg property\n"); if (bank >= FMC2_MAX_BANKS) { dev_err(dev, "invalid reg value: %d\n", bank); - of_node_put(child); return -EINVAL; } if (ebi->bank_assigned & BIT(bank)) { dev_err(dev, "bank already assigned: %d\n", bank); - of_node_put(child); return -EINVAL; } - if (bank < FMC2_MAX_EBI_CE) { - ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank); + if (ebi->data->check_rif) { + ret = ebi->data->check_rif(ebi, bank + 1); if (ret) { - dev_err(dev, "setup chip select %d failed: %d\n", - bank, ret); - of_node_put(child); + dev_err(dev, "bank access failed: %d\n", bank); return ret; } } + if (bank < FMC2_MAX_EBI_CE) { + ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank); + if (ret) + return dev_err_probe(dev, ret, + "setup chip select %d failed\n", bank); + } + ebi->bank_assigned |= BIT(bank); child_found = true; } @@ -1083,9 +1616,10 @@ static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) return -ENODEV; } - if (stm32_fmc2_ebi_nwait_used_by_ctrls(ebi)) { - dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n"); - return -EINVAL; + if (ebi->data->nwait_used_by_ctrls) { + ret = ebi->data->nwait_used_by_ctrls(ebi); + if (ret) + return ret; } stm32_fmc2_ebi_enable(ebi); @@ -1105,6 +1639,11 @@ static int stm32_fmc2_ebi_probe(struct platform_device *pdev) return -ENOMEM; ebi->dev = dev; + platform_set_drvdata(pdev, ebi); + + ebi->data = of_device_get_match_data(dev); + if (!ebi->data) + return -EINVAL; ebi->regmap = device_node_to_regmap(dev->of_node); if (IS_ERR(ebi->regmap)) @@ -1118,50 +1657,97 @@ static int stm32_fmc2_ebi_probe(struct platform_device *pdev) if (PTR_ERR(rstc) == -EPROBE_DEFER) return -EPROBE_DEFER; - ret = clk_prepare_enable(ebi->clk); + ret = devm_pm_runtime_enable(dev); if (ret) return ret; + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + if (!IS_ERR(rstc)) { reset_control_assert(rstc); reset_control_deassert(rstc); } + /* Check if CFGR register can be modified */ + ebi->access_granted = true; + if (ebi->data->check_rif) { + ret = ebi->data->check_rif(ebi, 0); + if (ret) { + u32 sr; + + ebi->access_granted = false; + + ret = regmap_read(ebi->regmap, FMC2_SR, &sr); + if (ret) + goto err_release; + + /* In case of CFGR is secure, just check that the FMC2 is enabled */ + if (sr & FMC2_SR_ISOST) { + dev_err(dev, "FMC2 is not ready to be used.\n"); + ret = -EACCES; + goto err_release; + } + } + } + ret = stm32_fmc2_ebi_parse_dt(ebi); if (ret) goto err_release; - stm32_fmc2_ebi_save_setup(ebi); - platform_set_drvdata(pdev, ebi); + ret = ebi->data->save_setup(ebi); + if (ret) + goto err_release; return 0; err_release: stm32_fmc2_ebi_disable_banks(ebi); stm32_fmc2_ebi_disable(ebi); - clk_disable_unprepare(ebi->clk); + if (ebi->data->put_sems) + ebi->data->put_sems(ebi); + pm_runtime_put_sync_suspend(dev); return ret; } -static int stm32_fmc2_ebi_remove(struct platform_device *pdev) +static void stm32_fmc2_ebi_remove(struct platform_device *pdev) { struct stm32_fmc2_ebi *ebi = platform_get_drvdata(pdev); of_platform_depopulate(&pdev->dev); stm32_fmc2_ebi_disable_banks(ebi); stm32_fmc2_ebi_disable(ebi); + if (ebi->data->put_sems) + ebi->data->put_sems(ebi); + pm_runtime_put_sync_suspend(&pdev->dev); +} + +static int __maybe_unused stm32_fmc2_ebi_runtime_suspend(struct device *dev) +{ + struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev); + clk_disable_unprepare(ebi->clk); return 0; } +static int __maybe_unused stm32_fmc2_ebi_runtime_resume(struct device *dev) +{ + struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev); + + return clk_prepare_enable(ebi->clk); +} + static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev) { struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev); stm32_fmc2_ebi_disable(ebi); - clk_disable_unprepare(ebi->clk); + if (ebi->data->put_sems) + ebi->data->put_sems(ebi); + pm_runtime_put_sync_suspend(dev); pinctrl_pm_select_sleep_state(dev); return 0; @@ -1174,28 +1760,62 @@ static int __maybe_unused stm32_fmc2_ebi_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - ret = clk_prepare_enable(ebi->clk); - if (ret) + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - stm32_fmc2_ebi_set_setup(ebi); + if (ebi->data->get_sems) + ebi->data->get_sems(ebi); + ebi->data->set_setup(ebi); stm32_fmc2_ebi_enable(ebi); return 0; } -static SIMPLE_DEV_PM_OPS(stm32_fmc2_ebi_pm_ops, stm32_fmc2_ebi_suspend, - stm32_fmc2_ebi_resume); +static const struct dev_pm_ops stm32_fmc2_ebi_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_fmc2_ebi_runtime_suspend, + stm32_fmc2_ebi_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(stm32_fmc2_ebi_suspend, stm32_fmc2_ebi_resume) +}; + +static const struct stm32_fmc2_ebi_data stm32_fmc2_ebi_mp1_data = { + .child_props = stm32_fmc2_child_props, + .nb_child_props = ARRAY_SIZE(stm32_fmc2_child_props), + .fmc2_enable_reg = FMC2_BCR1, + .fmc2_enable_bit = FMC2_BCR1_FMC2EN, + .nwait_used_by_ctrls = stm32_fmc2_ebi_nwait_used_by_ctrls, + .set_setup = stm32_fmc2_ebi_mp1_set_setup, + .save_setup = stm32_fmc2_ebi_mp1_save_setup, +}; + +static const struct stm32_fmc2_ebi_data stm32_fmc2_ebi_mp25_data = { + .child_props = stm32_fmc2_mp25_child_props, + .nb_child_props = ARRAY_SIZE(stm32_fmc2_mp25_child_props), + .fmc2_enable_reg = FMC2_CFGR, + .fmc2_enable_bit = FMC2_CFGR_FMC2EN, + .set_setup = stm32_fmc2_ebi_mp25_set_setup, + .save_setup = stm32_fmc2_ebi_mp25_save_setup, + .check_rif = stm32_fmc2_ebi_mp25_check_rif, + .put_sems = stm32_fmc2_ebi_mp25_put_sems, + .get_sems = stm32_fmc2_ebi_mp25_get_sems, +}; static const struct of_device_id stm32_fmc2_ebi_match[] = { - {.compatible = "st,stm32mp1-fmc2-ebi"}, + { + .compatible = "st,stm32mp1-fmc2-ebi", + .data = &stm32_fmc2_ebi_mp1_data, + }, + { + .compatible = "st,stm32mp25-fmc2-ebi", + .data = &stm32_fmc2_ebi_mp25_data, + }, {} }; MODULE_DEVICE_TABLE(of, stm32_fmc2_ebi_match); static struct platform_driver stm32_fmc2_ebi_driver = { .probe = stm32_fmc2_ebi_probe, - .remove = stm32_fmc2_ebi_remove, + .remove = stm32_fmc2_ebi_remove, .driver = { .name = "stm32_fmc2_ebi", .of_match_table = stm32_fmc2_ebi_match, diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c new file mode 100644 index 000000000000..5d06623f3f68 --- /dev/null +++ b/drivers/memory/stm32_omm.c @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) STMicroelectronics 2025 - All Rights Reserved + * Author(s): Patrice Chotard <patrice.chotard@foss.st.com> for STMicroelectronics. + */ + +#include <linux/bitfield.h> +#include <linux/bus/stm32_firewall_device.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/mfd/syscon.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/reset.h> + +#define OMM_CR 0 +#define CR_MUXEN BIT(0) +#define CR_MUXENMODE_MASK GENMASK(1, 0) +#define CR_CSSEL_OVR_EN BIT(4) +#define CR_CSSEL_OVR_MASK GENMASK(6, 5) +#define CR_REQ2ACK_MASK GENMASK(23, 16) + +#define OMM_CHILD_NB 2 +#define OMM_CLK_NB 3 + +struct stm32_omm { + struct resource *mm_res; + struct clk_bulk_data clk_bulk[OMM_CLK_NB]; + struct reset_control *child_reset[OMM_CHILD_NB]; + void __iomem *io_base; + u32 cr; + u8 nb_child; + bool restore_omm; +}; + +static int stm32_omm_set_amcr(struct device *dev, bool set) +{ + struct stm32_omm *omm = dev_get_drvdata(dev); + resource_size_t mm_ospi2_size = 0; + static const char * const mm_name[] = { "ospi1", "ospi2" }; + struct regmap *syscfg_regmap; + struct device_node *node; + struct resource res, res1; + unsigned int syscon_args[2]; + int ret, idx; + unsigned int i, amcr, read_amcr; + + for (i = 0; i < omm->nb_child; i++) { + idx = of_property_match_string(dev->of_node, + "memory-region-names", + mm_name[i]); + if (idx < 0) + continue; + + /* res1 only used on second loop iteration */ + res1.start = res.start; + res1.end = res.end; + + node = of_parse_phandle(dev->of_node, "memory-region", idx); + if (!node) + continue; + + ret = of_address_to_resource(node, 0, &res); + if (ret) { + of_node_put(node); + dev_err(dev, "unable to resolve memory region\n"); + return ret; + } + + /* check that memory region fits inside OMM memory map area */ + if (!resource_contains(omm->mm_res, &res)) { + dev_err(dev, "%s doesn't fit inside OMM memory map area\n", + mm_name[i]); + dev_err(dev, "%pR doesn't fit inside %pR\n", &res, omm->mm_res); + of_node_put(node); + + return -EFAULT; + } + + if (i == 1) { + mm_ospi2_size = resource_size(&res); + + /* check that OMM memory region 1 doesn't overlap memory region 2 */ + if (resource_overlaps(&res, &res1)) { + dev_err(dev, "OMM memory-region %s overlaps memory region %s\n", + mm_name[0], mm_name[1]); + dev_err(dev, "%pR overlaps %pR\n", &res1, &res); + of_node_put(node); + + return -EFAULT; + } + } + of_node_put(node); + } + + syscfg_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node, "st,syscfg-amcr", + 2, syscon_args); + if (IS_ERR(syscfg_regmap)) + return dev_err_probe(dev, PTR_ERR(syscfg_regmap), + "Failed to get st,syscfg-amcr property\n"); + + amcr = mm_ospi2_size / SZ_64M; + + if (set) + regmap_update_bits(syscfg_regmap, syscon_args[0], syscon_args[1], amcr); + + /* read AMCR and check coherency with memory-map areas defined in DT */ + regmap_read(syscfg_regmap, syscon_args[0], &read_amcr); + read_amcr = read_amcr >> (ffs(syscon_args[1]) - 1); + + if (amcr != read_amcr) { + dev_err(dev, "AMCR value not coherent with DT memory-map areas\n"); + ret = -EINVAL; + } + + return ret; +} + +static int stm32_omm_toggle_child_clock(struct device *dev, bool enable) +{ + struct stm32_omm *omm = dev_get_drvdata(dev); + int i, ret; + + for (i = 0; i < omm->nb_child; i++) { + if (enable) { + ret = clk_prepare_enable(omm->clk_bulk[i + 1].clk); + if (ret) { + dev_err(dev, "Can not enable clock\n"); + goto clk_error; + } + } else { + clk_disable_unprepare(omm->clk_bulk[i + 1].clk); + } + } + + return 0; + +clk_error: + while (i--) + clk_disable_unprepare(omm->clk_bulk[i + 1].clk); + + return ret; +} + +static int stm32_omm_disable_child(struct device *dev) +{ + struct stm32_omm *omm = dev_get_drvdata(dev); + struct reset_control *reset; + int ret; + u8 i; + + ret = stm32_omm_toggle_child_clock(dev, true); + if (ret) + return ret; + + for (i = 0; i < omm->nb_child; i++) { + /* reset OSPI to ensure CR_EN bit is set to 0 */ + reset = omm->child_reset[i]; + ret = reset_control_acquire(reset); + if (ret) { + stm32_omm_toggle_child_clock(dev, false); + dev_err(dev, "Can not acquire reset %d\n", ret); + return ret; + } + + reset_control_assert(reset); + udelay(2); + reset_control_deassert(reset); + + reset_control_release(reset); + } + + return stm32_omm_toggle_child_clock(dev, false); +} + +static int stm32_omm_configure(struct device *dev) +{ + static const char * const clocks_name[] = {"omm", "ospi1", "ospi2"}; + struct stm32_omm *omm = dev_get_drvdata(dev); + unsigned long clk_rate_max = 0; + u32 mux = 0; + u32 cssel_ovr = 0; + u32 req2ack = 0; + struct reset_control *rstc; + unsigned long clk_rate; + int ret; + u8 i; + + for (i = 0; i < OMM_CLK_NB; i++) + omm->clk_bulk[i].id = clocks_name[i]; + + /* retrieve OMM, OSPI1 and OSPI2 clocks */ + ret = devm_clk_bulk_get(dev, OMM_CLK_NB, omm->clk_bulk); + if (ret) + return dev_err_probe(dev, ret, "Failed to get OMM/OSPI's clocks\n"); + + /* Ensure both OSPI instance are disabled before configuring OMM */ + ret = stm32_omm_disable_child(dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + /* parse children's clock */ + for (i = 1; i <= omm->nb_child; i++) { + clk_rate = clk_get_rate(omm->clk_bulk[i].clk); + if (!clk_rate) { + dev_err(dev, "Invalid clock rate\n"); + ret = -EINVAL; + goto error; + } + + if (clk_rate > clk_rate_max) + clk_rate_max = clk_rate; + } + + rstc = devm_reset_control_get_exclusive(dev, "omm"); + if (IS_ERR(rstc)) { + ret = dev_err_probe(dev, PTR_ERR(rstc), "reset get failed\n"); + goto error; + } + + reset_control_assert(rstc); + udelay(2); + reset_control_deassert(rstc); + + omm->cr = readl_relaxed(omm->io_base + OMM_CR); + /* optional */ + ret = of_property_read_u32(dev->of_node, "st,omm-mux", &mux); + if (!ret) { + if (mux & CR_MUXEN) { + ret = of_property_read_u32(dev->of_node, "st,omm-req2ack-ns", + &req2ack); + if (!ret && req2ack) { + req2ack = DIV_ROUND_UP(req2ack, NSEC_PER_SEC / clk_rate_max) - 1; + + if (req2ack > 256) + req2ack = 256; + } + + req2ack = FIELD_PREP(CR_REQ2ACK_MASK, req2ack); + + omm->cr &= ~CR_REQ2ACK_MASK; + omm->cr |= FIELD_PREP(CR_REQ2ACK_MASK, req2ack); + + /* + * If the mux is enabled, the 2 OSPI clocks have to be + * always enabled + */ + ret = stm32_omm_toggle_child_clock(dev, true); + if (ret) + goto error; + } + + omm->cr &= ~CR_MUXENMODE_MASK; + omm->cr |= FIELD_PREP(CR_MUXENMODE_MASK, mux); + } + + /* optional */ + ret = of_property_read_u32(dev->of_node, "st,omm-cssel-ovr", &cssel_ovr); + if (!ret) { + omm->cr &= ~CR_CSSEL_OVR_MASK; + omm->cr |= FIELD_PREP(CR_CSSEL_OVR_MASK, cssel_ovr); + omm->cr |= CR_CSSEL_OVR_EN; + } + + omm->restore_omm = true; + writel_relaxed(omm->cr, omm->io_base + OMM_CR); + + ret = stm32_omm_set_amcr(dev, true); + +error: + pm_runtime_put_sync_suspend(dev); + + return ret; +} + +static int stm32_omm_check_access(struct device_node *np) +{ + struct stm32_firewall firewall; + int ret; + + ret = stm32_firewall_get_firewall(np, &firewall, 1); + if (ret) + return ret; + + return stm32_firewall_grant_access(&firewall); +} + +static int stm32_omm_probe(struct platform_device *pdev) +{ + static const char * const resets_name[] = {"ospi1", "ospi2"}; + struct device *dev = &pdev->dev; + u8 child_access_granted = 0; + struct stm32_omm *omm; + int i, ret; + + omm = devm_kzalloc(dev, sizeof(*omm), GFP_KERNEL); + if (!omm) + return -ENOMEM; + + omm->io_base = devm_platform_ioremap_resource_byname(pdev, "regs"); + if (IS_ERR(omm->io_base)) + return PTR_ERR(omm->io_base); + + omm->mm_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory_map"); + if (!omm->mm_res) + return -ENODEV; + + /* check child's access */ + for_each_child_of_node_scoped(dev->of_node, child) { + if (omm->nb_child >= OMM_CHILD_NB) { + dev_err(dev, "Bad DT, found too much children\n"); + return -E2BIG; + } + + ret = stm32_omm_check_access(child); + if (ret < 0 && ret != -EACCES) + return ret; + + if (!ret) + child_access_granted++; + + omm->nb_child++; + } + + if (omm->nb_child != OMM_CHILD_NB) + return -EINVAL; + + platform_set_drvdata(pdev, omm); + + devm_pm_runtime_enable(dev); + + /* check if OMM's resource access is granted */ + ret = stm32_omm_check_access(dev->of_node); + if (ret < 0 && ret != -EACCES) + return ret; + + for (i = 0; i < omm->nb_child; i++) { + omm->child_reset[i] = devm_reset_control_get_exclusive_released(dev, + resets_name[i]); + + if (IS_ERR(omm->child_reset[i])) + return dev_err_probe(dev, PTR_ERR(omm->child_reset[i]), + "Can't get %s reset\n", resets_name[i]); + } + + if (!ret && child_access_granted == OMM_CHILD_NB) { + ret = stm32_omm_configure(dev); + if (ret) + return ret; + } else { + dev_dbg(dev, "Octo Memory Manager resource's access not granted\n"); + /* + * AMCR can't be set, so check if current value is coherent + * with memory-map areas defined in DT + */ + ret = stm32_omm_set_amcr(dev, false); + if (ret) + return ret; + } + + ret = devm_of_platform_populate(dev); + if (ret) { + if (omm->cr & CR_MUXEN) + stm32_omm_toggle_child_clock(&pdev->dev, false); + + return dev_err_probe(dev, ret, "Failed to create Octo Memory Manager child\n"); + } + + return 0; +} + +static void stm32_omm_remove(struct platform_device *pdev) +{ + struct stm32_omm *omm = platform_get_drvdata(pdev); + + if (omm->cr & CR_MUXEN) + stm32_omm_toggle_child_clock(&pdev->dev, false); +} + +static const struct of_device_id stm32_omm_of_match[] = { + { .compatible = "st,stm32mp25-omm", }, + {} +}; +MODULE_DEVICE_TABLE(of, stm32_omm_of_match); + +static int __maybe_unused stm32_omm_runtime_suspend(struct device *dev) +{ + struct stm32_omm *omm = dev_get_drvdata(dev); + + clk_disable_unprepare(omm->clk_bulk[0].clk); + + return 0; +} + +static int __maybe_unused stm32_omm_runtime_resume(struct device *dev) +{ + struct stm32_omm *omm = dev_get_drvdata(dev); + + return clk_prepare_enable(omm->clk_bulk[0].clk); +} + +static int __maybe_unused stm32_omm_suspend(struct device *dev) +{ + struct stm32_omm *omm = dev_get_drvdata(dev); + + if (omm->restore_omm && omm->cr & CR_MUXEN) + stm32_omm_toggle_child_clock(dev, false); + + return pinctrl_pm_select_sleep_state(dev); +} + +static int __maybe_unused stm32_omm_resume(struct device *dev) +{ + struct stm32_omm *omm = dev_get_drvdata(dev); + int ret; + + pinctrl_pm_select_default_state(dev); + + if (!omm->restore_omm) + return 0; + + /* Ensure both OSPI instance are disabled before configuring OMM */ + ret = stm32_omm_disable_child(dev); + if (ret) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + writel_relaxed(omm->cr, omm->io_base + OMM_CR); + ret = stm32_omm_set_amcr(dev, true); + pm_runtime_put_sync_suspend(dev); + if (ret) + return ret; + + if (omm->cr & CR_MUXEN) + ret = stm32_omm_toggle_child_clock(dev, true); + + return ret; +} + +static const struct dev_pm_ops stm32_omm_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_omm_runtime_suspend, + stm32_omm_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(stm32_omm_suspend, stm32_omm_resume) +}; + +static struct platform_driver stm32_omm_driver = { + .probe = stm32_omm_probe, + .remove = stm32_omm_remove, + .driver = { + .name = "stm32-omm", + .of_match_table = stm32_omm_of_match, + .pm = &stm32_omm_pm_ops, + }, +}; +module_platform_driver(stm32_omm_driver); + +MODULE_DESCRIPTION("STMicroelectronics Octo Memory Manager driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig index 3fe83d7c2bf8..fc5a27791826 100644 --- a/drivers/memory/tegra/Kconfig +++ b/drivers/memory/tegra/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config TEGRA_MC bool "NVIDIA Tegra Memory Controller support" - default y + default ARCH_TEGRA depends on ARCH_TEGRA || (COMPILE_TEST && COMMON_CLK) select INTERCONNECT help @@ -12,7 +12,7 @@ if TEGRA_MC config TEGRA20_EMC tristate "NVIDIA Tegra20 External Memory Controller driver" - default y + default ARCH_TEGRA_2x_SOC depends on ARCH_TEGRA_2x_SOC || COMPILE_TEST select DEVFREQ_GOV_SIMPLE_ONDEMAND select PM_DEVFREQ @@ -25,7 +25,7 @@ config TEGRA20_EMC config TEGRA30_EMC tristate "NVIDIA Tegra30 External Memory Controller driver" - default y + default ARCH_TEGRA_3x_SOC depends on ARCH_TEGRA_3x_SOC || COMPILE_TEST select PM_OPP select DDR @@ -37,7 +37,7 @@ config TEGRA30_EMC config TEGRA124_EMC tristate "NVIDIA Tegra124 External Memory Controller driver" - default y + default ARCH_TEGRA_124_SOC depends on ARCH_TEGRA_124_SOC || COMPILE_TEST select TEGRA124_CLK_EMC if ARCH_TEGRA select PM_OPP diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile index 0750847dac3c..6334601e6120 100644 --- a/drivers/memory/tegra/Makefile +++ b/drivers/memory/tegra/Makefile @@ -10,6 +10,7 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o tegra-mc-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o tegra-mc-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186.o tegra194.o tegra-mc-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra186.o tegra234.o +tegra-mc-$(CONFIG_ARCH_TEGRA_264_SOC) += tegra186.o tegra264.o obj-$(CONFIG_TEGRA_MC) += tegra-mc.o @@ -21,5 +22,6 @@ obj-$(CONFIG_TEGRA210_EMC) += tegra210-emc.o obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186-emc.o obj-$(CONFIG_ARCH_TEGRA_194_SOC) += tegra186-emc.o obj-$(CONFIG_ARCH_TEGRA_234_SOC) += tegra186-emc.o +obj-$(CONFIG_ARCH_TEGRA_264_SOC) += tegra186-emc.o tegra210-emc-y := tegra210-emc-core.o tegra210-emc-cc-r21021.o diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 592907546ee6..6edb210287dc 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2014-2025 NVIDIA CORPORATION. All rights reserved. */ #include <linux/clk.h> @@ -11,10 +11,11 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/sort.h> +#include <linux/tegra-icc.h> #include <soc/tegra/fuse.h> @@ -48,6 +49,9 @@ static const struct of_device_id tegra_mc_of_match[] = { #ifdef CONFIG_ARCH_TEGRA_234_SOC { .compatible = "nvidia,tegra234-mc", .data = &tegra234_mc_soc }, #endif +#ifdef CONFIG_ARCH_TEGRA_264_SOC + { .compatible = "nvidia,tegra264-mc", .data = &tegra264_mc_soc }, +#endif { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, tegra_mc_of_match); @@ -449,7 +453,6 @@ static int load_one_timing(struct tegra_mc *mc, static int load_timings(struct tegra_mc *mc, struct device_node *node) { - struct device_node *child; struct tegra_mc_timing *timing; int child_count = of_get_child_count(node); int i = 0, err; @@ -461,14 +464,12 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node) mc->num_timings = child_count; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { timing = &mc->timings[i++]; err = load_one_timing(mc, timing, child); - if (err) { - of_node_put(child); + if (err) return err; - } } return 0; @@ -476,7 +477,6 @@ static int load_timings(struct tegra_mc *mc, struct device_node *node) static int tegra_mc_setup_timings(struct tegra_mc *mc) { - struct device_node *node; u32 ram_code, node_ram_code; int err; @@ -484,14 +484,13 @@ static int tegra_mc_setup_timings(struct tegra_mc *mc) mc->num_timings = 0; - for_each_child_of_node(mc->dev->of_node, node) { + for_each_child_of_node_scoped(mc->dev->of_node, node) { err = of_property_read_u32(node, "nvidia,ram-code", &node_ram_code); if (err || (node_ram_code != ram_code)) continue; err = load_timings(mc, node); - of_node_put(node); if (err) return err; break; @@ -754,6 +753,43 @@ const char *const tegra_mc_error_names[8] = { [6] = "SMMU translation error", }; +struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec, void *data) +{ + struct tegra_mc *mc = icc_provider_to_tegra_mc(data); + struct icc_node *node; + + list_for_each_entry(node, &mc->provider.nodes, node_list) { + if (node->id == spec->args[0]) + return node; + } + + /* + * If a client driver calls devm_of_icc_get() before the MC driver + * is probed, then return EPROBE_DEFER to the client driver. + */ + return ERR_PTR(-EPROBE_DEFER); +} + +static int tegra_mc_icc_get(struct icc_node *node, u32 *average, u32 *peak) +{ + *average = 0; + *peak = 0; + + return 0; +} + +static int tegra_mc_icc_set(struct icc_node *src, struct icc_node *dst) +{ + return 0; +} + +const struct tegra_mc_icc_ops tegra_mc_icc_ops = { + .xlate = tegra_mc_icc_xlate, + .aggregate = icc_std_aggregate, + .get_bw = tegra_mc_icc_get, + .set = tegra_mc_icc_set, +}; + /* * Memory Controller (MC) has few Memory Clients that are issuing memory * bandwidth allocation requests to the MC interconnect provider. The MC @@ -792,18 +828,16 @@ static int tegra_mc_interconnect_setup(struct tegra_mc *mc) mc->provider.data = &mc->provider; mc->provider.set = mc->soc->icc_ops->set; mc->provider.aggregate = mc->soc->icc_ops->aggregate; + mc->provider.get_bw = mc->soc->icc_ops->get_bw; + mc->provider.xlate = mc->soc->icc_ops->xlate; mc->provider.xlate_extended = mc->soc->icc_ops->xlate_extended; - err = icc_provider_add(&mc->provider); - if (err) - return err; + icc_provider_init(&mc->provider); /* create Memory Controller node */ node = icc_node_create(TEGRA_ICC_MC); - if (IS_ERR(node)) { - err = PTR_ERR(node); - goto del_provider; - } + if (IS_ERR(node)) + return PTR_ERR(node); node->name = "Memory Controller"; icc_node_add(node, &mc->provider); @@ -828,18 +862,39 @@ static int tegra_mc_interconnect_setup(struct tegra_mc *mc) err = icc_link_create(node, TEGRA_ICC_MC); if (err) goto remove_nodes; + + node->data = (struct tegra_mc_client *)&(mc->soc->clients[i]); } + err = icc_provider_register(&mc->provider); + if (err) + goto remove_nodes; + return 0; remove_nodes: icc_nodes_remove(&mc->provider); -del_provider: - icc_provider_del(&mc->provider); return err; } +static void tegra_mc_num_channel_enabled(struct tegra_mc *mc) +{ + unsigned int i; + u32 value; + + value = mc_ch_readl(mc, 0, MC_EMEM_ADR_CFG_CHANNEL_ENABLE); + if (value <= 0) { + mc->num_channels = mc->soc->num_channels; + return; + } + + for (i = 0; i < 32; i++) { + if (value & BIT(i)) + mc->num_channels++; + } +} + static int tegra_mc_probe(struct platform_device *pdev) { struct tegra_mc *mc; @@ -878,6 +933,8 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } + tegra_mc_num_channel_enabled(mc); + if (mc->soc->ops && mc->soc->ops->handle_irq) { mc->irq = platform_get_irq(pdev, 0); if (mc->irq < 0) @@ -920,35 +977,6 @@ static int tegra_mc_probe(struct platform_device *pdev) } } - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { - mc->gart = tegra_gart_probe(&pdev->dev, mc); - if (IS_ERR(mc->gart)) { - dev_err(&pdev->dev, "failed to probe GART: %ld\n", - PTR_ERR(mc->gart)); - mc->gart = NULL; - } - } - - return 0; -} - -static int __maybe_unused tegra_mc_suspend(struct device *dev) -{ - struct tegra_mc *mc = dev_get_drvdata(dev); - - if (mc->soc->ops && mc->soc->ops->suspend) - return mc->soc->ops->suspend(mc); - - return 0; -} - -static int __maybe_unused tegra_mc_resume(struct device *dev) -{ - struct tegra_mc *mc = dev_get_drvdata(dev); - - if (mc->soc->ops && mc->soc->ops->resume) - return mc->soc->ops->resume(mc); - return 0; } @@ -961,15 +989,10 @@ static void tegra_mc_sync_state(struct device *dev) icc_sync_state(dev); } -static const struct dev_pm_ops tegra_mc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(tegra_mc_suspend, tegra_mc_resume) -}; - static struct platform_driver tegra_mc_driver = { .driver = { .name = "tegra-mc", .of_match_table = tegra_mc_of_match, - .pm = &tegra_mc_pm_ops, .suppress_bind_attrs = true, .sync_state = tegra_mc_sync_state, }, @@ -985,4 +1008,3 @@ arch_initcall(tegra_mc_init); MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index bc01586b6560..1d97cf4d3a94 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2014-2025 NVIDIA CORPORATION. All rights reserved. */ #ifndef MEMORY_TEGRA_MC_H @@ -53,6 +53,7 @@ #define MC_ERR_ROUTE_SANITY_ADR 0x9c4 #define MC_ERR_GENERALIZED_CARVEOUT_STATUS 0xc00 #define MC_ERR_GENERALIZED_CARVEOUT_ADR 0xc04 +#define MC_EMEM_ADR_CFG_CHANNEL_ENABLE 0xdf8 #define MC_GLOBAL_INTSTATUS 0xf24 #define MC_ERR_ADR_HI 0x11fc @@ -181,6 +182,10 @@ extern const struct tegra_mc_soc tegra194_mc_soc; extern const struct tegra_mc_soc tegra234_mc_soc; #endif +#ifdef CONFIG_ARCH_TEGRA_264_SOC +extern const struct tegra_mc_soc tegra264_mc_soc; +#endif + #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ defined(CONFIG_ARCH_TEGRA_114_SOC) || \ defined(CONFIG_ARCH_TEGRA_124_SOC) || \ @@ -192,7 +197,8 @@ extern const struct tegra_mc_ops tegra30_mc_ops; #if defined(CONFIG_ARCH_TEGRA_186_SOC) || \ defined(CONFIG_ARCH_TEGRA_194_SOC) || \ - defined(CONFIG_ARCH_TEGRA_234_SOC) + defined(CONFIG_ARCH_TEGRA_234_SOC) || \ + defined(CONFIG_ARCH_TEGRA_264_SOC) extern const struct tegra_mc_ops tegra186_mc_ops; #endif diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index 85bc936c02f9..9978ff911c47 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -571,8 +571,8 @@ static void emc_seq_wait_clkchange(struct tegra_emc *emc) dev_err(emc->dev, "clock change timed out\n"); } -static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, - unsigned long rate) +static struct emc_timing *tegra124_emc_find_timing(struct tegra_emc *emc, + unsigned long rate) { struct emc_timing *timing = NULL; unsigned int i; @@ -592,10 +592,10 @@ static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, return timing; } -static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, - unsigned long rate) +static int tegra124_emc_prepare_timing_change(struct tegra_emc *emc, + unsigned long rate) { - struct emc_timing *timing = tegra_emc_find_timing(emc, rate); + struct emc_timing *timing = tegra124_emc_find_timing(emc, rate); struct emc_timing *last = &emc->last_timing; enum emc_dll_change dll_change; unsigned int pre_wait = 0; @@ -820,10 +820,10 @@ static int tegra_emc_prepare_timing_change(struct tegra_emc *emc, return 0; } -static void tegra_emc_complete_timing_change(struct tegra_emc *emc, - unsigned long rate) +static void tegra124_emc_complete_timing_change(struct tegra_emc *emc, + unsigned long rate) { - struct emc_timing *timing = tegra_emc_find_timing(emc, rate); + struct emc_timing *timing = tegra124_emc_find_timing(emc, rate); struct emc_timing *last = &emc->last_timing; u32 val; @@ -896,7 +896,7 @@ static void emc_read_current_timing(struct tegra_emc *emc, timing->emc_mode_reset = 0; } -static int emc_init(struct tegra_emc *emc) +static void emc_init(struct tegra_emc *emc) { emc->dram_type = readl(emc->regs + EMC_FBIO_CFG5); @@ -913,8 +913,6 @@ static int emc_init(struct tegra_emc *emc) emc->dram_num = tegra_mc_get_emem_device_count(emc->mc); emc_read_current_timing(emc, &emc->last_timing); - - return 0; } static int load_one_timing_from_dt(struct tegra_emc *emc, @@ -988,11 +986,10 @@ static int cmp_timings(const void *_a, const void *_b) return 1; } -static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, - struct device_node *node) +static int tegra124_emc_load_timings_from_dt(struct tegra_emc *emc, + struct device_node *node) { int child_count = of_get_child_count(node); - struct device_node *child; struct emc_timing *timing; unsigned int i = 0; int err; @@ -1004,14 +1001,12 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, emc->num_timings = child_count; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { timing = &emc->timings[i++]; err = load_one_timing_from_dt(emc, timing, child); - if (err) { - of_node_put(child); + if (err) return err; - } } sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, @@ -1020,15 +1015,15 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, return 0; } -static const struct of_device_id tegra_emc_of_match[] = { +static const struct of_device_id tegra124_emc_of_match[] = { { .compatible = "nvidia,tegra124-emc" }, { .compatible = "nvidia,tegra132-emc" }, {} }; -MODULE_DEVICE_TABLE(of, tegra_emc_of_match); +MODULE_DEVICE_TABLE(of, tegra124_emc_of_match); static struct device_node * -tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) +tegra124_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) { struct device_node *np; int err; @@ -1046,7 +1041,7 @@ tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code) return NULL; } -static void tegra_emc_rate_requests_init(struct tegra_emc *emc) +static void tegra124_emc_rate_requests_init(struct tegra_emc *emc) { unsigned int i; @@ -1148,7 +1143,7 @@ static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate, * valid range. */ -static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) +static bool tegra124_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) { unsigned int i; @@ -1159,8 +1154,8 @@ static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) return false; } -static int tegra_emc_debug_available_rates_show(struct seq_file *s, - void *data) +static int tegra124_emc_debug_available_rates_show(struct seq_file *s, + void *data) { struct tegra_emc *emc = s->private; const char *prefix = ""; @@ -1176,9 +1171,9 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s, return 0; } -DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates); +DEFINE_SHOW_ATTRIBUTE(tegra124_emc_debug_available_rates); -static int tegra_emc_debug_min_rate_get(void *data, u64 *rate) +static int tegra124_emc_debug_min_rate_get(void *data, u64 *rate) { struct tegra_emc *emc = data; @@ -1187,12 +1182,12 @@ static int tegra_emc_debug_min_rate_get(void *data, u64 *rate) return 0; } -static int tegra_emc_debug_min_rate_set(void *data, u64 rate) +static int tegra124_emc_debug_min_rate_set(void *data, u64 rate) { struct tegra_emc *emc = data; int err; - if (!tegra_emc_validate_rate(emc, rate)) + if (!tegra124_emc_validate_rate(emc, rate)) return -EINVAL; err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG); @@ -1204,11 +1199,11 @@ static int tegra_emc_debug_min_rate_set(void *data, u64 rate) return 0; } -DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_min_rate_fops, - tegra_emc_debug_min_rate_get, - tegra_emc_debug_min_rate_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(tegra124_emc_debug_min_rate_fops, + tegra124_emc_debug_min_rate_get, + tegra124_emc_debug_min_rate_set, "%llu\n"); -static int tegra_emc_debug_max_rate_get(void *data, u64 *rate) +static int tegra124_emc_debug_max_rate_get(void *data, u64 *rate) { struct tegra_emc *emc = data; @@ -1217,12 +1212,12 @@ static int tegra_emc_debug_max_rate_get(void *data, u64 *rate) return 0; } -static int tegra_emc_debug_max_rate_set(void *data, u64 rate) +static int tegra124_emc_debug_max_rate_set(void *data, u64 rate) { struct tegra_emc *emc = data; int err; - if (!tegra_emc_validate_rate(emc, rate)) + if (!tegra124_emc_validate_rate(emc, rate)) return -EINVAL; err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG); @@ -1234,9 +1229,9 @@ static int tegra_emc_debug_max_rate_set(void *data, u64 rate) return 0; } -DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_max_rate_fops, - tegra_emc_debug_max_rate_get, - tegra_emc_debug_max_rate_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(tegra124_emc_debug_max_rate_fops, + tegra124_emc_debug_max_rate_get, + tegra124_emc_debug_max_rate_set, "%llu\n"); static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc) { @@ -1271,11 +1266,11 @@ static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc) emc->debugfs.root = debugfs_create_dir("emc", NULL); debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, - &tegra_emc_debug_available_rates_fops); + &tegra124_emc_debug_available_rates_fops); debugfs_create_file("min_rate", 0644, emc->debugfs.root, - emc, &tegra_emc_debug_min_rate_fops); + emc, &tegra124_emc_debug_min_rate_fops); debugfs_create_file("max_rate", 0644, emc->debugfs.root, - emc, &tegra_emc_debug_max_rate_fops); + emc, &tegra124_emc_debug_max_rate_fops); } static inline struct tegra_emc * @@ -1285,7 +1280,7 @@ to_tegra_emc_provider(struct icc_provider *provider) } static struct icc_node_data * -emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data) +emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data) { struct icc_provider *provider = data; struct icc_node_data *ndata; @@ -1339,7 +1334,7 @@ static int emc_icc_set(struct icc_node *src, struct icc_node *dst) return 0; } -static int tegra_emc_interconnect_init(struct tegra_emc *emc) +static int tegra124_emc_interconnect_init(struct tegra_emc *emc) { const struct tegra_mc_soc *soc = emc->mc->soc; struct icc_node *node; @@ -1351,16 +1346,12 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc) emc->provider.aggregate = soc->icc_ops->aggregate; emc->provider.xlate_extended = emc_of_icc_xlate_extended; - err = icc_provider_add(&emc->provider); - if (err) - goto err_msg; + icc_provider_init(&emc->provider); /* create External Memory Controller node */ node = icc_node_create(TEGRA_ICC_EMC); - if (IS_ERR(node)) { - err = PTR_ERR(node); - goto del_provider; - } + if (IS_ERR(node)) + return PTR_ERR(node); node->name = "External Memory Controller"; icc_node_add(node, &emc->provider); @@ -1380,36 +1371,36 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc) node->name = "External Memory (DRAM)"; icc_node_add(node, &emc->provider); + err = icc_provider_register(&emc->provider); + if (err) + goto remove_nodes; + return 0; remove_nodes: icc_nodes_remove(&emc->provider); -del_provider: - icc_provider_del(&emc->provider); -err_msg: - dev_err(emc->dev, "failed to initialize ICC: %d\n", err); - return err; + return dev_err_probe(emc->dev, err, "failed to initialize ICC\n"); } -static int tegra_emc_opp_table_init(struct tegra_emc *emc) +static int tegra124_emc_opp_table_init(struct tegra_emc *emc) { u32 hw_version = BIT(tegra_sku_info.soc_speedo_id); int opp_token, err; err = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1); - if (err < 0) { - dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err); - return err; - } + if (err < 0) + return dev_err_probe(emc->dev, err, "failed to set OPP supported HW\n"); + opp_token = err; err = dev_pm_opp_of_add_table(emc->dev); if (err) { if (err == -ENODEV) - dev_err(emc->dev, "OPP table not found, please update your device tree\n"); + dev_err_probe(emc->dev, err, + "OPP table not found, please update your device tree\n"); else - dev_err(emc->dev, "failed to add OPP table: %d\n", err); + dev_err_probe(emc->dev, err, "failed to add OPP table\n"); goto put_hw_table; } @@ -1420,7 +1411,7 @@ static int tegra_emc_opp_table_init(struct tegra_emc *emc) /* first dummy rate-set initializes voltage state */ err = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk)); if (err) { - dev_err(emc->dev, "failed to initialize OPP clock: %d\n", err); + dev_err_probe(emc->dev, err, "failed to initialize OPP clock\n"); goto remove_table; } @@ -1434,12 +1425,12 @@ put_hw_table: return err; } -static void devm_tegra_emc_unset_callback(void *data) +static void devm_tegra124_emc_unset_callback(void *data) { tegra124_clk_set_emc_callbacks(NULL, NULL); } -static int tegra_emc_probe(struct platform_device *pdev) +static int tegra124_emc_probe(struct platform_device *pdev) { struct device_node *np; struct tegra_emc *emc; @@ -1463,9 +1454,9 @@ static int tegra_emc_probe(struct platform_device *pdev) ram_code = tegra_read_ram_code(); - np = tegra_emc_find_node_by_ram_code(pdev->dev.of_node, ram_code); + np = tegra124_emc_find_node_by_ram_code(pdev->dev.of_node, ram_code); if (np) { - err = tegra_emc_load_timings_from_dt(emc, np); + err = tegra124_emc_load_timings_from_dt(emc, np); of_node_put(np); if (err) return err; @@ -1475,39 +1466,33 @@ static int tegra_emc_probe(struct platform_device *pdev) ram_code); } - err = emc_init(emc); - if (err) { - dev_err(&pdev->dev, "EMC initialization failed: %d\n", err); - return err; - } + emc_init(emc); platform_set_drvdata(pdev, emc); - tegra124_clk_set_emc_callbacks(tegra_emc_prepare_timing_change, - tegra_emc_complete_timing_change); + tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change, + tegra124_emc_complete_timing_change); - err = devm_add_action_or_reset(&pdev->dev, devm_tegra_emc_unset_callback, + err = devm_add_action_or_reset(&pdev->dev, devm_tegra124_emc_unset_callback, NULL); if (err) return err; emc->clk = devm_clk_get(&pdev->dev, "emc"); - if (IS_ERR(emc->clk)) { - err = PTR_ERR(emc->clk); - dev_err(&pdev->dev, "failed to get EMC clock: %d\n", err); - return err; - } + if (IS_ERR(emc->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(emc->clk), + "failed to get EMC clock\n"); - err = tegra_emc_opp_table_init(emc); + err = tegra124_emc_opp_table_init(emc); if (err) return err; - tegra_emc_rate_requests_init(emc); + tegra124_emc_rate_requests_init(emc); if (IS_ENABLED(CONFIG_DEBUG_FS)) emc_debugfs_init(&pdev->dev, emc); - tegra_emc_interconnect_init(emc); + tegra124_emc_interconnect_init(emc); /* * Don't allow the kernel module to be unloaded. Unloading adds some @@ -1519,16 +1504,16 @@ static int tegra_emc_probe(struct platform_device *pdev) return 0; }; -static struct platform_driver tegra_emc_driver = { - .probe = tegra_emc_probe, +static struct platform_driver tegra124_emc_driver = { + .probe = tegra124_emc_probe, .driver = { .name = "tegra-emc", - .of_match_table = tegra_emc_of_match, + .of_match_table = tegra124_emc_of_match, .suppress_bind_attrs = true, .sync_state = icc_sync_state, }, }; -module_platform_driver(tegra_emc_driver); +module_platform_driver(tegra124_emc_driver); MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); MODULE_DESCRIPTION("NVIDIA Tegra124 EMC driver"); diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index d780a84241fe..9d7393e19f12 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -4,7 +4,7 @@ */ #include <linux/of.h> -#include <linux/of_device.h> +#include <linux/device.h> #include <linux/slab.h> #include <dt-bindings/memory/tegra124-mc.h> @@ -1170,7 +1170,7 @@ static int tegra124_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw, } static struct icc_node_data * -tegra124_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data) +tegra124_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data) { struct tegra_mc *mc = icc_provider_to_tegra_mc(data); const struct tegra_mc_client *client; diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c index 26e763bde92a..dfddceecdd1a 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -1,15 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2019 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2019-2025 NVIDIA CORPORATION. All rights reserved. */ #include <linux/clk.h> #include <linux/debugfs.h> #include <linux/module.h> #include <linux/mod_devicetable.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <soc/tegra/bpmp.h> +#include "mc.h" struct tegra186_emc_dvfs { unsigned long latency; @@ -29,6 +31,8 @@ struct tegra186_emc { unsigned long min_rate; unsigned long max_rate; } debugfs; + + struct icc_provider provider; }; /* @@ -146,32 +150,13 @@ DEFINE_DEBUGFS_ATTRIBUTE(tegra186_emc_debug_max_rate_fops, tegra186_emc_debug_max_rate_get, tegra186_emc_debug_max_rate_set, "%llu\n"); -static int tegra186_emc_probe(struct platform_device *pdev) +static int tegra186_emc_get_emc_dvfs_latency(struct tegra186_emc *emc) { struct mrq_emc_dvfs_latency_response response; struct tegra_bpmp_message msg; - struct tegra186_emc *emc; unsigned int i; int err; - emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL); - if (!emc) - return -ENOMEM; - - emc->bpmp = tegra_bpmp_get(&pdev->dev); - if (IS_ERR(emc->bpmp)) - return dev_err_probe(&pdev->dev, PTR_ERR(emc->bpmp), "failed to get BPMP\n"); - - emc->clk = devm_clk_get(&pdev->dev, "emc"); - if (IS_ERR(emc->clk)) { - err = PTR_ERR(emc->clk); - dev_err(&pdev->dev, "failed to get EMC clock: %d\n", err); - goto put_bpmp; - } - - platform_set_drvdata(pdev, emc); - emc->dev = &pdev->dev; - memset(&msg, 0, sizeof(msg)); msg.mrq = MRQ_EMC_DVFS_LATENCY; msg.tx.data = NULL; @@ -181,13 +166,12 @@ static int tegra186_emc_probe(struct platform_device *pdev) err = tegra_bpmp_transfer(emc->bpmp, &msg); if (err < 0) { - dev_err(&pdev->dev, "failed to EMC DVFS pairs: %d\n", err); - goto put_bpmp; + dev_err(emc->dev, "failed to EMC DVFS pairs: %d\n", err); + return err; } if (msg.rx.ret < 0) { - err = -EINVAL; - dev_err(&pdev->dev, "EMC DVFS MRQ failed: %d (BPMP error code)\n", msg.rx.ret); - goto put_bpmp; + dev_err(emc->dev, "EMC DVFS MRQ failed: %d (BPMP error code)\n", msg.rx.ret); + return -EINVAL; } emc->debugfs.min_rate = ULONG_MAX; @@ -195,14 +179,11 @@ static int tegra186_emc_probe(struct platform_device *pdev) emc->num_dvfs = response.num_pairs; - emc->dvfs = devm_kmalloc_array(&pdev->dev, emc->num_dvfs, - sizeof(*emc->dvfs), GFP_KERNEL); - if (!emc->dvfs) { - err = -ENOMEM; - goto put_bpmp; - } + emc->dvfs = devm_kmalloc_array(emc->dev, emc->num_dvfs, sizeof(*emc->dvfs), GFP_KERNEL); + if (!emc->dvfs) + return -ENOMEM; - dev_dbg(&pdev->dev, "%u DVFS pairs:\n", emc->num_dvfs); + dev_dbg(emc->dev, "%u DVFS pairs:\n", emc->num_dvfs); for (i = 0; i < emc->num_dvfs; i++) { emc->dvfs[i].rate = response.pairs[i].freq * 1000; @@ -214,27 +195,173 @@ static int tegra186_emc_probe(struct platform_device *pdev) if (emc->dvfs[i].rate > emc->debugfs.max_rate) emc->debugfs.max_rate = emc->dvfs[i].rate; - dev_dbg(&pdev->dev, " %2u: %lu Hz -> %lu us\n", i, + dev_dbg(emc->dev, " %2u: %lu Hz -> %lu us\n", i, emc->dvfs[i].rate, emc->dvfs[i].latency); } - err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, - emc->debugfs.max_rate); + err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, emc->debugfs.max_rate); if (err < 0) { - dev_err(&pdev->dev, - "failed to set rate range [%lu-%lu] for %pC\n", - emc->debugfs.min_rate, emc->debugfs.max_rate, - emc->clk); - goto put_bpmp; + dev_err(emc->dev, "failed to set rate range [%lu-%lu] for %pC\n", + emc->debugfs.min_rate, emc->debugfs.max_rate, emc->clk); + return err; } emc->debugfs.root = debugfs_create_dir("emc", NULL); - debugfs_create_file("available_rates", S_IRUGO, emc->debugfs.root, - emc, &tegra186_emc_debug_available_rates_fops); - debugfs_create_file("min_rate", S_IRUGO | S_IWUSR, emc->debugfs.root, - emc, &tegra186_emc_debug_min_rate_fops); - debugfs_create_file("max_rate", S_IRUGO | S_IWUSR, emc->debugfs.root, - emc, &tegra186_emc_debug_max_rate_fops); + debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, + &tegra186_emc_debug_available_rates_fops); + debugfs_create_file("min_rate", 0644, emc->debugfs.root, emc, + &tegra186_emc_debug_min_rate_fops); + debugfs_create_file("max_rate", 0644, emc->debugfs.root, emc, + &tegra186_emc_debug_max_rate_fops); + + return 0; +} + +/* + * tegra186_emc_icc_set_bw() - Set BW api for EMC provider + * @src: ICC node for External Memory Controller (EMC) + * @dst: ICC node for External Memory (DRAM) + * + * Do nothing here as info to BPMP-FW is now passed in the BW set function + * of the MC driver. BPMP-FW sets the final Freq based on the passed values. + */ +static int tegra186_emc_icc_set_bw(struct icc_node *src, struct icc_node *dst) +{ + return 0; +} + +static struct icc_node * +tegra186_emc_of_icc_xlate(const struct of_phandle_args *spec, void *data) +{ + struct icc_provider *provider = data; + struct icc_node *node; + + /* External Memory is the only possible ICC route */ + list_for_each_entry(node, &provider->nodes, node_list) { + if (node->id != TEGRA_ICC_EMEM) + continue; + + return node; + } + + return ERR_PTR(-EPROBE_DEFER); +} + +static int tegra186_emc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *peak) +{ + *avg = 0; + *peak = 0; + + return 0; +} + +static int tegra186_emc_interconnect_init(struct tegra186_emc *emc) +{ + struct tegra_mc *mc = dev_get_drvdata(emc->dev->parent); + const struct tegra_mc_soc *soc = mc->soc; + struct icc_node *node; + int err; + + emc->provider.dev = emc->dev; + emc->provider.set = tegra186_emc_icc_set_bw; + emc->provider.data = &emc->provider; + emc->provider.aggregate = soc->icc_ops->aggregate; + emc->provider.xlate = tegra186_emc_of_icc_xlate; + emc->provider.get_bw = tegra186_emc_icc_get_init_bw; + + icc_provider_init(&emc->provider); + + /* create External Memory Controller node */ + node = icc_node_create(TEGRA_ICC_EMC); + if (IS_ERR(node)) + return PTR_ERR(node); + + node->name = "External Memory Controller"; + icc_node_add(node, &emc->provider); + + /* link External Memory Controller to External Memory (DRAM) */ + err = icc_link_create(node, TEGRA_ICC_EMEM); + if (err) + goto remove_nodes; + + /* create External Memory node */ + node = icc_node_create(TEGRA_ICC_EMEM); + if (IS_ERR(node)) { + err = PTR_ERR(node); + goto remove_nodes; + } + + node->name = "External Memory (DRAM)"; + icc_node_add(node, &emc->provider); + + err = icc_provider_register(&emc->provider); + if (err) + goto remove_nodes; + + return 0; + +remove_nodes: + icc_nodes_remove(&emc->provider); + + return dev_err_probe(emc->dev, err, "failed to initialize ICC\n"); +} + +static int tegra186_emc_probe(struct platform_device *pdev) +{ + struct tegra_mc *mc = dev_get_drvdata(pdev->dev.parent); + struct tegra186_emc *emc; + int err; + + emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL); + if (!emc) + return -ENOMEM; + + emc->bpmp = tegra_bpmp_get(&pdev->dev); + if (IS_ERR(emc->bpmp)) + return dev_err_probe(&pdev->dev, PTR_ERR(emc->bpmp), + "failed to get BPMP\n"); + + emc->clk = devm_clk_get(&pdev->dev, "emc"); + if (IS_ERR(emc->clk)) { + err = dev_err_probe(&pdev->dev, PTR_ERR(emc->clk), + "failed to get EMC clock\n"); + goto put_bpmp; + } + + platform_set_drvdata(pdev, emc); + emc->dev = &pdev->dev; + + if (tegra_bpmp_mrq_is_supported(emc->bpmp, MRQ_EMC_DVFS_LATENCY)) { + err = tegra186_emc_get_emc_dvfs_latency(emc); + if (err) + goto put_bpmp; + } + + if (mc && mc->soc->icc_ops) { + if (tegra_bpmp_mrq_is_supported(emc->bpmp, MRQ_BWMGR_INT)) { + mc->bwmgr_mrq_supported = true; + + /* + * MC driver probe can't get BPMP reference as it gets probed + * earlier than BPMP. So, save the BPMP ref got from the EMC + * DT node in the mc->bpmp and use it in MC's icc_set hook. + */ + mc->bpmp = emc->bpmp; + barrier(); + } + + /* + * Initialize the ICC even if BPMP-FW doesn't support 'MRQ_BWMGR_INT'. + * Use the flag 'mc->bwmgr_mrq_supported' within MC driver and return + * EINVAL instead of passing the request to BPMP-FW later when the BW + * request is made by client with 'icc_set_bw()' call. + */ + err = tegra186_emc_interconnect_init(emc); + if (err) { + mc->bpmp = NULL; + goto put_bpmp; + } + } return 0; @@ -243,14 +370,15 @@ put_bpmp: return err; } -static int tegra186_emc_remove(struct platform_device *pdev) +static void tegra186_emc_remove(struct platform_device *pdev) { + struct tegra_mc *mc = dev_get_drvdata(pdev->dev.parent); struct tegra186_emc *emc = platform_get_drvdata(pdev); debugfs_remove_recursive(emc->debugfs.root); - tegra_bpmp_put(emc->bpmp); - return 0; + mc->bpmp = NULL; + tegra_bpmp_put(emc->bpmp); } static const struct of_device_id tegra186_emc_of_match[] = { @@ -263,6 +391,9 @@ static const struct of_device_id tegra186_emc_of_match[] = { #if defined(CONFIG_ARCH_TEGRA_234_SOC) { .compatible = "nvidia,tegra234-emc" }, #endif +#if defined(CONFIG_ARCH_TEGRA_264_SOC) + { .compatible = "nvidia,tegra264-emc" }, +#endif { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, tegra186_emc_of_match); @@ -272,6 +403,7 @@ static struct platform_driver tegra186_emc_driver = { .name = "tegra186-emc", .of_match_table = tegra186_emc_of_match, .suppress_bind_attrs = true, + .sync_state = icc_sync_state, }, .probe = tegra186_emc_probe, .remove = tegra186_emc_remove, @@ -280,4 +412,3 @@ module_platform_driver(tegra186_emc_driver); MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); MODULE_DESCRIPTION("NVIDIA Tegra186 External Memory Controller driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index 7bb73f06fad3..aee11457bf8e 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -1,13 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2017-2021 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2017-2025 NVIDIA CORPORATION. All rights reserved. */ #include <linux/io.h> #include <linux/iommu.h> #include <linux/module.h> #include <linux/mod_devicetable.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <soc/tegra/mc.h> @@ -25,11 +26,24 @@ static int tegra186_mc_probe(struct tegra_mc *mc) { struct platform_device *pdev = to_platform_device(mc->dev); + struct resource *res; unsigned int i; char name[8]; int err; - mc->bcast_ch_regs = devm_platform_ioremap_resource_byname(pdev, "broadcast"); + /* + * From Tegra264, the SID region is not present in MC node and BROADCAST is first. + * The common function 'tegra_mc_probe()' already maps first region entry from DT. + * Check if the SID region is present in DT then map BROADCAST. Otherwise, consider + * the first entry mapped in mc probe as the BROADCAST region. This is done to avoid + * mapping the region twice when SID is not present and keep backward compatibility. + */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sid"); + if (res) + mc->bcast_ch_regs = devm_platform_ioremap_resource_byname(pdev, "broadcast"); + else + mc->bcast_ch_regs = mc->regs; + if (IS_ERR(mc->bcast_ch_regs)) { if (PTR_ERR(mc->bcast_ch_regs) == -EINVAL) { dev_warn(&pdev->dev, @@ -74,6 +88,9 @@ static void tegra186_mc_client_sid_override(struct tegra_mc *mc, { u32 value, old; + if (client->regs.sid.security == 0 && client->regs.sid.override == 0) + return; + value = readl(mc->regs + client->regs.sid.security); if ((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0) { /* @@ -110,9 +127,12 @@ static void tegra186_mc_client_sid_override(struct tegra_mc *mc, static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev) { #if IS_ENABLED(CONFIG_IOMMU_API) - struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev); struct of_phandle_args args; unsigned int i, index = 0; + u32 sid; + + if (!tegra_dev_iommu_get_stream_id(dev, &sid)) + return 0; while (!of_parse_phandle_with_args(dev->of_node, "interconnects", "#interconnect-cells", index, &args)) { @@ -120,11 +140,10 @@ static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev) for (i = 0; i < mc->soc->num_clients; i++) { const struct tegra_mc_client *client = &mc->soc->clients[i]; - if (client->id == args.args[0]) { - u32 sid = fwspec->ids[0] & MC_SID_STREAMID_OVERRIDE_MASK; - - tegra186_mc_client_sid_override(mc, client, sid); - } + if (client->id == args.args[0]) + tegra186_mc_client_sid_override( + mc, client, + sid & MC_SID_STREAMID_OVERRIDE_MASK); } } @@ -135,9 +154,25 @@ static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev) return 0; } +static int tegra186_mc_resume(struct tegra_mc *mc) +{ +#if IS_ENABLED(CONFIG_IOMMU_API) + unsigned int i; + + for (i = 0; i < mc->soc->num_clients; i++) { + const struct tegra_mc_client *client = &mc->soc->clients[i]; + + tegra186_mc_client_sid_override(mc, client, client->sid); + } +#endif + + return 0; +} + const struct tegra_mc_ops tegra186_mc_ops = { .probe = tegra186_mc_probe, .remove = tegra186_mc_remove, + .resume = tegra186_mc_resume, .probe_device = tegra186_mc_probe_device, .handle_irq = tegra30_mc_handle_irq, }; diff --git a/drivers/memory/tegra/tegra194.c b/drivers/memory/tegra/tegra194.c index b2416ee3ac26..26035ac3a1eb 100644 --- a/drivers/memory/tegra/tegra194.c +++ b/drivers/memory/tegra/tegra194.c @@ -1355,6 +1355,7 @@ const struct tegra_mc_soc tegra194_mc_soc = { MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, .has_addr_hi_reg = true, .ops = &tegra186_mc_ops, + .icc_ops = &tegra_mc_icc_ops, .ch_intmask = 0x00000f00, .global_intstatus_channel_shift = 8, }; diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c index bd4e37b6552d..398cb8ae2e38 100644 --- a/drivers/memory/tegra/tegra20-emc.c +++ b/drivers/memory/tegra/tegra20-emc.c @@ -232,7 +232,7 @@ struct tegra_emc { bool mrr_error; }; -static irqreturn_t tegra_emc_isr(int irq, void *data) +static irqreturn_t tegra20_emc_isr(int irq, void *data) { struct tegra_emc *emc = data; u32 intmask = EMC_REFRESH_OVERFLOW_INT; @@ -253,8 +253,8 @@ static irqreturn_t tegra_emc_isr(int irq, void *data) return IRQ_HANDLED; } -static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, - unsigned long rate) +static struct emc_timing *tegra20_emc_find_timing(struct tegra_emc *emc, + unsigned long rate) { struct emc_timing *timing = NULL; unsigned int i; @@ -276,7 +276,7 @@ static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) { - struct emc_timing *timing = tegra_emc_find_timing(emc, rate); + struct emc_timing *timing = tegra20_emc_find_timing(emc, rate); unsigned int i; if (!timing) @@ -321,8 +321,8 @@ static int emc_complete_timing_change(struct tegra_emc *emc, bool flush) return 0; } -static int tegra_emc_clk_change_notify(struct notifier_block *nb, - unsigned long msg, void *data) +static int tegra20_emc_clk_change_notify(struct notifier_block *nb, + unsigned long msg, void *data) { struct tegra_emc *emc = container_of(nb, struct tegra_emc, clk_nb); struct clk_notifier_data *cnd = data; @@ -407,10 +407,9 @@ static int cmp_timings(const void *_a, const void *_b) return 0; } -static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, - struct device_node *node) +static int tegra20_emc_load_timings_from_dt(struct tegra_emc *emc, + struct device_node *node) { - struct device_node *child; struct emc_timing *timing; int child_count; int err; @@ -428,15 +427,13 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, timing = emc->timings; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { if (of_node_name_eq(child, "lpddr2")) continue; err = load_one_timing_from_dt(emc, timing++, child); - if (err) { - of_node_put(child); + if (err) return err; - } emc->num_timings++; } @@ -455,7 +452,7 @@ static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, } static struct device_node * -tegra_emc_find_node_by_ram_code(struct tegra_emc *emc) +tegra20_emc_find_node_by_ram_code(struct tegra_emc *emc) { struct device *dev = emc->dev; struct device_node *np; @@ -477,14 +474,15 @@ tegra_emc_find_node_by_ram_code(struct tegra_emc *emc) ram_code = tegra_read_ram_code(); - for (np = of_find_node_by_name(dev->of_node, "emc-tables"); np; - np = of_find_node_by_name(np, "emc-tables")) { + for_each_child_of_node(dev->of_node, np) { + if (!of_node_name_eq(np, "emc-tables")) + continue; err = of_property_read_u32(np, "nvidia,ram-code", &value); if (err || value != ram_code) { struct device_node *lpddr2_np; bool cfg_mismatches = false; - lpddr2_np = of_find_node_by_name(np, "lpddr2"); + lpddr2_np = of_get_child_by_name(np, "lpddr2"); if (lpddr2_np) { const struct lpddr2_info *info; @@ -521,7 +519,6 @@ tegra_emc_find_node_by_ram_code(struct tegra_emc *emc) } if (cfg_mismatches) { - of_node_put(np); continue; } } @@ -713,7 +710,7 @@ static long emc_round_rate(unsigned long rate, return timing->rate; } -static void tegra_emc_rate_requests_init(struct tegra_emc *emc) +static void tegra20_emc_rate_requests_init(struct tegra_emc *emc) { unsigned int i; @@ -815,7 +812,7 @@ static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate, * valid range. */ -static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) +static bool tegra20_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) { unsigned int i; @@ -826,7 +823,7 @@ static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) return false; } -static int tegra_emc_debug_available_rates_show(struct seq_file *s, void *data) +static int tegra20_emc_debug_available_rates_show(struct seq_file *s, void *data) { struct tegra_emc *emc = s->private; const char *prefix = ""; @@ -841,9 +838,9 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s, void *data) return 0; } -DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates); +DEFINE_SHOW_ATTRIBUTE(tegra20_emc_debug_available_rates); -static int tegra_emc_debug_min_rate_get(void *data, u64 *rate) +static int tegra20_emc_debug_min_rate_get(void *data, u64 *rate) { struct tegra_emc *emc = data; @@ -852,12 +849,12 @@ static int tegra_emc_debug_min_rate_get(void *data, u64 *rate) return 0; } -static int tegra_emc_debug_min_rate_set(void *data, u64 rate) +static int tegra20_emc_debug_min_rate_set(void *data, u64 rate) { struct tegra_emc *emc = data; int err; - if (!tegra_emc_validate_rate(emc, rate)) + if (!tegra20_emc_validate_rate(emc, rate)) return -EINVAL; err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG); @@ -869,11 +866,11 @@ static int tegra_emc_debug_min_rate_set(void *data, u64 rate) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_min_rate_fops, - tegra_emc_debug_min_rate_get, - tegra_emc_debug_min_rate_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(tegra20_emc_debug_min_rate_fops, + tegra20_emc_debug_min_rate_get, + tegra20_emc_debug_min_rate_set, "%llu\n"); -static int tegra_emc_debug_max_rate_get(void *data, u64 *rate) +static int tegra20_emc_debug_max_rate_get(void *data, u64 *rate) { struct tegra_emc *emc = data; @@ -882,12 +879,12 @@ static int tegra_emc_debug_max_rate_get(void *data, u64 *rate) return 0; } -static int tegra_emc_debug_max_rate_set(void *data, u64 rate) +static int tegra20_emc_debug_max_rate_set(void *data, u64 rate) { struct tegra_emc *emc = data; int err; - if (!tegra_emc_validate_rate(emc, rate)) + if (!tegra20_emc_validate_rate(emc, rate)) return -EINVAL; err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG); @@ -899,11 +896,11 @@ static int tegra_emc_debug_max_rate_set(void *data, u64 rate) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(tegra_emc_debug_max_rate_fops, - tegra_emc_debug_max_rate_get, - tegra_emc_debug_max_rate_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(tegra20_emc_debug_max_rate_fops, + tegra20_emc_debug_max_rate_get, + tegra20_emc_debug_max_rate_set, "%llu\n"); -static void tegra_emc_debugfs_init(struct tegra_emc *emc) +static void tegra20_emc_debugfs_init(struct tegra_emc *emc) { struct device *dev = emc->dev; unsigned int i; @@ -936,11 +933,11 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc) emc->debugfs.root = debugfs_create_dir("emc", NULL); debugfs_create_file("available_rates", 0444, emc->debugfs.root, - emc, &tegra_emc_debug_available_rates_fops); + emc, &tegra20_emc_debug_available_rates_fops); debugfs_create_file("min_rate", 0644, emc->debugfs.root, - emc, &tegra_emc_debug_min_rate_fops); + emc, &tegra20_emc_debug_min_rate_fops); debugfs_create_file("max_rate", 0644, emc->debugfs.root, - emc, &tegra_emc_debug_max_rate_fops); + emc, &tegra20_emc_debug_max_rate_fops); } static inline struct tegra_emc * @@ -950,7 +947,7 @@ to_tegra_emc_provider(struct icc_provider *provider) } static struct icc_node_data * -emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data) +emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data) { struct icc_provider *provider = data; struct icc_node_data *ndata; @@ -1003,7 +1000,7 @@ static int emc_icc_set(struct icc_node *src, struct icc_node *dst) return 0; } -static int tegra_emc_interconnect_init(struct tegra_emc *emc) +static int tegra20_emc_interconnect_init(struct tegra_emc *emc) { const struct tegra_mc_soc *soc; struct icc_node *node; @@ -1021,16 +1018,12 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc) emc->provider.aggregate = soc->icc_ops->aggregate; emc->provider.xlate_extended = emc_of_icc_xlate_extended; - err = icc_provider_add(&emc->provider); - if (err) - goto err_msg; + icc_provider_init(&emc->provider); /* create External Memory Controller node */ node = icc_node_create(TEGRA_ICC_EMC); - if (IS_ERR(node)) { - err = PTR_ERR(node); - goto del_provider; - } + if (IS_ERR(node)) + return PTR_ERR(node); node->name = "External Memory Controller"; icc_node_add(node, &emc->provider); @@ -1050,63 +1043,60 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc) node->name = "External Memory (DRAM)"; icc_node_add(node, &emc->provider); + err = icc_provider_register(&emc->provider); + if (err) + goto remove_nodes; + return 0; remove_nodes: icc_nodes_remove(&emc->provider); -del_provider: - icc_provider_del(&emc->provider); -err_msg: - dev_err(emc->dev, "failed to initialize ICC: %d\n", err); - return err; + return dev_err_probe(emc->dev, err, "failed to initialize ICC\n"); } -static void devm_tegra_emc_unset_callback(void *data) +static void devm_tegra20_emc_unset_callback(void *data) { tegra20_clk_set_emc_round_callback(NULL, NULL); } -static void devm_tegra_emc_unreg_clk_notifier(void *data) +static void devm_tegra20_emc_unreg_clk_notifier(void *data) { struct tegra_emc *emc = data; clk_notifier_unregister(emc->clk, &emc->clk_nb); } -static int tegra_emc_init_clk(struct tegra_emc *emc) +static int tegra20_emc_init_clk(struct tegra_emc *emc) { int err; tegra20_clk_set_emc_round_callback(emc_round_rate, emc); - err = devm_add_action_or_reset(emc->dev, devm_tegra_emc_unset_callback, + err = devm_add_action_or_reset(emc->dev, devm_tegra20_emc_unset_callback, NULL); if (err) return err; emc->clk = devm_clk_get(emc->dev, NULL); - if (IS_ERR(emc->clk)) { - dev_err(emc->dev, "failed to get EMC clock: %pe\n", emc->clk); - return PTR_ERR(emc->clk); - } + if (IS_ERR(emc->clk)) + return dev_err_probe(emc->dev, PTR_ERR(emc->clk), + "failed to get EMC clock\n"); err = clk_notifier_register(emc->clk, &emc->clk_nb); - if (err) { - dev_err(emc->dev, "failed to register clk notifier: %d\n", err); - return err; - } + if (err) + return dev_err_probe(emc->dev, err, "failed to register clk notifier\n"); err = devm_add_action_or_reset(emc->dev, - devm_tegra_emc_unreg_clk_notifier, emc); + devm_tegra20_emc_unreg_clk_notifier, emc); if (err) return err; return 0; } -static int tegra_emc_devfreq_target(struct device *dev, unsigned long *freq, - u32 flags) +static int tegra20_emc_devfreq_target(struct device *dev, unsigned long *freq, + u32 flags) { struct tegra_emc *emc = dev_get_drvdata(dev); struct dev_pm_opp *opp; @@ -1124,8 +1114,8 @@ static int tegra_emc_devfreq_target(struct device *dev, unsigned long *freq, return emc_set_min_rate(emc, rate, EMC_RATE_DEVFREQ); } -static int tegra_emc_devfreq_get_dev_status(struct device *dev, - struct devfreq_dev_status *stat) +static int tegra20_emc_devfreq_get_dev_status(struct device *dev, + struct devfreq_dev_status *stat) { struct tegra_emc *emc = dev_get_drvdata(dev); @@ -1147,13 +1137,13 @@ static int tegra_emc_devfreq_get_dev_status(struct device *dev, return 0; } -static struct devfreq_dev_profile tegra_emc_devfreq_profile = { +static struct devfreq_dev_profile tegra20_emc_devfreq_profile = { .polling_ms = 30, - .target = tegra_emc_devfreq_target, - .get_dev_status = tegra_emc_devfreq_get_dev_status, + .target = tegra20_emc_devfreq_target, + .get_dev_status = tegra20_emc_devfreq_get_dev_status, }; -static int tegra_emc_devfreq_init(struct tegra_emc *emc) +static int tegra20_emc_devfreq_init(struct tegra_emc *emc) { struct devfreq *devfreq; @@ -1175,18 +1165,17 @@ static int tegra_emc_devfreq_init(struct tegra_emc *emc) writel_relaxed(0x00000000, emc->regs + EMC_STAT_LLMC_CONTROL); writel_relaxed(0xffffffff, emc->regs + EMC_STAT_PWR_CLOCK_LIMIT); - devfreq = devm_devfreq_add_device(emc->dev, &tegra_emc_devfreq_profile, + devfreq = devm_devfreq_add_device(emc->dev, &tegra20_emc_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND, &emc->ondemand_data); - if (IS_ERR(devfreq)) { - dev_err(emc->dev, "failed to initialize devfreq: %pe", devfreq); - return PTR_ERR(devfreq); - } + if (IS_ERR(devfreq)) + return dev_err_probe(emc->dev, PTR_ERR(devfreq), + "failed to initialize devfreq\n"); return 0; } -static int tegra_emc_probe(struct platform_device *pdev) +static int tegra20_emc_probe(struct platform_device *pdev) { struct tegra_core_opp_params opp_params = {}; struct device_node *np; @@ -1194,17 +1183,15 @@ static int tegra_emc_probe(struct platform_device *pdev) int irq, err; irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "please update your device tree\n"); + if (irq < 0) return irq; - } emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL); if (!emc) return -ENOMEM; mutex_init(&emc->rate_lock); - emc->clk_nb.notifier_call = tegra_emc_clk_change_notify; + emc->clk_nb.notifier_call = tegra20_emc_clk_change_notify; emc->dev = &pdev->dev; emc->regs = devm_platform_ioremap_resource(pdev, 0); @@ -1215,22 +1202,22 @@ static int tegra_emc_probe(struct platform_device *pdev) if (err) return err; - np = tegra_emc_find_node_by_ram_code(emc); + np = tegra20_emc_find_node_by_ram_code(emc); if (np) { - err = tegra_emc_load_timings_from_dt(emc, np); + err = tegra20_emc_load_timings_from_dt(emc, np); of_node_put(np); if (err) return err; } - err = devm_request_irq(&pdev->dev, irq, tegra_emc_isr, 0, + err = devm_request_irq(&pdev->dev, irq, tegra20_emc_isr, 0, dev_name(&pdev->dev), emc); if (err) { dev_err(&pdev->dev, "failed to request IRQ: %d\n", err); return err; } - err = tegra_emc_init_clk(emc); + err = tegra20_emc_init_clk(emc); if (err) return err; @@ -1241,10 +1228,10 @@ static int tegra_emc_probe(struct platform_device *pdev) return err; platform_set_drvdata(pdev, emc); - tegra_emc_rate_requests_init(emc); - tegra_emc_debugfs_init(emc); - tegra_emc_interconnect_init(emc); - tegra_emc_devfreq_init(emc); + tegra20_emc_rate_requests_init(emc); + tegra20_emc_debugfs_init(emc); + tegra20_emc_interconnect_init(emc); + tegra20_emc_devfreq_init(emc); /* * Don't allow the kernel module to be unloaded. Unloading adds some @@ -1256,22 +1243,22 @@ static int tegra_emc_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id tegra_emc_of_match[] = { +static const struct of_device_id tegra20_emc_of_match[] = { { .compatible = "nvidia,tegra20-emc", }, {}, }; -MODULE_DEVICE_TABLE(of, tegra_emc_of_match); +MODULE_DEVICE_TABLE(of, tegra20_emc_of_match); -static struct platform_driver tegra_emc_driver = { - .probe = tegra_emc_probe, +static struct platform_driver tegra20_emc_driver = { + .probe = tegra20_emc_probe, .driver = { .name = "tegra20-emc", - .of_match_table = tegra_emc_of_match, + .of_match_table = tegra20_emc_of_match, .suppress_bind_attrs = true, .sync_state = icc_sync_state, }, }; -module_platform_driver(tegra_emc_driver); +module_platform_driver(tegra20_emc_driver); MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>"); MODULE_DESCRIPTION("NVIDIA Tegra20 EMC driver"); diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index fcd7738fcb53..a3022e715dee 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c @@ -5,8 +5,9 @@ #include <linux/bitfield.h> #include <linux/delay.h> +#include <linux/device.h> #include <linux/mutex.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/slab.h> #include <linux/string.h> @@ -389,7 +390,7 @@ static int tegra20_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw, } static struct icc_node_data * -tegra20_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data) +tegra20_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data) { struct tegra_mc *mc = icc_provider_to_tegra_mc(data); unsigned int i, idx = spec->args[0]; @@ -687,32 +688,6 @@ static int tegra20_mc_probe(struct tegra_mc *mc) return 0; } -static int tegra20_mc_suspend(struct tegra_mc *mc) -{ - int err; - - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { - err = tegra_gart_suspend(mc->gart); - if (err < 0) - return err; - } - - return 0; -} - -static int tegra20_mc_resume(struct tegra_mc *mc) -{ - int err; - - if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && mc->gart) { - err = tegra_gart_resume(mc->gart); - if (err < 0) - return err; - } - - return 0; -} - static irqreturn_t tegra20_mc_handle_irq(int irq, void *data) { struct tegra_mc *mc = data; @@ -788,8 +763,6 @@ static irqreturn_t tegra20_mc_handle_irq(int irq, void *data) static const struct tegra_mc_ops tegra20_mc_ops = { .probe = tegra20_mc_probe, - .suspend = tegra20_mc_suspend, - .resume = tegra20_mc_resume, .handle_irq = tegra20_mc_handle_irq, }; diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index cc76adb8d7e8..a30a646ec468 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -75,29 +75,29 @@ enum { * The division portion of the average operation. */ #define __AVERAGE_PTFV(dev) \ - ({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] = \ - next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \ + ({ next->ptfv_list[(dev)] = \ + next->ptfv_list[(dev)] / \ next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; }) /* * Convert val to fixed point and add it to the temporary average. */ #define __INCREMENT_PTFV(dev, val) \ - ({ next->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] += \ + ({ next->ptfv_list[(dev)] += \ ((val) * MOVAVG_PRECISION_FACTOR); }) /* * Convert a moving average back to integral form and return the value. */ #define __MOVAVG_AC(timing, dev) \ - ((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX] / \ + ((timing)->ptfv_list[(dev)] / \ MOVAVG_PRECISION_FACTOR) /* Weighted update. */ #define __WEIGHTED_UPDATE_PTFV(dev, nval) \ do { \ int w = PTFV_MOVAVG_WEIGHT_INDEX; \ - int dqs = PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX; \ + int dqs = (dev); \ \ next->ptfv_list[dqs] = \ ((nval * MOVAVG_PRECISION_FACTOR) + \ @@ -105,315 +105,91 @@ enum { next->ptfv_list[w])) / \ (next->ptfv_list[w] + 1); \ \ - emc_dbg(emc, EMA_UPDATES, "%s: (s=%lu) EMA: %u\n", \ + emc_dbg(emc, EMA_UPDATES, "%s: (s=%u) EMA: %u\n", \ __stringify(dev), nval, next->ptfv_list[dqs]); \ } while (0) /* Access a particular average. */ #define __MOVAVG(timing, dev) \ - ((timing)->ptfv_list[PTFV_DQSOSC_MOVAVG_ ## dev ## _INDEX]) + ((timing)->ptfv_list[(dev)]) -static u32 update_clock_tree_delay(struct tegra210_emc *emc, int type) +static bool tegra210_emc_compare_update_delay(struct tegra210_emc_timing *timing, + u32 measured, u32 idx) { - bool periodic_training_update = type == PERIODIC_TRAINING_UPDATE; - struct tegra210_emc_timing *last = emc->last; - struct tegra210_emc_timing *next = emc->next; - u32 last_timing_rate_mhz = last->rate / 1000; - u32 next_timing_rate_mhz = next->rate / 1000; - bool dvfs_update = type == DVFS_UPDATE; - s32 tdel = 0, tmdel = 0, adel = 0; - bool dvfs_pt1 = type == DVFS_PT1; - unsigned long cval = 0; - u32 temp[2][2], value; - unsigned int i; - - /* - * Dev0 MSB. - */ - if (dvfs_pt1 || periodic_training_update) { - value = tegra210_emc_mrr_read(emc, 2, 19); - - for (i = 0; i < emc->num_channels; i++) { - temp[i][0] = (value & 0x00ff) << 8; - temp[i][1] = (value & 0xff00) << 0; - value >>= 16; - } - - /* - * Dev0 LSB. - */ - value = tegra210_emc_mrr_read(emc, 2, 18); - - for (i = 0; i < emc->num_channels; i++) { - temp[i][0] |= (value & 0x00ff) >> 0; - temp[i][1] |= (value & 0xff00) >> 8; - value >>= 16; - } - } - - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[0][0]; - } + u32 *curr = &timing->current_dram_clktree[idx]; + u32 rate_mhz = timing->rate / 1000; + u32 tmdel; - if (dvfs_pt1) - __INCREMENT_PTFV(C0D0U0, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C0D0U0); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C0D0U0, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C0D0U0] - - __MOVAVG_AC(next, C0D0U0); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C0D0U0] = - __MOVAVG_AC(next, C0D0U0); - } + tmdel = abs(*curr - measured); - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[0][1]; + if (tmdel * 128 * rate_mhz / 1000000 > timing->tree_margin) { + *curr = measured; + return true; } - if (dvfs_pt1) - __INCREMENT_PTFV(C0D0U1, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C0D0U1); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C0D0U1, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C0D0U1] - - __MOVAVG_AC(next, C0D0U1); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C0D0U1] = - __MOVAVG_AC(next, C0D0U1); - } - - if (emc->num_channels > 1) { - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[1][0]; - } - - if (dvfs_pt1) - __INCREMENT_PTFV(C1D0U0, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C1D0U0); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C1D0U0, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C1D0U0] - - __MOVAVG_AC(next, C1D0U0); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C1D0U0] = - __MOVAVG_AC(next, C1D0U0); - } - - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[1][1]; - } - - if (dvfs_pt1) - __INCREMENT_PTFV(C1D0U1, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C1D0U1); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C1D0U1, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C1D0U1] - - __MOVAVG_AC(next, C1D0U1); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C1D0U1] = - __MOVAVG_AC(next, C1D0U1); - } - } - - if (emc->num_devices < 2) - goto done; - - /* - * Dev1 MSB. - */ - if (dvfs_pt1 || periodic_training_update) { - value = tegra210_emc_mrr_read(emc, 1, 19); + return false; +} - for (i = 0; i < emc->num_channels; i++) { - temp[i][0] = (value & 0x00ff) << 8; - temp[i][1] = (value & 0xff00) << 0; - value >>= 16; - } +static void tegra210_emc_get_clktree_delay(struct tegra210_emc *emc, + u32 delay[DRAM_CLKTREE_NUM]) +{ + struct tegra210_emc_timing *curr = emc->last; + u32 rate_mhz = curr->rate / 1000; + u32 msb, lsb, dqsosc, delay_us; + unsigned int c, d, idx; + unsigned long clocks; - /* - * Dev1 LSB. - */ - value = tegra210_emc_mrr_read(emc, 2, 18); + clocks = tegra210_emc_actual_osc_clocks(curr->run_clocks); + delay_us = 2 + (clocks / rate_mhz); - for (i = 0; i < emc->num_channels; i++) { - temp[i][0] |= (value & 0x00ff) >> 0; - temp[i][1] |= (value & 0xff00) >> 8; - value >>= 16; - } - } + tegra210_emc_start_periodic_compensation(emc); + udelay(delay_us); - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[0][0]; - } + for (d = 0; d < emc->num_devices; d++) { + /* Read DQSOSC from MRR18/19 */ + msb = tegra210_emc_mrr_read(emc, 2 - d, 19); + lsb = tegra210_emc_mrr_read(emc, 2 - d, 18); - if (dvfs_pt1) - __INCREMENT_PTFV(C0D1U0, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C0D1U0); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C0D1U0, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C0D1U0] - - __MOVAVG_AC(next, C0D1U0); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C0D1U0] = - __MOVAVG_AC(next, C0D1U0); - } + for (c = 0; c < emc->num_channels; c++) { + /* C[c]D[d]U[0] */ + idx = c * 4 + d * 2; - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[0][1]; - } + dqsosc = (msb & 0x00ff) << 8; + dqsosc |= (lsb & 0x00ff) >> 0; - if (dvfs_pt1) - __INCREMENT_PTFV(C0D1U1, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C0D1U1); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C0D1U1, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C0D1U1] - - __MOVAVG_AC(next, C0D1U1); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C0D1U1] = - __MOVAVG_AC(next, C0D1U1); - } + /* Check for unpopulated channels */ + if (dqsosc) + delay[idx] = (clocks * 1000000) / + (rate_mhz * 2 * dqsosc); - if (emc->num_channels > 1) { - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[1][0]; - } + /* C[c]D[d]U[1] */ + idx++; - if (dvfs_pt1) - __INCREMENT_PTFV(C1D1U0, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C1D1U0); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C1D1U0, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C1D1U0] - - __MOVAVG_AC(next, C1D1U0); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C1D1U0] = - __MOVAVG_AC(next, C1D1U0); - } + dqsosc = (msb & 0xff00) << 0; + dqsosc |= (lsb & 0xff00) >> 8; - if (dvfs_pt1 || periodic_training_update) { - cval = tegra210_emc_actual_osc_clocks(last->run_clocks); - cval *= 1000000; - cval /= last_timing_rate_mhz * 2 * temp[1][1]; - } + /* Check for unpopulated channels */ + if (dqsosc) + delay[idx] = (clocks * 1000000) / + (rate_mhz * 2 * dqsosc); - if (dvfs_pt1) - __INCREMENT_PTFV(C1D1U1, cval); - else if (dvfs_update) - __AVERAGE_PTFV(C1D1U1); - else if (periodic_training_update) - __WEIGHTED_UPDATE_PTFV(C1D1U1, cval); - - if (dvfs_update || periodic_training_update) { - tdel = next->current_dram_clktree[C1D1U1] - - __MOVAVG_AC(next, C1D1U1); - tmdel = (tdel < 0) ? -1 * tdel : tdel; - - if (tmdel > adel) - adel = tmdel; - - if (tmdel * 128 * next_timing_rate_mhz / 1000000 > - next->tree_margin) - next->current_dram_clktree[C1D1U1] = - __MOVAVG_AC(next, C1D1U1); + msb >>= 16; + lsb >>= 16; } } - -done: - return adel; } -static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, - struct tegra210_emc_timing *last, - struct tegra210_emc_timing *next) +static bool periodic_compensation_handler(struct tegra210_emc *emc, u32 type, + struct tegra210_emc_timing *last, + struct tegra210_emc_timing *next) { #define __COPY_EMA(nt, lt, dev) \ ({ __MOVAVG(nt, dev) = __MOVAVG(lt, dev) * \ (nt)->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; }) - u32 i, adel = 0, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; - u32 delay; - - delay = tegra210_emc_actual_osc_clocks(last->run_clocks); - delay *= 1000; - delay = 2 + (delay / last->rate); + u32 i, samples = next->ptfv_list[PTFV_DVFS_SAMPLES_INDEX]; + u32 delay[DRAM_CLKTREE_NUM], idx; + bool over = false; if (!next->periodic_training) return 0; @@ -427,57 +203,46 @@ static u32 periodic_compensation_handler(struct tegra210_emc *emc, u32 type, * calibration then we can reuse the previous * frequencies EMA data. */ - __COPY_EMA(next, last, C0D0U0); - __COPY_EMA(next, last, C0D0U1); - __COPY_EMA(next, last, C1D0U0); - __COPY_EMA(next, last, C1D0U1); - __COPY_EMA(next, last, C0D1U0); - __COPY_EMA(next, last, C0D1U1); - __COPY_EMA(next, last, C1D1U0); - __COPY_EMA(next, last, C1D1U1); + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) + __COPY_EMA(next, last, idx); } else { /* Reset the EMA.*/ - __MOVAVG(next, C0D0U0) = 0; - __MOVAVG(next, C0D0U1) = 0; - __MOVAVG(next, C1D0U0) = 0; - __MOVAVG(next, C1D0U1) = 0; - __MOVAVG(next, C0D1U0) = 0; - __MOVAVG(next, C0D1U1) = 0; - __MOVAVG(next, C1D1U0) = 0; - __MOVAVG(next, C1D1U1) = 0; + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) + __MOVAVG(next, idx) = 0; for (i = 0; i < samples; i++) { - tegra210_emc_start_periodic_compensation(emc); - udelay(delay); + /* Generate next sample of data. */ + tegra210_emc_get_clktree_delay(emc, delay); - /* - * Generate next sample of data. - */ - adel = update_clock_tree_delay(emc, DVFS_PT1); + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) + __INCREMENT_PTFV(idx, delay[idx]); } } - /* - * Seems like it should be part of the - * 'if (last_timing->periodic_training)' conditional - * since is already done for the else clause. - */ - adel = update_clock_tree_delay(emc, DVFS_UPDATE); + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) { + /* Do the division part of the moving average */ + __AVERAGE_PTFV(idx); + over |= tegra210_emc_compare_update_delay(next, + __MOVAVG_AC(next, idx), idx); + } } if (type == PERIODIC_TRAINING_SEQUENCE) { - tegra210_emc_start_periodic_compensation(emc); - udelay(delay); + tegra210_emc_get_clktree_delay(emc, delay); - adel = update_clock_tree_delay(emc, PERIODIC_TRAINING_UPDATE); + for (idx = 0; idx < DRAM_CLKTREE_NUM; idx++) { + __WEIGHTED_UPDATE_PTFV(idx, delay[idx]); + over |= tegra210_emc_compare_update_delay(next, + __MOVAVG_AC(next, idx), idx); + } } - return adel; + return over; } static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc) { - u32 emc_cfg, emc_cfg_o, emc_cfg_update, del, value; + u32 emc_cfg, emc_cfg_o, emc_cfg_update, value; static const u32 list[] = { EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_0, EMC_PMACRO_OB_DDLL_LONG_DQ_RANK0_1, @@ -492,7 +257,6 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc) }; struct tegra210_emc_timing *last = emc->last; unsigned int items = ARRAY_SIZE(list), i; - unsigned long delay; if (last->periodic_training) { emc_dbg(emc, PER_TRAIN, "Periodic training starting\n"); @@ -530,30 +294,18 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc) /* * 2. osc kick off - this assumes training and dvfs have set * correct MR23. - */ - tegra210_emc_start_periodic_compensation(emc); - - /* + * * 3. Let dram capture its clock tree delays. - */ - delay = tegra210_emc_actual_osc_clocks(last->run_clocks); - delay *= 1000; - delay /= last->rate + 1; - udelay(delay); - - /* + * * 4. Check delta wrt previous values (save value if margin * exceeds what is set in table). */ - del = periodic_compensation_handler(emc, - PERIODIC_TRAINING_SEQUENCE, - last, last); - + if (periodic_compensation_handler(emc, PERIODIC_TRAINING_SEQUENCE, + last, last)) { /* * 5. Apply compensation w.r.t. trained values (if clock tree * has drifted more than the set margin). */ - if (last->tree_margin < ((del * 128 * (last->rate / 1000)) / 1000000)) { for (i = 0; i < items; i++) { value = tegra210_emc_compensate(last, list[i]); emc_dbg(emc, EMA_WRITES, "0x%08x <= 0x%08x\n", @@ -734,16 +486,7 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc) EMC_EMC_STATUS_DRAM_IN_SELF_REFRESH_MASK, 0); - tegra210_emc_start_periodic_compensation(emc); - - delay = 1000 * tegra210_emc_actual_osc_clocks(last->run_clocks); - udelay((delay / last->rate) + 2); - - value = periodic_compensation_handler(emc, DVFS_SEQUENCE, fake, - next); - value = (value * 128 * next->rate / 1000) / 1000000; - - if (next->periodic_training && value > next->tree_margin) + if (periodic_compensation_handler(emc, DVFS_SEQUENCE, fake, next)) compensate_trimmer_applicable = true; } diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c index ae5f982f861b..e96ca4157d48 100644 --- a/drivers/memory/tegra/tegra210-emc-core.c +++ b/drivers/memory/tegra/tegra210-emc-core.c @@ -9,10 +9,10 @@ #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_platform.h> #include <linux/of_reserved_mem.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/thermal.h> #include <soc/tegra/fuse.h> @@ -558,7 +558,7 @@ tegra210_emc_table_register_offsets = { static void tegra210_emc_train(struct timer_list *timer) { - struct tegra210_emc *emc = from_timer(emc, timer, training); + struct tegra210_emc *emc = timer_container_of(emc, timer, training); unsigned long flags; if (!emc->last) @@ -583,7 +583,7 @@ static void tegra210_emc_training_start(struct tegra210_emc *emc) static void tegra210_emc_training_stop(struct tegra210_emc *emc) { - del_timer(&emc->training); + timer_delete(&emc->training); } static unsigned int tegra210_emc_get_temperature(struct tegra210_emc *emc) @@ -614,7 +614,8 @@ static unsigned int tegra210_emc_get_temperature(struct tegra210_emc *emc) static void tegra210_emc_poll_refresh(struct timer_list *timer) { - struct tegra210_emc *emc = from_timer(emc, timer, refresh_timer); + struct tegra210_emc *emc = timer_container_of(emc, timer, + refresh_timer); unsigned int temperature; if (!emc->debugfs.temperature) @@ -666,7 +667,7 @@ reset: static void tegra210_emc_poll_refresh_stop(struct tegra210_emc *emc) { atomic_set(&emc->refresh_poll, 0); - del_timer_sync(&emc->refresh_timer); + timer_delete_sync(&emc->refresh_timer); } static void tegra210_emc_poll_refresh_start(struct tegra210_emc *emc) @@ -1985,15 +1986,13 @@ release: return err; } -static int tegra210_emc_remove(struct platform_device *pdev) +static void tegra210_emc_remove(struct platform_device *pdev) { struct tegra210_emc *emc = platform_get_drvdata(pdev); debugfs_remove_recursive(emc->debugfs.root); tegra210_clk_emc_detach(emc->clk); of_reserved_mem_device_release(emc->dev); - - return 0; } static int __maybe_unused tegra210_emc_suspend(struct device *dev) diff --git a/drivers/memory/tegra/tegra210-emc-table.c b/drivers/memory/tegra/tegra210-emc-table.c index 3e0598363b87..34a8785d2861 100644 --- a/drivers/memory/tegra/tegra210-emc-table.c +++ b/drivers/memory/tegra/tegra210-emc-table.c @@ -22,8 +22,6 @@ static int tegra210_emc_table_device_init(struct reserved_mem *rmem, return -ENOMEM; } - count = 0; - for (i = 0; i < TEGRA_EMC_MAX_FREQS; i++) { if (timings[i].revision == 0) break; diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index 8ab6498dbe7d..3c2949c16fde 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -9,11 +9,11 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { { - .id = 0x00, + .id = TEGRA210_MC_PTCR, .name = "ptcr", .swgroup = TEGRA_SWGROUP_PTC, }, { - .id = 0x01, + .id = TEGRA210_MC_DISPLAY0A, .name = "display0a", .swgroup = TEGRA_SWGROUP_DC, .regs = { @@ -29,7 +29,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x02, + .id = TEGRA210_MC_DISPLAY0AB, .name = "display0ab", .swgroup = TEGRA_SWGROUP_DCB, .regs = { @@ -45,7 +45,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x03, + .id = TEGRA210_MC_DISPLAY0B, .name = "display0b", .swgroup = TEGRA_SWGROUP_DC, .regs = { @@ -61,7 +61,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x04, + .id = TEGRA210_MC_DISPLAY0BB, .name = "display0bb", .swgroup = TEGRA_SWGROUP_DCB, .regs = { @@ -77,7 +77,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x05, + .id = TEGRA210_MC_DISPLAY0C, .name = "display0c", .swgroup = TEGRA_SWGROUP_DC, .regs = { @@ -93,7 +93,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x06, + .id = TEGRA210_MC_DISPLAY0CB, .name = "display0cb", .swgroup = TEGRA_SWGROUP_DCB, .regs = { @@ -109,7 +109,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x0e, + .id = TEGRA210_MC_AFIR, .name = "afir", .swgroup = TEGRA_SWGROUP_AFI, .regs = { @@ -125,7 +125,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x0f, + .id = TEGRA210_MC_AVPCARM7R, .name = "avpcarm7r", .swgroup = TEGRA_SWGROUP_AVPC, .regs = { @@ -141,7 +141,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x10, + .id = TEGRA210_MC_DISPLAYHC, .name = "displayhc", .swgroup = TEGRA_SWGROUP_DC, .regs = { @@ -157,7 +157,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x11, + .id = TEGRA210_MC_DISPLAYHCB, .name = "displayhcb", .swgroup = TEGRA_SWGROUP_DCB, .regs = { @@ -173,7 +173,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x15, + .id = TEGRA210_MC_HDAR, .name = "hdar", .swgroup = TEGRA_SWGROUP_HDA, .regs = { @@ -189,7 +189,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x16, + .id = TEGRA210_MC_HOST1XDMAR, .name = "host1xdmar", .swgroup = TEGRA_SWGROUP_HC, .regs = { @@ -205,7 +205,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x17, + .id = TEGRA210_MC_HOST1XR, .name = "host1xr", .swgroup = TEGRA_SWGROUP_HC, .regs = { @@ -221,7 +221,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x1c, + .id = TEGRA210_MC_NVENCSRD, .name = "nvencsrd", .swgroup = TEGRA_SWGROUP_NVENC, .regs = { @@ -237,7 +237,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x1d, + .id = TEGRA210_MC_PPCSAHBDMAR, .name = "ppcsahbdmar", .swgroup = TEGRA_SWGROUP_PPCS, .regs = { @@ -253,7 +253,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x1e, + .id = TEGRA210_MC_PPCSAHBSLVR, .name = "ppcsahbslvr", .swgroup = TEGRA_SWGROUP_PPCS, .regs = { @@ -269,7 +269,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x1f, + .id = TEGRA210_MC_SATAR, .name = "satar", .swgroup = TEGRA_SWGROUP_SATA, .regs = { @@ -285,7 +285,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x27, + .id = TEGRA210_MC_MPCORER, .name = "mpcorer", .swgroup = TEGRA_SWGROUP_MPCORE, .regs = { @@ -297,7 +297,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x2b, + .id = TEGRA210_MC_NVENCSWR, .name = "nvencswr", .swgroup = TEGRA_SWGROUP_NVENC, .regs = { @@ -313,7 +313,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x31, + .id = TEGRA210_MC_AFIW, .name = "afiw", .swgroup = TEGRA_SWGROUP_AFI, .regs = { @@ -329,7 +329,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x32, + .id = TEGRA210_MC_AVPCARM7W, .name = "avpcarm7w", .swgroup = TEGRA_SWGROUP_AVPC, .regs = { @@ -345,7 +345,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x35, + .id = TEGRA210_MC_HDAW, .name = "hdaw", .swgroup = TEGRA_SWGROUP_HDA, .regs = { @@ -361,7 +361,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x36, + .id = TEGRA210_MC_HOST1XW, .name = "host1xw", .swgroup = TEGRA_SWGROUP_HC, .regs = { @@ -377,7 +377,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x39, + .id = TEGRA210_MC_MPCOREW, .name = "mpcorew", .swgroup = TEGRA_SWGROUP_MPCORE, .regs = { @@ -389,7 +389,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x3b, + .id = TEGRA210_MC_PPCSAHBDMAW, .name = "ppcsahbdmaw", .swgroup = TEGRA_SWGROUP_PPCS, .regs = { @@ -405,7 +405,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x3c, + .id = TEGRA210_MC_PPCSAHBSLVW, .name = "ppcsahbslvw", .swgroup = TEGRA_SWGROUP_PPCS, .regs = { @@ -421,7 +421,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x3d, + .id = TEGRA210_MC_SATAW, .name = "sataw", .swgroup = TEGRA_SWGROUP_SATA, .regs = { @@ -437,7 +437,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x44, + .id = TEGRA210_MC_ISPRA, .name = "ispra", .swgroup = TEGRA_SWGROUP_ISP2, .regs = { @@ -453,7 +453,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x46, + .id = TEGRA210_MC_ISPWA, .name = "ispwa", .swgroup = TEGRA_SWGROUP_ISP2, .regs = { @@ -469,7 +469,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x47, + .id = TEGRA210_MC_ISPWB, .name = "ispwb", .swgroup = TEGRA_SWGROUP_ISP2, .regs = { @@ -485,7 +485,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x4a, + .id = TEGRA210_MC_XUSB_HOSTR, .name = "xusb_hostr", .swgroup = TEGRA_SWGROUP_XUSB_HOST, .regs = { @@ -501,7 +501,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x4b, + .id = TEGRA210_MC_XUSB_HOSTW, .name = "xusb_hostw", .swgroup = TEGRA_SWGROUP_XUSB_HOST, .regs = { @@ -517,7 +517,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x4c, + .id = TEGRA210_MC_XUSB_DEVR, .name = "xusb_devr", .swgroup = TEGRA_SWGROUP_XUSB_DEV, .regs = { @@ -533,7 +533,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x4d, + .id = TEGRA210_MC_XUSB_DEVW, .name = "xusb_devw", .swgroup = TEGRA_SWGROUP_XUSB_DEV, .regs = { @@ -549,7 +549,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x4e, + .id = TEGRA210_MC_ISPRAB, .name = "isprab", .swgroup = TEGRA_SWGROUP_ISP2B, .regs = { @@ -565,7 +565,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x50, + .id = TEGRA210_MC_ISPWAB, .name = "ispwab", .swgroup = TEGRA_SWGROUP_ISP2B, .regs = { @@ -581,7 +581,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x51, + .id = TEGRA210_MC_ISPWBB, .name = "ispwbb", .swgroup = TEGRA_SWGROUP_ISP2B, .regs = { @@ -597,7 +597,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x54, + .id = TEGRA210_MC_TSECSRD, .name = "tsecsrd", .swgroup = TEGRA_SWGROUP_TSEC, .regs = { @@ -613,7 +613,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x55, + .id = TEGRA210_MC_TSECSWR, .name = "tsecswr", .swgroup = TEGRA_SWGROUP_TSEC, .regs = { @@ -629,7 +629,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x56, + .id = TEGRA210_MC_A9AVPSCR, .name = "a9avpscr", .swgroup = TEGRA_SWGROUP_A9AVP, .regs = { @@ -645,7 +645,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x57, + .id = TEGRA210_MC_A9AVPSCW, .name = "a9avpscw", .swgroup = TEGRA_SWGROUP_A9AVP, .regs = { @@ -661,7 +661,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x58, + .id = TEGRA210_MC_GPUSRD, .name = "gpusrd", .swgroup = TEGRA_SWGROUP_GPU, .regs = { @@ -678,7 +678,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x59, + .id = TEGRA210_MC_GPUSWR, .name = "gpuswr", .swgroup = TEGRA_SWGROUP_GPU, .regs = { @@ -695,7 +695,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x5a, + .id = TEGRA210_MC_DISPLAYT, .name = "displayt", .swgroup = TEGRA_SWGROUP_DC, .regs = { @@ -711,7 +711,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x60, + .id = TEGRA210_MC_SDMMCRA, .name = "sdmmcra", .swgroup = TEGRA_SWGROUP_SDMMC1A, .regs = { @@ -727,7 +727,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x61, + .id = TEGRA210_MC_SDMMCRAA, .name = "sdmmcraa", .swgroup = TEGRA_SWGROUP_SDMMC2A, .regs = { @@ -743,7 +743,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x62, + .id = TEGRA210_MC_SDMMCR, .name = "sdmmcr", .swgroup = TEGRA_SWGROUP_SDMMC3A, .regs = { @@ -759,7 +759,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x63, + .id = TEGRA210_MC_SDMMCRAB, .swgroup = TEGRA_SWGROUP_SDMMC4A, .name = "sdmmcrab", .regs = { @@ -775,7 +775,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x64, + .id = TEGRA210_MC_SDMMCWA, .name = "sdmmcwa", .swgroup = TEGRA_SWGROUP_SDMMC1A, .regs = { @@ -791,7 +791,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x65, + .id = TEGRA210_MC_SDMMCWAA, .name = "sdmmcwaa", .swgroup = TEGRA_SWGROUP_SDMMC2A, .regs = { @@ -807,7 +807,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x66, + .id = TEGRA210_MC_SDMMCW, .name = "sdmmcw", .swgroup = TEGRA_SWGROUP_SDMMC3A, .regs = { @@ -823,7 +823,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x67, + .id = TEGRA210_MC_SDMMCWAB, .name = "sdmmcwab", .swgroup = TEGRA_SWGROUP_SDMMC4A, .regs = { @@ -839,7 +839,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x6c, + .id = TEGRA210_MC_VICSRD, .name = "vicsrd", .swgroup = TEGRA_SWGROUP_VIC, .regs = { @@ -855,7 +855,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x6d, + .id = TEGRA210_MC_VICSWR, .name = "vicswr", .swgroup = TEGRA_SWGROUP_VIC, .regs = { @@ -871,7 +871,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x72, + .id = TEGRA210_MC_VIW, .name = "viw", .swgroup = TEGRA_SWGROUP_VI, .regs = { @@ -887,7 +887,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x73, + .id = TEGRA210_MC_DISPLAYD, .name = "displayd", .swgroup = TEGRA_SWGROUP_DC, .regs = { @@ -903,7 +903,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x78, + .id = TEGRA210_MC_NVDECSRD, .name = "nvdecsrd", .swgroup = TEGRA_SWGROUP_NVDEC, .regs = { @@ -919,7 +919,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x79, + .id = TEGRA210_MC_NVDECSWR, .name = "nvdecswr", .swgroup = TEGRA_SWGROUP_NVDEC, .regs = { @@ -935,7 +935,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x7a, + .id = TEGRA210_MC_APER, .name = "aper", .swgroup = TEGRA_SWGROUP_APE, .regs = { @@ -951,7 +951,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x7b, + .id = TEGRA210_MC_APEW, .name = "apew", .swgroup = TEGRA_SWGROUP_APE, .regs = { @@ -967,7 +967,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x7e, + .id = TEGRA210_MC_NVJPGRD, .name = "nvjpgsrd", .swgroup = TEGRA_SWGROUP_NVJPG, .regs = { @@ -983,7 +983,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x7f, + .id = TEGRA210_MC_NVJPGWR, .name = "nvjpgswr", .swgroup = TEGRA_SWGROUP_NVJPG, .regs = { @@ -999,7 +999,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x80, + .id = TEGRA210_MC_SESRD, .name = "sesrd", .swgroup = TEGRA_SWGROUP_SE, .regs = { @@ -1015,7 +1015,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x81, + .id = TEGRA210_MC_SESWR, .name = "seswr", .swgroup = TEGRA_SWGROUP_SE, .regs = { @@ -1031,7 +1031,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x82, + .id = TEGRA210_MC_AXIAPR, .name = "axiapr", .swgroup = TEGRA_SWGROUP_AXIAP, .regs = { @@ -1047,7 +1047,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x83, + .id = TEGRA210_MC_AXIAPW, .name = "axiapw", .swgroup = TEGRA_SWGROUP_AXIAP, .regs = { @@ -1063,7 +1063,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x84, + .id = TEGRA210_MC_ETRR, .name = "etrr", .swgroup = TEGRA_SWGROUP_ETR, .regs = { @@ -1079,7 +1079,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x85, + .id = TEGRA210_MC_ETRW, .name = "etrw", .swgroup = TEGRA_SWGROUP_ETR, .regs = { @@ -1095,7 +1095,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x86, + .id = TEGRA210_MC_TSECSRDB, .name = "tsecsrdb", .swgroup = TEGRA_SWGROUP_TSECB, .regs = { @@ -1111,7 +1111,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x87, + .id = TEGRA210_MC_TSECSWRB, .name = "tsecswrb", .swgroup = TEGRA_SWGROUP_TSECB, .regs = { @@ -1127,7 +1127,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x88, + .id = TEGRA210_MC_GPUSRD2, .name = "gpusrd2", .swgroup = TEGRA_SWGROUP_GPU, .regs = { @@ -1144,7 +1144,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, }, }, { - .id = 0x89, + .id = TEGRA210_MC_GPUSWR2, .name = "gpuswr2", .swgroup = TEGRA_SWGROUP_GPU, .regs = { diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c index 02dcc5748bba..5f57cea48b62 100644 --- a/drivers/memory/tegra/tegra234.c +++ b/drivers/memory/tegra/tegra234.c @@ -1,18 +1,279 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2021-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2022-2023, NVIDIA CORPORATION. All rights reserved. */ #include <soc/tegra/mc.h> #include <dt-bindings/memory/tegra234-mc.h> +#include <linux/interconnect.h> +#include <linux/tegra-icc.h> +#include <soc/tegra/bpmp.h> #include "mc.h" +/* + * MC Client entries are sorted in the increasing order of the + * override and security register offsets. + */ static const struct tegra_mc_client tegra234_mc_clients[] = { { + .id = TEGRA234_MEMORY_CLIENT_HDAR, + .name = "hdar", + .bpmp_id = TEGRA_ICC_BPMP_HDA, + .type = TEGRA_ICC_ISO_AUDIO, + .sid = TEGRA234_SID_HDA, + .regs = { + .sid = { + .override = 0xa8, + .security = 0xac, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVENCSRD, + .name = "nvencsrd", + .bpmp_id = TEGRA_ICC_BPMP_NVENC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVENC, + .regs = { + .sid = { + .override = 0xe0, + .security = 0xe4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE6AR, + .name = "pcie6ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE6, + .regs = { + .sid = { + .override = 0x140, + .security = 0x144, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE6AW, + .name = "pcie6aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE6, + .regs = { + .sid = { + .override = 0x148, + .security = 0x14c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE7AR, + .name = "pcie7ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE7, + .regs = { + .sid = { + .override = 0x150, + .security = 0x154, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVENCSWR, + .name = "nvencswr", + .bpmp_id = TEGRA_ICC_BPMP_NVENC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVENC, + .regs = { + .sid = { + .override = 0x158, + .security = 0x15c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA0RDB, + .name = "dla0rdb", + .bpmp_id = TEGRA_ICC_BPMP_DLA_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x160, + .security = 0x164, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA0RDB1, + .name = "dla0rdb1", + .bpmp_id = TEGRA_ICC_BPMP_DLA_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x168, + .security = 0x16c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA0WRB, + .name = "dla0wrb", + .bpmp_id = TEGRA_ICC_BPMP_DLA_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x170, + .security = 0x174, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDB, + .name = "dla1rdb", + .bpmp_id = TEGRA_ICC_BPMP_DLA_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x178, + .security = 0x17c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE7AW, + .name = "pcie7aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE7, + .regs = { + .sid = { + .override = 0x180, + .security = 0x184, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE8AR, + .name = "pcie8ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_8, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE8, + .regs = { + .sid = { + .override = 0x190, + .security = 0x194, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_HDAW, + .name = "hdaw", + .bpmp_id = TEGRA_ICC_BPMP_HDA, + .type = TEGRA_ICC_ISO_AUDIO, + .sid = TEGRA234_SID_HDA, + .regs = { + .sid = { + .override = 0x1a8, + .security = 0x1ac, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE8AW, + .name = "pcie8aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_8, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE8, + .regs = { + .sid = { + .override = 0x1d8, + .security = 0x1dc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE9AR, + .name = "pcie9ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_9, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE9, + .regs = { + .sid = { + .override = 0x1e0, + .security = 0x1e4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE6AR1, + .name = "pcie6ar1", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE6, + .regs = { + .sid = { + .override = 0x1e8, + .security = 0x1ec, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE9AW, + .name = "pcie9aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_9, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE9, + .regs = { + .sid = { + .override = 0x1f0, + .security = 0x1f4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE10AR, + .name = "pcie10ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE10, + .regs = { + .sid = { + .override = 0x1f8, + .security = 0x1fc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE10AW, + .name = "pcie10aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE10, + .regs = { + .sid = { + .override = 0x200, + .security = 0x204, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE10AR1, + .name = "pcie10ar1", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE10, + .regs = { + .sid = { + .override = 0x240, + .security = 0x244, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE7AR1, + .name = "pcie7ar1", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE7, + .regs = { + .sid = { + .override = 0x248, + .security = 0x24c, + }, + }, + }, { .id = TEGRA234_MEMORY_CLIENT_MGBEARD, .name = "mgbeard", + .bpmp_id = TEGRA_ICC_BPMP_EQOS, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_MGBE, .regs = { .sid = { @@ -23,6 +284,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_MGBEBRD, .name = "mgbebrd", + .bpmp_id = TEGRA_ICC_BPMP_EQOS, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_MGBE_VF1, .regs = { .sid = { @@ -33,6 +296,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_MGBECRD, .name = "mgbecrd", + .bpmp_id = TEGRA_ICC_BPMP_EQOS, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_MGBE_VF2, .regs = { .sid = { @@ -43,6 +308,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_MGBEDRD, .name = "mgbedrd", + .bpmp_id = TEGRA_ICC_BPMP_EQOS, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_MGBE_VF3, .regs = { .sid = { @@ -52,6 +319,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, { .id = TEGRA234_MEMORY_CLIENT_MGBEAWR, + .bpmp_id = TEGRA_ICC_BPMP_EQOS, + .type = TEGRA_ICC_NISO, .name = "mgbeawr", .sid = TEGRA234_SID_MGBE, .regs = { @@ -63,6 +332,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_MGBEBWR, .name = "mgbebwr", + .bpmp_id = TEGRA_ICC_BPMP_EQOS, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_MGBE_VF1, .regs = { .sid = { @@ -73,6 +344,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_MGBECWR, .name = "mgbecwr", + .bpmp_id = TEGRA_ICC_BPMP_EQOS, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_MGBE_VF2, .regs = { .sid = { @@ -83,6 +356,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_SDMMCRAB, .name = "sdmmcrab", + .bpmp_id = TEGRA_ICC_BPMP_SDMMC_4, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_SDMMC4, .regs = { .sid = { @@ -93,6 +368,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_MGBEDWR, .name = "mgbedwr", + .bpmp_id = TEGRA_ICC_BPMP_EQOS, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_MGBE_VF3, .regs = { .sid = { @@ -103,6 +380,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_SDMMCWAB, .name = "sdmmcwab", + .bpmp_id = TEGRA_ICC_BPMP_SDMMC_4, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_SDMMC4, .regs = { .sid = { @@ -111,6 +390,186 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { + .id = TEGRA234_MEMORY_CLIENT_VICSRD, + .name = "vicsrd", + .bpmp_id = TEGRA_ICC_BPMP_VIC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_VIC, + .regs = { + .sid = { + .override = 0x360, + .security = 0x364, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VICSWR, + .name = "vicswr", + .bpmp_id = TEGRA_ICC_BPMP_VIC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_VIC, + .regs = { + .sid = { + .override = 0x368, + .security = 0x36c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDB1, + .name = "dla1rdb1", + .bpmp_id = TEGRA_ICC_BPMP_DLA_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x370, + .security = 0x374, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1WRB, + .name = "dla1wrb", + .bpmp_id = TEGRA_ICC_BPMP_DLA_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x378, + .security = 0x37c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VI2W, + .name = "vi2w", + .bpmp_id = TEGRA_ICC_BPMP_VI2, + .type = TEGRA_ICC_ISO_VI, + .sid = TEGRA234_SID_ISO_VI2, + .regs = { + .sid = { + .override = 0x380, + .security = 0x384, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VI2FALR, + .name = "vi2falr", + .bpmp_id = TEGRA_ICC_BPMP_VI2FAL, + .type = TEGRA_ICC_ISO_VIFAL, + .sid = TEGRA234_SID_ISO_VI2FALC, + .regs = { + .sid = { + .override = 0x388, + .security = 0x38c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VIW, + .name = "viw", + .bpmp_id = TEGRA_ICC_BPMP_VI, + .type = TEGRA_ICC_ISO_VI, + .sid = TEGRA234_SID_ISO_VI, + .regs = { + .sid = { + .override = 0x390, + .security = 0x394, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVDECSRD, + .name = "nvdecsrd", + .bpmp_id = TEGRA_ICC_BPMP_NVDEC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDEC, + .regs = { + .sid = { + .override = 0x3c0, + .security = 0x3c4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVDECSWR, + .name = "nvdecswr", + .bpmp_id = TEGRA_ICC_BPMP_NVDEC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDEC, + .regs = { + .sid = { + .override = 0x3c8, + .security = 0x3cc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_APER, + .name = "aper", + .bpmp_id = TEGRA_ICC_BPMP_APE, + .type = TEGRA_ICC_ISO_AUDIO, + .sid = TEGRA234_SID_APE, + .regs = { + .sid = { + .override = 0x3d0, + .security = 0x3d4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_APEW, + .name = "apew", + .bpmp_id = TEGRA_ICC_BPMP_APE, + .type = TEGRA_ICC_ISO_AUDIO, + .sid = TEGRA234_SID_APE, + .regs = { + .sid = { + .override = 0x3d8, + .security = 0x3dc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VI2FALW, + .name = "vi2falw", + .bpmp_id = TEGRA_ICC_BPMP_VI2FAL, + .type = TEGRA_ICC_ISO_VIFAL, + .sid = TEGRA234_SID_ISO_VI2FALC, + .regs = { + .sid = { + .override = 0x3e0, + .security = 0x3e4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVJPGSRD, + .name = "nvjpgsrd", + .bpmp_id = TEGRA_ICC_BPMP_NVJPG_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVJPG, + .regs = { + .sid = { + .override = 0x3f0, + .security = 0x3f4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVJPGSWR, + .name = "nvjpgswr", + .bpmp_id = TEGRA_ICC_BPMP_NVJPG_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVJPG, + .regs = { + .sid = { + .override = 0x3f8, + .security = 0x3fc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVDISPLAYR, + .name = "nvdisplayr", + .bpmp_id = TEGRA_ICC_BPMP_DISPLAY, + .type = TEGRA_ICC_ISO_DISPLAY, + .sid = TEGRA234_SID_ISO_NVDISPLAY, + .regs = { + .sid = { + .override = 0x490, + .security = 0x494, + }, + }, + }, { .id = TEGRA234_MEMORY_CLIENT_BPMPR, .name = "bpmpr", .sid = TEGRA234_SID_BPMP, @@ -153,6 +612,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_APEDMAR, .name = "apedmar", + .bpmp_id = TEGRA_ICC_BPMP_APEDMA, + .type = TEGRA_ICC_ISO_AUDIO, .sid = TEGRA234_SID_APE, .regs = { .sid = { @@ -163,6 +624,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_APEDMAW, .name = "apedmaw", + .bpmp_id = TEGRA_ICC_BPMP_APEDMA, + .type = TEGRA_ICC_ISO_AUDIO, .sid = TEGRA234_SID_APE, .regs = { .sid = { @@ -171,8 +634,46 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { + .id = TEGRA234_MEMORY_CLIENT_NVDISPLAYR1, + .name = "nvdisplayr1", + .bpmp_id = TEGRA_ICC_BPMP_DISPLAY, + .type = TEGRA_ICC_ISO_DISPLAY, + .sid = TEGRA234_SID_ISO_NVDISPLAY, + .regs = { + .sid = { + .override = 0x508, + .security = 0x50c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VIFALR, + .name = "vifalr", + .bpmp_id = TEGRA_ICC_BPMP_VIFAL, + .type = TEGRA_ICC_ISO_VIFAL, + .sid = TEGRA234_SID_ISO_VIFALC, + .regs = { + .sid = { + .override = 0x5e0, + .security = 0x5e4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VIFALW, + .name = "vifalw", + .bpmp_id = TEGRA_ICC_BPMP_VIFAL, + .type = TEGRA_ICC_ISO_VIFAL, + .sid = TEGRA234_SID_ISO_VIFALC, + .regs = { + .sid = { + .override = 0x5e8, + .security = 0x5ec, + }, + }, + }, { .id = TEGRA234_MEMORY_CLIENT_DLA0RDA, .name = "dla0rda", + .bpmp_id = TEGRA_ICC_BPMP_DLA_0, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_NVDLA0, .regs = { .sid = { @@ -183,6 +684,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_DLA0FALRDB, .name = "dla0falrdb", + .bpmp_id = TEGRA_ICC_BPMP_DLA_0, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_NVDLA0, .regs = { .sid = { @@ -193,6 +696,8 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, { .id = TEGRA234_MEMORY_CLIENT_DLA0WRA, .name = "dla0wra", + .bpmp_id = TEGRA_ICC_BPMP_DLA_0, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_NVDLA0, .regs = { .sid = { @@ -201,98 +706,248 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0RDB, - .name = "dla0rdb", + .id = TEGRA234_MEMORY_CLIENT_DLA0FALWRB, + .name = "dla0falwrb", + .bpmp_id = TEGRA_ICC_BPMP_DLA_0, + .type = TEGRA_ICC_NISO, .sid = TEGRA234_SID_NVDLA0, .regs = { .sid = { - .override = 0x160, - .security = 0x164, + .override = 0x608, + .security = 0x60c, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0RDA1, - .name = "dla0rda1", - .sid = TEGRA234_SID_NVDLA0, + .id = TEGRA234_MEMORY_CLIENT_DLA1RDA, + .name = "dla1rda", + .bpmp_id = TEGRA_ICC_BPMP_DLA_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA1, .regs = { .sid = { - .override = 0x748, - .security = 0x74c, + .override = 0x610, + .security = 0x614, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0FALWRB, - .name = "dla0falwrb", - .sid = TEGRA234_SID_NVDLA0, + .id = TEGRA234_MEMORY_CLIENT_DLA1FALRDB, + .name = "dla1falrdb", + .bpmp_id = TEGRA_ICC_BPMP_DLA_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA1, .regs = { .sid = { - .override = 0x608, - .security = 0x60c, + .override = 0x618, + .security = 0x61c, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0RDB1, - .name = "dla0rdb1", - .sid = TEGRA234_SID_NVDLA0, + .id = TEGRA234_MEMORY_CLIENT_DLA1WRA, + .name = "dla1wra", + .bpmp_id = TEGRA_ICC_BPMP_DLA_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA1, .regs = { .sid = { - .override = 0x168, - .security = 0x16c, + .override = 0x620, + .security = 0x624, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0WRB, - .name = "dla0wrb", - .sid = TEGRA234_SID_NVDLA0, + .id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB, + .name = "dla1falwrb", + .bpmp_id = TEGRA_ICC_BPMP_DLA_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA1, .regs = { .sid = { - .override = 0x170, - .security = 0x174, + .override = 0x628, + .security = 0x62c, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1RDA, - .name = "dla0rda", - .sid = TEGRA234_SID_NVDLA1, + .id = TEGRA234_MEMORY_CLIENT_RCER, + .name = "rcer", + .bpmp_id = TEGRA_ICC_BPMP_RCE, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_RCE, .regs = { .sid = { - .override = 0x610, - .security = 0x614, + .override = 0x690, + .security = 0x694, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1FALRDB, - .name = "dla0falrdb", - .sid = TEGRA234_SID_NVDLA1, + .id = TEGRA234_MEMORY_CLIENT_RCEW, + .name = "rcew", + .bpmp_id = TEGRA_ICC_BPMP_RCE, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_RCE, .regs = { .sid = { - .override = 0x618, - .security = 0x61c, + .override = 0x698, + .security = 0x69c, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1WRA, - .name = "dla0wra", - .sid = TEGRA234_SID_NVDLA1, + .id = TEGRA234_MEMORY_CLIENT_PCIE0R, + .name = "pcie0r", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE0, .regs = { .sid = { - .override = 0x620, - .security = 0x624, + .override = 0x6c0, + .security = 0x6c4, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1RDB, - .name = "dla0rdb", - .sid = TEGRA234_SID_NVDLA1, + .id = TEGRA234_MEMORY_CLIENT_PCIE0W, + .name = "pcie0w", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE0, .regs = { .sid = { - .override = 0x178, - .security = 0x17c, + .override = 0x6c8, + .security = 0x6cc, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1RDA1, + .id = TEGRA234_MEMORY_CLIENT_PCIE1R, + .name = "pcie1r", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE1, + .regs = { + .sid = { + .override = 0x6d0, + .security = 0x6d4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE1W, + .name = "pcie1w", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE1, + .regs = { + .sid = { + .override = 0x6d8, + .security = 0x6dc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE2AR, + .name = "pcie2ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_2, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE2, + .regs = { + .sid = { + .override = 0x6e0, + .security = 0x6e4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE2AW, + .name = "pcie2aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_2, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE2, + .regs = { + .sid = { + .override = 0x6e8, + .security = 0x6ec, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE3R, + .name = "pcie3r", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_3, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE3, + .regs = { + .sid = { + .override = 0x6f0, + .security = 0x6f4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE3W, + .name = "pcie3w", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_3, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE3, + .regs = { + .sid = { + .override = 0x6f8, + .security = 0x6fc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE4R, + .name = "pcie4r", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_4, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE4, + .regs = { + .sid = { + .override = 0x700, + .security = 0x704, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE4W, + .name = "pcie4w", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_4, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE4, + .regs = { + .sid = { + .override = 0x708, + .security = 0x70c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE5R, + .name = "pcie5r", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_5, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE5, + .regs = { + .sid = { + .override = 0x710, + .security = 0x714, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE5W, + .name = "pcie5w", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_5, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE5, + .regs = { + .sid = { + .override = 0x718, + .security = 0x71c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA0RDA1, .name = "dla0rda1", + .bpmp_id = TEGRA_ICC_BPMP_DLA_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x748, + .security = 0x74c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDA1, + .name = "dla1rda1", .sid = TEGRA234_SID_NVDLA1, .regs = { .sid = { @@ -301,38 +956,182 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB, - .name = "dla0falwrb", - .sid = TEGRA234_SID_NVDLA1, + .id = TEGRA234_MEMORY_CLIENT_PCIE5R1, + .name = "pcie5r1", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_5, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE5, .regs = { .sid = { - .override = 0x628, - .security = 0x62c, + .override = 0x778, + .security = 0x77c, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1RDB1, - .name = "dla0rdb1", - .sid = TEGRA234_SID_NVDLA1, + .id = TEGRA234_MEMORY_CLIENT_NVJPG1SRD, + .name = "nvjpg1srd", + .bpmp_id = TEGRA_ICC_BPMP_NVJPG_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVJPG1, .regs = { .sid = { - .override = 0x370, - .security = 0x374, + .override = 0x918, + .security = 0x91c, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1WRB, - .name = "dla0wrb", - .sid = TEGRA234_SID_NVDLA1, + .id = TEGRA234_MEMORY_CLIENT_NVJPG1SWR, + .name = "nvjpg1swr", + .bpmp_id = TEGRA_ICC_BPMP_NVJPG_1, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVJPG1, .regs = { .sid = { - .override = 0x378, - .security = 0x37c, + .override = 0x920, + .security = 0x924, }, }, + }, { + .id = TEGRA_ICC_MC_CPU_CLUSTER0, + .name = "sw_cluster0", + .bpmp_id = TEGRA_ICC_BPMP_CPU_CLUSTER0, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA_ICC_MC_CPU_CLUSTER1, + .name = "sw_cluster1", + .bpmp_id = TEGRA_ICC_BPMP_CPU_CLUSTER1, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA_ICC_MC_CPU_CLUSTER2, + .name = "sw_cluster2", + .bpmp_id = TEGRA_ICC_BPMP_CPU_CLUSTER2, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVL1R, + .name = "nvl1r", + .bpmp_id = TEGRA_ICC_BPMP_GPU, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVL1W, + .name = "nvl1w", + .bpmp_id = TEGRA_ICC_BPMP_GPU, + .type = TEGRA_ICC_NISO, }, }; +/* + * tegra234_mc_icc_set() - Pass MC client info to the BPMP-FW + * @src: ICC node for Memory Controller's (MC) Client + * @dst: ICC node for Memory Controller (MC) + * + * Passing the current request info from the MC to the BPMP-FW where + * LA and PTSA registers are accessed and the final EMC freq is set + * based on client_id, type, latency and bandwidth. + * icc_set_bw() makes set_bw calls for both MC and EMC providers in + * sequence. Both the calls are protected by 'mutex_lock(&icc_lock)'. + * So, the data passed won't be updated by concurrent set calls from + * other clients. + */ +static int tegra234_mc_icc_set(struct icc_node *src, struct icc_node *dst) +{ + struct tegra_mc *mc = icc_provider_to_tegra_mc(dst->provider); + struct mrq_bwmgr_int_request bwmgr_req = { 0 }; + struct mrq_bwmgr_int_response bwmgr_resp = { 0 }; + const struct tegra_mc_client *pclient = src->data; + struct tegra_bpmp_message msg; + int ret; + + /* + * Same Src and Dst node will happen during boot from icc_node_add(). + * This can be used to pre-initialize and set bandwidth for all clients + * before their drivers are loaded. We are skipping this case as for us, + * the pre-initialization already happened in Bootloader(MB2) and BPMP-FW. + */ + if (src->id == dst->id) + return 0; + + if (!mc->bwmgr_mrq_supported) + return 0; + + if (!mc->bpmp) { + dev_err(mc->dev, "BPMP reference NULL\n"); + return -ENOENT; + } + + if (pclient->type == TEGRA_ICC_NISO) + bwmgr_req.bwmgr_calc_set_req.niso_bw = src->avg_bw; + else + bwmgr_req.bwmgr_calc_set_req.iso_bw = src->avg_bw; + + bwmgr_req.bwmgr_calc_set_req.client_id = pclient->bpmp_id; + + bwmgr_req.cmd = CMD_BWMGR_INT_CALC_AND_SET; + bwmgr_req.bwmgr_calc_set_req.mc_floor = src->peak_bw; + bwmgr_req.bwmgr_calc_set_req.floor_unit = BWMGR_INT_UNIT_KBPS; + + memset(&msg, 0, sizeof(msg)); + msg.mrq = MRQ_BWMGR_INT; + msg.tx.data = &bwmgr_req; + msg.tx.size = sizeof(bwmgr_req); + msg.rx.data = &bwmgr_resp; + msg.rx.size = sizeof(bwmgr_resp); + + if (pclient->bpmp_id >= TEGRA_ICC_BPMP_CPU_CLUSTER0 && + pclient->bpmp_id <= TEGRA_ICC_BPMP_CPU_CLUSTER2) + msg.flags = TEGRA_BPMP_MESSAGE_RESET; + + ret = tegra_bpmp_transfer(mc->bpmp, &msg); + if (ret < 0) { + dev_err(mc->dev, "BPMP transfer failed: %d\n", ret); + goto error; + } + if (msg.rx.ret < 0) { + pr_err("failed to set bandwidth for %u: %d\n", + bwmgr_req.bwmgr_calc_set_req.client_id, msg.rx.ret); + ret = -EINVAL; + } + +error: + return ret; +} + +static int tegra234_mc_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, + u32 peak_bw, u32 *agg_avg, u32 *agg_peak) +{ + struct icc_provider *p = node->provider; + struct tegra_mc *mc = icc_provider_to_tegra_mc(p); + + if (!mc->bwmgr_mrq_supported) + return 0; + + if (node->id == TEGRA_ICC_MC_CPU_CLUSTER0 || + node->id == TEGRA_ICC_MC_CPU_CLUSTER1 || + node->id == TEGRA_ICC_MC_CPU_CLUSTER2) { + if (mc) + peak_bw = peak_bw * mc->num_channels; + } + + *agg_avg += avg_bw; + *agg_peak = max(*agg_peak, peak_bw); + + return 0; +} + +static int tegra234_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *peak) +{ + *avg = 0; + *peak = 0; + + return 0; +} + +static const struct tegra_mc_icc_ops tegra234_mc_icc_ops = { + .xlate = tegra_mc_icc_xlate, + .aggregate = tegra234_mc_icc_aggregate, + .get_bw = tegra234_mc_icc_get_init_bw, + .set = tegra234_mc_icc_set, +}; + const struct tegra_mc_soc tegra234_mc_soc = { .num_clients = ARRAY_SIZE(tegra234_mc_clients), .clients = tegra234_mc_clients, @@ -345,6 +1144,7 @@ const struct tegra_mc_soc tegra234_mc_soc = { MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, .has_addr_hi_reg = true, .ops = &tegra186_mc_ops, + .icc_ops = &tegra234_mc_icc_ops, .ch_intmask = 0x0000ff00, .global_intstatus_channel_shift = 8, /* diff --git a/drivers/memory/tegra/tegra264-bwmgr.h b/drivers/memory/tegra/tegra264-bwmgr.h new file mode 100644 index 000000000000..93bfceaac9c8 --- /dev/null +++ b/drivers/memory/tegra/tegra264-bwmgr.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2025 NVIDIA CORPORATION. All rights reserved. */ + +#ifndef MEMORY_TEGRA_TEGRA264_BWMGR_H +#define MEMORY_TEGRA_TEGRA264_BWMGR_H + +#define TEGRA264_BWMGR_ICC_PRIMARY 1 +#define TEGRA264_BWMGR_DEBUG 2 +#define TEGRA264_BWMGR_CPU_CLUSTER0 3 +#define TEGRA264_BWMGR_CPU_CLUSTER1 4 +#define TEGRA264_BWMGR_CPU_CLUSTER2 5 +#define TEGRA264_BWMGR_CPU_CLUSTER3 6 +#define TEGRA264_BWMGR_CPU_CLUSTER4 7 +#define TEGRA264_BWMGR_CPU_CLUSTER5 8 +#define TEGRA264_BWMGR_CPU_CLUSTER6 9 +#define TEGRA264_BWMGR_CACTMON 10 +#define TEGRA264_BWMGR_DISPLAY 11 +#define TEGRA264_BWMGR_VI 12 +#define TEGRA264_BWMGR_APE 13 +#define TEGRA264_BWMGR_VIFAL 14 +#define TEGRA264_BWMGR_GPU 15 +#define TEGRA264_BWMGR_EQOS 16 +#define TEGRA264_BWMGR_PCIE_0 17 +#define TEGRA264_BWMGR_PCIE_1 18 +#define TEGRA264_BWMGR_PCIE_2 19 +#define TEGRA264_BWMGR_PCIE_3 20 +#define TEGRA264_BWMGR_PCIE_4 21 +#define TEGRA264_BWMGR_PCIE_5 22 +#define TEGRA264_BWMGR_SDMMC_1 23 +#define TEGRA264_BWMGR_SDMMC_2 24 +#define TEGRA264_BWMGR_NVDEC 25 +#define TEGRA264_BWMGR_NVENC 26 +#define TEGRA264_BWMGR_NVJPG_0 27 +#define TEGRA264_BWMGR_NVJPG_1 28 +#define TEGRA264_BWMGR_OFAA 29 +#define TEGRA264_BWMGR_XUSB_HOST 30 +#define TEGRA264_BWMGR_XUSB_DEV 31 +#define TEGRA264_BWMGR_TSEC 32 +#define TEGRA264_BWMGR_VIC 33 +#define TEGRA264_BWMGR_APEDMA 34 +#define TEGRA264_BWMGR_SE 35 +#define TEGRA264_BWMGR_ISP 36 +#define TEGRA264_BWMGR_HDA 37 +#define TEGRA264_BWMGR_VI2FAL 38 +#define TEGRA264_BWMGR_VI2 39 +#define TEGRA264_BWMGR_RCE 40 +#define TEGRA264_BWMGR_PVA 41 +#define TEGRA264_BWMGR_NVPMODEL 42 + +#endif diff --git a/drivers/memory/tegra/tegra264.c b/drivers/memory/tegra/tegra264.c new file mode 100644 index 000000000000..5203e6c11372 --- /dev/null +++ b/drivers/memory/tegra/tegra264.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025, NVIDIA CORPORATION. All rights reserved. + */ + +#include <dt-bindings/memory/nvidia,tegra264.h> + +#include <linux/interconnect.h> +#include <linux/of_device.h> +#include <linux/tegra-icc.h> + +#include <soc/tegra/bpmp.h> +#include <soc/tegra/mc.h> + +#include "mc.h" +#include "tegra264-bwmgr.h" + +/* + * MC Client entries are sorted in the increasing order of the + * override and security register offsets. + */ +static const struct tegra_mc_client tegra264_mc_clients[] = { + { + .id = TEGRA264_MEMORY_CLIENT_HDAR, + .name = "hdar", + .bpmp_id = TEGRA264_BWMGR_HDA, + .type = TEGRA_ICC_ISO_AUDIO, + }, { + .id = TEGRA264_MEMORY_CLIENT_HDAW, + .name = "hdaw", + .bpmp_id = TEGRA264_BWMGR_HDA, + .type = TEGRA_ICC_ISO_AUDIO, + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE0R, + .name = "mgbe0r", + .bpmp_id = TEGRA264_BWMGR_EQOS, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE0W, + .name = "mgbe0w", + .bpmp_id = TEGRA264_BWMGR_EQOS, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE1R, + .name = "mgbe1r", + .bpmp_id = TEGRA264_BWMGR_EQOS, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_MGBE1W, + .name = "mgbe1w", + .bpmp_id = TEGRA264_BWMGR_EQOS, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_SDMMC0R, + .name = "sdmmc0r", + .bpmp_id = TEGRA264_BWMGR_SDMMC_1, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_SDMMC0W, + .name = "sdmmc0w", + .bpmp_id = TEGRA264_BWMGR_SDMMC_1, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_VICR, + .name = "vicr", + .bpmp_id = TEGRA264_BWMGR_VIC, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_VICW, + .name = "vicw", + .bpmp_id = TEGRA264_BWMGR_VIC, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_APER, + .name = "aper", + .bpmp_id = TEGRA264_BWMGR_APE, + .type = TEGRA_ICC_ISO_AUDIO, + }, { + .id = TEGRA264_MEMORY_CLIENT_APEW, + .name = "apew", + .bpmp_id = TEGRA264_BWMGR_APE, + .type = TEGRA_ICC_ISO_AUDIO, + }, { + .id = TEGRA264_MEMORY_CLIENT_APEDMAR, + .name = "apedmar", + .bpmp_id = TEGRA264_BWMGR_APEDMA, + .type = TEGRA_ICC_ISO_AUDIO, + }, { + .id = TEGRA264_MEMORY_CLIENT_APEDMAW, + .name = "apedmaw", + .bpmp_id = TEGRA264_BWMGR_APEDMA, + .type = TEGRA_ICC_ISO_AUDIO, + }, { + .id = TEGRA264_MEMORY_CLIENT_VIFALCONR, + .name = "vifalconr", + .bpmp_id = TEGRA264_BWMGR_VIFAL, + .type = TEGRA_ICC_ISO_VIFAL, + }, { + .id = TEGRA264_MEMORY_CLIENT_VIFALCONW, + .name = "vifalconw", + .bpmp_id = TEGRA264_BWMGR_VIFAL, + .type = TEGRA_ICC_ISO_VIFAL, + }, { + .id = TEGRA264_MEMORY_CLIENT_RCER, + .name = "rcer", + .bpmp_id = TEGRA264_BWMGR_RCE, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_RCEW, + .name = "rcew", + .bpmp_id = TEGRA264_BWMGR_RCE, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE0W, + .name = "pcie0w", + .bpmp_id = TEGRA264_BWMGR_PCIE_0, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE1R, + .name = "pcie1r", + .bpmp_id = TEGRA264_BWMGR_PCIE_1, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE1W, + .name = "pcie1w", + .bpmp_id = TEGRA264_BWMGR_PCIE_1, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE2AR, + .name = "pcie2ar", + .bpmp_id = TEGRA264_BWMGR_PCIE_2, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE2AW, + .name = "pcie2aw", + .bpmp_id = TEGRA264_BWMGR_PCIE_2, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE3R, + .name = "pcie3r", + .bpmp_id = TEGRA264_BWMGR_PCIE_3, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE3W, + .name = "pcie3w", + .bpmp_id = TEGRA264_BWMGR_PCIE_3, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE4R, + .name = "pcie4r", + .bpmp_id = TEGRA264_BWMGR_PCIE_4, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE4W, + .name = "pcie4w", + .bpmp_id = TEGRA264_BWMGR_PCIE_4, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE5R, + .name = "pcie5r", + .bpmp_id = TEGRA264_BWMGR_PCIE_5, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_PCIE5W, + .name = "pcie5w", + .bpmp_id = TEGRA264_BWMGR_PCIE_5, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_GPUR02MC, + .name = "gpur02mc", + .bpmp_id = TEGRA264_BWMGR_GPU, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_GPUW02MC, + .name = "gpuw02mc", + .bpmp_id = TEGRA264_BWMGR_GPU, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_NVDECSRD2MC, + .name = "nvdecsrd2mc", + .bpmp_id = TEGRA264_BWMGR_NVDEC, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA264_MEMORY_CLIENT_NVDECSWR2MC, + .name = "nvdecswr2mc", + .bpmp_id = TEGRA264_BWMGR_NVDEC, + .type = TEGRA_ICC_NISO, + }, +}; + +/* + * tegra264_mc_icc_set() - Pass MC client info to the BPMP-FW + * @src: ICC node for Memory Controller's (MC) Client + * @dst: ICC node for Memory Controller (MC) + * + * Passing the current request info from the MC to the BPMP-FW where + * LA and PTSA registers are accessed and the final EMC freq is set + * based on client_id, type, latency and bandwidth. + * icc_set_bw() makes set_bw calls for both MC and EMC providers in + * sequence. Both the calls are protected by 'mutex_lock(&icc_lock)'. + * So, the data passed won't be updated by concurrent set calls from + * other clients. + */ +static int tegra264_mc_icc_set(struct icc_node *src, struct icc_node *dst) +{ + struct tegra_mc *mc = icc_provider_to_tegra_mc(dst->provider); + struct mrq_bwmgr_int_request bwmgr_req = { 0 }; + struct mrq_bwmgr_int_response bwmgr_resp = { 0 }; + const struct tegra_mc_client *pclient = src->data; + struct tegra_bpmp_message msg; + int ret; + + /* + * Same Src and Dst node will happen during boot from icc_node_add(). + * This can be used to pre-initialize and set bandwidth for all clients + * before their drivers are loaded. We are skipping this case as for us, + * the pre-initialization already happened in Bootloader(MB2) and BPMP-FW. + */ + if (src->id == dst->id) + return 0; + + if (!mc->bwmgr_mrq_supported) + return 0; + + if (!mc->bpmp) { + dev_err(mc->dev, "BPMP reference NULL\n"); + return -ENOENT; + } + + if (pclient->type == TEGRA_ICC_NISO) + bwmgr_req.bwmgr_calc_set_req.niso_bw = src->avg_bw; + else + bwmgr_req.bwmgr_calc_set_req.iso_bw = src->avg_bw; + + bwmgr_req.bwmgr_calc_set_req.client_id = pclient->bpmp_id; + + bwmgr_req.cmd = CMD_BWMGR_INT_CALC_AND_SET; + bwmgr_req.bwmgr_calc_set_req.mc_floor = src->peak_bw; + bwmgr_req.bwmgr_calc_set_req.floor_unit = BWMGR_INT_UNIT_KBPS; + + memset(&msg, 0, sizeof(msg)); + msg.mrq = MRQ_BWMGR_INT; + msg.tx.data = &bwmgr_req; + msg.tx.size = sizeof(bwmgr_req); + msg.rx.data = &bwmgr_resp; + msg.rx.size = sizeof(bwmgr_resp); + + ret = tegra_bpmp_transfer(mc->bpmp, &msg); + if (ret < 0) { + dev_err(mc->dev, "BPMP transfer failed: %d\n", ret); + goto error; + } + if (msg.rx.ret < 0) { + pr_err("failed to set bandwidth for %u: %d\n", + bwmgr_req.bwmgr_calc_set_req.client_id, msg.rx.ret); + ret = -EINVAL; + } + +error: + return ret; +} + +static int tegra264_mc_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, + u32 peak_bw, u32 *agg_avg, u32 *agg_peak) +{ + struct icc_provider *p = node->provider; + struct tegra_mc *mc = icc_provider_to_tegra_mc(p); + + if (!mc->bwmgr_mrq_supported) + return 0; + + *agg_avg += avg_bw; + *agg_peak = max(*agg_peak, peak_bw); + + return 0; +} + +static int tegra264_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *peak) +{ + *avg = 0; + *peak = 0; + + return 0; +} + +static const struct tegra_mc_icc_ops tegra264_mc_icc_ops = { + .xlate = tegra_mc_icc_xlate, + .aggregate = tegra264_mc_icc_aggregate, + .get_bw = tegra264_mc_icc_get_init_bw, + .set = tegra264_mc_icc_set, +}; + +const struct tegra_mc_soc tegra264_mc_soc = { + .num_clients = ARRAY_SIZE(tegra264_mc_clients), + .clients = tegra264_mc_clients, + .num_address_bits = 40, + .num_channels = 16, + .client_id_mask = 0x1ff, + .intmask = MC_INT_DECERR_ROUTE_SANITY | + MC_INT_DECERR_GENERALIZED_CARVEOUT | MC_INT_DECERR_MTS | + MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | + MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, + .has_addr_hi_reg = true, + .ops = &tegra186_mc_ops, + .icc_ops = &tegra264_mc_icc_ops, + .ch_intmask = 0x0000ff00, + .global_intstatus_channel_shift = 8, + /* + * Additionally, there are lite carveouts but those are not currently + * supported. + */ + .num_carveouts = 32, +}; diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c index 77706e9bc543..914116d8ec16 100644 --- a/drivers/memory/tegra/tegra30-emc.c +++ b/drivers/memory/tegra/tegra30-emc.c @@ -22,7 +22,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> -#include <linux/of_platform.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_opp.h> #include <linux/slab.h> @@ -413,7 +413,7 @@ static int emc_seq_update_timing(struct tegra_emc *emc) return 0; } -static irqreturn_t tegra_emc_isr(int irq, void *data) +static irqreturn_t tegra30_emc_isr(int irq, void *data) { struct tegra_emc *emc = data; u32 intmask = EMC_REFRESH_OVERFLOW_INT; @@ -979,7 +979,6 @@ static int emc_check_mc_timings(struct tegra_emc *emc) static int emc_load_timings_from_dt(struct tegra_emc *emc, struct device_node *node) { - struct device_node *child; struct emc_timing *timing; int child_count; int err; @@ -998,12 +997,10 @@ static int emc_load_timings_from_dt(struct tegra_emc *emc, emc->num_timings = child_count; timing = emc->timings; - for_each_child_of_node(node, child) { + for_each_child_of_node_scoped(node, child) { err = load_one_timing_from_dt(emc, timing++, child); - if (err) { - of_node_put(child); + if (err) return err; - } } sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, @@ -1231,7 +1228,7 @@ static long emc_round_rate(unsigned long rate, return timing->rate; } -static void tegra_emc_rate_requests_init(struct tegra_emc *emc) +static void tegra30_emc_rate_requests_init(struct tegra_emc *emc) { unsigned int i; @@ -1333,7 +1330,7 @@ static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate, * valid range. */ -static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) +static bool tegra30_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) { unsigned int i; @@ -1344,7 +1341,7 @@ static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate) return false; } -static int tegra_emc_debug_available_rates_show(struct seq_file *s, void *data) +static int tegra30_emc_debug_available_rates_show(struct seq_file *s, void *data) { struct tegra_emc *emc = s->private; const char *prefix = ""; @@ -1359,9 +1356,9 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s, void *data) return 0; } -DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates); +DEFINE_SHOW_ATTRIBUTE(tegra30_emc_debug_available_rates); -static int tegra_emc_debug_min_rate_get(void *data, u64 *rate) +static int tegra30_emc_debug_min_rate_get(void *data, u64 *rate) { struct tegra_emc *emc = data; @@ -1370,12 +1367,12 @@ static int tegra_emc_debug_min_rate_get(void *data, u64 *rate) return 0; } -static int tegra_emc_debug_min_rate_set(void *data, u64 rate) +static int tegra30_emc_debug_min_rate_set(void *data, u64 rate) { struct tegra_emc *emc = data; int err; - if (!tegra_emc_validate_rate(emc, rate)) + if (!tegra30_emc_validate_rate(emc, rate)) return -EINVAL; err = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG); @@ -1387,11 +1384,11 @@ static int tegra_emc_debug_min_rate_set(void *data, u64 rate) return 0; } -DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_min_rate_fops, - tegra_emc_debug_min_rate_get, - tegra_emc_debug_min_rate_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(tegra30_emc_debug_min_rate_fops, + tegra30_emc_debug_min_rate_get, + tegra30_emc_debug_min_rate_set, "%llu\n"); -static int tegra_emc_debug_max_rate_get(void *data, u64 *rate) +static int tegra30_emc_debug_max_rate_get(void *data, u64 *rate) { struct tegra_emc *emc = data; @@ -1400,12 +1397,12 @@ static int tegra_emc_debug_max_rate_get(void *data, u64 *rate) return 0; } -static int tegra_emc_debug_max_rate_set(void *data, u64 rate) +static int tegra30_emc_debug_max_rate_set(void *data, u64 rate) { struct tegra_emc *emc = data; int err; - if (!tegra_emc_validate_rate(emc, rate)) + if (!tegra30_emc_validate_rate(emc, rate)) return -EINVAL; err = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG); @@ -1417,11 +1414,11 @@ static int tegra_emc_debug_max_rate_set(void *data, u64 rate) return 0; } -DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_max_rate_fops, - tegra_emc_debug_max_rate_get, - tegra_emc_debug_max_rate_set, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(tegra30_emc_debug_max_rate_fops, + tegra30_emc_debug_max_rate_get, + tegra30_emc_debug_max_rate_set, "%llu\n"); -static void tegra_emc_debugfs_init(struct tegra_emc *emc) +static void tegra30_emc_debugfs_init(struct tegra_emc *emc) { struct device *dev = emc->dev; unsigned int i; @@ -1454,11 +1451,11 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc) emc->debugfs.root = debugfs_create_dir("emc", NULL); debugfs_create_file("available_rates", 0444, emc->debugfs.root, - emc, &tegra_emc_debug_available_rates_fops); + emc, &tegra30_emc_debug_available_rates_fops); debugfs_create_file("min_rate", 0644, emc->debugfs.root, - emc, &tegra_emc_debug_min_rate_fops); + emc, &tegra30_emc_debug_min_rate_fops); debugfs_create_file("max_rate", 0644, emc->debugfs.root, - emc, &tegra_emc_debug_max_rate_fops); + emc, &tegra30_emc_debug_max_rate_fops); } static inline struct tegra_emc * @@ -1468,7 +1465,7 @@ to_tegra_emc_provider(struct icc_provider *provider) } static struct icc_node_data * -emc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data) +emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data) { struct icc_provider *provider = data; struct icc_node_data *ndata; @@ -1521,7 +1518,7 @@ static int emc_icc_set(struct icc_node *src, struct icc_node *dst) return 0; } -static int tegra_emc_interconnect_init(struct tegra_emc *emc) +static int tegra30_emc_interconnect_init(struct tegra_emc *emc) { const struct tegra_mc_soc *soc = emc->mc->soc; struct icc_node *node; @@ -1533,16 +1530,12 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc) emc->provider.aggregate = soc->icc_ops->aggregate; emc->provider.xlate_extended = emc_of_icc_xlate_extended; - err = icc_provider_add(&emc->provider); - if (err) - goto err_msg; + icc_provider_init(&emc->provider); /* create External Memory Controller node */ node = icc_node_create(TEGRA_ICC_EMC); - if (IS_ERR(node)) { - err = PTR_ERR(node); - goto del_provider; - } + if (IS_ERR(node)) + return PTR_ERR(node); node->name = "External Memory Controller"; icc_node_add(node, &emc->provider); @@ -1562,62 +1555,59 @@ static int tegra_emc_interconnect_init(struct tegra_emc *emc) node->name = "External Memory (DRAM)"; icc_node_add(node, &emc->provider); + err = icc_provider_register(&emc->provider); + if (err) + goto remove_nodes; + return 0; remove_nodes: icc_nodes_remove(&emc->provider); -del_provider: - icc_provider_del(&emc->provider); -err_msg: - dev_err(emc->dev, "failed to initialize ICC: %d\n", err); - return err; + return dev_err_probe(emc->dev, err, "failed to initialize ICC\n"); } -static void devm_tegra_emc_unset_callback(void *data) +static void devm_tegra30_emc_unset_callback(void *data) { tegra20_clk_set_emc_round_callback(NULL, NULL); } -static void devm_tegra_emc_unreg_clk_notifier(void *data) +static void devm_tegra30_emc_unreg_clk_notifier(void *data) { struct tegra_emc *emc = data; clk_notifier_unregister(emc->clk, &emc->clk_nb); } -static int tegra_emc_init_clk(struct tegra_emc *emc) +static int tegra30_emc_init_clk(struct tegra_emc *emc) { int err; tegra20_clk_set_emc_round_callback(emc_round_rate, emc); - err = devm_add_action_or_reset(emc->dev, devm_tegra_emc_unset_callback, + err = devm_add_action_or_reset(emc->dev, devm_tegra30_emc_unset_callback, NULL); if (err) return err; emc->clk = devm_clk_get(emc->dev, NULL); - if (IS_ERR(emc->clk)) { - dev_err(emc->dev, "failed to get EMC clock: %pe\n", emc->clk); - return PTR_ERR(emc->clk); - } + if (IS_ERR(emc->clk)) + return dev_err_probe(emc->dev, PTR_ERR(emc->clk), + "failed to get EMC clock\n"); err = clk_notifier_register(emc->clk, &emc->clk_nb); - if (err) { - dev_err(emc->dev, "failed to register clk notifier: %d\n", err); - return err; - } + if (err) + return dev_err_probe(emc->dev, err, "failed to register clk notifier\n"); err = devm_add_action_or_reset(emc->dev, - devm_tegra_emc_unreg_clk_notifier, emc); + devm_tegra30_emc_unreg_clk_notifier, emc); if (err) return err; return 0; } -static int tegra_emc_probe(struct platform_device *pdev) +static int tegra30_emc_probe(struct platform_device *pdev) { struct tegra_core_opp_params opp_params = {}; struct device_node *np; @@ -1658,14 +1648,12 @@ static int tegra_emc_probe(struct platform_device *pdev) emc->irq = err; - err = devm_request_irq(&pdev->dev, emc->irq, tegra_emc_isr, 0, + err = devm_request_irq(&pdev->dev, emc->irq, tegra30_emc_isr, 0, dev_name(&pdev->dev), emc); - if (err) { - dev_err(&pdev->dev, "failed to request irq: %d\n", err); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, "failed to request irq\n"); - err = tegra_emc_init_clk(emc); + err = tegra30_emc_init_clk(emc); if (err) return err; @@ -1676,9 +1664,9 @@ static int tegra_emc_probe(struct platform_device *pdev) return err; platform_set_drvdata(pdev, emc); - tegra_emc_rate_requests_init(emc); - tegra_emc_debugfs_init(emc); - tegra_emc_interconnect_init(emc); + tegra30_emc_rate_requests_init(emc); + tegra30_emc_debugfs_init(emc); + tegra30_emc_interconnect_init(emc); /* * Don't allow the kernel module to be unloaded. Unloading adds some @@ -1690,7 +1678,7 @@ static int tegra_emc_probe(struct platform_device *pdev) return 0; } -static int tegra_emc_suspend(struct device *dev) +static int tegra30_emc_suspend(struct device *dev) { struct tegra_emc *emc = dev_get_drvdata(dev); int err; @@ -1711,7 +1699,7 @@ static int tegra_emc_suspend(struct device *dev) return 0; } -static int tegra_emc_resume(struct device *dev) +static int tegra30_emc_resume(struct device *dev) { struct tegra_emc *emc = dev_get_drvdata(dev); @@ -1723,28 +1711,28 @@ static int tegra_emc_resume(struct device *dev) return 0; } -static const struct dev_pm_ops tegra_emc_pm_ops = { - .suspend = tegra_emc_suspend, - .resume = tegra_emc_resume, +static const struct dev_pm_ops tegra30_emc_pm_ops = { + .suspend = tegra30_emc_suspend, + .resume = tegra30_emc_resume, }; -static const struct of_device_id tegra_emc_of_match[] = { +static const struct of_device_id tegra30_emc_of_match[] = { { .compatible = "nvidia,tegra30-emc", }, {}, }; -MODULE_DEVICE_TABLE(of, tegra_emc_of_match); +MODULE_DEVICE_TABLE(of, tegra30_emc_of_match); -static struct platform_driver tegra_emc_driver = { - .probe = tegra_emc_probe, +static struct platform_driver tegra30_emc_driver = { + .probe = tegra30_emc_probe, .driver = { .name = "tegra30-emc", - .of_match_table = tegra_emc_of_match, - .pm = &tegra_emc_pm_ops, + .of_match_table = tegra30_emc_of_match, + .pm = &tegra30_emc_pm_ops, .suppress_bind_attrs = true, .sync_state = icc_sync_state, }, }; -module_platform_driver(tegra_emc_driver); +module_platform_driver(tegra30_emc_driver); MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>"); MODULE_DESCRIPTION("NVIDIA Tegra30 EMC driver"); diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index 84316357513d..d3e685c8431f 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -3,8 +3,8 @@ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. */ +#include <linux/device.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/slab.h> #include <dt-bindings/memory/tegra30-mc.h> @@ -1332,7 +1332,7 @@ static int tegra30_mc_icc_aggreate(struct icc_node *node, u32 tag, u32 avg_bw, } static struct icc_node_data * -tegra30_mc_of_icc_xlate_extended(struct of_phandle_args *spec, void *data) +tegra30_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data) { struct tegra_mc *mc = icc_provider_to_tegra_mc(data); const struct tegra_mc_client *client; diff --git a/drivers/memory/ti-aemif.c b/drivers/memory/ti-aemif.c index f81e7df8798a..c8b83c9edbd5 100644 --- a/drivers/memory/ti-aemif.c +++ b/drivers/memory/ti-aemif.c @@ -13,11 +13,12 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/memory/ti-aemif.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> -#include <linux/platform_data/ti-aemif.h> #define TA_SHIFT 2 #define RHOLD_SHIFT 4 @@ -70,39 +71,27 @@ #define ACR_SSTROBE_MASK BIT(31) #define ASIZE_16BIT 1 -#define CONFIG_MASK (TA(TA_MAX) | \ - RHOLD(RHOLD_MAX) | \ - RSTROBE(RSTROBE_MAX) | \ - RSETUP(RSETUP_MAX) | \ - WHOLD(WHOLD_MAX) | \ - WSTROBE(WSTROBE_MAX) | \ - WSETUP(WSETUP_MAX) | \ - EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | \ - ASIZE_MAX) +#define TIMINGS_MASK (TA(TA_MAX) | \ + RHOLD(RHOLD_MAX) | \ + RSTROBE(RSTROBE_MAX) | \ + RSETUP(RSETUP_MAX) | \ + WHOLD(WHOLD_MAX) | \ + WSTROBE(WSTROBE_MAX) | \ + WSETUP(WSETUP_MAX)) + +#define CONFIG_MASK (EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | ASIZE_MAX) /** - * struct aemif_cs_data: structure to hold cs parameters + * struct aemif_cs_data: structure to hold CS parameters + * @timings: timings configuration * @cs: chip-select number - * @wstrobe: write strobe width, ns - * @rstrobe: read strobe width, ns - * @wsetup: write setup width, ns - * @whold: write hold width, ns - * @rsetup: read setup width, ns - * @rhold: read hold width, ns - * @ta: minimum turn around time, ns * @enable_ss: enable/disable select strobe mode * @enable_ew: enable/disable extended wait mode * @asize: width of the asynchronous device's data bus */ struct aemif_cs_data { + struct aemif_cs_timings timings; u8 cs; - u16 wstrobe; - u16 rstrobe; - u8 wsetup; - u8 whold; - u8 rsetup; - u8 rhold; - u8 ta; u8 enable_ss; u8 enable_ew; u8 asize; @@ -116,6 +105,7 @@ struct aemif_cs_data { * @num_cs: number of assigned chip-selects * @cs_offset: start number of cs nodes * @cs_data: array of chip-select settings + * @config_cs_lock: lock used to access CS configuration */ struct aemif_device { void __iomem *base; @@ -124,20 +114,94 @@ struct aemif_device { u8 num_cs; int cs_offset; struct aemif_cs_data cs_data[NUM_CS]; + struct mutex config_cs_lock; }; /** + * aemif_check_cs_timings() - Check the validity of a CS timing configuration. + * @timings: timings configuration + * + * @return: 0 if the timing configuration is valid, negative error number otherwise. + */ +int aemif_check_cs_timings(struct aemif_cs_timings *timings) +{ + if (timings->ta > TA_MAX) + return -EINVAL; + + if (timings->rhold > RHOLD_MAX) + return -EINVAL; + + if (timings->rstrobe > RSTROBE_MAX) + return -EINVAL; + + if (timings->rsetup > RSETUP_MAX) + return -EINVAL; + + if (timings->whold > WHOLD_MAX) + return -EINVAL; + + if (timings->wstrobe > WSTROBE_MAX) + return -EINVAL; + + if (timings->wsetup > WSETUP_MAX) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(aemif_check_cs_timings); + +/** + * aemif_set_cs_timings() - Set the timing configuration of a given chip select. + * @aemif: aemif device to configure + * @cs: index of the chip select to configure + * @timings: timings configuration to set + * + * @return: 0 on success, else negative errno. + */ +int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, + struct aemif_cs_timings *timings) +{ + unsigned int offset; + u32 val, set; + int ret; + + if (!timings || !aemif) + return -EINVAL; + + if (cs > aemif->num_cs) + return -EINVAL; + + ret = aemif_check_cs_timings(timings); + if (ret) + return ret; + + set = TA(timings->ta) | RHOLD(timings->rhold) | RSTROBE(timings->rstrobe) | + RSETUP(timings->rsetup) | WHOLD(timings->whold) | + WSTROBE(timings->wstrobe) | WSETUP(timings->wsetup); + + offset = A1CR_OFFSET + cs * 4; + + mutex_lock(&aemif->config_cs_lock); + val = readl(aemif->base + offset); + val &= ~TIMINGS_MASK; + val |= set; + writel(val, aemif->base + offset); + mutex_unlock(&aemif->config_cs_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(aemif_set_cs_timings); + +/** * aemif_calc_rate - calculate timing data. * @pdev: platform device to calculate for * @wanted: The cycle time needed in nanoseconds. * @clk: The input clock rate in kHz. - * @max: The maximum divider value that can be programmed. * - * On success, returns the calculated timing value minus 1 for easy - * programming into AEMIF timing registers, else negative errno. + * @return: the calculated timing value minus 1 for easy + * programming into AEMIF timing registers. */ -static int aemif_calc_rate(struct platform_device *pdev, int wanted, - unsigned long clk, int max) +static u32 aemif_calc_rate(struct platform_device *pdev, int wanted, unsigned long clk) { int result; @@ -150,10 +214,6 @@ static int aemif_calc_rate(struct platform_device *pdev, int wanted, if (result < 0) result = 0; - /* ... But configuring tighter timings is not an option. */ - else if (result > max) - result = -EINVAL; - return result; } @@ -175,48 +235,25 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum) { struct aemif_device *aemif = platform_get_drvdata(pdev); struct aemif_cs_data *data = &aemif->cs_data[csnum]; - int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup; - unsigned long clk_rate = aemif->clk_rate; unsigned offset; u32 set, val; offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4; - ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX); - rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX); - rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX); - rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX); - whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX); - wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX); - wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX); - - if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 || - whold < 0 || wstrobe < 0 || wsetup < 0) { - dev_err(&pdev->dev, "%s: cannot get suitable timings\n", - __func__); - return -EINVAL; - } - - set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) | - WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup); - - set |= (data->asize & ACR_ASIZE_MASK); + set = (data->asize & ACR_ASIZE_MASK); if (data->enable_ew) set |= ACR_EW_MASK; if (data->enable_ss) set |= ACR_SSTROBE_MASK; + mutex_lock(&aemif->config_cs_lock); val = readl(aemif->base + offset); val &= ~CONFIG_MASK; val |= set; writel(val, aemif->base + offset); + mutex_unlock(&aemif->config_cs_lock); - return 0; -} - -static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate) -{ - return ((val + 1) * NSEC_PER_MSEC) / clk_rate; + return aemif_set_cs_timings(aemif, data->cs - aemif->cs_offset, &data->timings); } /** @@ -232,19 +269,18 @@ static void aemif_get_hw_params(struct platform_device *pdev, int csnum) { struct aemif_device *aemif = platform_get_drvdata(pdev); struct aemif_cs_data *data = &aemif->cs_data[csnum]; - unsigned long clk_rate = aemif->clk_rate; u32 val, offset; offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4; val = readl(aemif->base + offset); - data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate); - data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate); - data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate); - data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate); - data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate); - data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate); - data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate); + data->timings.ta = TA_VAL(val); + data->timings.rhold = RHOLD_VAL(val); + data->timings.rstrobe = RSTROBE_VAL(val); + data->timings.rsetup = RSETUP_VAL(val); + data->timings.whold = WHOLD_VAL(val); + data->timings.wstrobe = WSTROBE_VAL(val); + data->timings.wsetup = WSETUP_VAL(val); data->enable_ew = EW_VAL(val); data->enable_ss = SSTROBE_VAL(val); data->asize = val & ASIZE_MAX; @@ -262,6 +298,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev, struct device_node *np) { struct aemif_device *aemif = platform_get_drvdata(pdev); + unsigned long clk_rate = aemif->clk_rate; struct aemif_cs_data *data; u32 cs; u32 val; @@ -289,32 +326,33 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev, /* override the values from device node */ if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val)) - data->ta = val; + data->timings.ta = aemif_calc_rate(pdev, val, clk_rate); if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val)) - data->rhold = val; + data->timings.rhold = aemif_calc_rate(pdev, val, clk_rate); if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val)) - data->rstrobe = val; + data->timings.rstrobe = aemif_calc_rate(pdev, val, clk_rate); if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val)) - data->rsetup = val; + data->timings.rsetup = aemif_calc_rate(pdev, val, clk_rate); if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val)) - data->whold = val; + data->timings.whold = aemif_calc_rate(pdev, val, clk_rate); if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val)) - data->wstrobe = val; + data->timings.wstrobe = aemif_calc_rate(pdev, val, clk_rate); if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val)) - data->wsetup = val; + data->timings.wsetup = aemif_calc_rate(pdev, val, clk_rate); if (!of_property_read_u32(np, "ti,cs-bus-width", &val)) if (val == 16) data->asize = 1; data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode"); data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode"); - return 0; + + return aemif_check_cs_timings(&data->timings); } static const struct of_device_id aemif_of_match[] = { @@ -330,43 +368,29 @@ static int aemif_probe(struct platform_device *pdev) int ret = -ENODEV; struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *child_np; struct aemif_device *aemif; - struct aemif_platform_data *pdata; - struct of_dev_auxdata *dev_lookup; aemif = devm_kzalloc(dev, sizeof(*aemif), GFP_KERNEL); if (!aemif) return -ENOMEM; - pdata = dev_get_platdata(&pdev->dev); - dev_lookup = pdata ? pdata->dev_lookup : NULL; - platform_set_drvdata(pdev, aemif); - aemif->clk = devm_clk_get(dev, NULL); - if (IS_ERR(aemif->clk)) { - dev_err(dev, "cannot get clock 'aemif'\n"); - return PTR_ERR(aemif->clk); - } - - ret = clk_prepare_enable(aemif->clk); - if (ret) - return ret; + aemif->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(aemif->clk)) + return dev_err_probe(dev, PTR_ERR(aemif->clk), + "cannot get clock 'aemif'\n"); aemif->clk_rate = clk_get_rate(aemif->clk) / MSEC_PER_SEC; if (np && of_device_is_compatible(np, "ti,da850-aemif")) aemif->cs_offset = 2; - else if (pdata) - aemif->cs_offset = pdata->cs_offset; aemif->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(aemif->base)) { - ret = PTR_ERR(aemif->base); - goto error; - } + if (IS_ERR(aemif->base)) + return PTR_ERR(aemif->base); + mutex_init(&aemif->config_cs_lock); if (np) { /* * For every controller device node, there is a cs device node @@ -374,17 +398,10 @@ static int aemif_probe(struct platform_device *pdev) * functions iterate over these nodes and update the cs data * array. */ - for_each_available_child_of_node(np, child_np) { + for_each_available_child_of_node_scoped(np, child_np) { ret = of_aemif_parse_abus_config(pdev, child_np); - if (ret < 0) { - of_node_put(child_np); - goto error; - } - } - } else if (pdata && pdata->num_abus_data > 0) { - for (i = 0; i < pdata->num_abus_data; i++, aemif->num_cs++) { - aemif->cs_data[i].cs = pdata->abus_data[i].cs; - aemif_get_hw_params(pdev, i); + if (ret < 0) + return ret; } } @@ -393,7 +410,7 @@ static int aemif_probe(struct platform_device *pdev) if (ret < 0) { dev_err(dev, "Error configuring chip select %d\n", aemif->cs_data[i].cs); - goto error; + return ret; } } @@ -402,42 +419,18 @@ static int aemif_probe(struct platform_device *pdev) * child will be probed after the AEMIF timing parameters are set. */ if (np) { - for_each_available_child_of_node(np, child_np) { - ret = of_platform_populate(child_np, NULL, - dev_lookup, dev); - if (ret < 0) { - of_node_put(child_np); - goto error; - } - } - } else if (pdata) { - for (i = 0; i < pdata->num_sub_devices; i++) { - pdata->sub_devices[i].dev.parent = dev; - ret = platform_device_register(&pdata->sub_devices[i]); - if (ret) { - dev_warn(dev, "Error register sub device %s\n", - pdata->sub_devices[i].name); - } + for_each_available_child_of_node_scoped(np, child_np) { + ret = of_platform_populate(child_np, NULL, NULL, dev); + if (ret < 0) + return ret; } } return 0; -error: - clk_disable_unprepare(aemif->clk); - return ret; -} - -static int aemif_remove(struct platform_device *pdev) -{ - struct aemif_device *aemif = platform_get_drvdata(pdev); - - clk_disable_unprepare(aemif->clk); - return 0; } static struct platform_driver aemif_driver = { .probe = aemif_probe, - .remove = aemif_remove, .driver = { .name = "ti-aemif", .of_match_table = of_match_ptr(aemif_of_match), diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c index 31d6266f008c..df362ecc59e9 100644 --- a/drivers/memory/ti-emif-pm.c +++ b/drivers/memory/ti-emif-pm.c @@ -277,18 +277,13 @@ static int ti_emif_probe(struct platform_device *pdev) int ret; struct resource *res; struct device *dev = &pdev->dev; - const struct of_device_id *match; struct ti_emif_data *emif_data; emif_data = devm_kzalloc(dev, sizeof(*emif_data), GFP_KERNEL); if (!emif_data) return -ENOMEM; - match = of_match_device(ti_emif_of_match, &pdev->dev); - if (!match) - return -ENODEV; - - emif_data->pm_data.ti_emif_sram_config = (unsigned long)match->data; + emif_data->pm_data.ti_emif_sram_config = (unsigned long) device_get_match_data(&pdev->dev); emif_data->pm_data.ti_emif_base_addr_virt = devm_platform_get_and_ioremap_resource(pdev, 0, @@ -320,15 +315,13 @@ fail_free_sram: return ret; } -static int ti_emif_remove(struct platform_device *pdev) +static void ti_emif_remove(struct platform_device *pdev) { struct ti_emif_data *emif_data = emif_instance; emif_instance = NULL; ti_emif_free_sram(emif_data); - - return 0; } static const struct dev_pm_ops ti_emif_pm_ops = { diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S index d60a8cfd63f3..7756b3971244 100644 --- a/drivers/memory/ti-emif-sram-pm.S +++ b/drivers/memory/ti-emif-sram-pm.S @@ -8,7 +8,7 @@ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/memory.h> +#include <asm/page.h> #include "emif.h" #include "ti-emif-asm-offsets.h" |
