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 4289184651SThierry Reding { } 4389184651SThierry Reding }; 4489184651SThierry Reding MODULE_DEVICE_TABLE(of, tegra_mc_of_match); 4589184651SThierry Reding 466c6bd207SDmitry Osipenko static void tegra_mc_devm_action_put_device(void *data) 476c6bd207SDmitry Osipenko { 486c6bd207SDmitry Osipenko struct tegra_mc *mc = data; 496c6bd207SDmitry Osipenko 506c6bd207SDmitry Osipenko put_device(mc->dev); 516c6bd207SDmitry Osipenko } 526c6bd207SDmitry Osipenko 536c6bd207SDmitry Osipenko /** 546c6bd207SDmitry Osipenko * devm_tegra_memory_controller_get() - get Tegra Memory Controller handle 556c6bd207SDmitry Osipenko * @dev: device pointer for the consumer device 566c6bd207SDmitry Osipenko * 576c6bd207SDmitry Osipenko * This function will search for the Memory Controller node in a device-tree 586c6bd207SDmitry Osipenko * and retrieve the Memory Controller handle. 596c6bd207SDmitry Osipenko * 606c6bd207SDmitry Osipenko * Return: ERR_PTR() on error or a valid pointer to a struct tegra_mc. 616c6bd207SDmitry Osipenko */ 626c6bd207SDmitry Osipenko struct tegra_mc *devm_tegra_memory_controller_get(struct device *dev) 636c6bd207SDmitry Osipenko { 646c6bd207SDmitry Osipenko struct platform_device *pdev; 656c6bd207SDmitry Osipenko struct device_node *np; 666c6bd207SDmitry Osipenko struct tegra_mc *mc; 676c6bd207SDmitry Osipenko int err; 686c6bd207SDmitry Osipenko 696c6bd207SDmitry Osipenko np = of_parse_phandle(dev->of_node, "nvidia,memory-controller", 0); 706c6bd207SDmitry Osipenko if (!np) 716c6bd207SDmitry Osipenko return ERR_PTR(-ENOENT); 726c6bd207SDmitry Osipenko 736c6bd207SDmitry Osipenko pdev = of_find_device_by_node(np); 746c6bd207SDmitry Osipenko of_node_put(np); 756c6bd207SDmitry Osipenko if (!pdev) 766c6bd207SDmitry Osipenko return ERR_PTR(-ENODEV); 776c6bd207SDmitry Osipenko 786c6bd207SDmitry Osipenko mc = platform_get_drvdata(pdev); 796c6bd207SDmitry Osipenko if (!mc) { 806c6bd207SDmitry Osipenko put_device(&pdev->dev); 816c6bd207SDmitry Osipenko return ERR_PTR(-EPROBE_DEFER); 826c6bd207SDmitry Osipenko } 836c6bd207SDmitry Osipenko 846c6bd207SDmitry Osipenko err = devm_add_action(dev, tegra_mc_devm_action_put_device, mc); 856c6bd207SDmitry Osipenko if (err) { 866c6bd207SDmitry Osipenko put_device(mc->dev); 876c6bd207SDmitry Osipenko return ERR_PTR(err); 886c6bd207SDmitry Osipenko } 896c6bd207SDmitry Osipenko 906c6bd207SDmitry Osipenko return mc; 916c6bd207SDmitry Osipenko } 926c6bd207SDmitry Osipenko EXPORT_SYMBOL_GPL(devm_tegra_memory_controller_get); 936c6bd207SDmitry Osipenko 94cb2b5839SThierry Reding static int tegra_mc_block_dma_common(struct tegra_mc *mc, 9520e92462SDmitry Osipenko const struct tegra_mc_reset *rst) 9620e92462SDmitry Osipenko { 9720e92462SDmitry Osipenko unsigned long flags; 9820e92462SDmitry Osipenko u32 value; 9920e92462SDmitry Osipenko 10020e92462SDmitry Osipenko spin_lock_irqsave(&mc->lock, flags); 10120e92462SDmitry Osipenko 10220e92462SDmitry Osipenko value = mc_readl(mc, rst->control) | BIT(rst->bit); 10320e92462SDmitry Osipenko mc_writel(mc, value, rst->control); 10420e92462SDmitry Osipenko 10520e92462SDmitry Osipenko spin_unlock_irqrestore(&mc->lock, flags); 10620e92462SDmitry Osipenko 10720e92462SDmitry Osipenko return 0; 10820e92462SDmitry Osipenko } 10920e92462SDmitry Osipenko 110cb2b5839SThierry Reding static bool tegra_mc_dma_idling_common(struct tegra_mc *mc, 11120e92462SDmitry Osipenko const struct tegra_mc_reset *rst) 11220e92462SDmitry Osipenko { 11320e92462SDmitry Osipenko return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0; 11420e92462SDmitry Osipenko } 11520e92462SDmitry Osipenko 116cb2b5839SThierry Reding static int tegra_mc_unblock_dma_common(struct tegra_mc *mc, 11720e92462SDmitry Osipenko const struct tegra_mc_reset *rst) 11820e92462SDmitry Osipenko { 11920e92462SDmitry Osipenko unsigned long flags; 12020e92462SDmitry Osipenko u32 value; 12120e92462SDmitry Osipenko 12220e92462SDmitry Osipenko spin_lock_irqsave(&mc->lock, flags); 12320e92462SDmitry Osipenko 12420e92462SDmitry Osipenko value = mc_readl(mc, rst->control) & ~BIT(rst->bit); 12520e92462SDmitry Osipenko mc_writel(mc, value, rst->control); 12620e92462SDmitry Osipenko 12720e92462SDmitry Osipenko spin_unlock_irqrestore(&mc->lock, flags); 12820e92462SDmitry Osipenko 12920e92462SDmitry Osipenko return 0; 13020e92462SDmitry Osipenko } 13120e92462SDmitry Osipenko 132cb2b5839SThierry Reding static int tegra_mc_reset_status_common(struct tegra_mc *mc, 13320e92462SDmitry Osipenko const struct tegra_mc_reset *rst) 13420e92462SDmitry Osipenko { 13520e92462SDmitry Osipenko return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0; 13620e92462SDmitry Osipenko } 13720e92462SDmitry Osipenko 138cb2b5839SThierry Reding const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = { 139cb2b5839SThierry Reding .block_dma = tegra_mc_block_dma_common, 140cb2b5839SThierry Reding .dma_idling = tegra_mc_dma_idling_common, 141cb2b5839SThierry Reding .unblock_dma = tegra_mc_unblock_dma_common, 142cb2b5839SThierry Reding .reset_status = tegra_mc_reset_status_common, 14320e92462SDmitry Osipenko }; 14420e92462SDmitry Osipenko 14520e92462SDmitry Osipenko static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev) 14620e92462SDmitry Osipenko { 14720e92462SDmitry Osipenko return container_of(rcdev, struct tegra_mc, reset); 14820e92462SDmitry Osipenko } 14920e92462SDmitry Osipenko 15020e92462SDmitry Osipenko static const struct tegra_mc_reset *tegra_mc_reset_find(struct tegra_mc *mc, 15120e92462SDmitry Osipenko unsigned long id) 15220e92462SDmitry Osipenko { 15320e92462SDmitry Osipenko unsigned int i; 15420e92462SDmitry Osipenko 15520e92462SDmitry Osipenko for (i = 0; i < mc->soc->num_resets; i++) 15620e92462SDmitry Osipenko if (mc->soc->resets[i].id == id) 15720e92462SDmitry Osipenko return &mc->soc->resets[i]; 15820e92462SDmitry Osipenko 15920e92462SDmitry Osipenko return NULL; 16020e92462SDmitry Osipenko } 16120e92462SDmitry Osipenko 16220e92462SDmitry Osipenko static int tegra_mc_hotreset_assert(struct reset_controller_dev *rcdev, 16320e92462SDmitry Osipenko unsigned long id) 16420e92462SDmitry Osipenko { 16520e92462SDmitry Osipenko struct tegra_mc *mc = reset_to_mc(rcdev); 16620e92462SDmitry Osipenko const struct tegra_mc_reset_ops *rst_ops; 16720e92462SDmitry Osipenko const struct tegra_mc_reset *rst; 16820e92462SDmitry Osipenko int retries = 500; 16920e92462SDmitry Osipenko int err; 17020e92462SDmitry Osipenko 17120e92462SDmitry Osipenko rst = tegra_mc_reset_find(mc, id); 17220e92462SDmitry Osipenko if (!rst) 17320e92462SDmitry Osipenko return -ENODEV; 17420e92462SDmitry Osipenko 17520e92462SDmitry Osipenko rst_ops = mc->soc->reset_ops; 17620e92462SDmitry Osipenko if (!rst_ops) 17720e92462SDmitry Osipenko return -ENODEV; 17820e92462SDmitry Osipenko 1796ce84ab6SDmitry Osipenko /* DMA flushing will fail if reset is already asserted */ 1806ce84ab6SDmitry Osipenko if (rst_ops->reset_status) { 1816ce84ab6SDmitry Osipenko /* check whether reset is asserted */ 1826ce84ab6SDmitry Osipenko if (rst_ops->reset_status(mc, rst)) 1836ce84ab6SDmitry Osipenko return 0; 1846ce84ab6SDmitry Osipenko } 1856ce84ab6SDmitry Osipenko 18620e92462SDmitry Osipenko if (rst_ops->block_dma) { 18720e92462SDmitry Osipenko /* block clients DMA requests */ 18820e92462SDmitry Osipenko err = rst_ops->block_dma(mc, rst); 18920e92462SDmitry Osipenko if (err) { 190f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to block %s DMA: %d\n", 19120e92462SDmitry Osipenko rst->name, err); 19220e92462SDmitry Osipenko return err; 19320e92462SDmitry Osipenko } 19420e92462SDmitry Osipenko } 19520e92462SDmitry Osipenko 19620e92462SDmitry Osipenko if (rst_ops->dma_idling) { 19720e92462SDmitry Osipenko /* wait for completion of the outstanding DMA requests */ 19820e92462SDmitry Osipenko while (!rst_ops->dma_idling(mc, rst)) { 19920e92462SDmitry Osipenko if (!retries--) { 200f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to flush %s DMA\n", 20120e92462SDmitry Osipenko rst->name); 20220e92462SDmitry Osipenko return -EBUSY; 20320e92462SDmitry Osipenko } 20420e92462SDmitry Osipenko 20520e92462SDmitry Osipenko usleep_range(10, 100); 20620e92462SDmitry Osipenko } 20720e92462SDmitry Osipenko } 20820e92462SDmitry Osipenko 20920e92462SDmitry Osipenko if (rst_ops->hotreset_assert) { 21020e92462SDmitry Osipenko /* clear clients DMA requests sitting before arbitration */ 21120e92462SDmitry Osipenko err = rst_ops->hotreset_assert(mc, rst); 21220e92462SDmitry Osipenko if (err) { 213f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to hot reset %s: %d\n", 21420e92462SDmitry Osipenko rst->name, err); 21520e92462SDmitry Osipenko return err; 21620e92462SDmitry Osipenko } 21720e92462SDmitry Osipenko } 21820e92462SDmitry Osipenko 21920e92462SDmitry Osipenko return 0; 22020e92462SDmitry Osipenko } 22120e92462SDmitry Osipenko 22220e92462SDmitry Osipenko static int tegra_mc_hotreset_deassert(struct reset_controller_dev *rcdev, 22320e92462SDmitry Osipenko unsigned long id) 22420e92462SDmitry Osipenko { 22520e92462SDmitry Osipenko struct tegra_mc *mc = reset_to_mc(rcdev); 22620e92462SDmitry Osipenko const struct tegra_mc_reset_ops *rst_ops; 22720e92462SDmitry Osipenko const struct tegra_mc_reset *rst; 22820e92462SDmitry Osipenko int err; 22920e92462SDmitry Osipenko 23020e92462SDmitry Osipenko rst = tegra_mc_reset_find(mc, id); 23120e92462SDmitry Osipenko if (!rst) 23220e92462SDmitry Osipenko return -ENODEV; 23320e92462SDmitry Osipenko 23420e92462SDmitry Osipenko rst_ops = mc->soc->reset_ops; 23520e92462SDmitry Osipenko if (!rst_ops) 23620e92462SDmitry Osipenko return -ENODEV; 23720e92462SDmitry Osipenko 23820e92462SDmitry Osipenko if (rst_ops->hotreset_deassert) { 23920e92462SDmitry Osipenko /* take out client from hot reset */ 24020e92462SDmitry Osipenko err = rst_ops->hotreset_deassert(mc, rst); 24120e92462SDmitry Osipenko if (err) { 242f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to deassert hot reset %s: %d\n", 24320e92462SDmitry Osipenko rst->name, err); 24420e92462SDmitry Osipenko return err; 24520e92462SDmitry Osipenko } 24620e92462SDmitry Osipenko } 24720e92462SDmitry Osipenko 24820e92462SDmitry Osipenko if (rst_ops->unblock_dma) { 24920e92462SDmitry Osipenko /* allow new DMA requests to proceed to arbitration */ 25020e92462SDmitry Osipenko err = rst_ops->unblock_dma(mc, rst); 25120e92462SDmitry Osipenko if (err) { 252f2dcded1SDmitry Osipenko dev_err(mc->dev, "failed to unblock %s DMA : %d\n", 25320e92462SDmitry Osipenko rst->name, err); 25420e92462SDmitry Osipenko return err; 25520e92462SDmitry Osipenko } 25620e92462SDmitry Osipenko } 25720e92462SDmitry Osipenko 25820e92462SDmitry Osipenko return 0; 25920e92462SDmitry Osipenko } 26020e92462SDmitry Osipenko 26120e92462SDmitry Osipenko static int tegra_mc_hotreset_status(struct reset_controller_dev *rcdev, 26220e92462SDmitry Osipenko unsigned long id) 26320e92462SDmitry Osipenko { 26420e92462SDmitry Osipenko struct tegra_mc *mc = reset_to_mc(rcdev); 26520e92462SDmitry Osipenko const struct tegra_mc_reset_ops *rst_ops; 26620e92462SDmitry Osipenko const struct tegra_mc_reset *rst; 26720e92462SDmitry Osipenko 26820e92462SDmitry Osipenko rst = tegra_mc_reset_find(mc, id); 26920e92462SDmitry Osipenko if (!rst) 27020e92462SDmitry Osipenko return -ENODEV; 27120e92462SDmitry Osipenko 27220e92462SDmitry Osipenko rst_ops = mc->soc->reset_ops; 27320e92462SDmitry Osipenko if (!rst_ops) 27420e92462SDmitry Osipenko return -ENODEV; 27520e92462SDmitry Osipenko 27620e92462SDmitry Osipenko return rst_ops->reset_status(mc, rst); 27720e92462SDmitry Osipenko } 27820e92462SDmitry Osipenko 27920e92462SDmitry Osipenko static const struct reset_control_ops tegra_mc_reset_ops = { 28020e92462SDmitry Osipenko .assert = tegra_mc_hotreset_assert, 28120e92462SDmitry Osipenko .deassert = tegra_mc_hotreset_deassert, 28220e92462SDmitry Osipenko .status = tegra_mc_hotreset_status, 28320e92462SDmitry Osipenko }; 28420e92462SDmitry Osipenko 28520e92462SDmitry Osipenko static int tegra_mc_reset_setup(struct tegra_mc *mc) 28620e92462SDmitry Osipenko { 28720e92462SDmitry Osipenko int err; 28820e92462SDmitry Osipenko 28920e92462SDmitry Osipenko mc->reset.ops = &tegra_mc_reset_ops; 29020e92462SDmitry Osipenko mc->reset.owner = THIS_MODULE; 29120e92462SDmitry Osipenko mc->reset.of_node = mc->dev->of_node; 29220e92462SDmitry Osipenko mc->reset.of_reset_n_cells = 1; 29320e92462SDmitry Osipenko mc->reset.nr_resets = mc->soc->num_resets; 29420e92462SDmitry Osipenko 29520e92462SDmitry Osipenko err = reset_controller_register(&mc->reset); 29620e92462SDmitry Osipenko if (err < 0) 29720e92462SDmitry Osipenko return err; 29820e92462SDmitry Osipenko 29920e92462SDmitry Osipenko return 0; 30020e92462SDmitry Osipenko } 30120e92462SDmitry Osipenko 302e34212c7SDmitry Osipenko int tegra_mc_write_emem_configuration(struct tegra_mc *mc, unsigned long rate) 3033d9dd6fdSMikko Perttunen { 3043d9dd6fdSMikko Perttunen unsigned int i; 3053d9dd6fdSMikko Perttunen struct tegra_mc_timing *timing = NULL; 3063d9dd6fdSMikko Perttunen 3073d9dd6fdSMikko Perttunen for (i = 0; i < mc->num_timings; i++) { 3083d9dd6fdSMikko Perttunen if (mc->timings[i].rate == rate) { 3093d9dd6fdSMikko Perttunen timing = &mc->timings[i]; 3103d9dd6fdSMikko Perttunen break; 3113d9dd6fdSMikko Perttunen } 3123d9dd6fdSMikko Perttunen } 3133d9dd6fdSMikko Perttunen 3143d9dd6fdSMikko Perttunen if (!timing) { 3153d9dd6fdSMikko Perttunen dev_err(mc->dev, "no memory timing registered for rate %lu\n", 3163d9dd6fdSMikko Perttunen rate); 317e34212c7SDmitry Osipenko return -EINVAL; 3183d9dd6fdSMikko Perttunen } 3193d9dd6fdSMikko Perttunen 3203d9dd6fdSMikko Perttunen for (i = 0; i < mc->soc->num_emem_regs; ++i) 3213d9dd6fdSMikko Perttunen mc_writel(mc, timing->emem_data[i], mc->soc->emem_regs[i]); 322e34212c7SDmitry Osipenko 323e34212c7SDmitry Osipenko return 0; 3243d9dd6fdSMikko Perttunen } 3250c56eda8SDmitry Osipenko EXPORT_SYMBOL_GPL(tegra_mc_write_emem_configuration); 3263d9dd6fdSMikko Perttunen 3273d9dd6fdSMikko Perttunen unsigned int tegra_mc_get_emem_device_count(struct tegra_mc *mc) 3283d9dd6fdSMikko Perttunen { 3293d9dd6fdSMikko Perttunen u8 dram_count; 3303d9dd6fdSMikko Perttunen 3313d9dd6fdSMikko Perttunen dram_count = mc_readl(mc, MC_EMEM_ADR_CFG); 3323d9dd6fdSMikko Perttunen dram_count &= MC_EMEM_ADR_CFG_EMEM_NUMDEV; 3333d9dd6fdSMikko Perttunen dram_count++; 3343d9dd6fdSMikko Perttunen 3353d9dd6fdSMikko Perttunen return dram_count; 3363d9dd6fdSMikko Perttunen } 3370c56eda8SDmitry Osipenko EXPORT_SYMBOL_GPL(tegra_mc_get_emem_device_count); 3383d9dd6fdSMikko Perttunen 339*ddeceab0SThierry Reding #if defined(CONFIG_ARCH_TEGRA_3x_SOC) || \ 340*ddeceab0SThierry Reding defined(CONFIG_ARCH_TEGRA_114_SOC) || \ 341*ddeceab0SThierry Reding defined(CONFIG_ARCH_TEGRA_124_SOC) || \ 342*ddeceab0SThierry Reding defined(CONFIG_ARCH_TEGRA_132_SOC) || \ 343*ddeceab0SThierry Reding defined(CONFIG_ARCH_TEGRA_210_SOC) 344*ddeceab0SThierry Reding static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) 345*ddeceab0SThierry Reding { 346*ddeceab0SThierry Reding unsigned long long tick; 347*ddeceab0SThierry Reding unsigned int i; 348*ddeceab0SThierry Reding u32 value; 349*ddeceab0SThierry Reding 350*ddeceab0SThierry Reding /* compute the number of MC clock cycles per tick */ 351*ddeceab0SThierry Reding tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk); 352*ddeceab0SThierry Reding do_div(tick, NSEC_PER_SEC); 353*ddeceab0SThierry Reding 354*ddeceab0SThierry Reding value = mc_readl(mc, MC_EMEM_ARB_CFG); 355*ddeceab0SThierry Reding value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; 356*ddeceab0SThierry Reding value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); 357*ddeceab0SThierry Reding mc_writel(mc, value, MC_EMEM_ARB_CFG); 358*ddeceab0SThierry Reding 359*ddeceab0SThierry Reding /* write latency allowance defaults */ 360*ddeceab0SThierry Reding for (i = 0; i < mc->soc->num_clients; i++) { 361*ddeceab0SThierry Reding const struct tegra_mc_client *client = &mc->soc->clients[i]; 362*ddeceab0SThierry Reding u32 value; 363*ddeceab0SThierry Reding 364*ddeceab0SThierry Reding value = mc_readl(mc, client->regs.la.reg); 365*ddeceab0SThierry Reding value &= ~(client->regs.la.mask << client->regs.la.shift); 366*ddeceab0SThierry Reding value |= (client->regs.la.def & client->regs.la.mask) << client->regs.la.shift; 367*ddeceab0SThierry Reding mc_writel(mc, value, client->regs.la.reg); 368*ddeceab0SThierry Reding } 369*ddeceab0SThierry Reding 370*ddeceab0SThierry Reding /* latch new values */ 371*ddeceab0SThierry Reding mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL); 372*ddeceab0SThierry Reding 373*ddeceab0SThierry Reding return 0; 374*ddeceab0SThierry Reding } 375*ddeceab0SThierry Reding 3763d9dd6fdSMikko Perttunen static int load_one_timing(struct tegra_mc *mc, 3773d9dd6fdSMikko Perttunen struct tegra_mc_timing *timing, 3783d9dd6fdSMikko Perttunen struct device_node *node) 3793d9dd6fdSMikko Perttunen { 3803d9dd6fdSMikko Perttunen int err; 3813d9dd6fdSMikko Perttunen u32 tmp; 3823d9dd6fdSMikko Perttunen 3833d9dd6fdSMikko Perttunen err = of_property_read_u32(node, "clock-frequency", &tmp); 3843d9dd6fdSMikko Perttunen if (err) { 3853d9dd6fdSMikko Perttunen dev_err(mc->dev, 386c86f9854SRob Herring "timing %pOFn: failed to read rate\n", node); 3873d9dd6fdSMikko Perttunen return err; 3883d9dd6fdSMikko Perttunen } 3893d9dd6fdSMikko Perttunen 3903d9dd6fdSMikko Perttunen timing->rate = tmp; 3913d9dd6fdSMikko Perttunen timing->emem_data = devm_kcalloc(mc->dev, mc->soc->num_emem_regs, 3923d9dd6fdSMikko Perttunen sizeof(u32), GFP_KERNEL); 3933d9dd6fdSMikko Perttunen if (!timing->emem_data) 3943d9dd6fdSMikko Perttunen return -ENOMEM; 3953d9dd6fdSMikko Perttunen 3963d9dd6fdSMikko Perttunen err = of_property_read_u32_array(node, "nvidia,emem-configuration", 3973d9dd6fdSMikko Perttunen timing->emem_data, 3983d9dd6fdSMikko Perttunen mc->soc->num_emem_regs); 3993d9dd6fdSMikko Perttunen if (err) { 4003d9dd6fdSMikko Perttunen dev_err(mc->dev, 401c86f9854SRob Herring "timing %pOFn: failed to read EMEM configuration\n", 402c86f9854SRob Herring node); 4033d9dd6fdSMikko Perttunen return err; 4043d9dd6fdSMikko Perttunen } 4053d9dd6fdSMikko Perttunen 4063d9dd6fdSMikko Perttunen return 0; 4073d9dd6fdSMikko Perttunen } 4083d9dd6fdSMikko Perttunen 4093d9dd6fdSMikko Perttunen static int load_timings(struct tegra_mc *mc, struct device_node *node) 4103d9dd6fdSMikko Perttunen { 4113d9dd6fdSMikko Perttunen struct device_node *child; 4123d9dd6fdSMikko Perttunen struct tegra_mc_timing *timing; 4133d9dd6fdSMikko Perttunen int child_count = of_get_child_count(node); 4143d9dd6fdSMikko Perttunen int i = 0, err; 4153d9dd6fdSMikko Perttunen 4163d9dd6fdSMikko Perttunen mc->timings = devm_kcalloc(mc->dev, child_count, sizeof(*timing), 4173d9dd6fdSMikko Perttunen GFP_KERNEL); 4183d9dd6fdSMikko Perttunen if (!mc->timings) 4193d9dd6fdSMikko Perttunen return -ENOMEM; 4203d9dd6fdSMikko Perttunen 4213d9dd6fdSMikko Perttunen mc->num_timings = child_count; 4223d9dd6fdSMikko Perttunen 4233d9dd6fdSMikko Perttunen for_each_child_of_node(node, child) { 4243d9dd6fdSMikko Perttunen timing = &mc->timings[i++]; 4253d9dd6fdSMikko Perttunen 4263d9dd6fdSMikko Perttunen err = load_one_timing(mc, timing, child); 42755bb1d83SAmitoj Kaur Chawla if (err) { 42855bb1d83SAmitoj Kaur Chawla of_node_put(child); 4293d9dd6fdSMikko Perttunen return err; 4303d9dd6fdSMikko Perttunen } 43155bb1d83SAmitoj Kaur Chawla } 4323d9dd6fdSMikko Perttunen 4333d9dd6fdSMikko Perttunen return 0; 4343d9dd6fdSMikko Perttunen } 4353d9dd6fdSMikko Perttunen 4363d9dd6fdSMikko Perttunen static int tegra_mc_setup_timings(struct tegra_mc *mc) 4373d9dd6fdSMikko Perttunen { 4383d9dd6fdSMikko Perttunen struct device_node *node; 4393d9dd6fdSMikko Perttunen u32 ram_code, node_ram_code; 4403d9dd6fdSMikko Perttunen int err; 4413d9dd6fdSMikko Perttunen 4423d9dd6fdSMikko Perttunen ram_code = tegra_read_ram_code(); 4433d9dd6fdSMikko Perttunen 4443d9dd6fdSMikko Perttunen mc->num_timings = 0; 4453d9dd6fdSMikko Perttunen 4463d9dd6fdSMikko Perttunen for_each_child_of_node(mc->dev->of_node, node) { 4473d9dd6fdSMikko Perttunen err = of_property_read_u32(node, "nvidia,ram-code", 4483d9dd6fdSMikko Perttunen &node_ram_code); 449d1122e4bSJulia Lawall if (err || (node_ram_code != ram_code)) 4503d9dd6fdSMikko Perttunen continue; 4513d9dd6fdSMikko Perttunen 4523d9dd6fdSMikko Perttunen err = load_timings(mc, node); 45355bb1d83SAmitoj Kaur Chawla of_node_put(node); 4543d9dd6fdSMikko Perttunen if (err) 4553d9dd6fdSMikko Perttunen return err; 4563d9dd6fdSMikko Perttunen break; 4573d9dd6fdSMikko Perttunen } 4583d9dd6fdSMikko Perttunen 4593d9dd6fdSMikko Perttunen if (mc->num_timings == 0) 4603d9dd6fdSMikko Perttunen dev_warn(mc->dev, 4613d9dd6fdSMikko Perttunen "no memory timings for RAM code %u registered\n", 4623d9dd6fdSMikko Perttunen ram_code); 4633d9dd6fdSMikko Perttunen 4643d9dd6fdSMikko Perttunen return 0; 4653d9dd6fdSMikko Perttunen } 4663d9dd6fdSMikko Perttunen 467*ddeceab0SThierry Reding int tegra30_mc_probe(struct tegra_mc *mc) 468*ddeceab0SThierry Reding { 469*ddeceab0SThierry Reding int err; 470*ddeceab0SThierry Reding 471*ddeceab0SThierry Reding mc->clk = devm_clk_get_optional(mc->dev, "mc"); 472*ddeceab0SThierry Reding if (IS_ERR(mc->clk)) { 473*ddeceab0SThierry Reding dev_err(mc->dev, "failed to get MC clock: %ld\n", PTR_ERR(mc->clk)); 474*ddeceab0SThierry Reding return PTR_ERR(mc->clk); 475*ddeceab0SThierry Reding } 476*ddeceab0SThierry Reding 477*ddeceab0SThierry Reding /* ensure that debug features are disabled */ 478*ddeceab0SThierry Reding mc_writel(mc, 0x00000000, MC_TIMING_CONTROL_DBG); 479*ddeceab0SThierry Reding 480*ddeceab0SThierry Reding err = tegra_mc_setup_latency_allowance(mc); 481*ddeceab0SThierry Reding if (err < 0) { 482*ddeceab0SThierry Reding dev_err(mc->dev, "failed to setup latency allowance: %d\n", err); 483*ddeceab0SThierry Reding return err; 484*ddeceab0SThierry Reding } 485*ddeceab0SThierry Reding 486*ddeceab0SThierry Reding err = tegra_mc_setup_timings(mc); 487*ddeceab0SThierry Reding if (err < 0) { 488*ddeceab0SThierry Reding dev_err(mc->dev, "failed to setup timings: %d\n", err); 489*ddeceab0SThierry Reding return err; 490*ddeceab0SThierry Reding } 491*ddeceab0SThierry Reding 492*ddeceab0SThierry Reding return 0; 493*ddeceab0SThierry Reding } 494*ddeceab0SThierry Reding 495*ddeceab0SThierry Reding const struct tegra_mc_ops tegra30_mc_ops = { 496*ddeceab0SThierry Reding .probe = tegra30_mc_probe, 497*ddeceab0SThierry Reding }; 498*ddeceab0SThierry Reding #endif 499*ddeceab0SThierry Reding 50089184651SThierry Reding static const char *const status_names[32] = { 50189184651SThierry Reding [ 1] = "External interrupt", 50289184651SThierry Reding [ 6] = "EMEM address decode error", 503a8d502fdSDmitry Osipenko [ 7] = "GART page fault", 50489184651SThierry Reding [ 8] = "Security violation", 50589184651SThierry Reding [ 9] = "EMEM arbitration error", 50689184651SThierry Reding [10] = "Page fault", 50789184651SThierry Reding [11] = "Invalid APB ASID update", 50889184651SThierry Reding [12] = "VPR violation", 50989184651SThierry Reding [13] = "Secure carveout violation", 51089184651SThierry Reding [16] = "MTS carveout violation", 51189184651SThierry Reding }; 51289184651SThierry Reding 51389184651SThierry Reding static const char *const error_names[8] = { 51489184651SThierry Reding [2] = "EMEM decode error", 51589184651SThierry Reding [3] = "TrustZone violation", 51689184651SThierry Reding [4] = "Carveout violation", 51789184651SThierry Reding [6] = "SMMU translation error", 51889184651SThierry Reding }; 51989184651SThierry Reding 52089184651SThierry Reding static irqreturn_t tegra_mc_irq(int irq, void *data) 52189184651SThierry Reding { 52289184651SThierry Reding struct tegra_mc *mc = data; 5231c74d5c0SDmitry Osipenko unsigned long status; 52489184651SThierry Reding unsigned int bit; 52589184651SThierry Reding 52689184651SThierry Reding /* mask all interrupts to avoid flooding */ 5271c74d5c0SDmitry Osipenko status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; 528bf3fbdfbSDmitry Osipenko if (!status) 529bf3fbdfbSDmitry Osipenko return IRQ_NONE; 53089184651SThierry Reding 53189184651SThierry Reding for_each_set_bit(bit, &status, 32) { 53289184651SThierry Reding const char *error = status_names[bit] ?: "unknown"; 53389184651SThierry Reding const char *client = "unknown", *desc; 53489184651SThierry Reding const char *direction, *secure; 53589184651SThierry Reding phys_addr_t addr = 0; 53689184651SThierry Reding unsigned int i; 53789184651SThierry Reding char perm[7]; 53889184651SThierry Reding u8 id, type; 53989184651SThierry Reding u32 value; 54089184651SThierry Reding 54189184651SThierry Reding value = mc_readl(mc, MC_ERR_STATUS); 54289184651SThierry Reding 54389184651SThierry Reding #ifdef CONFIG_PHYS_ADDR_T_64BIT 54489184651SThierry Reding if (mc->soc->num_address_bits > 32) { 54589184651SThierry Reding addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) & 54689184651SThierry Reding MC_ERR_STATUS_ADR_HI_MASK); 54789184651SThierry Reding addr <<= 32; 54889184651SThierry Reding } 54989184651SThierry Reding #endif 55089184651SThierry Reding 55189184651SThierry Reding if (value & MC_ERR_STATUS_RW) 55289184651SThierry Reding direction = "write"; 55389184651SThierry Reding else 55489184651SThierry Reding direction = "read"; 55589184651SThierry Reding 55689184651SThierry Reding if (value & MC_ERR_STATUS_SECURITY) 55789184651SThierry Reding secure = "secure "; 55889184651SThierry Reding else 55989184651SThierry Reding secure = ""; 56089184651SThierry Reding 5613c01cf3bSPaul Walmsley id = value & mc->soc->client_id_mask; 56289184651SThierry Reding 56389184651SThierry Reding for (i = 0; i < mc->soc->num_clients; i++) { 56489184651SThierry Reding if (mc->soc->clients[i].id == id) { 56589184651SThierry Reding client = mc->soc->clients[i].name; 56689184651SThierry Reding break; 56789184651SThierry Reding } 56889184651SThierry Reding } 56989184651SThierry Reding 57089184651SThierry Reding type = (value & MC_ERR_STATUS_TYPE_MASK) >> 57189184651SThierry Reding MC_ERR_STATUS_TYPE_SHIFT; 57289184651SThierry Reding desc = error_names[type]; 57389184651SThierry Reding 57489184651SThierry Reding switch (value & MC_ERR_STATUS_TYPE_MASK) { 57589184651SThierry Reding case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE: 57689184651SThierry Reding perm[0] = ' '; 57789184651SThierry Reding perm[1] = '['; 57889184651SThierry Reding 57989184651SThierry Reding if (value & MC_ERR_STATUS_READABLE) 58089184651SThierry Reding perm[2] = 'R'; 58189184651SThierry Reding else 58289184651SThierry Reding perm[2] = '-'; 58389184651SThierry Reding 58489184651SThierry Reding if (value & MC_ERR_STATUS_WRITABLE) 58589184651SThierry Reding perm[3] = 'W'; 58689184651SThierry Reding else 58789184651SThierry Reding perm[3] = '-'; 58889184651SThierry Reding 58989184651SThierry Reding if (value & MC_ERR_STATUS_NONSECURE) 59089184651SThierry Reding perm[4] = '-'; 59189184651SThierry Reding else 59289184651SThierry Reding perm[4] = 'S'; 59389184651SThierry Reding 59489184651SThierry Reding perm[5] = ']'; 59589184651SThierry Reding perm[6] = '\0'; 59689184651SThierry Reding break; 59789184651SThierry Reding 59889184651SThierry Reding default: 59989184651SThierry Reding perm[0] = '\0'; 60089184651SThierry Reding break; 60189184651SThierry Reding } 60289184651SThierry Reding 60389184651SThierry Reding value = mc_readl(mc, MC_ERR_ADR); 60489184651SThierry Reding addr |= value; 60589184651SThierry Reding 60689184651SThierry Reding dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s%s)\n", 60789184651SThierry Reding client, secure, direction, &addr, error, 60889184651SThierry Reding desc, perm); 60989184651SThierry Reding } 61089184651SThierry Reding 61189184651SThierry Reding /* clear interrupts */ 61289184651SThierry Reding mc_writel(mc, status, MC_INTSTATUS); 61389184651SThierry Reding 61489184651SThierry Reding return IRQ_HANDLED; 61589184651SThierry Reding } 61689184651SThierry Reding 617a8d502fdSDmitry Osipenko static __maybe_unused irqreturn_t tegra20_mc_irq(int irq, void *data) 618a8d502fdSDmitry Osipenko { 619a8d502fdSDmitry Osipenko struct tegra_mc *mc = data; 620a8d502fdSDmitry Osipenko unsigned long status; 621a8d502fdSDmitry Osipenko unsigned int bit; 622a8d502fdSDmitry Osipenko 623a8d502fdSDmitry Osipenko /* mask all interrupts to avoid flooding */ 624a8d502fdSDmitry Osipenko status = mc_readl(mc, MC_INTSTATUS) & mc->soc->intmask; 625a8d502fdSDmitry Osipenko if (!status) 626a8d502fdSDmitry Osipenko return IRQ_NONE; 627a8d502fdSDmitry Osipenko 628a8d502fdSDmitry Osipenko for_each_set_bit(bit, &status, 32) { 629a8d502fdSDmitry Osipenko const char *direction = "read", *secure = ""; 630a8d502fdSDmitry Osipenko const char *error = status_names[bit]; 631a8d502fdSDmitry Osipenko const char *client, *desc; 632a8d502fdSDmitry Osipenko phys_addr_t addr; 633a8d502fdSDmitry Osipenko u32 value, reg; 634a8d502fdSDmitry Osipenko u8 id, type; 635a8d502fdSDmitry Osipenko 636a8d502fdSDmitry Osipenko switch (BIT(bit)) { 637a8d502fdSDmitry Osipenko case MC_INT_DECERR_EMEM: 638a8d502fdSDmitry Osipenko reg = MC_DECERR_EMEM_OTHERS_STATUS; 639a8d502fdSDmitry Osipenko value = mc_readl(mc, reg); 640a8d502fdSDmitry Osipenko 641a8d502fdSDmitry Osipenko id = value & mc->soc->client_id_mask; 642a8d502fdSDmitry Osipenko desc = error_names[2]; 643a8d502fdSDmitry Osipenko 644a8d502fdSDmitry Osipenko if (value & BIT(31)) 645a8d502fdSDmitry Osipenko direction = "write"; 646a8d502fdSDmitry Osipenko break; 647a8d502fdSDmitry Osipenko 648a8d502fdSDmitry Osipenko case MC_INT_INVALID_GART_PAGE: 649b3bb6b85SDmitry Osipenko reg = MC_GART_ERROR_REQ; 650b3bb6b85SDmitry Osipenko value = mc_readl(mc, reg); 651b3bb6b85SDmitry Osipenko 652b3bb6b85SDmitry Osipenko id = (value >> 1) & mc->soc->client_id_mask; 653b3bb6b85SDmitry Osipenko desc = error_names[2]; 654b3bb6b85SDmitry Osipenko 655b3bb6b85SDmitry Osipenko if (value & BIT(0)) 656b3bb6b85SDmitry Osipenko direction = "write"; 657b3bb6b85SDmitry Osipenko break; 658a8d502fdSDmitry Osipenko 659a8d502fdSDmitry Osipenko case MC_INT_SECURITY_VIOLATION: 660a8d502fdSDmitry Osipenko reg = MC_SECURITY_VIOLATION_STATUS; 661a8d502fdSDmitry Osipenko value = mc_readl(mc, reg); 662a8d502fdSDmitry Osipenko 663a8d502fdSDmitry Osipenko id = value & mc->soc->client_id_mask; 664a8d502fdSDmitry Osipenko type = (value & BIT(30)) ? 4 : 3; 665a8d502fdSDmitry Osipenko desc = error_names[type]; 666a8d502fdSDmitry Osipenko secure = "secure "; 667a8d502fdSDmitry Osipenko 668a8d502fdSDmitry Osipenko if (value & BIT(31)) 669a8d502fdSDmitry Osipenko direction = "write"; 670a8d502fdSDmitry Osipenko break; 671a8d502fdSDmitry Osipenko 672a8d502fdSDmitry Osipenko default: 673a8d502fdSDmitry Osipenko continue; 674a8d502fdSDmitry Osipenko } 675a8d502fdSDmitry Osipenko 676a8d502fdSDmitry Osipenko client = mc->soc->clients[id].name; 677a8d502fdSDmitry Osipenko addr = mc_readl(mc, reg + sizeof(u32)); 678a8d502fdSDmitry Osipenko 679a8d502fdSDmitry Osipenko dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s)\n", 680a8d502fdSDmitry Osipenko client, secure, direction, &addr, error, 681a8d502fdSDmitry Osipenko desc); 682a8d502fdSDmitry Osipenko } 683a8d502fdSDmitry Osipenko 684a8d502fdSDmitry Osipenko /* clear interrupts */ 685a8d502fdSDmitry Osipenko mc_writel(mc, status, MC_INTSTATUS); 686a8d502fdSDmitry Osipenko 687a8d502fdSDmitry Osipenko return IRQ_HANDLED; 688a8d502fdSDmitry Osipenko } 689a8d502fdSDmitry Osipenko 69006f07981SDmitry Osipenko /* 69106f07981SDmitry Osipenko * Memory Controller (MC) has few Memory Clients that are issuing memory 69206f07981SDmitry Osipenko * bandwidth allocation requests to the MC interconnect provider. The MC 69306f07981SDmitry Osipenko * provider aggregates the requests and then sends the aggregated request 69406f07981SDmitry Osipenko * up to the External Memory Controller (EMC) interconnect provider which 69506f07981SDmitry Osipenko * re-configures hardware interface to External Memory (EMEM) in accordance 69606f07981SDmitry Osipenko * to the required bandwidth. Each MC interconnect node represents an 69706f07981SDmitry Osipenko * individual Memory Client. 69806f07981SDmitry Osipenko * 69906f07981SDmitry Osipenko * Memory interconnect topology: 70006f07981SDmitry Osipenko * 70106f07981SDmitry Osipenko * +----+ 70206f07981SDmitry Osipenko * +--------+ | | 70306f07981SDmitry Osipenko * | TEXSRD +--->+ | 70406f07981SDmitry Osipenko * +--------+ | | 70506f07981SDmitry Osipenko * | | +-----+ +------+ 70606f07981SDmitry Osipenko * ... | MC +--->+ EMC +--->+ EMEM | 70706f07981SDmitry Osipenko * | | +-----+ +------+ 70806f07981SDmitry Osipenko * +--------+ | | 70906f07981SDmitry Osipenko * | DISP.. +--->+ | 71006f07981SDmitry Osipenko * +--------+ | | 71106f07981SDmitry Osipenko * +----+ 71206f07981SDmitry Osipenko */ 71306f07981SDmitry Osipenko static int tegra_mc_interconnect_setup(struct tegra_mc *mc) 71406f07981SDmitry Osipenko { 71506f07981SDmitry Osipenko struct icc_node *node; 71606f07981SDmitry Osipenko unsigned int i; 71706f07981SDmitry Osipenko int err; 71806f07981SDmitry Osipenko 71906f07981SDmitry Osipenko /* older device-trees don't have interconnect properties */ 72006f07981SDmitry Osipenko if (!device_property_present(mc->dev, "#interconnect-cells") || 72106f07981SDmitry Osipenko !mc->soc->icc_ops) 72206f07981SDmitry Osipenko return 0; 72306f07981SDmitry Osipenko 72406f07981SDmitry Osipenko mc->provider.dev = mc->dev; 72506f07981SDmitry Osipenko mc->provider.data = &mc->provider; 72606f07981SDmitry Osipenko mc->provider.set = mc->soc->icc_ops->set; 72706f07981SDmitry Osipenko mc->provider.aggregate = mc->soc->icc_ops->aggregate; 72806f07981SDmitry Osipenko mc->provider.xlate_extended = mc->soc->icc_ops->xlate_extended; 72906f07981SDmitry Osipenko 73006f07981SDmitry Osipenko err = icc_provider_add(&mc->provider); 73106f07981SDmitry Osipenko if (err) 73206f07981SDmitry Osipenko return err; 73306f07981SDmitry Osipenko 73406f07981SDmitry Osipenko /* create Memory Controller node */ 73506f07981SDmitry Osipenko node = icc_node_create(TEGRA_ICC_MC); 73606f07981SDmitry Osipenko if (IS_ERR(node)) { 73706f07981SDmitry Osipenko err = PTR_ERR(node); 73806f07981SDmitry Osipenko goto del_provider; 73906f07981SDmitry Osipenko } 74006f07981SDmitry Osipenko 74106f07981SDmitry Osipenko node->name = "Memory Controller"; 74206f07981SDmitry Osipenko icc_node_add(node, &mc->provider); 74306f07981SDmitry Osipenko 74406f07981SDmitry Osipenko /* link Memory Controller to External Memory Controller */ 74506f07981SDmitry Osipenko err = icc_link_create(node, TEGRA_ICC_EMC); 74606f07981SDmitry Osipenko if (err) 74706f07981SDmitry Osipenko goto remove_nodes; 74806f07981SDmitry Osipenko 74906f07981SDmitry Osipenko for (i = 0; i < mc->soc->num_clients; i++) { 75006f07981SDmitry Osipenko /* create MC client node */ 75106f07981SDmitry Osipenko node = icc_node_create(mc->soc->clients[i].id); 75206f07981SDmitry Osipenko if (IS_ERR(node)) { 75306f07981SDmitry Osipenko err = PTR_ERR(node); 75406f07981SDmitry Osipenko goto remove_nodes; 75506f07981SDmitry Osipenko } 75606f07981SDmitry Osipenko 75706f07981SDmitry Osipenko node->name = mc->soc->clients[i].name; 75806f07981SDmitry Osipenko icc_node_add(node, &mc->provider); 75906f07981SDmitry Osipenko 76006f07981SDmitry Osipenko /* link Memory Client to Memory Controller */ 76106f07981SDmitry Osipenko err = icc_link_create(node, TEGRA_ICC_MC); 76206f07981SDmitry Osipenko if (err) 76306f07981SDmitry Osipenko goto remove_nodes; 76406f07981SDmitry Osipenko } 76506f07981SDmitry Osipenko 76606f07981SDmitry Osipenko /* 76706f07981SDmitry Osipenko * MC driver is registered too early, so early that generic driver 76806f07981SDmitry Osipenko * syncing doesn't work for the MC. But it doesn't really matter 76906f07981SDmitry Osipenko * since syncing works for the EMC drivers, hence we can sync the 77006f07981SDmitry Osipenko * MC driver by ourselves and then EMC will complete syncing of 77106f07981SDmitry Osipenko * the whole ICC state. 77206f07981SDmitry Osipenko */ 77306f07981SDmitry Osipenko icc_sync_state(mc->dev); 77406f07981SDmitry Osipenko 77506f07981SDmitry Osipenko return 0; 77606f07981SDmitry Osipenko 77706f07981SDmitry Osipenko remove_nodes: 77806f07981SDmitry Osipenko icc_nodes_remove(&mc->provider); 77906f07981SDmitry Osipenko del_provider: 78006f07981SDmitry Osipenko icc_provider_del(&mc->provider); 78106f07981SDmitry Osipenko 78206f07981SDmitry Osipenko return err; 78306f07981SDmitry Osipenko } 78406f07981SDmitry Osipenko 78589184651SThierry Reding static int tegra_mc_probe(struct platform_device *pdev) 78689184651SThierry Reding { 78789184651SThierry Reding struct resource *res; 78889184651SThierry Reding struct tegra_mc *mc; 789a8d502fdSDmitry Osipenko void *isr; 790c4c21f22SThierry Reding u64 mask; 79189184651SThierry Reding int err; 79289184651SThierry Reding 79389184651SThierry Reding mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); 79489184651SThierry Reding if (!mc) 79589184651SThierry Reding return -ENOMEM; 79689184651SThierry Reding 79789184651SThierry Reding platform_set_drvdata(pdev, mc); 79820e92462SDmitry Osipenko spin_lock_init(&mc->lock); 79959cd046fSDmitry Osipenko mc->soc = of_device_get_match_data(&pdev->dev); 80089184651SThierry Reding mc->dev = &pdev->dev; 80189184651SThierry Reding 802c4c21f22SThierry Reding mask = DMA_BIT_MASK(mc->soc->num_address_bits); 803c4c21f22SThierry Reding 804c4c21f22SThierry Reding err = dma_coerce_mask_and_coherent(&pdev->dev, mask); 805c4c21f22SThierry Reding if (err < 0) { 806c4c21f22SThierry Reding dev_err(&pdev->dev, "failed to set DMA mask: %d\n", err); 807c4c21f22SThierry Reding return err; 808c4c21f22SThierry Reding } 809c4c21f22SThierry Reding 81089184651SThierry Reding /* length of MC tick in nanoseconds */ 81189184651SThierry Reding mc->tick = 30; 81289184651SThierry Reding 81389184651SThierry Reding res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 81489184651SThierry Reding mc->regs = devm_ioremap_resource(&pdev->dev, res); 81589184651SThierry Reding if (IS_ERR(mc->regs)) 81689184651SThierry Reding return PTR_ERR(mc->regs); 81789184651SThierry Reding 818c64738e9SThierry Reding mc->debugfs.root = debugfs_create_dir("mc", NULL); 819c64738e9SThierry Reding 820c64738e9SThierry Reding if (mc->soc->ops && mc->soc->ops->probe) { 821c64738e9SThierry Reding err = mc->soc->ops->probe(mc); 822c64738e9SThierry Reding if (err < 0) 823c64738e9SThierry Reding return err; 824c64738e9SThierry Reding } 825c64738e9SThierry Reding 82696efa118SDmitry Osipenko #ifdef CONFIG_ARCH_TEGRA_2x_SOC 82796efa118SDmitry Osipenko if (mc->soc == &tegra20_mc_soc) { 82896efa118SDmitry Osipenko isr = tegra20_mc_irq; 82996efa118SDmitry Osipenko } else 83096efa118SDmitry Osipenko #endif 83196efa118SDmitry Osipenko { 832a8d502fdSDmitry Osipenko isr = tegra_mc_irq; 833be4dbdecSDmitry Osipenko } 8343d9dd6fdSMikko Perttunen 83589184651SThierry Reding mc->irq = platform_get_irq(pdev, 0); 836162641a6SDmitry Osipenko if (mc->irq < 0) 83789184651SThierry Reding return mc->irq; 83889184651SThierry Reding 839f2dcded1SDmitry Osipenko WARN(!mc->soc->client_id_mask, "missing client ID mask for this SoC\n"); 8403c01cf3bSPaul Walmsley 8411c74d5c0SDmitry Osipenko mc_writel(mc, mc->soc->intmask, MC_INTMASK); 84289184651SThierry Reding 84333ea002aSDmitry Osipenko err = devm_request_irq(&pdev->dev, mc->irq, isr, 0, 844db4a9c19SDmitry Osipenko dev_name(&pdev->dev), mc); 845db4a9c19SDmitry Osipenko if (err < 0) { 846db4a9c19SDmitry Osipenko dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq, 847db4a9c19SDmitry Osipenko err); 848db4a9c19SDmitry Osipenko return err; 849db4a9c19SDmitry Osipenko } 850db4a9c19SDmitry Osipenko 8511662dd64SDmitry Osipenko err = tegra_mc_reset_setup(mc); 8521662dd64SDmitry Osipenko if (err < 0) 8531662dd64SDmitry Osipenko dev_err(&pdev->dev, "failed to register reset controller: %d\n", 8541662dd64SDmitry Osipenko err); 8551662dd64SDmitry Osipenko 85606f07981SDmitry Osipenko err = tegra_mc_interconnect_setup(mc); 85706f07981SDmitry Osipenko if (err < 0) 85806f07981SDmitry Osipenko dev_err(&pdev->dev, "failed to initialize interconnect: %d\n", 85906f07981SDmitry Osipenko err); 86006f07981SDmitry Osipenko 861568ece5bSDmitry Osipenko if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU) && mc->soc->smmu) { 86245a81df0SDmitry Osipenko mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); 863568ece5bSDmitry Osipenko if (IS_ERR(mc->smmu)) { 86445a81df0SDmitry Osipenko dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", 86545a81df0SDmitry Osipenko PTR_ERR(mc->smmu)); 866568ece5bSDmitry Osipenko mc->smmu = NULL; 867568ece5bSDmitry Osipenko } 86845a81df0SDmitry Osipenko } 86945a81df0SDmitry Osipenko 870ce2785a7SDmitry Osipenko if (IS_ENABLED(CONFIG_TEGRA_IOMMU_GART) && !mc->soc->smmu) { 871ce2785a7SDmitry Osipenko mc->gart = tegra_gart_probe(&pdev->dev, mc); 872ce2785a7SDmitry Osipenko if (IS_ERR(mc->gart)) { 873ce2785a7SDmitry Osipenko dev_err(&pdev->dev, "failed to probe GART: %ld\n", 874ce2785a7SDmitry Osipenko PTR_ERR(mc->gart)); 875ce2785a7SDmitry Osipenko mc->gart = NULL; 876ce2785a7SDmitry Osipenko } 877ce2785a7SDmitry Osipenko } 878ce2785a7SDmitry Osipenko 87989184651SThierry Reding return 0; 88089184651SThierry Reding } 88189184651SThierry Reding 8825c9016f0SThierry Reding static int __maybe_unused tegra_mc_suspend(struct device *dev) 883ce2785a7SDmitry Osipenko { 884ce2785a7SDmitry Osipenko struct tegra_mc *mc = dev_get_drvdata(dev); 885ce2785a7SDmitry Osipenko 8865c9016f0SThierry Reding if (mc->soc->ops && mc->soc->ops->suspend) 8875c9016f0SThierry Reding return mc->soc->ops->suspend(mc); 888ce2785a7SDmitry Osipenko 889ce2785a7SDmitry Osipenko return 0; 890ce2785a7SDmitry Osipenko } 891ce2785a7SDmitry Osipenko 8925c9016f0SThierry Reding static int __maybe_unused tegra_mc_resume(struct device *dev) 893ce2785a7SDmitry Osipenko { 894ce2785a7SDmitry Osipenko struct tegra_mc *mc = dev_get_drvdata(dev); 895ce2785a7SDmitry Osipenko 8965c9016f0SThierry Reding if (mc->soc->ops && mc->soc->ops->resume) 8975c9016f0SThierry Reding return mc->soc->ops->resume(mc); 898ce2785a7SDmitry Osipenko 899ce2785a7SDmitry Osipenko return 0; 900ce2785a7SDmitry Osipenko } 901ce2785a7SDmitry Osipenko 902ce2785a7SDmitry Osipenko static const struct dev_pm_ops tegra_mc_pm_ops = { 9035c9016f0SThierry Reding SET_SYSTEM_SLEEP_PM_OPS(tegra_mc_suspend, tegra_mc_resume) 904ce2785a7SDmitry Osipenko }; 905ce2785a7SDmitry Osipenko 90689184651SThierry Reding static struct platform_driver tegra_mc_driver = { 90789184651SThierry Reding .driver = { 90889184651SThierry Reding .name = "tegra-mc", 90989184651SThierry Reding .of_match_table = tegra_mc_of_match, 910ce2785a7SDmitry Osipenko .pm = &tegra_mc_pm_ops, 91189184651SThierry Reding .suppress_bind_attrs = true, 91289184651SThierry Reding }, 91389184651SThierry Reding .prevent_deferred_probe = true, 91489184651SThierry Reding .probe = tegra_mc_probe, 91589184651SThierry Reding }; 91689184651SThierry Reding 91789184651SThierry Reding static int tegra_mc_init(void) 91889184651SThierry Reding { 91989184651SThierry Reding return platform_driver_register(&tegra_mc_driver); 92089184651SThierry Reding } 92189184651SThierry Reding arch_initcall(tegra_mc_init); 92289184651SThierry Reding 92389184651SThierry Reding MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); 92489184651SThierry Reding MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver"); 92589184651SThierry Reding MODULE_LICENSE("GPL v2"); 926