Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

memory: tegra-mc: Add interconnect framework

Add common SoC-agnostic ICC framework which turns Tegra Memory Controller
into a memory interconnection provider. This allows us to use interconnect
API for tuning of memory configurations.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Tested-by: Peter Geis <pgwipeout@gmail.com>
Tested-by: Nicolas Chauvet <kwizart@gmail.com>
Link: https://lore.kernel.org/r/20201104164923.21238-33-digetx@gmail.com
Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>

authored by

Dmitry Osipenko and committed by
Krzysztof Kozlowski
06f07981 d5ecac0a

+140
+1
drivers/memory/tegra/Kconfig
··· 3 3 bool "NVIDIA Tegra Memory Controller support" 4 4 default y 5 5 depends on ARCH_TEGRA 6 + select INTERCONNECT 6 7 help 7 8 This driver supports the Memory Controller (MC) hardware found on 8 9 NVIDIA Tegra SoCs.
+100
drivers/memory/tegra/mc.c
··· 639 639 return IRQ_HANDLED; 640 640 } 641 641 642 + /* 643 + * Memory Controller (MC) has few Memory Clients that are issuing memory 644 + * bandwidth allocation requests to the MC interconnect provider. The MC 645 + * provider aggregates the requests and then sends the aggregated request 646 + * up to the External Memory Controller (EMC) interconnect provider which 647 + * re-configures hardware interface to External Memory (EMEM) in accordance 648 + * to the required bandwidth. Each MC interconnect node represents an 649 + * individual Memory Client. 650 + * 651 + * Memory interconnect topology: 652 + * 653 + * +----+ 654 + * +--------+ | | 655 + * | TEXSRD +--->+ | 656 + * +--------+ | | 657 + * | | +-----+ +------+ 658 + * ... | MC +--->+ EMC +--->+ EMEM | 659 + * | | +-----+ +------+ 660 + * +--------+ | | 661 + * | DISP.. +--->+ | 662 + * +--------+ | | 663 + * +----+ 664 + */ 665 + static int tegra_mc_interconnect_setup(struct tegra_mc *mc) 666 + { 667 + struct icc_node *node; 668 + unsigned int i; 669 + int err; 670 + 671 + /* older device-trees don't have interconnect properties */ 672 + if (!device_property_present(mc->dev, "#interconnect-cells") || 673 + !mc->soc->icc_ops) 674 + return 0; 675 + 676 + mc->provider.dev = mc->dev; 677 + mc->provider.data = &mc->provider; 678 + mc->provider.set = mc->soc->icc_ops->set; 679 + mc->provider.aggregate = mc->soc->icc_ops->aggregate; 680 + mc->provider.xlate_extended = mc->soc->icc_ops->xlate_extended; 681 + 682 + err = icc_provider_add(&mc->provider); 683 + if (err) 684 + return err; 685 + 686 + /* create Memory Controller node */ 687 + node = icc_node_create(TEGRA_ICC_MC); 688 + if (IS_ERR(node)) { 689 + err = PTR_ERR(node); 690 + goto del_provider; 691 + } 692 + 693 + node->name = "Memory Controller"; 694 + icc_node_add(node, &mc->provider); 695 + 696 + /* link Memory Controller to External Memory Controller */ 697 + err = icc_link_create(node, TEGRA_ICC_EMC); 698 + if (err) 699 + goto remove_nodes; 700 + 701 + for (i = 0; i < mc->soc->num_clients; i++) { 702 + /* create MC client node */ 703 + node = icc_node_create(mc->soc->clients[i].id); 704 + if (IS_ERR(node)) { 705 + err = PTR_ERR(node); 706 + goto remove_nodes; 707 + } 708 + 709 + node->name = mc->soc->clients[i].name; 710 + icc_node_add(node, &mc->provider); 711 + 712 + /* link Memory Client to Memory Controller */ 713 + err = icc_link_create(node, TEGRA_ICC_MC); 714 + if (err) 715 + goto remove_nodes; 716 + } 717 + 718 + /* 719 + * MC driver is registered too early, so early that generic driver 720 + * syncing doesn't work for the MC. But it doesn't really matter 721 + * since syncing works for the EMC drivers, hence we can sync the 722 + * MC driver by ourselves and then EMC will complete syncing of 723 + * the whole ICC state. 724 + */ 725 + icc_sync_state(mc->dev); 726 + 727 + return 0; 728 + 729 + remove_nodes: 730 + icc_nodes_remove(&mc->provider); 731 + del_provider: 732 + icc_provider_del(&mc->provider); 733 + 734 + return err; 735 + } 736 + 642 737 static int tegra_mc_probe(struct platform_device *pdev) 643 738 { 644 739 struct resource *res; ··· 820 725 err = tegra_mc_reset_setup(mc); 821 726 if (err < 0) 822 727 dev_err(&pdev->dev, "failed to register reset controller: %d\n", 728 + err); 729 + 730 + err = tegra_mc_interconnect_setup(mc); 731 + if (err < 0) 732 + dev_err(&pdev->dev, "failed to initialize interconnect: %d\n", 823 733 err); 824 734 825 735 if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU) && mc->soc->smmu) {
+22
drivers/memory/tegra/mc.h
··· 78 78 79 79 #define MC_TIMING_UPDATE BIT(0) 80 80 81 + static inline u32 tegra_mc_scale_percents(u64 val, unsigned int percents) 82 + { 83 + val = val * percents; 84 + do_div(val, 100); 85 + 86 + return min_t(u64, val, U32_MAX); 87 + } 88 + 89 + static inline struct tegra_mc * 90 + icc_provider_to_tegra_mc(struct icc_provider *provider) 91 + { 92 + return container_of(provider, struct tegra_mc, provider); 93 + } 94 + 81 95 static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset) 82 96 { 83 97 return readl_relaxed(mc->regs + offset); ··· 128 114 #ifdef CONFIG_ARCH_TEGRA_210_SOC 129 115 extern const struct tegra_mc_soc tegra210_mc_soc; 130 116 #endif 117 + 118 + /* 119 + * These IDs are for internal use of Tegra ICC drivers. The ID numbers are 120 + * chosen such that they don't conflict with the device-tree ICC node IDs. 121 + */ 122 + #define TEGRA_ICC_MC 1000 123 + #define TEGRA_ICC_EMC 1001 124 + #define TEGRA_ICC_EMEM 1002 131 125 132 126 #endif /* MEMORY_TEGRA_MC_H */
+17
include/soc/tegra/mc.h
··· 6 6 #ifndef __SOC_TEGRA_MC_H__ 7 7 #define __SOC_TEGRA_MC_H__ 8 8 9 + #include <linux/bits.h> 9 10 #include <linux/err.h> 11 + #include <linux/interconnect-provider.h> 10 12 #include <linux/reset-controller.h> 11 13 #include <linux/types.h> 12 14 ··· 143 141 const struct tegra_mc_reset *rst); 144 142 }; 145 143 144 + #define TEGRA_MC_ICC_TAG_DEFAULT 0 145 + #define TEGRA_MC_ICC_TAG_ISO BIT(0) 146 + 147 + struct tegra_mc_icc_ops { 148 + int (*set)(struct icc_node *src, struct icc_node *dst); 149 + int (*aggregate)(struct icc_node *node, u32 tag, u32 avg_bw, 150 + u32 peak_bw, u32 *agg_avg, u32 *agg_peak); 151 + struct icc_node_data *(*xlate_extended)(struct of_phandle_args *spec, 152 + void *data); 153 + }; 154 + 146 155 struct tegra_mc_soc { 147 156 const struct tegra_mc_client *clients; 148 157 unsigned int num_clients; ··· 173 160 const struct tegra_mc_reset_ops *reset_ops; 174 161 const struct tegra_mc_reset *resets; 175 162 unsigned int num_resets; 163 + 164 + const struct tegra_mc_icc_ops *icc_ops; 176 165 }; 177 166 178 167 struct tegra_mc { ··· 192 177 unsigned int num_timings; 193 178 194 179 struct reset_controller_dev reset; 180 + 181 + struct icc_provider provider; 195 182 196 183 spinlock_t lock; 197 184 };