1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 289184651SThierry Reding /* 389184651SThierry Reding * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. 489184651SThierry Reding */ 589184651SThierry Reding 689184651SThierry Reding #include <linux/clk.h> 720e92462SDmitry Osipenko #include <linux/delay.h> 8c4c21f22SThierry Reding #include <linux/dma-mapping.h> 90c56eda8SDmitry Osipenko #include <linux/export.h> 1089184651SThierry Reding #include <linux/interrupt.h> 1189184651SThierry Reding #include <linux/kernel.h> 1289184651SThierry Reding #include <linux/module.h> 1389184651SThierry Reding #include <linux/of.h> 1459cd046fSDmitry Osipenko #include <linux/of_device.h> 1589184651SThierry Reding #include <linux/platform_device.h> 1689184651SThierry Reding #include <linux/slab.h> 173d9dd6fdSMikko Perttunen #include <linux/sort.h> 183d9dd6fdSMikko Perttunen 193d9dd6fdSMikko Perttunen #include <soc/tegra/fuse.h> 2089184651SThierry Reding 2189184651SThierry Reding #include "mc.h" 2289184651SThierry Reding 2389184651SThierry Reding static const struct of_device_id tegra_mc_of_match[] = { 24a8d502fdSDmitry Osipenko #ifdef CONFIG_ARCH_TEGRA_2x_SOC 2596efa118SDmitry Osipenko { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc }, 26a8d502fdSDmitry Osipenko #endif 2789184651SThierry Reding #ifdef CONFIG_ARCH_TEGRA_3x_SOC 2889184651SThierry Reding { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc }, 2989184651SThierry Reding #endif 3089184651SThierry Reding #ifdef CONFIG_ARCH_TEGRA_114_SOC 3189184651SThierry Reding { .compatible = "nvidia,tegra114-mc", .data = &tegra114_mc_soc }, 3289184651SThierry Reding #endif 3389184651SThierry Reding #ifdef CONFIG_ARCH_TEGRA_124_SOC 3489184651SThierry Reding { .compatible = "nvidia,tegra124-mc", .data = &tegra124_mc_soc }, 3589184651SThierry Reding #endif 36242b1d71SThierry Reding #ifdef CONFIG_ARCH_TEGRA_132_SOC 37242b1d71SThierry Reding { .compatible = "nvidia,tegra132-mc", .data = &tegra132_mc_soc }, 38242b1d71SThierry Reding #endif 39588c43a7SThierry Reding #ifdef CONFIG_ARCH_TEGRA_210_SOC 40588c43a7SThierry Reding { .compatible = "nvidia,tegra210-mc", .data = &tegra210_mc_soc }, 41588c43a7SThierry Reding #endif 427355c7b9SThierry Reding #ifdef CONFIG_ARCH_TEGRA_186_SOC 437355c7b9SThierry Reding { .compatible = "nvidia,tegra186-mc", .data = &tegra186_mc_soc }, 447355c7b9SThierry Reding #endif 457355c7b9SThierry Reding #ifdef CONFIG_ARCH_TEGRA_194_SOC 467355c7b9SThierry Reding { .compatible = "nvidia,tegra194-mc", .data = &tegra194_mc_soc }, 477355c7b9SThierry Reding #endif 487355c7b9SThierry Reding { /* sentinel */ } 4989184651SThierry Reding }; 5089184651SThierry Reding MODULE_DEVICE_TABLE(of, tegra_mc_of_match); 5189184651SThierry Reding 526c6bd207SDmitry Osipenko static void tegra_mc_devm_action_put_device(void *data) 536c6bd207SDmitry Osipenko { 546c6bd207SDmitry Osipenko struct tegra_mc *mc = data; 556c6bd207SDmitry Osipenko 566c6bd207SDmitry Osipenko put_device(mc->dev); 576c6bd207SDmitry Osipenko } 586c6bd207SDmitry Osipenko 596c6bd207SDmitry Osipenko /** 606c6bd207SDmitry Osipenko * devm_tegra_memory_controller_get() - get Tegra Memory Controller handle 616c6bd207SDmitry Osipenko * @dev: device pointer for the consumer device 626c6bd207SDmitry Osipenko * 636c6bd207SDmitry Osipenko * This function will search for the Memory Controller node in a device-tree 646c6bd207SDmitry Osipenko * and retrieve the Memory Controller handle. 656c6bd207SDmitry Osipenko * 666c6bd207SDmitry Osipenko * Return: ERR_PTR() on error or a valid pointer to a struct tegra_mc. 676c6bd207SDmitry Osipenko */ 686c6bd207SDmitry Osipenko struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev) 696c6bd207SDmitry Osipenko { 706c6bd207SDmitry Osipenko struct platform_device *pdev; 716c6bd207SDmitry Osipenko struct device_node *np; 726c6bd207SDmitry Osipenko struct tegra_mc *mc; 736c6bd207SDmitry Osipenko int err; 746c6bd207SDmitry Osipenko 756c6bd207SDmitry Osipenko np = of_parse_phandle(dev->of_node, "nvidia,memory-controller", 0); 766c6bd207SDmitry Osipenko if (!np) 776c6bd207SDmitry Osipenko return ERR_PTR(-ENOENT); 786c6bd207SDmitry Osipenko 796c6bd207SDmitry Osipenko pdev = of_find_device_by_node(np); 806c6bd207SDmitry Osipenko of_node_put(np); 816c6bd207SDmitry Osipenko if (!pdev) 826c6bd207SDmitry Osipenko return ERR_PTR(-ENODEV); 836c6bd207SDmitry Osipenko 846c6bd207SDmitry Osipenko mc = platform_get_drvdata(pdev); 856c6bd207SDmitry Osipenko if (!mc) { 866c6bd207SDmitry Osipenko put_device(&pdev->dev); 876c6bd207SDmitry Osipenko return ERR_PTR(-EPROBE_DEFER); 886c6bd207SDmitry Osipenko } 896c6bd207SDmitry Osipenko 90*1d8e0223SCai Huoqing err = devm_add_action_or_reset(dev, tegra_mc_devm_action_put_device, mc); 91*1d8e0223SCai Huoqing if (err) 926c6bd207SDmitry Osipenko return ERR_PTR(err); 936c6bd207SDmitry Osipenko 946c6bd207SDmitry Osipenko return mc; 956c6bd207SDmitry Osipenko } 966c6bd207SDmitry Osipenko EXPORT_SYMBOL_GPL(devm_tegra_memory_controller_get); 976c6bd207SDmitry Osipenko 98393d66fdSThierry Reding int tegra_mc_probe_device(struct tegra_mc *mc, struct device *dev) 99393d66fdSThierry Reding { 100393d66fdSThierry Reding if (mc->soc->ops && mc->soc->ops->probe_device) 101393d66fdSThierry Reding return mc->soc->ops->probe_device(mc, dev); 102393d66fdSThierry Reding 103393d66fdSThierry Reding return 0; 104393d66fdSThierry Reding } 105393d66fdSThierry Reding EXPORT_SYMBOL_GPL(tegra_mc_probe_device); 106393d66fdSThierry Reding 107cb2b5839SThierry Reding static int tegra_mc_block_dma_common(struct tegra_mc *mc, 10820e92462SDmitry Osipenko const struct tegra_mc_reset *rst) 10920e92462SDmitry Osipenko { 11020e92462SDmitry Osipenko unsigned long flags; 11120e92462SDmitry Osipenko u32 value; 11220e92462SDmitry Osipenko 11320e92462SDmitry Osipenko spin_lock_irqsave(&mc->lock, flags); 11420e92462SDmitry Osipenko 11520e92462SDmitry Osipenko value = mc_readl(mc, rst->control) | BIT(rst->bit); 11620e92462SDmitry Osipenko mc_writel(mc, value, rst->control); 11720e92462SDmitry Osipenko 11820e92462SDmitry Osipenko spin_unlock_irqrestore(&mc->lock, flags); 11920e92462SDmitry Osipenko 12020e92462SDmitry Osipenko return 0; 12120e92462SDmitry Osipenko } 12220e92462SDmitry Osipenko 123cb2b5839SThierry Reding static bool tegra_mc_dma_idling_common(struct tegra_mc *mc, 12420e92462SDmitry Osipenko const struct tegra_mc_reset *rst) 12520e92462SDmitry Osipenko { 12620e92462SDmitry Osipenko return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0; 12720e92462SDmitry Osipenko } 12820e92462SDmitry Osipenko 129cb2b5839SThierry Reding static int tegra_mc_unblock_dma_common(struct tegra_mc *mc, 13020e92462SDmitry Osipenko const struct tegra_mc_reset *rst) 13120e92462SDmitry Osipenko { 13220e92462SDmitry Osipenko unsigned long flags; 13320e92462SDmitry Osipenko u32 value; 13420e92462SDmitry Osipenko 13520e92462SDmitry Osipenko spin_lock_irqsave(&mc->lock, flags); 13620e92462SDmitry Osipenko 13720e92462SDmitry Osipenko value = mc_readl(mc, rst->control) & ~BIT(rst->bit); 13820e92462SDmitry Osipenko mc_writel(mc, value, rst->control); 13920e92462SDmitry Osipenko 14020e92462SDmitry Osipenko spin_unlock_irqrestore(&mc->lock, flags); 14120e92462SDmitry Osipenko 14220e92462SDmitry Osipenko return 0; 14320e92462SDmitry Osipenko } 14420e92462SDmitry Osipenko 145cb2b5839SThierry Reding static int tegra_mc_reset_status_common(struct tegra_mc *mc, 14620e92462SDmitry Osipenko const struct tegra_mc_reset *rst) 14720e92462SDmitry Osipenko { 14820e92462SDmitry Osipenko return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0; 14920e92462SDmitry Osipenko } 15020e92462SDmitry Osipenko 151cb2b5839SThierry Reding const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = { 152cb2b5839SThierry Reding .block_dma = tegra_mc_block_dma_common, 153cb2b5839SThierry Reding .dma_idling = tegra_mc_dma_idling_common, 154cb2b5839SThierry Reding .unblock_dma = tegra_mc_unblock_dma_common, 155cb2b5839SThierry Reding .reset_status = tegra_mc_reset_status_common, 15620e92462SDmitry Osipenko }; 15720e92462SDmitry Osipenko 15820e92462SDmitry Osipenko static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev) 15920e92462SDmitry Osipenko { 16020e92462SDmitry Osipenko return container_of(rcdev, struct tegra_mc, reset); 16120e92462SDmitry Osipenko } 16220e92462SDmitry Osipenko 16320e92462SDmitry Osipenko static const struct tegra_mc_reset *tegra_mc_reset_find(struct tegra_mc *mc, 16420e92462SDmitry Osipenko unsigned long id) 16520e92462SDmitry Osipenko { 16620e92462SDmitry Osipenko unsigned int i; 16720e92462SDmitry Osipenko 16820e92462SDmitry Osipenko for (i = 0; i < mc->soc->num_resets; i++) 16920e92462SDmitry Osipenko if (mc->soc->resets[i].id == id) 17020e92462SDmitry Osipenko return &mc->soc->resets[i]; 17120e92462SDmitry Osipenko 17220e92462SDmitry Osipenko return NULL; 17320e92462SDmitry Osipenko } 17420e92462SDmitry Osipenko 17520e92462SDmitry Osipenko static int tegra_mc_hotreset_assert(struct reset_controller_dev *rcdev, 17620e92462SDmitry Osipenko unsigned long id) 17720e92462SDmitry Osipenko { 17820e92462SDmitry Osipenko struct tegra_mc *mc = reset_to_mc(rcdev); 17920e92462SDmitry Osipenko const struct tegra_mc_reset_ops *rst_ops; 18020e92462SDmitry Osipenko const struct tegra_mc_reset *rst; 18120e92462SDmitry Osipenko int retries = 500; 18220e92462SDmitry Osipenko int err; 18320e92462SDmitry Osipenko 18420e92462SDmitry Osipenko rst = tegra_mc_reset_find(mc, id); 18520e92462SDmitry Osipenko if (!rst) 18620e92462SDmitry Osipenko return -ENODEV; 18720e92462SDmitry Osipenko 18820e92462SDmitry Osipenko rst_ops = mc->soc->reset_ops; 18920e92462SDmitry Osipenko if (!rst_ops) 19020e92462SDmitry Osipenko return -ENODEV; 19120e92462SDmitry Osipenko 1926ce84ab6SDmitry Osipenko /* DMA flushing will fail if reset is already asserted */ 1936ce84ab6SDmitry Osipenko if (rst_ops->reset_status) { 1946ce84ab6SDmitry Osipenko /* check whether reset is asserted */ 1956ce84ab6SDmitry Osipenko if (rst_ops->reset_status(mc, rst)) 1966ce84ab6SDmitry Osipenko return 0; 1976ce84ab6SDmitry Osipenko } 1986ce84ab6SDmitry Osipenko 19920e92462SDmitry Osipenko if (rst_ops->block_dma) { 20020e92462SDmitry Osipenko /* block clients DMA requests */ 20120e92462SDmitry Osipenko err = rst_ops->block_dma(mc, rst); 20220e92462SDmitry Osipenko if (err) { 203f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to block %s DMA: %d\n", 20420e92462SDmitry Osipenko rst->name, err); 20520e92462SDmitry Osipenko return err; 20620e92462SDmitry Osipenko } 20720e92462SDmitry Osipenko } 20820e92462SDmitry Osipenko 20920e92462SDmitry Osipenko if (rst_ops->dma_idling) { 21020e92462SDmitry Osipenko /* wait for completion of the outstanding DMA requests */ 21120e92462SDmitry Osipenko while (!rst_ops->dma_idling(mc, rst)) { 21220e92462SDmitry Osipenko if (!retries--) { 213f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to flush %s DMA\n", 21420e92462SDmitry Osipenko rst->name); 21520e92462SDmitry Osipenko return -EBUSY; 21620e92462SDmitry Osipenko } 21720e92462SDmitry Osipenko 21820e92462SDmitry Osipenko usleep_range(10, 100); 21920e92462SDmitry Osipenko } 22020e92462SDmitry Osipenko } 22120e92462SDmitry Osipenko 22220e92462SDmitry Osipenko if (rst_ops->hotreset_assert) { 22320e92462SDmitry Osipenko /* clear clients DMA requests sitting before arbitration */ 22420e92462SDmitry Osipenko err = rst_ops->hotreset_assert(mc, rst); 22520e92462SDmitry Osipenko if (err) { 226f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to hot reset %s: %d\n", 22720e92462SDmitry Osipenko rst->name, err); 22820e92462SDmitry Osipenko return err; 22920e92462SDmitry Osipenko } 23020e92462SDmitry Osipenko } 23120e92462SDmitry Osipenko 23220e92462SDmitry Osipenko return 0; 23320e92462SDmitry Osipenko } 23420e92462SDmitry Osipenko 23520e92462SDmitry Osipenko static int tegra_mc_hotreset_deassert(struct reset_controller_dev *rcdev, 23620e92462SDmitry Osipenko unsigned long id) 23720e92462SDmitry Osipenko { 23820e92462SDmitry Osipenko struct tegra_mc *mc = reset_to_mc(rcdev); 23920e92462SDmitry Osipenko const struct tegra_mc_reset_ops *rst_ops; 24020e92462SDmitry Osipenko const struct tegra_mc_reset *rst; 24120e92462SDmitry Osipenko int err; 24220e92462SDmitry Osipenko 24320e92462SDmitry Osipenko rst = tegra_mc_reset_find(mc, id); 24420e92462SDmitry Osipenko if (!rst) 24520e92462SDmitry Osipenko return -ENODEV; 24620e92462SDmitry Osipenko 24720e92462SDmitry Osipenko rst_ops = mc->soc->reset_ops; 24820e92462SDmitry Osipenko if (!rst_ops) 24920e92462SDmitry Osipenko return -ENODEV; 25020e92462SDmitry Osipenko 25120e92462SDmitry Osipenko if (rst_ops->hotreset_deassert) { 25220e92462SDmitry Osipenko /* take out client from hot reset */ 25320e92462SDmitry Osipenko err = rst_ops->hotreset_deassert(mc, rst); 25420e92462SDmitry Osipenko if (err) { 255f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to deassert hot reset %s: %d\n", 25620e92462SDmitry Osipenko rst->name, err); 25720e92462SDmitry Osipenko return err; 25820e92462SDmitry Osipenko } 25920e92462SDmitry Osipenko } 26020e92462SDmitry Osipenko 26120e92462SDmitry Osipenko if (rst_ops->unblock_dma) { 26220e92462SDmitry Osipenko /* allow new DMA requests to proceed to arbitration */ 26320e92462SDmitry Osipenko err = rst_ops->unblock_dma(mc, rst); 26420e92462SDmitry Osipenko if (err) { 265f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to unblock %s DMA : %d\n", 26620e92462SDmitry Osipenko rst->name, err); 26720e92462SDmitry Osipenko return err; 26820e92462SDmitry Osipenko } 26920e92462SDmitry Osipenko } 27020e92462SDmitry Osipenko 27120e92462SDmitry Osipenko return 0; 27220e92462SDmitry Osipenko } 27320e92462SDmitry Osipenko 27420e92462SDmitry Osipenko static int tegra_mc_hotreset_status(struct reset_controller_dev *rcdev, 27520e92462SDmitry Osipenko unsigned long id) 27620e92462SDmitry Osipenko { 27720e92462SDmitry Osipenko struct tegra_mc *mc = reset_to_mc(rcdev); 27820e92462SDmitry Osipenko const struct tegra_mc_reset_ops *rst_ops; 27920e92462SDmitry Osipenko const struct tegra_mc_reset *rst; 28020e92462SDmitry Osipenko 28120e92462SDmitry Osipenko rst = tegra_mc_reset_find(mc, id); 28220e92462SDmitry Osipenko if (!rst) 28320e92462SDmitry Osipenko return -ENODEV; 28420e92462SDmitry Osipenko 28520e92462SDmitry Osipenko rst_ops = mc->soc->reset_ops; 28620e92462SDmitry Osipenko if (!rst_ops) 28720e92462SDmitry Osipenko return -ENODEV; 28820e92462SDmitry Osipenko 28920e92462SDmitry Osipenko return rst_ops->reset_status(mc, rst); 29020e92462SDmitry Osipenko } 29120e92462SDmitry Osipenko 29220e92462SDmitry Osipenko static const struct reset_control_ops tegra_mc_reset_ops = { 29320e92462SDmitry Osipenko .assert = tegra_mc_hotreset_assert, 29420e92462SDmitry Osipenko .deassert = tegra_mc_hotreset_deassert, 29520e92462SDmitry Osipenko .status = tegra_mc_hotreset_status, 29620e92462SDmitry Osipenko }; 29720e92462SDmitry Osipenko 29820e92462SDmitry Osipenko static int tegra_mc_reset_setup(struct tegra_mc *mc) 29920e92462SDmitry Osipenko { 30020e92462SDmitry Osipenko int err; 30120e92462SDmitry Osipenko 30220e92462SDmitry Osipenko mc->reset.ops = &tegra_mc_reset_ops; 30320e92462SDmitry Osipenko mc->reset.owner = THIS_MODULE; 30420e92462SDmitry Osipenko mc->reset.of_node = mc->dev->of_node; 30520e92462SDmitry Osipenko mc->reset.of_reset_n_cells = 1; 30620e92462SDmitry Osipenko mc->reset.nr_resets = mc->soc->num_resets; 30720e92462SDmitry Osipenko 30820e92462SDmitry Osipenko err = reset_controller_register(&mc->reset); 30920e92462SDmitry Osipenko if (err < 0) 31020e92462SDmitry Osipenko return err; 31120e92462SDmitry Osipenko 31220e92462SDmitry Osipenko return 0; 31320e92462SDmitry Osipenko } 31420e92462SDmitry Osipenko 315e34212c7SDmitry Osipenko int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate) 3163d9dd6fdSMikko Perttunen { 3173d9dd6fdSMikko Perttunen unsigned int i; 3183d9dd6fdSMikko Perttunen struct tegra_mc_timing *timing = NULL; 3193d9dd6fdSMikko Perttunen 3203d9dd6fdSMikko Perttunen for (i = 0; i < mc->num_timings; i++) { 3213d9dd6fdSMikko Perttunen if (mc->timings[i].rate == rate) { 3223d9dd6fdSMikko Perttunen timing = &mc->timings[i]; 3233d9dd6fdSMikko Perttunen break; 3243d9dd6fdSMikko Perttunen } 3253d9dd6fdSMikko Perttunen } 3263d9dd6fdSMikko Perttunen 3273d9dd6fdSMikko Perttunen if (!timing) { 3283d9dd6fdSMikko Perttunen dev_err(mc->dev, "no memory timing registered for rate %lu\n", 3293d9dd6fdSMikko Perttunen rate); 330e34212c7SDmitry Osipenko return -EINVAL; 3313d9dd6fdSMikko Perttunen } 3323d9dd6fdSMikko Perttunen 3333d9dd6fdSMikko Perttunen for (i = 0; i < mc->soc->num_emem_regs; ++i) 3343d9dd6fdSMikko Perttunen mc_writel(mc, timing->emem_data[i], mc->soc->emem_regs[i]); 335e34212c7SDmitry Osipenko 336e34212c7SDmitry Osipenko return 0; 3373d9dd6fdSMikko Perttunen } 3380c56eda8SDmitry Osipenko EXPORT_SYMBOL_GPL(tegra_mc_write_emem_configuration); 3393d9dd6fdSMikko Perttunen 3403d9dd6fdSMikko Perttunen unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc) 3413d9dd6fdSMikko Perttunen { 3423d9dd6fdSMikko Perttunen u8 dram_count; 3433d9dd6fdSMikko Perttunen 3443d9dd6fdSMikko Perttunen dram_count = mc_readl(mc, MC_EMEM_ADR_CFG); 3453d9dd6fdSMikko Perttunen dram_count &= MC_EMEM_ADR_CFG_EMEM_NUMDEV; 3463d9dd6fdSMikko Perttunen dram_count++; 3473d9dd6fdSMikko Perttunen 3483d9dd6fdSMikko Perttunen return dram_count; 3493d9dd6fdSMikko Perttunen } 3500c56eda8SDmitry Osipenko EXPORT_SYMBOL_GPL(tegra_mc_get_emem_device_count); 3513d9dd6fdSMikko Perttunen 352ddeceab0SThierry Reding #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ 353ddeceab0SThierry Reding defined(CONFIG_ARCH_TEGRA_114_SOC) || \ 354ddeceab0SThierry Reding defined(CONFIG_ARCH_TEGRA_124_SOC) || \ 355ddeceab0SThierry Reding defined(CONFIG_ARCH_TEGRA_132_SOC) || \ 356ddeceab0SThierry Reding defined(CONFIG_ARCH_TEGRA_210_SOC) 357ddeceab0SThierry Reding static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) 358ddeceab0SThierry Reding { 359ddeceab0SThierry Reding unsigned long long tick; 360ddeceab0SThierry Reding unsigned int i; 361ddeceab0SThierry Reding u32 value; 362ddeceab0SThierry Reding 363ddeceab0SThierry Reding /* compute the number of MC clock cycles per tick */ 364ddeceab0SThierry Reding tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk); 365ddeceab0SThierry Reding do_div(tick, NSEC_PER_SEC); 366ddeceab0SThierry Reding 367ddeceab0SThierry Reding value = mc_readl(mc, MC_EMEM_ARB_CFG); 368ddeceab0SThierry Reding value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; 369ddeceab0SThierry Reding value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); 370ddeceab0SThierry Reding mc_writel(mc, value, MC_EMEM_ARB_CFG); 371ddeceab0SThierry Reding 372ddeceab0SThierry Reding /* write latency allowance defaults */ 373ddeceab0SThierry Reding for (i = 0; i < mc->soc->num_clients; i++) { 374ddeceab0SThierry Reding const struct tegra_mc_client *client = &mc->soc->clients[i]; 375ddeceab0SThierry Reding u32 value; 376ddeceab0SThierry Reding 377ddeceab0SThierry Reding value = mc_readl(mc, client->regs.la.reg); 378ddeceab0SThierry Reding value &= ~(client->regs.la.mask << client->regs.la.shift); 379ddeceab0SThierry Reding value |= (client->regs.la.def & client->regs.la.mask) << client->regs.la.shift; 380ddeceab0SThierry Reding mc_writel(mc, value, client->regs.la.reg); 381ddeceab0SThierry Reding } 382ddeceab0SThierry Reding 383ddeceab0SThierry Reding /* latch new values */ 384ddeceab0SThierry Reding mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL); 385ddeceab0SThierry Reding 386ddeceab0SThierry Reding return 0; 387ddeceab0SThierry Reding } 388ddeceab0SThierry Reding 3893d9dd6fdSMikko Perttunen static int load_one_timing(struct tegra_mc *mc, 3903d9dd6fdSMikko Perttunen struct tegra_mc_timing *timing, 3913d9dd6fdSMikko Perttunen struct device_node *node) 3923d9dd6fdSMikko Perttunen { 3933d9dd6fdSMikko Perttunen int err; 3943d9dd6fdSMikko Perttunen u32 tmp; 3953d9dd6fdSMikko Perttunen 3963d9dd6fdSMikko Perttunen err = of_property_read_u32(node, "clock-frequency", &tmp); 3973d9dd6fdSMikko Perttunen if (err) { 3983d9dd6fdSMikko Perttunen dev_err(mc->dev, 399c86f9854SRob Herring "timing %pOFn: failed to read rate\n", node); 4003d9dd6fdSMikko Perttunen return err; 4013d9dd6fdSMikko Perttunen } 4023d9dd6fdSMikko Perttunen 4033d9dd6fdSMikko Perttunen timing->rate = tmp; 4043d9dd6fdSMikko Perttunen timing->emem_data = devm_kcalloc(mc->dev, mc->soc->num_emem_regs, 4053d9dd6fdSMikko Perttunen sizeof(u32), GFP_KERNEL); 4063d9dd6fdSMikko Perttunen if (!timing->emem_data) 4073d9dd6fdSMikko Perttunen return -ENOMEM; 4083d9dd6fdSMikko Perttunen 4093d9dd6fdSMikko Perttunen err = of_property_read_u32_array(node, "nvidia,emem-configuration", 4103d9dd6fdSMikko Perttunen timing->emem_data, 4113d9dd6fdSMikko Perttunen mc->soc->num_emem_regs); 4123d9dd6fdSMikko Perttunen if (err) { 4133d9dd6fdSMikko Perttunen dev_err(mc->dev, 414c86f9854SRob Herring "timing %pOFn: failed to read EMEM configuration\n", 415c86f9854SRob Herring node); 4163d9dd6fdSMikko Perttunen return err; 4173d9dd6fdSMikko Perttunen } 4183d9dd6fdSMikko Perttunen 4193d9dd6fdSMikko Perttunen return 0; 4203d9dd6fdSMikko Perttunen } 4213d9dd6fdSMikko Perttunen 4223d9dd6fdSMikko Perttunen static int load_timings(struct tegra_mc *mc, struct device_node *node) 4233d9dd6fdSMikko Perttunen { 4243d9dd6fdSMikko Perttunen struct device_node *child; 4253d9dd6fdSMikko Perttunen struct tegra_mc_timing *timing; 4263d9dd6fdSMikko Perttunen int child_count = of_get_child_count(node); 4273d9dd6fdSMikko Perttunen int i = 0, err; 4283d9dd6fdSMikko Perttunen 4293d9dd6fdSMikko Perttunen mc->timings = devm_kcalloc(mc->dev, child_count, sizeof(*timing), 4303d9dd6fdSMikko Perttunen GFP_KERNEL); 4313d9dd6fdSMikko Perttunen if (!mc->timings) 4323d9dd6fdSMikko Perttunen return -ENOMEM; 4333d9dd6fdSMikko Perttunen 4343d9dd6fdSMikko Perttunen mc->num_timings = child_count; 4353d9dd6fdSMikko Perttunen 4363d9dd6fdSMikko Perttunen for_each_child_of_node(node, child) { 4373d9dd6fdSMikko Perttunen timing = &mc->timings[i++]; 4383d9dd6fdSMikko Perttunen 4393d9dd6fdSMikko Perttunen err = load_one_timing(mc, timing, child); 44055bb1d83SAmitoj Kaur Chawla if (err) { 44155bb1d83SAmitoj Kaur Chawla of_node_put(child); 4423d9dd6fdSMikko Perttunen return err; 4433d9dd6fdSMikko Perttunen } 44455bb1d83SAmitoj Kaur Chawla } 4453d9dd6fdSMikko Perttunen 4463d9dd6fdSMikko Perttunen return 0; 4473d9dd6fdSMikko Perttunen } 4483d9dd6fdSMikko Perttunen 4493d9dd6fdSMikko Perttunen static int tegra_mc_setup_timings(struct tegra_mc *mc) 4503d9dd6fdSMikko Perttunen { 4513d9dd6fdSMikko Perttunen struct device_node *node; 4523d9dd6fdSMikko Perttunen u32 ram_code, node_ram_code; 4533d9dd6fdSMikko Perttunen int err; 4543d9dd6fdSMikko Perttunen 4553d9dd6fdSMikko Perttunen ram_code = tegra_read_ram_code(); 4563d9dd6fdSMikko Perttunen 4573d9dd6fdSMikko Perttunen mc->num_timings = 0; 4583d9dd6fdSMikko Perttunen 4593d9dd6fdSMikko Perttunen for_each_child_of_node(mc->dev->of_node, node) { 4603d9dd6fdSMikko Perttunen err = of_property_read_u32(node, "nvidia,ram-code", 4613d9dd6fdSMikko Perttunen &node_ram_code); 462d1122e4bSJulia Lawall if (err || (node_ram_code != ram_code)) 4633d9dd6fdSMikko Perttunen continue; 4643d9dd6fdSMikko Perttunen 4653d9dd6fdSMikko Perttunen err = load_timings(mc, node); 46655bb1d83SAmitoj Kaur Chawla of_node_put(node); 4673d9dd6fdSMikko Perttunen if (err) 4683d9dd6fdSMikko Perttunen return err; 4693d9dd6fdSMikko Perttunen break; 4703d9dd6fdSMikko Perttunen } 4713d9dd6fdSMikko Perttunen 4723d9dd6fdSMikko Perttunen if (mc->num_timings == 0) 4733d9dd6fdSMikko Perttunen dev_warn(mc->dev, 4743d9dd6fdSMikko Perttunen "no memory timings for RAM code %u registered\n", 4753d9dd6fdSMikko Perttunen ram_code); 4763d9dd6fdSMikko Perttunen 4773d9dd6fdSMikko Perttunen return 0; 4783d9dd6fdSMikko Perttunen } 4793d9dd6fdSMikko Perttunen 480ddeceab0SThierry Reding int tegra30_mc_probe(struct tegra_mc *mc) 481ddeceab0SThierry Reding { 482ddeceab0SThierry Reding int err; 483ddeceab0SThierry Reding 484ddeceab0SThierry Reding mc->clk = devm_clk_get_optional(mc->dev, "mc"); 485ddeceab0SThierry Reding if (IS_ERR(mc->clk)) { 486ddeceab0SThierry Reding dev_err(mc->dev, "failed to get MC clock: %ld\n", PTR_ERR(mc->clk)); 487ddeceab0SThierry Reding return PTR_ERR(mc->clk); 488ddeceab0SThierry Reding } 489ddeceab0SThierry Reding 490ddeceab0SThierry Reding /* ensure that debug features are disabled */ 491ddeceab0SThierry Reding mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG); 492ddeceab0SThierry Reding 493ddeceab0SThierry Reding err = tegra_mc_setup_latency_allowance(mc); 494ddeceab0SThierry Reding if (err < 0) { 495ddeceab0SThierry Reding dev_err(mc->dev, "failed to setup latency allowance: %d\n", err); 496ddeceab0SThierry Reding return err; 497ddeceab0SThierry Reding } 498ddeceab0SThierry Reding 499ddeceab0SThierry Reding err = tegra_mc_setup_timings(mc); 500ddeceab0SThierry Reding if (err < 0) { 501ddeceab0SThierry Reding dev_err(mc->dev, "failed to setup timings: %d\n", err); 502ddeceab0SThierry Reding return err; 503ddeceab0SThierry Reding } 504ddeceab0SThierry Reding 505ddeceab0SThierry Reding return 0; 506ddeceab0SThierry Reding } 507ddeceab0SThierry Reding 5081079a66bSThierry Reding static irqreturn_t tegra30_mc_handle_irq(int irq, void *data) 50989184651SThierry Reding { 51089184651SThierry Reding struct tegra_mc *mc = data; 5111c74d5c0SDmitry Osipenko unsigned long status; 51289184651SThierry Reding unsigned int bit; 51389184651SThierry Reding 51489184651SThierry Reding /* mask all interrupts to avoid flooding */ 5151c74d5c0SDmitry Osipenko status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; 516bf3fbdfbSDmitry Osipenko if (!status) 517bf3fbdfbSDmitry Osipenko return IRQ_NONE; 51889184651SThierry Reding 51989184651SThierry Reding for_each_set_bit(bit, &status, 32) { 5201079a66bSThierry Reding const char *error = tegra_mc_status_names[bit] ?: "unknown"; 52189184651SThierry Reding const char *client = "unknown", *desc; 52289184651SThierry Reding const char *direction, *secure; 52389184651SThierry Reding phys_addr_t addr = 0; 52489184651SThierry Reding unsigned int i; 52589184651SThierry Reding char perm[7]; 52689184651SThierry Reding u8 id, type; 52789184651SThierry Reding u32 value; 52889184651SThierry Reding 52989184651SThierry Reding value = mc_readl(mc, MC_ERR_STATUS); 53089184651SThierry Reding 53189184651SThierry Reding #ifdef CONFIG_PHYS_ADDR_T_64BIT 53289184651SThierry Reding if (mc->soc->num_address_bits > 32) { 53389184651SThierry Reding addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) & 53489184651SThierry Reding MC_ERR_STATUS_ADR_HI_MASK); 53589184651SThierry Reding addr <<= 32; 53689184651SThierry Reding } 53789184651SThierry Reding #endif 53889184651SThierry Reding 53989184651SThierry Reding if (value & MC_ERR_STATUS_RW) 54089184651SThierry Reding direction = "write"; 54189184651SThierry Reding else 54289184651SThierry Reding direction = "read"; 54389184651SThierry Reding 54489184651SThierry Reding if (value & MC_ERR_STATUS_SECURITY) 54589184651SThierry Reding secure = "secure "; 54689184651SThierry Reding else 54789184651SThierry Reding secure = ""; 54889184651SThierry Reding 5493c01cf3bSPaul Walmsley id = value & mc->soc->client_id_mask; 55089184651SThierry Reding 55189184651SThierry Reding for (i = 0; i < mc->soc->num_clients; i++) { 55289184651SThierry Reding if (mc->soc->clients[i].id == id) { 55389184651SThierry Reding client = mc->soc->clients[i].name; 55489184651SThierry Reding break; 55589184651SThierry Reding } 55689184651SThierry Reding } 55789184651SThierry Reding 55889184651SThierry Reding type = (value & MC_ERR_STATUS_TYPE_MASK) >> 55989184651SThierry Reding MC_ERR_STATUS_TYPE_SHIFT; 5601079a66bSThierry Reding desc = tegra_mc_error_names[type]; 56189184651SThierry Reding 56289184651SThierry Reding switch (value & MC_ERR_STATUS_TYPE_MASK) { 56389184651SThierry Reding case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE: 56489184651SThierry Reding perm[0] = ' '; 56589184651SThierry Reding perm[1] = '['; 56689184651SThierry Reding 56789184651SThierry Reding if (value & MC_ERR_STATUS_READABLE) 56889184651SThierry Reding perm[2] = 'R'; 56989184651SThierry Reding else 57089184651SThierry Reding perm[2] = '-'; 57189184651SThierry Reding 57289184651SThierry Reding if (value & MC_ERR_STATUS_WRITABLE) 57389184651SThierry Reding perm[3] = 'W'; 57489184651SThierry Reding else 57589184651SThierry Reding perm[3] = '-'; 57689184651SThierry Reding 57789184651SThierry Reding if (value & MC_ERR_STATUS_NONSECURE) 57889184651SThierry Reding perm[4] = '-'; 57989184651SThierry Reding else 58089184651SThierry Reding perm[4] = 'S'; 58189184651SThierry Reding 58289184651SThierry Reding perm[5] = ']'; 58389184651SThierry Reding perm[6] = '\0'; 58489184651SThierry Reding break; 58589184651SThierry Reding 58689184651SThierry Reding default: 58789184651SThierry Reding perm[0] = '\0'; 58889184651SThierry Reding break; 58989184651SThierry Reding } 59089184651SThierry Reding 59189184651SThierry Reding value = mc_readl(mc, MC_ERR_ADR); 59289184651SThierry Reding addr |= value; 59389184651SThierry Reding 59489184651SThierry Reding dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s%s)\n", 59589184651SThierry Reding client, secure, direction, &addr, error, 59689184651SThierry Reding desc, perm); 59789184651SThierry Reding } 59889184651SThierry Reding 59989184651SThierry Reding /* clear interrupts */ 60089184651SThierry Reding mc_writel(mc, status, MC_INTSTATUS); 60189184651SThierry Reding 60289184651SThierry Reding return IRQ_HANDLED; 60389184651SThierry Reding } 60489184651SThierry Reding 6051079a66bSThierry Reding const struct tegra_mc_ops tegra30_mc_ops = { 6061079a66bSThierry Reding .probe = tegra30_mc_probe, 6071079a66bSThierry Reding .handle_irq = tegra30_mc_handle_irq, 6081079a66bSThierry Reding }; 6091079a66bSThierry Reding #endif 610a8d502fdSDmitry Osipenko 6111079a66bSThierry Reding const char *const tegra_mc_status_names[32] = { 6121079a66bSThierry Reding [ 1] = "External interrupt", 6131079a66bSThierry Reding [ 6] = "EMEM address decode error", 6141079a66bSThierry Reding [ 7] = "GART page fault", 6151079a66bSThierry Reding [ 8] = "Security violation", 6161079a66bSThierry Reding [ 9] = "EMEM arbitration error", 6171079a66bSThierry Reding [10] = "Page fault", 6181079a66bSThierry Reding [11] = "Invalid APB ASID update", 6191079a66bSThierry Reding [12] = "VPR violation", 6201079a66bSThierry Reding [13] = "Secure carveout violation", 6211079a66bSThierry Reding [16] = "MTS carveout violation", 6221079a66bSThierry Reding }; 623a8d502fdSDmitry Osipenko 6241079a66bSThierry Reding const char *const tegra_mc_error_names[8] = { 6251079a66bSThierry Reding [2] = "EMEM decode error", 6261079a66bSThierry Reding [3] = "TrustZone violation", 6271079a66bSThierry Reding [4] = "Carveout violation", 6281079a66bSThierry Reding [6] = "SMMU translation error", 6291079a66bSThierry Reding }; 630a8d502fdSDmitry Osipenko 63106f07981SDmitry Osipenko /* 63206f07981SDmitry Osipenko * Memory Controller (MC) has few Memory Clients that are issuing memory 63306f07981SDmitry Osipenko * bandwidth allocation requests to the MC interconnect provider. The MC 63406f07981SDmitry Osipenko * provider aggregates the requests and then sends the aggregated request 63506f07981SDmitry Osipenko * up to the External Memory Controller (EMC) interconnect provider which 63606f07981SDmitry Osipenko * re-configures hardware interface to External Memory (EMEM) in accordance 63706f07981SDmitry Osipenko * to the required bandwidth. Each MC interconnect node represents an 63806f07981SDmitry Osipenko * individual Memory Client. 63906f07981SDmitry Osipenko * 64006f07981SDmitry Osipenko * Memory interconnect topology: 64106f07981SDmitry Osipenko * 64206f07981SDmitry Osipenko * +----+ 64306f07981SDmitry Osipenko * +--------+ | | 64406f07981SDmitry Osipenko * | TEXSRD +--->+ | 64506f07981SDmitry Osipenko * +--------+ | | 64606f07981SDmitry Osipenko * | | +-----+ +------+ 64706f07981SDmitry Osipenko * ... | MC +--->+ EMC +--->+ EMEM | 64806f07981SDmitry Osipenko * | | +-----+ +------+ 64906f07981SDmitry Osipenko * +--------+ | | 65006f07981SDmitry Osipenko * | DISP.. +--->+ | 65106f07981SDmitry Osipenko * +--------+ | | 65206f07981SDmitry Osipenko * +----+ 65306f07981SDmitry Osipenko */ 65406f07981SDmitry Osipenko static int tegra_mc_interconnect_setup(struct tegra_mc *mc) 65506f07981SDmitry Osipenko { 65606f07981SDmitry Osipenko struct icc_node *node; 65706f07981SDmitry Osipenko unsigned int i; 65806f07981SDmitry Osipenko int err; 65906f07981SDmitry Osipenko 66006f07981SDmitry Osipenko /* older device-trees don't have interconnect properties */ 66106f07981SDmitry Osipenko if (!device_property_present(mc->dev, "#interconnect-cells") || 66206f07981SDmitry Osipenko !mc->soc->icc_ops) 66306f07981SDmitry Osipenko return 0; 66406f07981SDmitry Osipenko 66506f07981SDmitry Osipenko mc->provider.dev = mc->dev; 66606f07981SDmitry Osipenko mc->provider.data = &mc->provider; 66706f07981SDmitry Osipenko mc->provider.set = mc->soc->icc_ops->set; 66806f07981SDmitry Osipenko mc->provider.aggregate = mc->soc->icc_ops->aggregate; 66906f07981SDmitry Osipenko mc->provider.xlate_extended = mc->soc->icc_ops->xlate_extended; 67006f07981SDmitry Osipenko 67106f07981SDmitry Osipenko err = icc_provider_add(&mc->provider); 67206f07981SDmitry Osipenko if (err) 67306f07981SDmitry Osipenko return err; 67406f07981SDmitry Osipenko 67506f07981SDmitry Osipenko /* create Memory Controller node */ 67606f07981SDmitry Osipenko node = icc_node_create(TEGRA_ICC_MC); 67706f07981SDmitry Osipenko if (IS_ERR(node)) { 67806f07981SDmitry Osipenko err = PTR_ERR(node); 67906f07981SDmitry Osipenko goto del_provider; 68006f07981SDmitry Osipenko } 68106f07981SDmitry Osipenko 68206f07981SDmitry Osipenko node->name = "Memory Controller"; 68306f07981SDmitry Osipenko icc_node_add(node, &mc->provider); 68406f07981SDmitry Osipenko 68506f07981SDmitry Osipenko /* link Memory Controller to External Memory Controller */ 68606f07981SDmitry Osipenko err = icc_link_create(node, TEGRA_ICC_EMC); 68706f07981SDmitry Osipenko if (err) 68806f07981SDmitry Osipenko goto remove_nodes; 68906f07981SDmitry Osipenko 69006f07981SDmitry Osipenko for (i = 0; i < mc->soc->num_clients; i++) { 69106f07981SDmitry Osipenko /* create MC client node */ 69206f07981SDmitry Osipenko node = icc_node_create(mc->soc->clients[i].id); 69306f07981SDmitry Osipenko if (IS_ERR(node)) { 69406f07981SDmitry Osipenko err = PTR_ERR(node); 69506f07981SDmitry Osipenko goto remove_nodes; 69606f07981SDmitry Osipenko } 69706f07981SDmitry Osipenko 69806f07981SDmitry Osipenko node->name = mc->soc->clients[i].name; 69906f07981SDmitry Osipenko icc_node_add(node, &mc->provider); 70006f07981SDmitry Osipenko 70106f07981SDmitry Osipenko /* link Memory Client to Memory Controller */ 70206f07981SDmitry Osipenko err = icc_link_create(node, TEGRA_ICC_MC); 70306f07981SDmitry Osipenko if (err) 70406f07981SDmitry Osipenko goto remove_nodes; 70506f07981SDmitry Osipenko } 70606f07981SDmitry Osipenko 70706f07981SDmitry Osipenko return 0; 70806f07981SDmitry Osipenko 70906f07981SDmitry Osipenko remove_nodes: 71006f07981SDmitry Osipenko icc_nodes_remove(&mc->provider); 71106f07981SDmitry Osipenko del_provider: 71206f07981SDmitry Osipenko icc_provider_del(&mc->provider); 71306f07981SDmitry Osipenko 71406f07981SDmitry Osipenko return err; 71506f07981SDmitry Osipenko } 71606f07981SDmitry Osipenko 71789184651SThierry Reding static int tegra_mc_probe(struct platform_device *pdev) 71889184651SThierry Reding { 71989184651SThierry Reding struct resource *res; 72089184651SThierry Reding struct tegra_mc *mc; 721c4c21f22SThierry Reding u64 mask; 72289184651SThierry Reding int err; 72389184651SThierry Reding 72489184651SThierry Reding mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); 72589184651SThierry Reding if (!mc) 72689184651SThierry Reding return -ENOMEM; 72789184651SThierry Reding 72889184651SThierry Reding platform_set_drvdata(pdev, mc); 72920e92462SDmitry Osipenko spin_lock_init(&mc->lock); 73059cd046fSDmitry Osipenko mc->soc = of_device_get_match_data(&pdev->dev); 73189184651SThierry Reding mc->dev = &pdev->dev; 73289184651SThierry Reding 733c4c21f22SThierry Reding mask = DMA_BIT_MASK(mc->soc->num_address_bits); 734c4c21f22SThierry Reding 735c4c21f22SThierry Reding err = dma_coerce_mask_and_coherent(&pdev->dev, mask); 736c4c21f22SThierry Reding if (err < 0) { 737c4c21f22SThierry Reding dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); 738c4c21f22SThierry Reding return err; 739c4c21f22SThierry Reding } 740c4c21f22SThierry Reding 74189184651SThierry Reding /* length of MC tick in nanoseconds */ 74289184651SThierry Reding mc->tick = 30; 74389184651SThierry Reding 74489184651SThierry Reding res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 74589184651SThierry Reding mc->regs = devm_ioremap_resource(&pdev->dev, res); 74689184651SThierry Reding if (IS_ERR(mc->regs)) 74789184651SThierry Reding return PTR_ERR(mc->regs); 74889184651SThierry Reding 749c64738e9SThierry Reding mc->debugfs.root = debugfs_create_dir("mc", NULL); 750c64738e9SThierry Reding 751c64738e9SThierry Reding if (mc->soc->ops && mc->soc->ops->probe) { 752c64738e9SThierry Reding err = mc->soc->ops->probe(mc); 753c64738e9SThierry Reding if (err < 0) 754c64738e9SThierry Reding return err; 755c64738e9SThierry Reding } 756c64738e9SThierry Reding 757e474b3a1SThierry Reding if (mc->soc->ops && mc->soc->ops->handle_irq) { 75889184651SThierry Reding mc->irq = platform_get_irq(pdev, 0); 759162641a6SDmitry Osipenko if (mc->irq < 0) 76089184651SThierry Reding return mc->irq; 76189184651SThierry Reding 762f2dcded1SDmitry Osipenko WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n"); 7633c01cf3bSPaul Walmsley 7641c74d5c0SDmitry Osipenko mc_writel(mc, mc->soc->intmask, MC_INTMASK); 76589184651SThierry Reding 7661079a66bSThierry Reding err = devm_request_irq(&pdev->dev, mc->irq, mc->soc->ops->handle_irq, 0, 767db4a9c19SDmitry Osipenko dev_name(&pdev->dev), mc); 768db4a9c19SDmitry Osipenko if (err < 0) { 769db4a9c19SDmitry Osipenko dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, 770db4a9c19SDmitry Osipenko err); 771db4a9c19SDmitry Osipenko return err; 772db4a9c19SDmitry Osipenko } 773e474b3a1SThierry Reding } 774db4a9c19SDmitry Osipenko 7750de93c69SThierry Reding if (mc->soc->reset_ops) { 7761662dd64SDmitry Osipenko err = tegra_mc_reset_setup(mc); 7771662dd64SDmitry Osipenko if (err < 0) 7780de93c69SThierry Reding dev_err(&pdev->dev, "failed to register reset controller: %d\n", err); 7790de93c69SThierry Reding } 7801662dd64SDmitry Osipenko 78106f07981SDmitry Osipenko err = tegra_mc_interconnect_setup(mc); 78206f07981SDmitry Osipenko if (err < 0) 78306f07981SDmitry Osipenko dev_err(&pdev->dev, "failed to initialize interconnect: %d\n", 78406f07981SDmitry Osipenko err); 78506f07981SDmitry Osipenko 786568ece5bSDmitry Osipenko if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU) && mc->soc->smmu) { 78745a81df0SDmitry Osipenko mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); 788568ece5bSDmitry Osipenko if (IS_ERR(mc->smmu)) { 78945a81df0SDmitry Osipenko dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", 79045a81df0SDmitry Osipenko PTR_ERR(mc->smmu)); 791568ece5bSDmitry Osipenko mc->smmu = NULL; 792568ece5bSDmitry Osipenko } 79345a81df0SDmitry Osipenko } 79445a81df0SDmitry Osipenko 795ce2785a7SDmitry Osipenko if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { 796ce2785a7SDmitry Osipenko mc->gart = tegra_gart_probe(&pdev->dev, mc); 797ce2785a7SDmitry Osipenko if (IS_ERR(mc->gart)) { 798ce2785a7SDmitry Osipenko dev_err(&pdev->dev, "failed to probe GART: %ld\n", 799ce2785a7SDmitry Osipenko PTR_ERR(mc->gart)); 800ce2785a7SDmitry Osipenko mc->gart = NULL; 801ce2785a7SDmitry Osipenko } 802ce2785a7SDmitry Osipenko } 803ce2785a7SDmitry Osipenko 80489184651SThierry Reding return 0; 80589184651SThierry Reding } 80689184651SThierry Reding 8075c9016f0SThierry Reding static int __maybe_unused tegra_mc_suspend(struct device *dev) 808ce2785a7SDmitry Osipenko { 809ce2785a7SDmitry Osipenko struct tegra_mc *mc = dev_get_drvdata(dev); 810ce2785a7SDmitry Osipenko 8115c9016f0SThierry Reding if (mc->soc->ops && mc->soc->ops->suspend) 8125c9016f0SThierry Reding return mc->soc->ops->suspend(mc); 813ce2785a7SDmitry Osipenko 814ce2785a7SDmitry Osipenko return 0; 815ce2785a7SDmitry Osipenko } 816ce2785a7SDmitry Osipenko 8175c9016f0SThierry Reding static int __maybe_unused tegra_mc_resume(struct device *dev) 818ce2785a7SDmitry Osipenko { 819ce2785a7SDmitry Osipenko struct tegra_mc *mc = dev_get_drvdata(dev); 820ce2785a7SDmitry Osipenko 8215c9016f0SThierry Reding if (mc->soc->ops && mc->soc->ops->resume) 8225c9016f0SThierry Reding return mc->soc->ops->resume(mc); 823ce2785a7SDmitry Osipenko 824ce2785a7SDmitry Osipenko return 0; 825ce2785a7SDmitry Osipenko } 826ce2785a7SDmitry Osipenko 82777b14c9dSDmitry Osipenko static void tegra_mc_sync_state(struct device *dev) 82877b14c9dSDmitry Osipenko { 82977b14c9dSDmitry Osipenko struct tegra_mc *mc = dev_get_drvdata(dev); 83077b14c9dSDmitry Osipenko 83177b14c9dSDmitry Osipenko /* check whether ICC provider is registered */ 83277b14c9dSDmitry Osipenko if (mc->provider.dev == dev) 83377b14c9dSDmitry Osipenko icc_sync_state(dev); 83477b14c9dSDmitry Osipenko } 83577b14c9dSDmitry Osipenko 836ce2785a7SDmitry Osipenko static const struct dev_pm_ops tegra_mc_pm_ops = { 8375c9016f0SThierry Reding SET_SYSTEM_SLEEP_PM_OPS(tegra_mc_suspend, tegra_mc_resume) 838ce2785a7SDmitry Osipenko }; 839ce2785a7SDmitry Osipenko 84089184651SThierry Reding static struct platform_driver tegra_mc_driver = { 84189184651SThierry Reding .driver = { 84289184651SThierry Reding .name = "tegra-mc", 84389184651SThierry Reding .of_match_table = tegra_mc_of_match, 844ce2785a7SDmitry Osipenko .pm = &tegra_mc_pm_ops, 84589184651SThierry Reding .suppress_bind_attrs = true, 84677b14c9dSDmitry Osipenko .sync_state = tegra_mc_sync_state, 84789184651SThierry Reding }, 84889184651SThierry Reding .prevent_deferred_probe = true, 84989184651SThierry Reding .probe = tegra_mc_probe, 85089184651SThierry Reding }; 85189184651SThierry Reding 85289184651SThierry Reding static int tegra_mc_init(void) 85389184651SThierry Reding { 85489184651SThierry Reding return platform_driver_register(&tegra_mc_driver); 85589184651SThierry Reding } 85689184651SThierry Reding arch_initcall(tegra_mc_init); 85789184651SThierry Reding 85889184651SThierry Reding MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); 85989184651SThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver"); 86089184651SThierry Reding MODULE_LICENSE("GPL v2"); 861