From nobody Mon Sep 8 21:34:27 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E9744C7EE2A for ; Thu, 11 May 2023 17:33:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238956AbjEKRdE (ORCPT ); Thu, 11 May 2023 13:33:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60320 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238381AbjEKRdC (ORCPT ); Thu, 11 May 2023 13:33:02 -0400 Received: from NAM10-MW2-obe.outbound.protection.outlook.com (mail-mw2nam10on2061.outbound.protection.outlook.com [40.107.94.61]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9939846BC; Thu, 11 May 2023 10:32:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=NiLuiwegV0Wcx0Hm8YM6xzzo+eF7M+Z3jnvWcXbMMI5OAU5FDA4cQQf8sloSxEiBjRTPVvxilN9DudRMeHjEUGUbr56F3inDsNiA4Q0B9qKiiQicxucG6qaASXeJ+K6hHI+4KI5/TTeo0S5S8czOUB8Da1Wiq7bDba+bvfupZ2Vt9HP6A2EYO9FUHWyeOXarellgeWpE/jv3eBNV5xI343CqyF2zoMmI3l1pgmTps6lvSwiruAg4qSBTZ13SFUgYDvhR9DIPaDM2DSFrHWLBm5+OvO1BgojmeUjj85CzwgIOt98WJp/vKlKuj9UGJdizO6waBR7T765jpRWuvCSQZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CF7YA1MM8lmeBi1R44fvCyem9xtF1PKrbvI0VUc5e4U=; b=malZZz/SuC+yQYtrM+uOHCjgD9ycEO9eREY6QNcOx416tYlpJE5XJi/lSkFDgMhtMG2YlZyj0CaZOLkb2wWKvmGI1CLf/wv106UJkP7Q+QHkY3clpz9oSRikrx01YWyYsB1+egrU+yHHICGhHxD7WOK6qxT68BQ+34vQ1Ly82uQRs6rdB0A9NPjMpPzNpwnvNfkgsL9EOle1JgVFGy2WZ3k9U9X3u5rwqPfvjpVCh5DVgrhRXzZcpjUj+TVOSeD6ooWFMFrClHDrIcGgegmUFXqFFF4hohbdJ9QDoPgSSG+IPaU3DLd2agT4xVXQsWw/3xVEjG8tAdLLsh3ZZ9qpIw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 216.228.118.232) smtp.rcpttodomain=google.com smtp.mailfrom=nvidia.com; dmarc=pass (p=reject sp=reject pct=100) action=none header.from=nvidia.com; dkim=none (message not signed); arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=CF7YA1MM8lmeBi1R44fvCyem9xtF1PKrbvI0VUc5e4U=; b=b0olrKSsG7jxwqfpeatwYMmSDeMsAxz5x2lptH5z/HZ8bw3eVhGf7vdpHH+P7zWv8Qx5yMG9me4k1k0O36KEJg9XSnkevJDJluKzDUx4//r3xYqf30gDyCC7Xe8PsFBmXqMpe7vf8Nrm8iK8EGvBc0rr2pvhAh4eWQQwjibAxiw7ahxiXVsIqDGSXE3w+GCDiwEdf7NvCnK9LVKz16U7SSQQgmXx3cmswmXgcHD7Bttq2BQSOlzs+7VAIo4j0YoXPo64G7EeU2vMAGVZ+pPRTQsOcwQYPCT92DPT0dM6puKgEsZNnyCCoaSgbAKtX69VrD2AeioVkenVI7sNLE5vRw== Received: from BN9PR03CA0798.namprd03.prod.outlook.com (2603:10b6:408:13f::23) by PH7PR12MB6394.namprd12.prod.outlook.com (2603:10b6:510:1fe::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6363.32; Thu, 11 May 2023 17:32:45 +0000 Received: from BN8NAM11FT011.eop-nam11.prod.protection.outlook.com (2603:10b6:408:13f:cafe::c3) by BN9PR03CA0798.outlook.office365.com (2603:10b6:408:13f::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6387.21 via Frontend Transport; Thu, 11 May 2023 17:32:45 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 216.228.118.232) smtp.mailfrom=nvidia.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=nvidia.com; Received-SPF: Pass (protection.outlook.com: domain of nvidia.com designates 216.228.118.232 as permitted sender) receiver=protection.outlook.com; client-ip=216.228.118.232; helo=mail.nvidia.com; pr=C Received: from mail.nvidia.com (216.228.118.232) by BN8NAM11FT011.mail.protection.outlook.com (10.13.176.140) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6387.22 via Frontend Transport; Thu, 11 May 2023 17:32:45 +0000 Received: from drhqmail202.nvidia.com (10.126.190.181) by mail.nvidia.com (10.127.129.5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.5; Thu, 11 May 2023 10:32:38 -0700 Received: from drhqmail203.nvidia.com (10.126.190.182) by drhqmail202.nvidia.com (10.126.190.181) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.37; Thu, 11 May 2023 10:32:37 -0700 Received: from sumitg-l4t.nvidia.com (10.127.8.10) by mail.nvidia.com (10.126.190.182) with Microsoft SMTP Server id 15.2.986.37 via Frontend Transport; Thu, 11 May 2023 10:32:32 -0700 From: Sumit Gupta To: , , , , , , , , CC: , , , , , , , , , , , , , Subject: [Patch v8 1/8] memory: tegra: add interconnect support for DRAM scaling in Tegra234 Date: Thu, 11 May 2023 23:02:04 +0530 Message-ID: <20230511173211.9127-2-sumitg@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230511173211.9127-1-sumitg@nvidia.com> References: <20230511173211.9127-1-sumitg@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BN8NAM11FT011:EE_|PH7PR12MB6394:EE_ X-MS-Office365-Filtering-Correlation-Id: 336f76ba-a268-478e-a53d-08db5245bba9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 3jBopuw+oLTjFv1gEfvUJhdlWrpv9czzVsBEwKK7hy4BXvAW1YqToFB2OYAYdMUtmD203b8KPjYxFz1pr2qUepWlUCxzHjAtwmgDBTcy+hgWIXcPDpilC8Kjvj14QOvAA1J3rGKNDT6/IUP5weSYctxk6aeIVvyKrDDLCvHldDsHMkqp6GZlUI7+X63rycIwBZOb85HK4hjNBNN6v8jO4/WaSlZ5Px5RYKTMIWOaqU1XKIKB/iiJyAmi/Za0eZ5m5e2OuOaUkmS7f3ZlLINt3rujasxFoC8ZCZn3L3jaJ/5qRq18NHf5RHFPFc37fvvVBTSUsFyzLb3wIVGmv/CKk3PtORdM6Aa5OM4HFP1CIzU+u7qK6dXGBsK/Bq6kkKQBoDPZxqteTKQCU2fmTvdtxz+Q5L2zeWEKV07ByAGBnedDmqcb+Sa2eV8ipGts/qYrhjd4p7aECMz+ZFXn/PB0mpDEgDtxoakIDL64HH8Lq4NI0JsY+ggeAtxt4MBvOuFsE6Yflay+9RwnB5t9Hj610fGnu/w3fjmmhJn+KlHFZtWr974eMm45575p0U1mp1rMY/OC2SQNjZ3UMqRJl65fZjMGL/DNosnN7ID4I0uZlevGFWkd5+IYOfoOhkTDeD53gNRiPqEGt6+1v8IE+l2ipgsHhedkUrDCRtEwEiTL3l5gLv1+gdSRIHUTDROn/j+m1tZnhfxFlprj8cl8Qmo0Ig== X-Forefront-Antispam-Report: CIP:216.228.118.232;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:mail.nvidia.com;PTR:dc7edge1.nvidia.com;CAT:NONE;SFS:(13230028)(4636009)(346002)(136003)(396003)(376002)(39860400002)(451199021)(36840700001)(40470700004)(46966006)(7696005)(6666004)(54906003)(1076003)(82310400005)(30864003)(83380400001)(41300700001)(7416002)(186003)(8936002)(4326008)(110136005)(70586007)(86362001)(316002)(26005)(2906002)(8676002)(40480700001)(5660300002)(70206006)(82740400003)(7636003)(426003)(36756003)(40460700003)(36860700001)(47076005)(2616005)(478600001)(107886003)(336012)(356005);DIR:OUT;SFP:1101; X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 11 May 2023 17:32:45.5860 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 336f76ba-a268-478e-a53d-08db5245bba9 X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=43083d15-7273-40c1-b7db-39efd9ccc17a;Ip=[216.228.118.232];Helo=[mail.nvidia.com] X-MS-Exchange-CrossTenant-AuthSource: BN8NAM11FT011.eop-nam11.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH7PR12MB6394 Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add Interconnect framework support to dynamically set the DRAM bandwidth from different clients. Both the MC and EMC drivers are added as ICC providers. The path for any request is: MC-Client[1-n] -> MC -> EMC -> EMEM/DRAM MC client's request for bandwidth will go to the MC driver which passes the client request info like BPMP Client ID, Client type and the Bandwidth to the BPMP-FW. The final DRAM freq to achieve the requested bandwidth is set by the BPMP-FW based on the passed parameters. Signed-off-by: Sumit Gupta Acked-by: Krzysztof Kozlowski --- drivers/memory/tegra/mc.c | 5 + drivers/memory/tegra/tegra186-emc.c | 133 +++++++++++++++++++++++++++ drivers/memory/tegra/tegra234.c | 138 +++++++++++++++++++++++++++- include/linux/tegra-icc.h | 65 +++++++++++++ include/soc/tegra/mc.h | 7 ++ 5 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 include/linux/tegra-icc.h diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 9082b6c3763d..983455b1f98d 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -15,6 +15,7 @@ #include #include #include +#include =20 #include =20 @@ -792,6 +793,8 @@ static int tegra_mc_interconnect_setup(struct tegra_mc = *mc) mc->provider.data =3D &mc->provider; mc->provider.set =3D mc->soc->icc_ops->set; mc->provider.aggregate =3D mc->soc->icc_ops->aggregate; + mc->provider.get_bw =3D mc->soc->icc_ops->get_bw; + mc->provider.xlate =3D mc->soc->icc_ops->xlate; mc->provider.xlate_extended =3D mc->soc->icc_ops->xlate_extended; =20 icc_provider_init(&mc->provider); @@ -824,6 +827,8 @@ static int tegra_mc_interconnect_setup(struct tegra_mc = *mc) err =3D icc_link_create(node, TEGRA_ICC_MC); if (err) goto remove_nodes; + + node->data =3D (struct tegra_mc_client *)&(mc->soc->clients[i]); } =20 err =3D icc_provider_register(&mc->provider); diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/teg= ra186-emc.c index e935ad4e95b6..6ad8a4023dd7 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -7,9 +7,11 @@ #include #include #include +#include #include =20 #include +#include "mc.h" =20 struct tegra186_emc_dvfs { unsigned long latency; @@ -29,8 +31,15 @@ struct tegra186_emc { unsigned long min_rate; unsigned long max_rate; } debugfs; + + struct icc_provider provider; }; =20 +static inline struct tegra186_emc *to_tegra186_emc(struct icc_provider *pr= ovider) +{ + return container_of(provider, struct tegra186_emc, provider); +} + /* * debugfs interface * @@ -146,8 +155,102 @@ DEFINE_DEBUGFS_ATTRIBUTE(tegra186_emc_debug_max_rate_= fops, tegra186_emc_debug_max_rate_get, tegra186_emc_debug_max_rate_set, "%llu\n"); =20 +/* + * tegra_emc_icc_set_bw() - Set BW api for EMC provider + * @src: ICC node for External Memory Controller (EMC) + * @dst: ICC node for External Memory (DRAM) + * + * Do nothing here as info to BPMP-FW is now passed in the BW set function + * of the MC driver. BPMP-FW sets the final Freq based on the passed value= s. + */ +static int tegra_emc_icc_set_bw(struct icc_node *src, struct icc_node *dst) +{ + return 0; +} + +static struct icc_node * +tegra_emc_of_icc_xlate(struct of_phandle_args *spec, void *data) +{ + struct icc_provider *provider =3D data; + struct icc_node *node; + + /* External Memory is the only possible ICC route */ + list_for_each_entry(node, &provider->nodes, node_list) { + if (node->id !=3D TEGRA_ICC_EMEM) + continue; + + return node; + } + + return ERR_PTR(-EPROBE_DEFER); +} + +static int tegra_emc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 = *peak) +{ + *avg =3D 0; + *peak =3D 0; + + return 0; +} + +static int tegra_emc_interconnect_init(struct tegra186_emc *emc) +{ + struct tegra_mc *mc =3D dev_get_drvdata(emc->dev->parent); + const struct tegra_mc_soc *soc =3D mc->soc; + struct icc_node *node; + int err; + + emc->provider.dev =3D emc->dev; + emc->provider.set =3D tegra_emc_icc_set_bw; + emc->provider.data =3D &emc->provider; + emc->provider.aggregate =3D soc->icc_ops->aggregate; + emc->provider.xlate =3D tegra_emc_of_icc_xlate; + emc->provider.get_bw =3D tegra_emc_icc_get_init_bw; + + icc_provider_init(&emc->provider); + + /* create External Memory Controller node */ + node =3D icc_node_create(TEGRA_ICC_EMC); + if (IS_ERR(node)) { + err =3D PTR_ERR(node); + goto err_msg; + } + + node->name =3D "External Memory Controller"; + icc_node_add(node, &emc->provider); + + /* link External Memory Controller to External Memory (DRAM) */ + err =3D icc_link_create(node, TEGRA_ICC_EMEM); + if (err) + goto remove_nodes; + + /* create External Memory node */ + node =3D icc_node_create(TEGRA_ICC_EMEM); + if (IS_ERR(node)) { + err =3D PTR_ERR(node); + goto remove_nodes; + } + + node->name =3D "External Memory (DRAM)"; + icc_node_add(node, &emc->provider); + + err =3D icc_provider_register(&emc->provider); + if (err) + goto remove_nodes; + + return 0; + +remove_nodes: + icc_nodes_remove(&emc->provider); +err_msg: + dev_err(emc->dev, "failed to initialize ICC: %d\n", err); + + return err; +} + static int tegra186_emc_probe(struct platform_device *pdev) { + struct tegra_mc *mc =3D dev_get_drvdata(pdev->dev.parent); struct mrq_emc_dvfs_latency_response response; struct tegra_bpmp_message msg; struct tegra186_emc *emc; @@ -236,6 +339,32 @@ static int tegra186_emc_probe(struct platform_device *= pdev) debugfs_create_file("max_rate", S_IRUGO | S_IWUSR, emc->debugfs.root, emc, &tegra186_emc_debug_max_rate_fops); =20 + if (mc && mc->soc->icc_ops) { + if (tegra_bpmp_mrq_is_supported(emc->bpmp, MRQ_BWMGR_INT)) { + mc->bwmgr_mrq_supported =3D true; + + /* + * MC driver probe can't get BPMP reference as it gets probed + * earlier than BPMP. So, save the BPMP ref got from the EMC + * DT node in the mc->bpmp and use it in MC's icc_set hook. + */ + mc->bpmp =3D emc->bpmp; + barrier(); + } + + /* + * Initialize the ICC even if BPMP-FW doesn't support 'MRQ_BWMGR_INT'. + * Use the flag 'mc->bwmgr_mrq_supported' within MC driver and return + * EINVAL instead of passing the request to BPMP-FW later when the BW + * request is made by client with 'icc_set_bw()' call. + */ + err =3D tegra_emc_interconnect_init(emc); + if (err) { + mc->bpmp =3D NULL; + goto put_bpmp; + } + } + return 0; =20 put_bpmp: @@ -245,9 +374,12 @@ static int tegra186_emc_probe(struct platform_device *= pdev) =20 static int tegra186_emc_remove(struct platform_device *pdev) { + struct tegra_mc *mc =3D dev_get_drvdata(pdev->dev.parent); struct tegra186_emc *emc =3D platform_get_drvdata(pdev); =20 debugfs_remove_recursive(emc->debugfs.root); + + mc->bpmp =3D NULL; tegra_bpmp_put(emc->bpmp); =20 return 0; @@ -272,6 +404,7 @@ static struct platform_driver tegra186_emc_driver =3D { .name =3D "tegra186-emc", .of_match_table =3D tegra186_emc_of_match, .suppress_bind_attrs =3D true, + .sync_state =3D icc_sync_state, }, .probe =3D tegra186_emc_probe, .remove =3D tegra186_emc_remove, diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra23= 4.c index 02dcc5748bba..56d911926d54 100644 --- a/drivers/memory/tegra/tegra234.c +++ b/drivers/memory/tegra/tegra234.c @@ -1,18 +1,23 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2021-2022, NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2022-2023, NVIDIA CORPORATION. All rights reserved. */ =20 #include =20 #include +#include +#include =20 +#include #include "mc.h" =20 static const struct tegra_mc_client tegra234_mc_clients[] =3D { { .id =3D TEGRA234_MEMORY_CLIENT_MGBEARD, .name =3D "mgbeard", + .bpmp_id =3D TEGRA_ICC_BPMP_EQOS, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_MGBE, .regs =3D { .sid =3D { @@ -23,6 +28,8 @@ static const struct tegra_mc_client tegra234_mc_clients[]= =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_MGBEBRD, .name =3D "mgbebrd", + .bpmp_id =3D TEGRA_ICC_BPMP_EQOS, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_MGBE_VF1, .regs =3D { .sid =3D { @@ -33,6 +40,8 @@ static const struct tegra_mc_client tegra234_mc_clients[]= =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_MGBECRD, .name =3D "mgbecrd", + .bpmp_id =3D TEGRA_ICC_BPMP_EQOS, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_MGBE_VF2, .regs =3D { .sid =3D { @@ -43,6 +52,8 @@ static const struct tegra_mc_client tegra234_mc_clients[]= =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_MGBEDRD, .name =3D "mgbedrd", + .bpmp_id =3D TEGRA_ICC_BPMP_EQOS, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_MGBE_VF3, .regs =3D { .sid =3D { @@ -52,6 +63,8 @@ static const struct tegra_mc_client tegra234_mc_clients[]= =3D { }, }, { .id =3D TEGRA234_MEMORY_CLIENT_MGBEAWR, + .bpmp_id =3D TEGRA_ICC_BPMP_EQOS, + .type =3D TEGRA_ICC_NISO, .name =3D "mgbeawr", .sid =3D TEGRA234_SID_MGBE, .regs =3D { @@ -63,6 +76,8 @@ static const struct tegra_mc_client tegra234_mc_clients[]= =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_MGBEBWR, .name =3D "mgbebwr", + .bpmp_id =3D TEGRA_ICC_BPMP_EQOS, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_MGBE_VF1, .regs =3D { .sid =3D { @@ -73,6 +88,8 @@ static const struct tegra_mc_client tegra234_mc_clients[]= =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_MGBECWR, .name =3D "mgbecwr", + .bpmp_id =3D TEGRA_ICC_BPMP_EQOS, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_MGBE_VF2, .regs =3D { .sid =3D { @@ -83,6 +100,8 @@ static const struct tegra_mc_client tegra234_mc_clients[= ] =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_SDMMCRAB, .name =3D "sdmmcrab", + .bpmp_id =3D TEGRA_ICC_BPMP_SDMMC_4, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_SDMMC4, .regs =3D { .sid =3D { @@ -93,6 +112,8 @@ static const struct tegra_mc_client tegra234_mc_clients[= ] =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_MGBEDWR, .name =3D "mgbedwr", + .bpmp_id =3D TEGRA_ICC_BPMP_EQOS, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_MGBE_VF3, .regs =3D { .sid =3D { @@ -103,6 +124,8 @@ static const struct tegra_mc_client tegra234_mc_clients= [] =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_SDMMCWAB, .name =3D "sdmmcwab", + .bpmp_id =3D TEGRA_ICC_BPMP_SDMMC_4, + .type =3D TEGRA_ICC_NISO, .sid =3D TEGRA234_SID_SDMMC4, .regs =3D { .sid =3D { @@ -153,6 +176,8 @@ static const struct tegra_mc_client tegra234_mc_clients= [] =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_APEDMAR, .name =3D "apedmar", + .bpmp_id =3D TEGRA_ICC_BPMP_APEDMA, + .type =3D TEGRA_ICC_ISO_AUDIO, .sid =3D TEGRA234_SID_APE, .regs =3D { .sid =3D { @@ -163,6 +188,8 @@ static const struct tegra_mc_client tegra234_mc_clients= [] =3D { }, { .id =3D TEGRA234_MEMORY_CLIENT_APEDMAW, .name =3D "apedmaw", + .bpmp_id =3D TEGRA_ICC_BPMP_APEDMA, + .type =3D TEGRA_ICC_ISO_AUDIO, .sid =3D TEGRA234_SID_APE, .regs =3D { .sid =3D { @@ -333,6 +360,114 @@ static const struct tegra_mc_client tegra234_mc_clien= ts[] =3D { }, }; =20 +/* + * tegra234_mc_icc_set() - Pass MC client info to the BPMP-FW + * @src: ICC node for Memory Controller's (MC) Client + * @dst: ICC node for Memory Controller (MC) + * + * Passing the current request info from the MC to the BPMP-FW where + * LA and PTSA registers are accessed and the final EMC freq is set + * based on client_id, type, latency and bandwidth. + * icc_set_bw() makes set_bw calls for both MC and EMC providers in + * sequence. Both the calls are protected by 'mutex_lock(&icc_lock)'. + * So, the data passed won't be updated by concurrent set calls from + * other clients. + */ +static int tegra234_mc_icc_set(struct icc_node *src, struct icc_node *dst) +{ + struct tegra_mc *mc =3D icc_provider_to_tegra_mc(dst->provider); + struct mrq_bwmgr_int_request bwmgr_req =3D { 0 }; + struct mrq_bwmgr_int_response bwmgr_resp =3D { 0 }; + const struct tegra_mc_client *pclient =3D src->data; + struct tegra_bpmp_message msg; + int ret; + + /* + * Same Src and Dst node will happen during boot from icc_node_add(). + * This can be used to pre-initialize and set bandwidth for all clients + * before their drivers are loaded. We are skipping this case as for us, + * the pre-initialization already happened in Bootloader(MB2) and BPMP-FW. + */ + if (src->id =3D=3D dst->id) + return 0; + + if (!mc->bwmgr_mrq_supported) + return -EINVAL; + + if (!mc->bpmp) { + dev_err(mc->dev, "BPMP reference NULL\n"); + return -ENOENT; + } + + if (pclient->type =3D=3D TEGRA_ICC_NISO) + bwmgr_req.bwmgr_calc_set_req.niso_bw =3D src->avg_bw; + else + bwmgr_req.bwmgr_calc_set_req.iso_bw =3D src->avg_bw; + + bwmgr_req.bwmgr_calc_set_req.client_id =3D pclient->bpmp_id; + + bwmgr_req.cmd =3D CMD_BWMGR_INT_CALC_AND_SET; + bwmgr_req.bwmgr_calc_set_req.mc_floor =3D src->peak_bw; + bwmgr_req.bwmgr_calc_set_req.floor_unit =3D BWMGR_INT_UNIT_KBPS; + + memset(&msg, 0, sizeof(msg)); + msg.mrq =3D MRQ_BWMGR_INT; + msg.tx.data =3D &bwmgr_req; + msg.tx.size =3D sizeof(bwmgr_req); + msg.rx.data =3D &bwmgr_resp; + msg.rx.size =3D sizeof(bwmgr_resp); + + ret =3D tegra_bpmp_transfer(mc->bpmp, &msg); + if (ret < 0) { + dev_err(mc->dev, "BPMP transfer failed: %d\n", ret); + goto error; + } + if (msg.rx.ret < 0) { + pr_err("failed to set bandwidth for %u: %d\n", + bwmgr_req.bwmgr_calc_set_req.client_id, msg.rx.ret); + ret =3D -EINVAL; + } + +error: + return ret; +} + +static struct icc_node* +tegra234_mc_of_icc_xlate(struct of_phandle_args *spec, void *data) +{ + struct tegra_mc *mc =3D icc_provider_to_tegra_mc(data); + unsigned int cl_id =3D spec->args[0]; + struct icc_node *node; + + list_for_each_entry(node, &mc->provider.nodes, node_list) { + if (node->id !=3D cl_id) + continue; + + return node; + } + + /* + * If a client driver calls devm_of_icc_get() before the MC driver + * is probed, then return EPROBE_DEFER to the client driver. + */ + return ERR_PTR(-EPROBE_DEFER); +} + +static int tegra234_mc_icc_get_init_bw(struct icc_node *node, u32 *avg, u3= 2 *peak) +{ + *avg =3D 0; + *peak =3D 0; + + return 0; +} + +static const struct tegra_mc_icc_ops tegra234_mc_icc_ops =3D { + .xlate =3D tegra234_mc_of_icc_xlate, + .aggregate =3D icc_std_aggregate, + .get_bw =3D tegra234_mc_icc_get_init_bw, + .set =3D tegra234_mc_icc_set, +}; + const struct tegra_mc_soc tegra234_mc_soc =3D { .num_clients =3D ARRAY_SIZE(tegra234_mc_clients), .clients =3D tegra234_mc_clients, @@ -345,6 +480,7 @@ const struct tegra_mc_soc tegra234_mc_soc =3D { MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, .has_addr_hi_reg =3D true, .ops =3D &tegra186_mc_ops, + .icc_ops =3D &tegra234_mc_icc_ops, .ch_intmask =3D 0x0000ff00, .global_intstatus_channel_shift =3D 8, /* diff --git a/include/linux/tegra-icc.h b/include/linux/tegra-icc.h new file mode 100644 index 000000000000..4b4d4bee290c --- /dev/null +++ b/include/linux/tegra-icc.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022-2023 NVIDIA CORPORATION. All rights reserved. + */ + +#ifndef LINUX_TEGRA_ICC_H +#define LINUX_TEGRA_ICC_H + +enum tegra_icc_client_type { + TEGRA_ICC_NONE, + TEGRA_ICC_NISO, + TEGRA_ICC_ISO_DISPLAY, + TEGRA_ICC_ISO_VI, + TEGRA_ICC_ISO_AUDIO, + TEGRA_ICC_ISO_VIFAL, +}; + +/* ICC ID's for MC client's used in BPMP */ +#define TEGRA_ICC_BPMP_DEBUG 1 +#define TEGRA_ICC_BPMP_CPU_CLUSTER0 2 +#define TEGRA_ICC_BPMP_CPU_CLUSTER1 3 +#define TEGRA_ICC_BPMP_CPU_CLUSTER2 4 +#define TEGRA_ICC_BPMP_GPU 5 +#define TEGRA_ICC_BPMP_CACTMON 6 +#define TEGRA_ICC_BPMP_DISPLAY 7 +#define TEGRA_ICC_BPMP_VI 8 +#define TEGRA_ICC_BPMP_EQOS 9 +#define TEGRA_ICC_BPMP_PCIE_0 10 +#define TEGRA_ICC_BPMP_PCIE_1 11 +#define TEGRA_ICC_BPMP_PCIE_2 12 +#define TEGRA_ICC_BPMP_PCIE_3 13 +#define TEGRA_ICC_BPMP_PCIE_4 14 +#define TEGRA_ICC_BPMP_PCIE_5 15 +#define TEGRA_ICC_BPMP_PCIE_6 16 +#define TEGRA_ICC_BPMP_PCIE_7 17 +#define TEGRA_ICC_BPMP_PCIE_8 18 +#define TEGRA_ICC_BPMP_PCIE_9 19 +#define TEGRA_ICC_BPMP_PCIE_10 20 +#define TEGRA_ICC_BPMP_DLA_0 21 +#define TEGRA_ICC_BPMP_DLA_1 22 +#define TEGRA_ICC_BPMP_SDMMC_1 23 +#define TEGRA_ICC_BPMP_SDMMC_2 24 +#define TEGRA_ICC_BPMP_SDMMC_3 25 +#define TEGRA_ICC_BPMP_SDMMC_4 26 +#define TEGRA_ICC_BPMP_NVDEC 27 +#define TEGRA_ICC_BPMP_NVENC 28 +#define TEGRA_ICC_BPMP_NVJPG_0 29 +#define TEGRA_ICC_BPMP_NVJPG_1 30 +#define TEGRA_ICC_BPMP_OFAA 31 +#define TEGRA_ICC_BPMP_XUSB_HOST 32 +#define TEGRA_ICC_BPMP_XUSB_DEV 33 +#define TEGRA_ICC_BPMP_TSEC 34 +#define TEGRA_ICC_BPMP_VIC 35 +#define TEGRA_ICC_BPMP_APE 36 +#define TEGRA_ICC_BPMP_APEDMA 37 +#define TEGRA_ICC_BPMP_SE 38 +#define TEGRA_ICC_BPMP_ISP 39 +#define TEGRA_ICC_BPMP_HDA 40 +#define TEGRA_ICC_BPMP_VIFAL 41 +#define TEGRA_ICC_BPMP_VI2FAL 42 +#define TEGRA_ICC_BPMP_VI2 43 +#define TEGRA_ICC_BPMP_RCE 44 +#define TEGRA_ICC_BPMP_PVA 45 + +#endif /* LINUX_TEGRA_ICC_H */ diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h index 51a2263e1bc5..900d88b26fae 100644 --- a/include/soc/tegra/mc.h +++ b/include/soc/tegra/mc.h @@ -13,6 +13,7 @@ #include #include #include +#include =20 struct clk; struct device; @@ -26,6 +27,8 @@ struct tegra_mc_timing { =20 struct tegra_mc_client { unsigned int id; + unsigned int bpmp_id; + enum tegra_icc_client_type type; const char *name; /* * For Tegra210 and earlier, this is the SWGROUP ID used for IOVA transla= tions in the @@ -166,8 +169,10 @@ struct tegra_mc_icc_ops { int (*set)(struct icc_node *src, struct icc_node *dst); int (*aggregate)(struct icc_node *node, u32 tag, u32 avg_bw, u32 peak_bw, u32 *agg_avg, u32 *agg_peak); + struct icc_node* (*xlate)(struct of_phandle_args *spec, void *data); struct icc_node_data *(*xlate_extended)(struct of_phandle_args *spec, void *data); + int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak); }; =20 struct tegra_mc_ops { @@ -214,6 +219,7 @@ struct tegra_mc_soc { }; =20 struct tegra_mc { + struct tegra_bpmp *bpmp; struct device *dev; struct tegra_smmu *smmu; struct gart_device *gart; @@ -229,6 +235,7 @@ struct tegra_mc { struct tegra_mc_timing *timings; unsigned int num_timings; =20 + bool bwmgr_mrq_supported; struct reset_controller_dev reset; =20 struct icc_provider provider; --=20 2.17.1