get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2137023/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2137023,
    "url": "http://patchwork.ozlabs.org/api/patches/2137023/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-tegra/patch/20250915080157.28195-9-clamor95@gmail.com/",
    "project": {
        "id": 21,
        "url": "http://patchwork.ozlabs.org/api/projects/21/?format=api",
        "name": "Linux Tegra Development",
        "link_name": "linux-tegra",
        "list_id": "linux-tegra.vger.kernel.org",
        "list_email": "linux-tegra@vger.kernel.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20250915080157.28195-9-clamor95@gmail.com>",
    "list_archive_url": null,
    "date": "2025-09-15T08:01:54",
    "name": "[v3,08/11] memory: tegra: Add Tegra114 EMC driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "changes-requested",
    "archived": false,
    "hash": "8642e6f3f4698663828dfe629c90f4d34ce3bae5",
    "submitter": {
        "id": 84146,
        "url": "http://patchwork.ozlabs.org/api/people/84146/?format=api",
        "name": "Svyatoslav Ryhel",
        "email": "clamor95@gmail.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-tegra/patch/20250915080157.28195-9-clamor95@gmail.com/mbox/",
    "series": [
        {
            "id": 473640,
            "url": "http://patchwork.ozlabs.org/api/series/473640/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-tegra/list/?series=473640",
            "date": "2025-09-15T08:01:46",
            "name": "Tegra114: implement EMC support",
            "version": 3,
            "mbox": "http://patchwork.ozlabs.org/series/473640/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2137023/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2137023/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "\n <linux-tegra+bounces-9254-incoming=patchwork.ozlabs.org@vger.kernel.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "linux-tegra@vger.kernel.org"
        ],
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20230601 header.b=eFpsV4Bw;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2604:1380:45e3:2400::1; helo=sv.mirrors.kernel.org;\n envelope-from=linux-tegra+bounces-9254-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)",
            "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"eFpsV4Bw\"",
            "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.167.42",
            "smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com",
            "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com"
        ],
        "Received": [
            "from sv.mirrors.kernel.org (sv.mirrors.kernel.org\n [IPv6:2604:1380:45e3:2400::1])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature ECDSA (secp384r1))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4cQHZT6cRLz1y1p\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 15 Sep 2025 18:02:41 +1000 (AEST)",
            "from smtp.subspace.kernel.org (relay.kernel.org [52.25.139.140])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby sv.mirrors.kernel.org (Postfix) with ESMTPS id 81E073AE3B9\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 15 Sep 2025 08:02:40 +0000 (UTC)",
            "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 276C52EF660;\n\tMon, 15 Sep 2025 08:02:40 +0000 (UTC)",
            "from mail-lf1-f42.google.com (mail-lf1-f42.google.com\n [209.85.167.42])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 15DF72ECD11\n\tfor <linux-tegra@vger.kernel.org>; Mon, 15 Sep 2025 08:02:34 +0000 (UTC)",
            "by mail-lf1-f42.google.com with SMTP id\n 2adb3069b0e04-55f7b6e4145so4150582e87.1\n        for <linux-tegra@vger.kernel.org>;\n Mon, 15 Sep 2025 01:02:34 -0700 (PDT)",
            "from xeon.. ([188.163.112.70])\n        by smtp.gmail.com with ESMTPSA id\n 2adb3069b0e04-56e6460dec4sm3392381e87.103.2025.09.15.01.02.31\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Mon, 15 Sep 2025 01:02:32 -0700 (PDT)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1757923359; cv=none;\n b=FXLBC3VNEV5gHsmTilUaPF4gfEKzQrVlNy6rjNgpUgdeJ1Z8kOt1X/bRAj8bCAv/Wcwuv+ip7qKxVETIWf1aFZvAVbLEhH9X3rn3bK2K2MacgEBBvetm/tNlYd0ej3PP67bfvbg/t47k9uShEbgOt7alP/a4qpzCH9z4PSgVEYg=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1757923359; c=relaxed/simple;\n\tbh=ggJTxwuVc87/mZHwchOGPG25EuZl20cKTsm90v+Iq4g=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=DmQa+pignd8HEGNLbKVL5XprzlwPG3mbrqskLb6lxrEtPv6SD7OXEwh/eGlCxz5vzhDnM7FnLSF7WIYoEXTloFP1q5U8zO0t8F9Yd380DEqOXTovN6W962ItqsgFJ4FAiGC1r6kufkzfwJ9IgBLTgQMNc6pFKfMuCVo/55gPsIA=",
        "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=eFpsV4Bw; arc=none smtp.client-ip=209.85.167.42",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20230601; t=1757923353; x=1758528153;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=JD8tOQTTtdC4jOAibu1mY4LM6JkABafsszS025rkn0I=;\n        b=eFpsV4BwHMf9SVAsTX8Wg28DoLy2ekHAuxbanHFbJWD3e6+XC2CbGUZ2dQJYCKy0F9\n         0mE3xiC46eKUGZW0fJT2UeWl+bXbt+1PKT9TDQ3EMxQ0ns/jtN4W3cIIU56EkDPQMN/K\n         Jpk86CoW++Y9USJt8ZZTCzWNuhIPl/gDCx5BMohilQFDiNCKfz/shatpcDuDpMX7UTie\n         sKLQe8T6fjZbbbsoaOe9Gbsl58DTzX4l010fsZ02VNifd1dXmSS9Yr3U1hCwsMtFsug5\n         +q3aICq+TeKwNaekb7nHFi8X04TsesdK+FXoDVIRnR8lkxCd0Xy0KaL+tWi/D50zXfV3\n         gmgQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20230601; t=1757923353; x=1758528153;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc\n         :subject:date:message-id:reply-to;\n        bh=JD8tOQTTtdC4jOAibu1mY4LM6JkABafsszS025rkn0I=;\n        b=lC3nYMPxw3UNIqoY/JhCRbmEXG4hhF1udFe3MpuksBv49hDUiuz7lrj9KZToikCxaS\n         Mbu8Eddwqf0zYZysujVwNvM8F2WkYszfdvcVkjcUJ267atKbszJObFiNZomJK4HuV1EM\n         /6NhRW7X3wFCvDTgkKQCh/9OQHi9eoHIdl0QpFbJ+uupFj5icf3KNFodznVTvkN7q7s4\n         b3TnTLUZcIDTkvlXQU/m4QDXxvdLyGEiWs5GBMLYb0ylpaCiOtCrxsETVwKgeg2cWgt1\n         ynV8MN2bAqZWrHHcXo3K3uZ+OVzYxygdTgz4MQM8JkHU1nKKrSSL6jbTlgFyHB1iEgA+\n         V/5w==",
        "X-Forwarded-Encrypted": "i=1;\n AJvYcCVqOJfw9U485cyCvrOKuVzqZLrHLrHZjb1BIpVGqMwmVh3Vn37tIvkqVdM+PKUJKb0eJM+dTYEdnhXBsw==@vger.kernel.org",
        "X-Gm-Message-State": "AOJu0YzogOaMpx4gv+I4uIHkA6Fq0rRogsF81T3eR05GLRzqbXhARFN5\n\ttcfBJ/W1/s+99j3nCWcqQ7Cm7CBIRvQ2l2YAd9onl8pjPHzDxwneU/ai",
        "X-Gm-Gg": "ASbGnctSR5E49N5ERsSDoEOVgCZuziEZ/TsA++XK/BBH58nSAPjJeQ9EcoEZQGkwCIM\n\t8NLShgnMrt3LWFkX54Gk4czFMBNVkaaAlKPRnrikv/VBO3voCXz5anYpM5rkFEIio/LQA0MH8u4\n\tRrA4WUpqQEgD9Ti5WSGHnVyLZXNOwLoCGFw1JB3kkhhmU9MNufF4w7zuhVXimnS9o05PFqCqVAn\n\tR4P3uLGbwEyUs6VDLVf4shPOKMtzBGoYi5X7Lz0rVn70vVNuIz1LdUSb9lZfutcWHoyElJ+MWsc\n\tHmUhUOq2bF1PgX4CIXAlpwOipAUsD1bEywFfni90zs07nGCE0hqpTVuojau8NYSBDBQUaOoIvgk\n\tsM3ezQU9GCHYIM1loZKxyLAu5",
        "X-Google-Smtp-Source": "\n AGHT+IGSZUcM50iwRYHV3oQLfCD2huPhYtBOrRI7WdmG+b+/1JeyZ+1o2xw4xf86UU9X6P4ydGN4Cg==",
        "X-Received": "by 2002:a05:6512:2381:b0:560:8c58:6ce2 with SMTP id\n 2adb3069b0e04-570489fc813mr3267998e87.3.1757923352723;\n        Mon, 15 Sep 2025 01:02:32 -0700 (PDT)",
        "From": "Svyatoslav Ryhel <clamor95@gmail.com>",
        "To": "Krzysztof Kozlowski <krzk@kernel.org>,\n\tRob Herring <robh@kernel.org>,\n\tConor Dooley <conor+dt@kernel.org>,\n\tThierry Reding <treding@nvidia.com>,\n\tThierry Reding <thierry.reding@gmail.com>,\n\tJonathan Hunter <jonathanh@nvidia.com>,\n\tPrashant Gaikwad <pgaikwad@nvidia.com>,\n\tMikko Perttunen <mperttunen@nvidia.com>,\n\tMichael Turquette <mturquette@baylibre.com>,\n\tStephen Boyd <sboyd@kernel.org>,\n\tDmitry Osipenko <digetx@gmail.com>,\n\tMyungJoo Ham <myungjoo.ham@samsung.com>,\n\tKyungmin Park <kyungmin.park@samsung.com>,\n\tChanwoo Choi <cw00.choi@samsung.com>,\n\tSvyatoslav Ryhel <clamor95@gmail.com>",
        "Cc": "linux-kernel@vger.kernel.org,\n\tdevicetree@vger.kernel.org,\n\tlinux-tegra@vger.kernel.org,\n\tlinux-clk@vger.kernel.org,\n\tlinux-pm@vger.kernel.org",
        "Subject": "[PATCH v3 08/11] memory: tegra: Add Tegra114 EMC driver",
        "Date": "Mon, 15 Sep 2025 11:01:54 +0300",
        "Message-ID": "<20250915080157.28195-9-clamor95@gmail.com>",
        "X-Mailer": "git-send-email 2.48.1",
        "In-Reply-To": "<20250915080157.28195-1-clamor95@gmail.com>",
        "References": "<20250915080157.28195-1-clamor95@gmail.com>",
        "Precedence": "bulk",
        "X-Mailing-List": "linux-tegra@vger.kernel.org",
        "List-Id": "<linux-tegra.vger.kernel.org>",
        "List-Subscribe": "<mailto:linux-tegra+subscribe@vger.kernel.org>",
        "List-Unsubscribe": "<mailto:linux-tegra+unsubscribe@vger.kernel.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit"
    },
    "content": "Introduce driver for the External Memory Controller (EMC) found in Tegra114\nSoC. It controls the external DRAM on the board. The purpose of this\ndriver is to program memory timing for external memory on the EMC clock\nrate change.\n\nSigned-off-by: Svyatoslav Ryhel <clamor95@gmail.com>\n---\n drivers/memory/tegra/Kconfig        |   12 +\n drivers/memory/tegra/Makefile       |    1 +\n drivers/memory/tegra/tegra114-emc.c | 1487 +++++++++++++++++++++++++++\n 3 files changed, 1500 insertions(+)\n create mode 100644 drivers/memory/tegra/tegra114-emc.c",
    "diff": "diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig\nindex fc5a27791826..11e7cc357d39 100644\n--- a/drivers/memory/tegra/Kconfig\n+++ b/drivers/memory/tegra/Kconfig\n@@ -35,6 +35,18 @@ config TEGRA30_EMC\n \t  This driver is required to change memory timings / clock rate for\n \t  external memory.\n \n+config TEGRA114_EMC\n+\ttristate \"NVIDIA Tegra114 External Memory Controller driver\"\n+\tdefault y\n+\tdepends on ARCH_TEGRA_114_SOC || COMPILE_TEST\n+\tselect TEGRA124_CLK_EMC if ARCH_TEGRA\n+\tselect PM_OPP\n+\thelp\n+\t  This driver is for the External Memory Controller (EMC) found on\n+\t  Tegra114 chips. The EMC controls the external DRAM on the board.\n+\t  This driver is required to change memory timings / clock rate for\n+\t  external memory.\n+\n config TEGRA124_EMC\n \ttristate \"NVIDIA Tegra124 External Memory Controller driver\"\n \tdefault ARCH_TEGRA_124_SOC\ndiff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile\nindex 0750847dac3c..d36be28efc4a 100644\n--- a/drivers/memory/tegra/Makefile\n+++ b/drivers/memory/tegra/Makefile\n@@ -15,6 +15,7 @@ obj-$(CONFIG_TEGRA_MC) += tegra-mc.o\n \n obj-$(CONFIG_TEGRA20_EMC)  += tegra20-emc.o\n obj-$(CONFIG_TEGRA30_EMC)  += tegra30-emc.o\n+obj-$(CONFIG_TEGRA114_EMC) += tegra114-emc.o\n obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o\n obj-$(CONFIG_TEGRA210_EMC_TABLE) += tegra210-emc-table.o\n obj-$(CONFIG_TEGRA210_EMC) += tegra210-emc.o\ndiff --git a/drivers/memory/tegra/tegra114-emc.c b/drivers/memory/tegra/tegra114-emc.c\nnew file mode 100644\nindex 000000000000..b986b5509f41\n--- /dev/null\n+++ b/drivers/memory/tegra/tegra114-emc.c\n@@ -0,0 +1,1487 @@\n+// SPDX-License-Identifier: GPL-2.0-only\n+/*\n+ * Tegra114 External Memory Controller driver\n+ *\n+ * Based on downstream driver from NVIDIA and tegra124-emc.c\n+ * Copyright (C) 2011-2014 NVIDIA Corporation\n+ *\n+ * Copyright (C) 2024 Svyatoslav Ryhel <clamor95@gmail.com>\n+ */\n+\n+#include <linux/clk-provider.h>\n+#include <linux/clk.h>\n+#include <linux/clkdev.h>\n+#include <linux/clk/tegra.h>\n+#include <linux/debugfs.h>\n+#include <linux/delay.h>\n+#include <linux/interconnect-provider.h>\n+#include <linux/interrupt.h>\n+#include <linux/io.h>\n+#include <linux/module.h>\n+#include <linux/mutex.h>\n+#include <linux/of_address.h>\n+#include <linux/of_platform.h>\n+#include <linux/platform_device.h>\n+#include <linux/pm_opp.h>\n+#include <linux/sort.h>\n+#include <linux/string.h>\n+\n+#include <soc/tegra/fuse.h>\n+#include <soc/tegra/mc.h>\n+\n+#include \"mc.h\"\n+\n+#define EMC_INTSTATUS\t\t\t\t0x0\n+#define EMC_REFRESH_OVERFLOW_INT\t\tBIT(3)\n+#define EMC_INTSTATUS_CLKCHANGE_COMPLETE\tBIT(4)\n+\n+#define EMC_INTMASK\t\t\t\t0x4\n+\n+#define EMC_DBG\t\t\t\t\t0x8\n+#define EMC_DBG_READ_MUX_ASSEMBLY\t\tBIT(0)\n+#define EMC_DBG_WRITE_MUX_ACTIVE\t\tBIT(1)\n+#define EMC_DBG_FORCE_UPDATE\t\t\tBIT(2)\n+#define EMC_DBG_CFG_PRIORITY\t\t\tBIT(24)\n+\n+#define EMC_CFG\t\t\t\t\t0xc\n+#define EMC_CFG_DRAM_CLKSTOP_PD\t\t\tBIT(31)\n+#define EMC_CFG_DRAM_CLKSTOP_SR\t\t\tBIT(30)\n+#define EMC_CFG_DRAM_ACPD\t\t\tBIT(29)\n+#define EMC_CFG_DYN_SREF\t\t\tBIT(28)\n+#define EMC_CFG_PWR_MASK\t\t\t((0xF << 28) | BIT(18))\n+#define EMC_CFG_DSR_VTTGEN_DRV_EN\t\tBIT(18)\n+\n+#define EMC_ADR_CFG\t\t\t\t0x10\n+#define EMC_ADR_CFG_EMEM_NUMDEV\t\t\tBIT(0)\n+\n+#define EMC_REFCTRL\t\t\t\t0x20\n+#define EMC_REFCTRL_DEV_SEL_SHIFT\t\t0\n+#define EMC_REFCTRL_ENABLE\t\t\tBIT(31)\n+\n+#define EMC_TIMING_CONTROL\t\t\t0x28\n+#define EMC_RC\t\t\t\t\t0x2c\n+#define EMC_RFC\t\t\t\t\t0x30\n+#define EMC_RAS\t\t\t\t\t0x34\n+#define EMC_RP\t\t\t\t\t0x38\n+#define EMC_R2W\t\t\t\t\t0x3c\n+#define EMC_W2R\t\t\t\t\t0x40\n+#define EMC_R2P\t\t\t\t\t0x44\n+#define EMC_W2P\t\t\t\t\t0x48\n+#define EMC_RD_RCD\t\t\t\t0x4c\n+#define EMC_WR_RCD\t\t\t\t0x50\n+#define EMC_RRD\t\t\t\t\t0x54\n+#define EMC_REXT\t\t\t\t0x58\n+#define EMC_WDV\t\t\t\t\t0x5c\n+#define EMC_QUSE\t\t\t\t0x60\n+#define EMC_QRST\t\t\t\t0x64\n+#define EMC_QSAFE\t\t\t\t0x68\n+#define EMC_RDV\t\t\t\t\t0x6c\n+#define EMC_REFRESH\t\t\t\t0x70\n+#define EMC_BURST_REFRESH_NUM\t\t\t0x74\n+#define EMC_PDEX2WR\t\t\t\t0x78\n+#define EMC_PDEX2RD\t\t\t\t0x7c\n+#define EMC_PCHG2PDEN\t\t\t\t0x80\n+#define EMC_ACT2PDEN\t\t\t\t0x84\n+#define EMC_AR2PDEN\t\t\t\t0x88\n+#define EMC_RW2PDEN\t\t\t\t0x8c\n+#define EMC_TXSR\t\t\t\t0x90\n+#define EMC_TCKE\t\t\t\t0x94\n+#define EMC_TFAW\t\t\t\t0x98\n+#define EMC_TRPAB\t\t\t\t0x9c\n+#define EMC_TCLKSTABLE\t\t\t\t0xa0\n+#define EMC_TCLKSTOP\t\t\t\t0xa4\n+#define EMC_TREFBW\t\t\t\t0xa8\n+#define EMC_QUSE_EXTRA\t\t\t\t0xac\n+#define EMC_ODT_WRITE\t\t\t\t0xb0\n+#define EMC_ODT_READ\t\t\t\t0xb4\n+#define EMC_WEXT\t\t\t\t0xb8\n+#define EMC_CTT\t\t\t\t\t0xbc\n+#define EMC_RFC_SLR\t\t\t\t0xc0\n+#define EMC_MRS_WAIT_CNT2\t\t\t0xc4\n+\n+#define EMC_MRS_WAIT_CNT\t\t\t0xc8\n+#define EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT\t0\n+#define EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK\t\\\n+\t(0x3FF << EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT)\n+#define EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT\t16\n+#define EMC_MRS_WAIT_CNT_LONG_WAIT_MASK\t\t\\\n+\t(0x3FF << EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT)\n+\n+#define EMC_MRS\t\t\t\t\t0xcc\n+#define EMC_MODE_SET_DLL_RESET\t\t\tBIT(8)\n+#define EMC_MODE_SET_LONG_CNT\t\t\tBIT(26)\n+#define EMC_EMRS\t\t\t\t0xd0\n+#define EMC_REF\t\t\t\t\t0xd4\n+#define EMC_PRE\t\t\t\t\t0xd8\n+\n+#define EMC_SELF_REF\t\t\t\t0xe0\n+#define EMC_SELF_REF_CMD_ENABLED\t\tBIT(0)\n+#define EMC_SELF_REF_DEV_SEL_SHIFT\t\t30\n+\n+#define EMC_MRW\t\t\t\t\t0xe8\n+\n+#define EMC_MRR\t\t\t\t\t0xec\n+#define EMC_MRR_MA_SHIFT\t\t\t16\n+#define LPDDR2_MR4_TEMP_SHIFT\t\t\t0\n+\n+#define EMC_XM2DQSPADCTRL3\t\t\t0xf8\n+#define EMC_FBIO_SPARE\t\t\t\t0x100\n+\n+#define EMC_FBIO_CFG5\t\t\t\t0x104\n+#define\tEMC_FBIO_CFG5_DRAM_TYPE_MASK\t\t0x3\n+#define\tEMC_FBIO_CFG5_DRAM_TYPE_SHIFT\t\t0\n+\n+#define EMC_FBIO_CFG6\t\t\t\t0x114\n+#define EMC_EMRS2\t\t\t\t0x12c\n+#define EMC_MRW2\t\t\t\t0x134\n+#define EMC_MRW4\t\t\t\t0x13c\n+#define EMC_EINPUT\t\t\t\t0x14c\n+#define EMC_EINPUT_DURATION\t\t\t0x150\n+#define EMC_PUTERM_EXTRA\t\t\t0x154\n+#define EMC_TCKESR\t\t\t\t0x158\n+#define EMC_TPD\t\t\t\t\t0x15c\n+\n+#define EMC_AUTO_CAL_CONFIG\t\t\t0x2a4\n+#define EMC_AUTO_CAL_CONFIG_AUTO_CAL_START\tBIT(31)\n+#define EMC_AUTO_CAL_INTERVAL\t\t\t0x2a8\n+#define EMC_AUTO_CAL_STATUS\t\t\t0x2ac\n+#define EMC_AUTO_CAL_STATUS_ACTIVE\t\tBIT(31)\n+#define EMC_STATUS\t\t\t\t0x2b4\n+#define EMC_STATUS_TIMING_UPDATE_STALLED\tBIT(23)\n+\n+#define EMC_CFG_2\t\t\t\t0x2b8\n+#define EMC_CLKCHANGE_REQ_ENABLE\t\tBIT(0)\n+#define EMC_CLKCHANGE_PD_ENABLE\t\t\tBIT(1)\n+#define EMC_CLKCHANGE_SR_ENABLE\t\t\tBIT(2)\n+\n+#define EMC_CFG_DIG_DLL\t\t\t\t0x2bc\n+#define EMC_CFG_DIG_DLL_PERIOD\t\t\t0x2c0\n+#define EMC_RDV_MASK\t\t\t\t0x2cc\n+#define EMC_WDV_MASK\t\t\t\t0x2d0\n+#define EMC_CTT_DURATION\t\t\t0x2d8\n+#define EMC_CTT_TERM_CTRL\t\t\t0x2dc\n+#define EMC_ZCAL_INTERVAL\t\t\t0x2e0\n+#define EMC_ZCAL_WAIT_CNT\t\t\t0x2e4\n+\n+#define EMC_ZQ_CAL\t\t\t\t0x2ec\n+#define EMC_ZQ_CAL_CMD\t\t\t\tBIT(0)\n+#define EMC_ZQ_CAL_LONG\t\t\t\tBIT(4)\n+#define EMC_ZQ_CAL_LONG_CMD_DEV0\t\t\\\n+\t(DRAM_DEV_SEL_0 | EMC_ZQ_CAL_LONG | EMC_ZQ_CAL_CMD)\n+#define EMC_ZQ_CAL_LONG_CMD_DEV1\t\t\\\n+\t(DRAM_DEV_SEL_1 | EMC_ZQ_CAL_LONG | EMC_ZQ_CAL_CMD)\n+\n+#define EMC_XM2CMDPADCTRL\t\t\t0x2f0\n+#define EMC_XM2DQSPADCTRL\t\t\t0x2f8\n+#define EMC_XM2DQSPADCTRL2\t\t\t0x2fc\n+#define EMC_XM2DQSPADCTRL2_RX_FT_REC_ENABLE\tBIT(0)\n+#define EMC_XM2DQSPADCTRL2_VREF_ENABLE\t\tBIT(5)\n+#define EMC_XM2DQPADCTRL\t\t\t0x300\n+#define EMC_XM2DQPADCTRL2\t\t\t0x304\n+#define EMC_XM2CLKPADCTRL\t\t\t0x308\n+#define EMC_XM2COMPPADCTRL\t\t\t0x30c\n+#define EMC_XM2VTTGENPADCTRL\t\t\t0x310\n+#define EMC_XM2VTTGENPADCTRL2\t\t\t0x314\n+#define EMC_XM2QUSEPADCTRL\t\t\t0x318\n+#define EMC_XM2DQSPADCTRL4\t\t\t0x320\n+#define EMC_DLL_XFORM_DQS0\t\t\t0x328\n+#define EMC_DLL_XFORM_DQS1\t\t\t0x32c\n+#define EMC_DLL_XFORM_DQS2\t\t\t0x330\n+#define EMC_DLL_XFORM_DQS3\t\t\t0x334\n+#define EMC_DLL_XFORM_DQS4\t\t\t0x338\n+#define EMC_DLL_XFORM_DQS5\t\t\t0x33c\n+#define EMC_DLL_XFORM_DQS6\t\t\t0x340\n+#define EMC_DLL_XFORM_DQS7\t\t\t0x344\n+#define EMC_DLL_XFORM_QUSE0\t\t\t0x348\n+#define EMC_DLL_XFORM_QUSE1\t\t\t0x34c\n+#define EMC_DLL_XFORM_QUSE2\t\t\t0x350\n+#define EMC_DLL_XFORM_QUSE3\t\t\t0x354\n+#define EMC_DLL_XFORM_QUSE4\t\t\t0x358\n+#define EMC_DLL_XFORM_QUSE5\t\t\t0x35c\n+#define EMC_DLL_XFORM_QUSE6\t\t\t0x360\n+#define EMC_DLL_XFORM_QUSE7\t\t\t0x364\n+#define EMC_DLL_XFORM_DQ0\t\t\t0x368\n+#define EMC_DLL_XFORM_DQ1\t\t\t0x36c\n+#define EMC_DLL_XFORM_DQ2\t\t\t0x370\n+#define EMC_DLL_XFORM_DQ3\t\t\t0x374\n+#define EMC_DLI_TRIM_TXDQS0\t\t\t0x3a8\n+#define EMC_DLI_TRIM_TXDQS1\t\t\t0x3ac\n+#define EMC_DLI_TRIM_TXDQS2\t\t\t0x3b0\n+#define EMC_DLI_TRIM_TXDQS3\t\t\t0x3b4\n+#define EMC_DLI_TRIM_TXDQS4\t\t\t0x3b8\n+#define EMC_DLI_TRIM_TXDQS5\t\t\t0x3bc\n+#define EMC_DLI_TRIM_TXDQS6\t\t\t0x3c0\n+#define EMC_DLI_TRIM_TXDQS7\t\t\t0x3c4\n+#define EMC_STALL_THEN_EXE_AFTER_CLKCHANGE\t0x3cc\n+#define EMC_SEL_DPD_CTRL\t\t\t0x3d8\n+#define EMC_SEL_DPD_CTRL_DATA_SEL_DPD\t\tBIT(8)\n+#define EMC_SEL_DPD_CTRL_ODT_SEL_DPD\t\tBIT(5)\n+#define EMC_SEL_DPD_CTRL_RESET_SEL_DPD\t\tBIT(4)\n+#define EMC_SEL_DPD_CTRL_CA_SEL_DPD\t\tBIT(3)\n+#define EMC_SEL_DPD_CTRL_CLK_SEL_DPD\t\tBIT(2)\n+#define EMC_SEL_DPD_CTRL_DDR3_MASK\t\\\n+\t((0xf << 2) | BIT(8))\n+#define EMC_SEL_DPD_CTRL_MASK \\\n+\t((0x3 << 2) | BIT(5) | BIT(8))\n+#define EMC_PRE_REFRESH_REQ_CNT\t\t\t0x3dc\n+#define EMC_DYN_SELF_REF_CONTROL\t\t0x3e0\n+#define EMC_TXSRDLL\t\t\t\t0x3e4\n+#define EMC_CCFIFO_ADDR\t\t\t\t0x3e8\n+#define EMC_CCFIFO_DATA\t\t\t\t0x3ec\n+#define EMC_CCFIFO_STATUS\t\t\t0x3f0\n+#define EMC_CDB_CNTL_1\t\t\t\t0x3f4\n+#define EMC_CDB_CNTL_2\t\t\t\t0x3f8\n+#define EMC_XM2CLKPADCTRL2\t\t\t0x3fc\n+#define EMC_AUTO_CAL_CONFIG2\t\t\t0x458\n+#define EMC_AUTO_CAL_CONFIG3\t\t\t0x45c\n+#define EMC_IBDLY\t\t\t\t0x468\n+#define EMC_DLL_XFORM_ADDR0\t\t\t0x46c\n+#define EMC_DLL_XFORM_ADDR1\t\t\t0x470\n+#define EMC_DLL_XFORM_ADDR2\t\t\t0x474\n+#define EMC_DSR_VTTGEN_DRV\t\t\t0x47c\n+#define EMC_TXDSRVTTGEN\t\t\t\t0x480\n+#define EMC_XM2CMDPADCTRL4\t\t\t0x484\n+\n+#define DRAM_DEV_SEL_ALL\t\t\t0\n+#define DRAM_DEV_SEL_0\t\t\t\tBIT(31)\n+#define DRAM_DEV_SEL_1\t\t\t\tBIT(30)\n+\n+#define EMC_CFG_POWER_FEATURES_MASK\t\t\\\n+\t(EMC_CFG_DYN_SREF | EMC_CFG_DRAM_ACPD | EMC_CFG_DRAM_CLKSTOP_SR | \\\n+\tEMC_CFG_DRAM_CLKSTOP_PD | EMC_CFG_DSR_VTTGEN_DRV_EN)\n+#define EMC_REFCTRL_DEV_SEL(n) ((((n) > 1) ? 0 : 2) << EMC_REFCTRL_DEV_SEL_SHIFT)\n+#define EMC_DRAM_DEV_SEL(n) (((n) > 1) ? DRAM_DEV_SEL_ALL : DRAM_DEV_SEL_0)\n+\n+/* Maximum amount of time in us. to wait for changes to become effective */\n+#define EMC_STATUS_UPDATE_TIMEOUT\t\t1000\n+\n+enum emc_dram_type {\n+\tDRAM_TYPE_DDR3,\n+\tDRAM_TYPE_DDR1,\n+\tDRAM_TYPE_LPDDR2,\n+\tDRAM_TYPE_DDR2\n+};\n+\n+enum emc_dll_change {\n+\tDLL_CHANGE_NONE,\n+\tDLL_CHANGE_ON,\n+\tDLL_CHANGE_OFF\n+};\n+\n+static const unsigned long emc_burst_regs[] = {\n+\tEMC_RC,\n+\tEMC_RFC,\n+\tEMC_RAS,\n+\tEMC_RP,\n+\tEMC_R2W,\n+\tEMC_W2R,\n+\tEMC_R2P,\n+\tEMC_W2P,\n+\tEMC_RD_RCD,\n+\tEMC_WR_RCD,\n+\tEMC_RRD,\n+\tEMC_REXT,\n+\tEMC_WEXT,\n+\tEMC_WDV,\n+\tEMC_WDV_MASK,\n+\tEMC_QUSE,\n+\tEMC_IBDLY,\n+\tEMC_EINPUT,\n+\tEMC_EINPUT_DURATION,\n+\tEMC_PUTERM_EXTRA,\n+\tEMC_CDB_CNTL_1,\n+\tEMC_CDB_CNTL_2,\n+\tEMC_QRST,\n+\tEMC_QSAFE,\n+\tEMC_RDV,\n+\tEMC_RDV_MASK,\n+\tEMC_REFRESH,\n+\tEMC_BURST_REFRESH_NUM,\n+\tEMC_PRE_REFRESH_REQ_CNT,\n+\tEMC_PDEX2WR,\n+\tEMC_PDEX2RD,\n+\tEMC_PCHG2PDEN,\n+\tEMC_ACT2PDEN,\n+\tEMC_AR2PDEN,\n+\tEMC_RW2PDEN,\n+\tEMC_TXSR,\n+\tEMC_TXSRDLL,\n+\tEMC_TCKE,\n+\tEMC_TCKESR,\n+\tEMC_TPD,\n+\tEMC_TFAW,\n+\tEMC_TRPAB,\n+\tEMC_TCLKSTABLE,\n+\tEMC_TCLKSTOP,\n+\tEMC_TREFBW,\n+\tEMC_QUSE_EXTRA,\n+\tEMC_FBIO_CFG6,\n+\tEMC_ODT_WRITE,\n+\tEMC_ODT_READ,\n+\tEMC_FBIO_CFG5,\n+\tEMC_CFG_DIG_DLL,\n+\tEMC_CFG_DIG_DLL_PERIOD,\n+\tEMC_DLL_XFORM_DQS0,\n+\tEMC_DLL_XFORM_DQS1,\n+\tEMC_DLL_XFORM_DQS2,\n+\tEMC_DLL_XFORM_DQS3,\n+\tEMC_DLL_XFORM_DQS4,\n+\tEMC_DLL_XFORM_DQS5,\n+\tEMC_DLL_XFORM_DQS6,\n+\tEMC_DLL_XFORM_DQS7,\n+\tEMC_DLL_XFORM_QUSE0,\n+\tEMC_DLL_XFORM_QUSE1,\n+\tEMC_DLL_XFORM_QUSE2,\n+\tEMC_DLL_XFORM_QUSE3,\n+\tEMC_DLL_XFORM_QUSE4,\n+\tEMC_DLL_XFORM_QUSE5,\n+\tEMC_DLL_XFORM_QUSE6,\n+\tEMC_DLL_XFORM_QUSE7,\n+\tEMC_DLI_TRIM_TXDQS0,\n+\tEMC_DLI_TRIM_TXDQS1,\n+\tEMC_DLI_TRIM_TXDQS2,\n+\tEMC_DLI_TRIM_TXDQS3,\n+\tEMC_DLI_TRIM_TXDQS4,\n+\tEMC_DLI_TRIM_TXDQS5,\n+\tEMC_DLI_TRIM_TXDQS6,\n+\tEMC_DLI_TRIM_TXDQS7,\n+\tEMC_DLL_XFORM_DQ0,\n+\tEMC_DLL_XFORM_DQ1,\n+\tEMC_DLL_XFORM_DQ2,\n+\tEMC_DLL_XFORM_DQ3,\n+\tEMC_XM2CMDPADCTRL,\n+\tEMC_XM2CMDPADCTRL4,\n+\tEMC_XM2DQPADCTRL2,\n+\tEMC_XM2CLKPADCTRL,\n+\tEMC_XM2COMPPADCTRL,\n+\tEMC_XM2VTTGENPADCTRL,\n+\tEMC_XM2VTTGENPADCTRL2,\n+\tEMC_XM2DQSPADCTRL3,\n+\tEMC_XM2DQSPADCTRL4,\n+\tEMC_DSR_VTTGEN_DRV,\n+\tEMC_TXDSRVTTGEN,\n+\tEMC_FBIO_SPARE,\n+\tEMC_ZCAL_WAIT_CNT,\n+\tEMC_MRS_WAIT_CNT2,\n+\tEMC_CTT,\n+\tEMC_CTT_DURATION,\n+\tEMC_DYN_SELF_REF_CONTROL,\n+};\n+\n+struct emc_timing {\n+\tunsigned long rate;\n+\n+\tu32 emc_burst_data[ARRAY_SIZE(emc_burst_regs)];\n+\n+\tu32 emc_auto_cal_config;\n+\tu32 emc_auto_cal_config2;\n+\tu32 emc_auto_cal_config3;\n+\tu32 emc_auto_cal_interval;\n+\tu32 emc_cfg;\n+\tu32 emc_ctt_term_ctrl;\n+\tu32 emc_mode_1;\n+\tu32 emc_mode_2;\n+\tu32 emc_mode_4;\n+\tu32 emc_mode_reset;\n+\tu32 emc_mrs_wait_cnt;\n+\tu32 emc_sel_dpd_ctrl;\n+\tu32 emc_xm2dqspadctrl2;\n+\tu32 emc_zcal_cnt_long;\n+\tu32 emc_zcal_interval;\n+};\n+\n+enum emc_rate_request_type {\n+\tEMC_RATE_DEBUG,\n+\tEMC_RATE_ICC,\n+\tEMC_RATE_TYPE_MAX,\n+};\n+\n+struct emc_rate_request {\n+\tunsigned long min_rate;\n+\tunsigned long max_rate;\n+};\n+\n+struct tegra_emc {\n+\tstruct device *dev;\n+\n+\tstruct tegra_mc *mc;\n+\n+\tvoid __iomem *regs;\n+\n+\tunsigned int irq;\n+\n+\tstruct clk *clk;\n+\n+\tenum emc_dram_type dram_type;\n+\tunsigned int dram_num;\n+\n+\tstruct emc_timing last_timing;\n+\tstruct emc_timing *timings;\n+\tunsigned int num_timings;\n+\n+\tstruct {\n+\t\tstruct dentry *root;\n+\t\tunsigned long min_rate;\n+\t\tunsigned long max_rate;\n+\t} debugfs;\n+\n+\tstruct icc_provider provider;\n+\n+\t/*\n+\t * There are multiple sources in the EMC driver which could request\n+\t * a min/max clock rate, these rates are contained in this array.\n+\t */\n+\tstruct emc_rate_request requested_rate[EMC_RATE_TYPE_MAX];\n+\n+\t/* protect shared rate-change code path */\n+\tstruct mutex rate_lock;\n+};\n+\n+static irqreturn_t tegra_emc_isr(int irq, void *data)\n+{\n+\tstruct tegra_emc *emc = data;\n+\tu32 intmask = EMC_REFRESH_OVERFLOW_INT;\n+\tu32 status;\n+\n+\tstatus = readl_relaxed(emc->regs + EMC_INTSTATUS) & intmask;\n+\tif (!status)\n+\t\treturn IRQ_NONE;\n+\n+\t/* notify about HW problem */\n+\tif (status & EMC_REFRESH_OVERFLOW_INT)\n+\t\tdev_err_ratelimited(emc->dev,\n+\t\t\t\t    \"refresh request overflow timeout\\n\");\n+\n+\t/* clear interrupts */\n+\twritel_relaxed(status, emc->regs + EMC_INTSTATUS);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+/* Timing change sequence functions */\n+\n+static void emc_ccfifo_writel(struct tegra_emc *emc, u32 value,\n+\t\t\t      unsigned long offset)\n+{\n+\twritel(value, emc->regs + EMC_CCFIFO_DATA);\n+\twritel(offset, emc->regs + EMC_CCFIFO_ADDR);\n+}\n+\n+static void emc_seq_update_timing(struct tegra_emc *emc)\n+{\n+\tunsigned int i;\n+\tu32 value;\n+\n+\twritel(1, emc->regs + EMC_TIMING_CONTROL);\n+\n+\tfor (i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; ++i) {\n+\t\tvalue = readl(emc->regs + EMC_STATUS);\n+\t\tif ((value & EMC_STATUS_TIMING_UPDATE_STALLED) == 0)\n+\t\t\treturn;\n+\t\tudelay(1);\n+\t}\n+\n+\tdev_err(emc->dev, \"timing update timed out\\n\");\n+}\n+\n+static void emc_seq_disable_auto_cal(struct tegra_emc *emc)\n+{\n+\tunsigned int i;\n+\tu32 value;\n+\n+\twritel(0, emc->regs + EMC_AUTO_CAL_INTERVAL);\n+\n+\tfor (i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; ++i) {\n+\t\tvalue = readl(emc->regs + EMC_AUTO_CAL_STATUS);\n+\t\tif ((value & EMC_AUTO_CAL_STATUS_ACTIVE) == 0)\n+\t\t\treturn;\n+\t\tudelay(1);\n+\t}\n+\n+\tdev_err(emc->dev, \"auto cal disable timed out\\n\");\n+}\n+\n+static void emc_seq_wait_clkchange(struct tegra_emc *emc)\n+{\n+\tunsigned int i;\n+\tu32 value;\n+\n+\tfor (i = 0; i < EMC_STATUS_UPDATE_TIMEOUT; ++i) {\n+\t\tvalue = readl(emc->regs + EMC_INTSTATUS);\n+\t\tif (value & EMC_INTSTATUS_CLKCHANGE_COMPLETE)\n+\t\t\treturn;\n+\t\tudelay(1);\n+\t}\n+\n+\tdev_err(emc->dev, \"clock change timed out\\n\");\n+}\n+\n+static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc,\n+\t\t\t\t\t\tunsigned long rate)\n+{\n+\tstruct emc_timing *timing = NULL;\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < emc->num_timings; i++) {\n+\t\tif (emc->timings[i].rate == rate) {\n+\t\t\ttiming = &emc->timings[i];\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (!timing) {\n+\t\tdev_err(emc->dev, \"no timing for rate %lu\\n\", rate);\n+\t\treturn NULL;\n+\t}\n+\n+\treturn timing;\n+}\n+\n+static int tegra_emc_prepare_timing_change(struct tegra_emc *emc,\n+\t\t\t\t\t   unsigned long rate)\n+{\n+\tstruct emc_timing *timing = tegra_emc_find_timing(emc, rate);\n+\tstruct emc_timing *last = &emc->last_timing;\n+\tenum emc_dll_change dll_change;\n+\tunsigned int pre_wait = 0;\n+\tu32 val, mask;\n+\tbool update = false;\n+\tunsigned int i;\n+\n+\tif (!timing)\n+\t\treturn -ENOENT;\n+\n+\tif ((last->emc_mode_1 & 0x1) == (timing->emc_mode_1 & 0x1))\n+\t\tdll_change = DLL_CHANGE_NONE;\n+\telse if (timing->emc_mode_1 & 0x1)\n+\t\tdll_change = DLL_CHANGE_ON;\n+\telse\n+\t\tdll_change = DLL_CHANGE_OFF;\n+\n+\t/* Clear CLKCHANGE_COMPLETE interrupts */\n+\twritel(EMC_INTSTATUS_CLKCHANGE_COMPLETE, emc->regs + EMC_INTSTATUS);\n+\n+\t/* Disable dynamic self-refresh */\n+\tval = readl(emc->regs + EMC_CFG);\n+\tif (val & EMC_CFG_PWR_MASK) {\n+\t\tval &= ~EMC_CFG_POWER_FEATURES_MASK;\n+\t\twritel(val, emc->regs + EMC_CFG);\n+\n+\t\tpre_wait = 5;\n+\t}\n+\n+\t/* Disable SEL_DPD_CTRL for clock change */\n+\tif (emc->dram_type == DRAM_TYPE_DDR3)\n+\t\tmask = EMC_SEL_DPD_CTRL_DDR3_MASK;\n+\telse\n+\t\tmask = EMC_SEL_DPD_CTRL_MASK;\n+\n+\tval = readl(emc->regs + EMC_SEL_DPD_CTRL);\n+\tif (val & mask) {\n+\t\tval &= ~mask;\n+\t\twritel(val, emc->regs + EMC_SEL_DPD_CTRL);\n+\t}\n+\n+\t/* Prepare DQ/DQS for clock change */\n+\tval = readl(emc->regs + EMC_XM2DQSPADCTRL2);\n+\tif (timing->emc_xm2dqspadctrl2 & EMC_XM2DQSPADCTRL2_VREF_ENABLE &&\n+\t    !(val & EMC_XM2DQSPADCTRL2_VREF_ENABLE)) {\n+\t\tval |= EMC_XM2DQSPADCTRL2_VREF_ENABLE;\n+\t\tupdate = true;\n+\t}\n+\n+\tif (timing->emc_xm2dqspadctrl2 & EMC_XM2DQSPADCTRL2_RX_FT_REC_ENABLE &&\n+\t    !(val & EMC_XM2DQSPADCTRL2_RX_FT_REC_ENABLE)) {\n+\t\tval |= EMC_XM2DQSPADCTRL2_RX_FT_REC_ENABLE;\n+\t\tupdate = true;\n+\t}\n+\n+\tif (update) {\n+\t\twritel(val, emc->regs + EMC_XM2DQSPADCTRL2);\n+\t\tif (pre_wait < 30)\n+\t\t\tpre_wait = 30;\n+\t}\n+\n+\t/* Wait to settle */\n+\tif (pre_wait) {\n+\t\temc_seq_update_timing(emc);\n+\t\tudelay(pre_wait);\n+\t}\n+\n+\t/* Program CTT_TERM control */\n+\tif (last->emc_ctt_term_ctrl != timing->emc_ctt_term_ctrl) {\n+\t\temc_seq_disable_auto_cal(emc);\n+\t\twritel(timing->emc_ctt_term_ctrl,\n+\t\t       emc->regs + EMC_CTT_TERM_CTRL);\n+\t\temc_seq_update_timing(emc);\n+\t}\n+\n+\t/* Program burst shadow registers */\n+\tfor (i = 0; i < ARRAY_SIZE(timing->emc_burst_data); ++i)\n+\t\twritel(timing->emc_burst_data[i],\n+\t\t       emc->regs + emc_burst_regs[i]);\n+\n+\twritel(timing->emc_xm2dqspadctrl2, emc->regs + EMC_XM2DQSPADCTRL2);\n+\twritel(timing->emc_zcal_interval, emc->regs + EMC_ZCAL_INTERVAL);\n+\n+\ttegra_mc_write_emem_configuration(emc->mc, timing->rate);\n+\n+\tval = timing->emc_cfg & ~EMC_CFG_POWER_FEATURES_MASK;\n+\temc_ccfifo_writel(emc, val, EMC_CFG);\n+\n+\t/* Program AUTO_CAL_CONFIG */\n+\tif (timing->emc_auto_cal_config2 != last->emc_auto_cal_config2)\n+\t\temc_ccfifo_writel(emc, timing->emc_auto_cal_config2,\n+\t\t\t\t  EMC_AUTO_CAL_CONFIG2);\n+\n+\tif (timing->emc_auto_cal_config3 != last->emc_auto_cal_config3)\n+\t\temc_ccfifo_writel(emc, timing->emc_auto_cal_config3,\n+\t\t\t\t  EMC_AUTO_CAL_CONFIG3);\n+\n+\tif (timing->emc_auto_cal_config != last->emc_auto_cal_config) {\n+\t\tval = timing->emc_auto_cal_config;\n+\t\tval &= EMC_AUTO_CAL_CONFIG_AUTO_CAL_START;\n+\t\temc_ccfifo_writel(emc, val, EMC_AUTO_CAL_CONFIG);\n+\t}\n+\n+\t/* DDR3: predict MRS long wait count */\n+\tif (emc->dram_type == DRAM_TYPE_DDR3 &&\n+\t    dll_change == DLL_CHANGE_ON) {\n+\t\tu32 cnt = 512;\n+\n+\t\tif (timing->emc_zcal_interval != 0 &&\n+\t\t    last->emc_zcal_interval == 0)\n+\t\t\tcnt -= emc->dram_num * 256;\n+\n+\t\tval = (timing->emc_mrs_wait_cnt\n+\t\t\t& EMC_MRS_WAIT_CNT_SHORT_WAIT_MASK)\n+\t\t\t>> EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT;\n+\t\tif (cnt < val)\n+\t\t\tcnt = val;\n+\n+\t\tval = timing->emc_mrs_wait_cnt\n+\t\t\t& ~EMC_MRS_WAIT_CNT_LONG_WAIT_MASK;\n+\t\tval |= (cnt << EMC_MRS_WAIT_CNT_LONG_WAIT_SHIFT)\n+\t\t\t& EMC_MRS_WAIT_CNT_LONG_WAIT_MASK;\n+\n+\t\twritel(val, emc->regs + EMC_MRS_WAIT_CNT);\n+\t}\n+\n+\t/* DDR3: Turn off DLL and enter self-refresh */\n+\tif (emc->dram_type == DRAM_TYPE_DDR3 && dll_change == DLL_CHANGE_OFF)\n+\t\temc_ccfifo_writel(emc, timing->emc_mode_1, EMC_EMRS);\n+\n+\t/* Disable refresh controller */\n+\temc_ccfifo_writel(emc, EMC_REFCTRL_DEV_SEL(emc->dram_num),\n+\t\t\t  EMC_REFCTRL);\n+\tif (emc->dram_type == DRAM_TYPE_DDR3)\n+\t\temc_ccfifo_writel(emc, EMC_DRAM_DEV_SEL(emc->dram_num) |\n+\t\t\t\t       EMC_SELF_REF_CMD_ENABLED,\n+\t\t\t\t  EMC_SELF_REF);\n+\n+\t/* Flow control marker */\n+\temc_ccfifo_writel(emc, 1, EMC_STALL_THEN_EXE_AFTER_CLKCHANGE);\n+\n+\t/* DDR3: Exit self-refresh */\n+\tif (emc->dram_type == DRAM_TYPE_DDR3)\n+\t\temc_ccfifo_writel(emc, EMC_DRAM_DEV_SEL(emc->dram_num),\n+\t\t\t\t  EMC_SELF_REF);\n+\temc_ccfifo_writel(emc, EMC_REFCTRL_DEV_SEL(emc->dram_num) |\n+\t\t\t       EMC_REFCTRL_ENABLE,\n+\t\t\t  EMC_REFCTRL);\n+\n+\t/* Set DRAM mode registers */\n+\tif (emc->dram_type == DRAM_TYPE_DDR3) {\n+\t\tif (timing->emc_mode_1 != last->emc_mode_1)\n+\t\t\temc_ccfifo_writel(emc, timing->emc_mode_1, EMC_EMRS);\n+\t\tif (timing->emc_mode_2 != last->emc_mode_2)\n+\t\t\temc_ccfifo_writel(emc, timing->emc_mode_2, EMC_EMRS2);\n+\n+\t\tif (timing->emc_mode_reset != last->emc_mode_reset ||\n+\t\t    dll_change == DLL_CHANGE_ON) {\n+\t\t\tval = timing->emc_mode_reset;\n+\t\t\tif (dll_change == DLL_CHANGE_ON) {\n+\t\t\t\tval |= EMC_MODE_SET_DLL_RESET;\n+\t\t\t\tval |= EMC_MODE_SET_LONG_CNT;\n+\t\t\t} else {\n+\t\t\t\tval &= ~EMC_MODE_SET_DLL_RESET;\n+\t\t\t}\n+\t\t\temc_ccfifo_writel(emc, val, EMC_MRS);\n+\t\t}\n+\t} else {\n+\t\tif (timing->emc_mode_2 != last->emc_mode_2)\n+\t\t\temc_ccfifo_writel(emc, timing->emc_mode_2, EMC_MRW2);\n+\t\tif (timing->emc_mode_1 != last->emc_mode_1)\n+\t\t\temc_ccfifo_writel(emc, timing->emc_mode_1, EMC_MRW);\n+\t\tif (timing->emc_mode_4 != last->emc_mode_4)\n+\t\t\temc_ccfifo_writel(emc, timing->emc_mode_4, EMC_MRW4);\n+\t}\n+\n+\t/*  Issue ZCAL command if turning ZCAL on */\n+\tif (timing->emc_zcal_interval != 0 && last->emc_zcal_interval == 0) {\n+\t\temc_ccfifo_writel(emc, EMC_ZQ_CAL_LONG_CMD_DEV0, EMC_ZQ_CAL);\n+\t\tif (emc->dram_num > 1)\n+\t\t\temc_ccfifo_writel(emc, EMC_ZQ_CAL_LONG_CMD_DEV1,\n+\t\t\t\t\t  EMC_ZQ_CAL);\n+\t}\n+\n+\t/*  Write to RO register to remove stall after change */\n+\temc_ccfifo_writel(emc, 0, EMC_CCFIFO_STATUS);\n+\n+\t/* Disable AUTO_CAL for clock change */\n+\temc_seq_disable_auto_cal(emc);\n+\n+\t/* Read register to wait until programming has settled */\n+\tmc_readl(emc->mc, MC_EMEM_ADR_CFG);\n+\n+\treturn 0;\n+}\n+\n+static void tegra_emc_complete_timing_change(struct tegra_emc *emc,\n+\t\t\t\t\t     unsigned long rate)\n+{\n+\tstruct emc_timing *timing = tegra_emc_find_timing(emc, rate);\n+\tstruct emc_timing *last = &emc->last_timing;\n+\n+\tif (!timing)\n+\t\treturn;\n+\n+\t/* Wait until the state machine has settled */\n+\temc_seq_wait_clkchange(emc);\n+\n+\t/* Restore AUTO_CAL */\n+\tif (timing->emc_ctt_term_ctrl != last->emc_ctt_term_ctrl)\n+\t\twritel(timing->emc_auto_cal_interval,\n+\t\t       emc->regs + EMC_AUTO_CAL_INTERVAL);\n+\n+\t/* Restore dynamic self-refresh */\n+\tif (timing->emc_cfg & EMC_CFG_PWR_MASK)\n+\t\twritel(timing->emc_cfg, emc->regs + EMC_CFG);\n+\n+\t/* Set ZCAL wait count */\n+\twritel(timing->emc_zcal_cnt_long, emc->regs + EMC_ZCAL_WAIT_CNT);\n+\n+\t/* Wait for timing to settle */\n+\tudelay(2);\n+\n+\t/* Reprogram SEL_DPD_CTRL */\n+\twritel(timing->emc_sel_dpd_ctrl, emc->regs + EMC_SEL_DPD_CTRL);\n+\temc_seq_update_timing(emc);\n+\n+\temc->last_timing = *timing;\n+}\n+\n+/* Initialization and deinitialization */\n+\n+static void emc_read_current_timing(struct tegra_emc *emc,\n+\t\t\t\t    struct emc_timing *timing)\n+{\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(emc_burst_regs); ++i)\n+\t\ttiming->emc_burst_data[i] =\n+\t\t\treadl(emc->regs + emc_burst_regs[i]);\n+\n+\ttiming->emc_cfg = readl(emc->regs + EMC_CFG);\n+\n+\ttiming->emc_auto_cal_interval = 0;\n+\ttiming->emc_zcal_cnt_long = 0;\n+\ttiming->emc_mode_1 = 0;\n+\ttiming->emc_mode_2 = 0;\n+\ttiming->emc_mode_4 = 0;\n+\ttiming->emc_mode_reset = 0;\n+}\n+\n+static int emc_init(struct tegra_emc *emc)\n+{\n+\tu32 emc_cfg, emc_dbg;\n+\tu32 intmask = EMC_REFRESH_OVERFLOW_INT;\n+\tconst char *dram_type_str;\n+\n+\temc->dram_type = readl(emc->regs + EMC_FBIO_CFG5);\n+\n+\temc->dram_type &= EMC_FBIO_CFG5_DRAM_TYPE_MASK;\n+\temc->dram_type >>= EMC_FBIO_CFG5_DRAM_TYPE_SHIFT;\n+\n+\temc->dram_num = tegra_mc_get_emem_device_count(emc->mc);\n+\n+\temc_cfg = readl_relaxed(emc->regs + EMC_CFG_2);\n+\n+\t/* enable EMC and CAR to handshake on PLL divider/source changes */\n+\temc_cfg |= EMC_CLKCHANGE_REQ_ENABLE;\n+\n+\t/* configure clock change mode accordingly to DRAM type */\n+\tswitch (emc->dram_type) {\n+\tcase DRAM_TYPE_LPDDR2:\n+\t\temc_cfg |= EMC_CLKCHANGE_PD_ENABLE;\n+\t\temc_cfg &= ~EMC_CLKCHANGE_SR_ENABLE;\n+\t\tbreak;\n+\n+\tdefault:\n+\t\temc_cfg &= ~EMC_CLKCHANGE_SR_ENABLE;\n+\t\temc_cfg &= ~EMC_CLKCHANGE_PD_ENABLE;\n+\t\tbreak;\n+\t}\n+\n+\twritel_relaxed(emc_cfg, emc->regs + EMC_CFG_2);\n+\n+\t/* initialize interrupt */\n+\twritel_relaxed(intmask, emc->regs + EMC_INTMASK);\n+\twritel_relaxed(0xffffffff, emc->regs + EMC_INTSTATUS);\n+\n+\t/* ensure that unwanted debug features are disabled */\n+\temc_dbg = readl_relaxed(emc->regs + EMC_DBG);\n+\temc_dbg |= EMC_DBG_CFG_PRIORITY;\n+\temc_dbg &= ~EMC_DBG_READ_MUX_ASSEMBLY;\n+\temc_dbg &= ~EMC_DBG_WRITE_MUX_ACTIVE;\n+\temc_dbg &= ~EMC_DBG_FORCE_UPDATE;\n+\twritel_relaxed(emc_dbg, emc->regs + EMC_DBG);\n+\n+\tswitch (emc->dram_type) {\n+\tcase DRAM_TYPE_DDR1:\n+\t\tdram_type_str = \"DDR1\";\n+\t\tbreak;\n+\tcase DRAM_TYPE_LPDDR2:\n+\t\tdram_type_str = \"LPDDR2\";\n+\t\tbreak;\n+\tcase DRAM_TYPE_DDR2:\n+\t\tdram_type_str = \"DDR2\";\n+\t\tbreak;\n+\tcase DRAM_TYPE_DDR3:\n+\t\tdram_type_str = \"DDR3\";\n+\t\tbreak;\n+\t}\n+\n+\tdev_info_once(emc->dev, \"%u %s %s attached\\n\", emc->dram_num,\n+\t\t      dram_type_str, emc->dram_num == 2 ? \"devices\" : \"device\");\n+\n+\temc_read_current_timing(emc, &emc->last_timing);\n+\n+\treturn 0;\n+}\n+\n+static int load_one_timing_from_dt(struct tegra_emc *emc,\n+\t\t\t\t   struct emc_timing *timing,\n+\t\t\t\t   struct device_node *node)\n+{\n+\tu32 value;\n+\tint err;\n+\n+\terr = of_property_read_u32(node, \"clock-frequency\", &value);\n+\tif (err) {\n+\t\tdev_err(emc->dev, \"timing %pOFn: failed to read rate: %d\\n\",\n+\t\t\tnode, err);\n+\t\treturn err;\n+\t}\n+\n+\ttiming->rate = value;\n+\n+\terr = of_property_read_u32_array(node, \"nvidia,emc-configuration\",\n+\t\t\t\t\t timing->emc_burst_data,\n+\t\t\t\t\t ARRAY_SIZE(timing->emc_burst_data));\n+\tif (err) {\n+\t\tdev_err(emc->dev,\n+\t\t\t\"timing %pOFn: failed to read emc burst data: %d\\n\",\n+\t\t\tnode, err);\n+\t\treturn err;\n+\t}\n+\n+#define EMC_READ_PROP(prop, dtprop) { \\\n+\terr = of_property_read_u32(node, dtprop, &timing->prop); \\\n+\tif (err) { \\\n+\t\tdev_err(emc->dev, \"timing %pOFn: failed to read \" #prop \": %d\\n\", \\\n+\t\t\tnode, err); \\\n+\t\treturn err; \\\n+\t} \\\n+}\n+\n+\tEMC_READ_PROP(emc_auto_cal_config, \"nvidia,emc-auto-cal-config\")\n+\tEMC_READ_PROP(emc_auto_cal_config2, \"nvidia,emc-auto-cal-config2\")\n+\tEMC_READ_PROP(emc_auto_cal_config3, \"nvidia,emc-auto-cal-config3\")\n+\tEMC_READ_PROP(emc_auto_cal_interval, \"nvidia,emc-auto-cal-interval\")\n+\tEMC_READ_PROP(emc_cfg, \"nvidia,emc-cfg\")\n+\tEMC_READ_PROP(emc_ctt_term_ctrl, \"nvidia,emc-ctt-term-ctrl\")\n+\tEMC_READ_PROP(emc_mode_1, \"nvidia,emc-mode-1\")\n+\tEMC_READ_PROP(emc_mode_2, \"nvidia,emc-mode-2\")\n+\tEMC_READ_PROP(emc_mode_4, \"nvidia,emc-mode-4\")\n+\tEMC_READ_PROP(emc_mode_reset, \"nvidia,emc-mode-reset\")\n+\tEMC_READ_PROP(emc_mrs_wait_cnt, \"nvidia,emc-mrs-wait-cnt\")\n+\tEMC_READ_PROP(emc_sel_dpd_ctrl, \"nvidia,emc-sel-dpd-ctrl\")\n+\tEMC_READ_PROP(emc_xm2dqspadctrl2, \"nvidia,emc-xm2dqspadctrl2\")\n+\tEMC_READ_PROP(emc_zcal_cnt_long, \"nvidia,emc-zcal-cnt-long\")\n+\tEMC_READ_PROP(emc_zcal_interval, \"nvidia,emc-zcal-interval\")\n+\n+#undef EMC_READ_PROP\n+\n+\treturn 0;\n+}\n+\n+static int cmp_timings(const void *_a, const void *_b)\n+{\n+\tconst struct emc_timing *a = _a;\n+\tconst struct emc_timing *b = _b;\n+\n+\tif (a->rate < b->rate)\n+\t\treturn -1;\n+\telse if (a->rate == b->rate)\n+\t\treturn 0;\n+\telse\n+\t\treturn 1;\n+}\n+\n+static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc,\n+\t\t\t\t\t  struct device_node *node)\n+{\n+\tint child_count = of_get_child_count(node);\n+\tstruct device_node *child;\n+\tstruct emc_timing *timing;\n+\tunsigned int i = 0;\n+\tint err;\n+\n+\temc->timings = devm_kcalloc(emc->dev, child_count, sizeof(*timing),\n+\t\t\t\t    GFP_KERNEL);\n+\tif (!emc->timings)\n+\t\treturn -ENOMEM;\n+\n+\temc->num_timings = child_count;\n+\n+\tfor_each_child_of_node(node, child) {\n+\t\ttiming = &emc->timings[i++];\n+\n+\t\terr = load_one_timing_from_dt(emc, timing, child);\n+\t\tif (err) {\n+\t\t\tof_node_put(child);\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\tsort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings,\n+\t     NULL);\n+\n+\treturn 0;\n+}\n+\n+static struct device_node *\n+tegra_emc_find_node_by_ram_code(struct device_node *node, u32 ram_code)\n+{\n+\tstruct device_node *np;\n+\tint err;\n+\n+\tfor_each_child_of_node(node, np) {\n+\t\tu32 value;\n+\n+\t\terr = of_property_read_u32(np, \"nvidia,ram-code\", &value);\n+\t\tif (err || value != ram_code)\n+\t\t\tcontinue;\n+\n+\t\treturn np;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static void tegra_emc_rate_requests_init(struct tegra_emc *emc)\n+{\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < EMC_RATE_TYPE_MAX; i++) {\n+\t\temc->requested_rate[i].min_rate = 0;\n+\t\temc->requested_rate[i].max_rate = ULONG_MAX;\n+\t}\n+}\n+\n+static int emc_request_rate(struct tegra_emc *emc,\n+\t\t\t    unsigned long new_min_rate,\n+\t\t\t    unsigned long new_max_rate,\n+\t\t\t    enum emc_rate_request_type type)\n+{\n+\tstruct emc_rate_request *req = emc->requested_rate;\n+\tunsigned long min_rate = 0, max_rate = ULONG_MAX;\n+\tunsigned int i;\n+\tint err;\n+\n+\t/* select minimum and maximum rates among the requested rates */\n+\tfor (i = 0; i < EMC_RATE_TYPE_MAX; i++, req++) {\n+\t\tif (i == type) {\n+\t\t\tmin_rate = max(new_min_rate, min_rate);\n+\t\t\tmax_rate = min(new_max_rate, max_rate);\n+\t\t} else {\n+\t\t\tmin_rate = max(req->min_rate, min_rate);\n+\t\t\tmax_rate = min(req->max_rate, max_rate);\n+\t\t}\n+\t}\n+\n+\tif (min_rate > max_rate) {\n+\t\tdev_err_ratelimited(emc->dev, \"%s: type %u: out of range: %lu %lu\\n\",\n+\t\t\t\t    __func__, type, min_rate, max_rate);\n+\t\treturn -ERANGE;\n+\t}\n+\n+\t/*\n+\t * EMC rate-changes should go via OPP API because it manages voltage\n+\t * changes.\n+\t */\n+\terr = dev_pm_opp_set_rate(emc->dev, min_rate);\n+\tif (err)\n+\t\treturn err;\n+\n+\temc->requested_rate[type].min_rate = new_min_rate;\n+\temc->requested_rate[type].max_rate = new_max_rate;\n+\n+\treturn 0;\n+}\n+\n+static int emc_set_min_rate(struct tegra_emc *emc, unsigned long rate,\n+\t\t\t    enum emc_rate_request_type type)\n+{\n+\tstruct emc_rate_request *req = &emc->requested_rate[type];\n+\tint ret;\n+\n+\tmutex_lock(&emc->rate_lock);\n+\tret = emc_request_rate(emc, rate, req->max_rate, type);\n+\tmutex_unlock(&emc->rate_lock);\n+\n+\treturn ret;\n+}\n+\n+static int emc_set_max_rate(struct tegra_emc *emc, unsigned long rate,\n+\t\t\t    enum emc_rate_request_type type)\n+{\n+\tstruct emc_rate_request *req = &emc->requested_rate[type];\n+\tint ret;\n+\n+\tmutex_lock(&emc->rate_lock);\n+\tret = emc_request_rate(emc, req->min_rate, rate, type);\n+\tmutex_unlock(&emc->rate_lock);\n+\n+\treturn ret;\n+}\n+\n+/*\n+ * debugfs interface\n+ *\n+ * The memory controller driver exposes some files in debugfs that can be used\n+ * to control the EMC frequency. The top-level directory can be found here:\n+ *\n+ *   /sys/kernel/debug/emc\n+ *\n+ * It contains the following files:\n+ *\n+ *   - available_rates: This file contains a list of valid, space-separated\n+ *     EMC frequencies.\n+ *\n+ *   - min_rate: Writing a value to this file sets the given frequency as the\n+ *       floor of the permitted range. If this is higher than the currently\n+ *       configured EMC frequency, this will cause the frequency to be\n+ *       increased so that it stays within the valid range.\n+ *\n+ *   - max_rate: Similarly to the min_rate file, writing a value to this file\n+ *       sets the given frequency as the ceiling of the permitted range. If\n+ *       the value is lower than the currently configured EMC frequency, this\n+ *       will cause the frequency to be decreased so that it stays within the\n+ *       valid range.\n+ */\n+\n+static bool tegra_emc_validate_rate(struct tegra_emc *emc, unsigned long rate)\n+{\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < emc->num_timings; i++)\n+\t\tif (rate == emc->timings[i].rate)\n+\t\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+static int tegra_emc_debug_available_rates_show(struct seq_file *s,\n+\t\t\t\t\t\tvoid *data)\n+{\n+\tstruct tegra_emc *emc = s->private;\n+\tconst char *prefix = \"\";\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < emc->num_timings; i++) {\n+\t\tseq_printf(s, \"%s%lu\", prefix, emc->timings[i].rate);\n+\t\tprefix = \" \";\n+\t}\n+\n+\tseq_puts(s, \"\\n\");\n+\n+\treturn 0;\n+}\n+\n+DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates);\n+\n+static int tegra_emc_debug_min_rate_get(void *data, u64 *rate)\n+{\n+\tstruct tegra_emc *emc = data;\n+\n+\t*rate = emc->debugfs.min_rate;\n+\n+\treturn 0;\n+}\n+\n+static int tegra_emc_debug_min_rate_set(void *data, u64 rate)\n+{\n+\tstruct tegra_emc *emc = data;\n+\tint err;\n+\n+\tif (!tegra_emc_validate_rate(emc, rate))\n+\t\treturn -EINVAL;\n+\n+\terr = emc_set_min_rate(emc, rate, EMC_RATE_DEBUG);\n+\tif (err < 0)\n+\t\treturn err;\n+\n+\temc->debugfs.min_rate = rate;\n+\n+\treturn 0;\n+}\n+\n+DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_min_rate_fops,\n+\t\t\t tegra_emc_debug_min_rate_get,\n+\t\t\t tegra_emc_debug_min_rate_set, \"%llu\\n\");\n+\n+static int tegra_emc_debug_max_rate_get(void *data, u64 *rate)\n+{\n+\tstruct tegra_emc *emc = data;\n+\n+\t*rate = emc->debugfs.max_rate;\n+\n+\treturn 0;\n+}\n+\n+static int tegra_emc_debug_max_rate_set(void *data, u64 rate)\n+{\n+\tstruct tegra_emc *emc = data;\n+\tint err;\n+\n+\tif (!tegra_emc_validate_rate(emc, rate))\n+\t\treturn -EINVAL;\n+\n+\terr = emc_set_max_rate(emc, rate, EMC_RATE_DEBUG);\n+\tif (err < 0)\n+\t\treturn err;\n+\n+\temc->debugfs.max_rate = rate;\n+\n+\treturn 0;\n+}\n+\n+DEFINE_DEBUGFS_ATTRIBUTE(tegra_emc_debug_max_rate_fops,\n+\t\t\t tegra_emc_debug_max_rate_get,\n+\t\t\t tegra_emc_debug_max_rate_set, \"%llu\\n\");\n+\n+static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc)\n+{\n+\tunsigned int i;\n+\tint err;\n+\n+\temc->debugfs.min_rate = ULONG_MAX;\n+\temc->debugfs.max_rate = 0;\n+\n+\tfor (i = 0; i < emc->num_timings; i++) {\n+\t\tif (emc->timings[i].rate < emc->debugfs.min_rate)\n+\t\t\temc->debugfs.min_rate = emc->timings[i].rate;\n+\n+\t\tif (emc->timings[i].rate > emc->debugfs.max_rate)\n+\t\t\temc->debugfs.max_rate = emc->timings[i].rate;\n+\t}\n+\n+\tif (!emc->num_timings) {\n+\t\temc->debugfs.min_rate = clk_get_rate(emc->clk);\n+\t\temc->debugfs.max_rate = emc->debugfs.min_rate;\n+\t}\n+\n+\terr = clk_set_rate_range(emc->clk, emc->debugfs.min_rate,\n+\t\t\t\t emc->debugfs.max_rate);\n+\tif (err < 0) {\n+\t\tdev_err(dev, \"failed to set rate range [%lu-%lu] for %pC\\n\",\n+\t\t\temc->debugfs.min_rate, emc->debugfs.max_rate,\n+\t\t\temc->clk);\n+\t\treturn;\n+\t}\n+\n+\temc->debugfs.root = debugfs_create_dir(\"emc\", NULL);\n+\n+\tdebugfs_create_file(\"available_rates\", 0444, emc->debugfs.root, emc,\n+\t\t\t    &tegra_emc_debug_available_rates_fops);\n+\tdebugfs_create_file(\"min_rate\", 0644, emc->debugfs.root,\n+\t\t\t    emc, &tegra_emc_debug_min_rate_fops);\n+\tdebugfs_create_file(\"max_rate\", 0644, emc->debugfs.root,\n+\t\t\t    emc, &tegra_emc_debug_max_rate_fops);\n+}\n+\n+static inline struct tegra_emc *\n+to_tegra_emc_provider(struct icc_provider *provider)\n+{\n+\treturn container_of(provider, struct tegra_emc, provider);\n+}\n+\n+static struct icc_node_data *\n+emc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)\n+{\n+\tstruct icc_provider *provider = data;\n+\tstruct icc_node_data *ndata;\n+\tstruct icc_node *node;\n+\n+\t/* External Memory is the only possible ICC route */\n+\tlist_for_each_entry(node, &provider->nodes, node_list) {\n+\t\tif (node->id != TEGRA_ICC_EMEM)\n+\t\t\tcontinue;\n+\n+\t\tndata = kzalloc(sizeof(*ndata), GFP_KERNEL);\n+\t\tif (!ndata)\n+\t\t\treturn ERR_PTR(-ENOMEM);\n+\n+\t\t/*\n+\t\t * SRC and DST nodes should have matching TAG in order to have\n+\t\t * it set by default for a requested path.\n+\t\t */\n+\t\tndata->tag = TEGRA_MC_ICC_TAG_ISO;\n+\t\tndata->node = node;\n+\n+\t\treturn ndata;\n+\t}\n+\n+\treturn ERR_PTR(-EPROBE_DEFER);\n+}\n+\n+static int emc_icc_set(struct icc_node *src, struct icc_node *dst)\n+{\n+\tstruct tegra_emc *emc = to_tegra_emc_provider(dst->provider);\n+\tunsigned long long peak_bw = icc_units_to_bps(dst->peak_bw);\n+\tunsigned long long avg_bw = icc_units_to_bps(dst->avg_bw);\n+\tunsigned long long rate = max(avg_bw, peak_bw);\n+\tunsigned int dram_data_bus_width_bytes = 4;\n+\tconst unsigned int ddr = 2;\n+\tint err;\n+\n+\t/*\n+\t * Tegra114 EMC runs on a clock rate of SDRAM bus. This means that\n+\t * EMC clock rate is twice smaller than the peak data rate because\n+\t * data is sampled on both EMC clock edges.\n+\t */\n+\tdo_div(rate, ddr * dram_data_bus_width_bytes);\n+\trate = min_t(u64, rate, U32_MAX);\n+\n+\terr = emc_set_min_rate(emc, rate, EMC_RATE_ICC);\n+\tif (err)\n+\t\treturn err;\n+\n+\treturn 0;\n+}\n+\n+static int tegra_emc_interconnect_init(struct tegra_emc *emc)\n+{\n+\tconst struct tegra_mc_soc *soc = emc->mc->soc;\n+\tstruct icc_node *node;\n+\tint err;\n+\n+\temc->provider.dev = emc->dev;\n+\temc->provider.set = emc_icc_set;\n+\temc->provider.data = &emc->provider;\n+\temc->provider.aggregate = soc->icc_ops->aggregate;\n+\temc->provider.xlate_extended = emc_of_icc_xlate_extended;\n+\n+\ticc_provider_init(&emc->provider);\n+\n+\t/* create External Memory Controller node */\n+\tnode = icc_node_create(TEGRA_ICC_EMC);\n+\tif (IS_ERR(node)) {\n+\t\terr = PTR_ERR(node);\n+\t\tgoto err_msg;\n+\t}\n+\n+\tnode->name = \"External Memory Controller\";\n+\ticc_node_add(node, &emc->provider);\n+\n+\t/* link External Memory Controller to External Memory (DRAM) */\n+\terr = icc_link_create(node, TEGRA_ICC_EMEM);\n+\tif (err)\n+\t\tgoto remove_nodes;\n+\n+\t/* create External Memory node */\n+\tnode = icc_node_create(TEGRA_ICC_EMEM);\n+\tif (IS_ERR(node)) {\n+\t\terr = PTR_ERR(node);\n+\t\tgoto remove_nodes;\n+\t}\n+\n+\tnode->name = \"External Memory (DRAM)\";\n+\ticc_node_add(node, &emc->provider);\n+\n+\terr = icc_provider_register(&emc->provider);\n+\tif (err)\n+\t\tgoto remove_nodes;\n+\n+\treturn 0;\n+\n+remove_nodes:\n+\ticc_nodes_remove(&emc->provider);\n+err_msg:\n+\tdev_err(emc->dev, \"failed to initialize ICC: %d\\n\", err);\n+\n+\treturn err;\n+}\n+\n+static int tegra_emc_opp_table_init(struct tegra_emc *emc)\n+{\n+\tu32 hw_version = BIT(tegra_sku_info.soc_speedo_id);\n+\tint opp_token, err;\n+\n+\terr = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);\n+\tif (err < 0) {\n+\t\tdev_err(emc->dev, \"failed to set OPP supported HW: %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\topp_token = err;\n+\n+\terr = dev_pm_opp_of_add_table(emc->dev);\n+\tif (err) {\n+\t\tif (err == -ENODEV)\n+\t\t\tdev_err(emc->dev, \"OPP table not found, please update your device tree\\n\");\n+\t\telse\n+\t\t\tdev_err(emc->dev, \"failed to add OPP table: %d\\n\", err);\n+\n+\t\tgoto put_hw_table;\n+\t}\n+\n+\tdev_info_once(emc->dev, \"OPP HW ver. 0x%x, current clock rate %lu MHz\\n\",\n+\t\t      hw_version, clk_get_rate(emc->clk) / 1000000);\n+\n+\t/* first dummy rate-set initializes voltage state */\n+\terr = dev_pm_opp_set_rate(emc->dev, clk_get_rate(emc->clk));\n+\tif (err) {\n+\t\tdev_err(emc->dev, \"failed to initialize OPP clock: %d\\n\", err);\n+\t\tgoto remove_table;\n+\t}\n+\n+\treturn 0;\n+\n+remove_table:\n+\tdev_pm_opp_of_remove_table(emc->dev);\n+put_hw_table:\n+\tdev_pm_opp_put_supported_hw(opp_token);\n+\n+\treturn err;\n+}\n+\n+static void devm_tegra_emc_unset_callback(void *data)\n+{\n+\ttegra124_clk_set_emc_callbacks(NULL, NULL);\n+}\n+\n+static int tegra_emc_probe(struct platform_device *pdev)\n+{\n+\tstruct device_node *np;\n+\tstruct tegra_emc *emc;\n+\tu32 ram_code;\n+\tint err;\n+\n+\temc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL);\n+\tif (!emc)\n+\t\treturn -ENOMEM;\n+\n+\tmutex_init(&emc->rate_lock);\n+\temc->dev = &pdev->dev;\n+\n+\temc->regs = devm_platform_ioremap_resource(pdev, 0);\n+\tif (IS_ERR(emc->regs))\n+\t\treturn PTR_ERR(emc->regs);\n+\n+\temc->mc = devm_tegra_memory_controller_get(&pdev->dev);\n+\tif (IS_ERR(emc->mc))\n+\t\treturn PTR_ERR(emc->mc);\n+\n+\tram_code = tegra_read_ram_code();\n+\n+\tnp = tegra_emc_find_node_by_ram_code(pdev->dev.of_node, ram_code);\n+\tif (np) {\n+\t\terr = tegra_emc_load_timings_from_dt(emc, np);\n+\t\tof_node_put(np);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t} else {\n+\t\tdev_info_once(&pdev->dev,\n+\t\t\t      \"no memory timings for RAM code %u found in DT\\n\",\n+\t\t\t      ram_code);\n+\t}\n+\n+\terr = emc_init(emc);\n+\tif (err) {\n+\t\tdev_err(&pdev->dev, \"EMC initialization failed: %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\tplatform_set_drvdata(pdev, emc);\n+\n+\ttegra124_clk_set_emc_callbacks(tegra_emc_prepare_timing_change,\n+\t\t\t\t       tegra_emc_complete_timing_change);\n+\n+\terr = devm_add_action_or_reset(&pdev->dev, devm_tegra_emc_unset_callback,\n+\t\t\t\t       NULL);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = platform_get_irq(pdev, 0);\n+\tif (err < 0)\n+\t\treturn err;\n+\n+\temc->irq = err;\n+\n+\terr = devm_request_irq(&pdev->dev, emc->irq, tegra_emc_isr, 0,\n+\t\t\t       dev_name(&pdev->dev), emc);\n+\tif (err) {\n+\t\tdev_err(&pdev->dev, \"failed to request irq: %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\temc->clk = devm_clk_get(&pdev->dev, \"emc\");\n+\tif (IS_ERR(emc->clk)) {\n+\t\terr = PTR_ERR(emc->clk);\n+\t\tdev_err(&pdev->dev, \"failed to get EMC clock: %d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\terr = tegra_emc_opp_table_init(emc);\n+\tif (err)\n+\t\treturn err;\n+\n+\ttegra_emc_rate_requests_init(emc);\n+\n+\tif (IS_ENABLED(CONFIG_DEBUG_FS))\n+\t\temc_debugfs_init(&pdev->dev, emc);\n+\n+\ttegra_emc_interconnect_init(emc);\n+\n+\t/*\n+\t * Don't allow the kernel module to be unloaded. Unloading adds some\n+\t * extra complexity which doesn't really worth the effort in a case of\n+\t * this driver.\n+\t */\n+\ttry_module_get(THIS_MODULE);\n+\n+\treturn 0;\n+};\n+\n+static const struct of_device_id tegra_emc_of_match[] = {\n+\t{ .compatible = \"nvidia,tegra114-emc\" },\n+\t{}\n+};\n+MODULE_DEVICE_TABLE(of, tegra_emc_of_match);\n+\n+static struct platform_driver tegra_emc_driver = {\n+\t.probe = tegra_emc_probe,\n+\t.driver = {\n+\t\t.name = \"tegra114-emc\",\n+\t\t.of_match_table = tegra_emc_of_match,\n+\t\t.suppress_bind_attrs = true,\n+\t\t.sync_state = icc_sync_state,\n+\t},\n+};\n+module_platform_driver(tegra_emc_driver);\n+\n+MODULE_AUTHOR(\"Svyatoslav Ryhel <clamor95@gmail.com>\");\n+MODULE_DESCRIPTION(\"NVIDIA Tegra114 EMC driver\");\n+MODULE_LICENSE(\"GPL\");\n",
    "prefixes": [
        "v3",
        "08/11"
    ]
}