Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1821149/?format=api
{ "id": 1821149, "url": "http://patchwork.ozlabs.org/api/patches/1821149/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20230814215457.4075025-13-bhupesh.sharma@linaro.org/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20230814215457.4075025-13-bhupesh.sharma@linaro.org>", "list_archive_url": null, "date": "2023-08-14T21:54:52", "name": "[12/17] ufs: Add Support for Qualcomm UFS HC driver", "commit_ref": null, "pull_url": null, "state": "changes-requested", "archived": false, "hash": "fbbaf3faeaac49f440c2ea8bef1670c7956bd49e", "submitter": { "id": 81316, "url": "http://patchwork.ozlabs.org/api/people/81316/?format=api", "name": "Bhupesh Sharma", "email": "bhupesh.sharma@linaro.org" }, "delegate": { "id": 3651, "url": "http://patchwork.ozlabs.org/api/users/3651/?format=api", "username": "trini", "first_name": "Tom", "last_name": "Rini", "email": "trini@ti.com" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20230814215457.4075025-13-bhupesh.sharma@linaro.org/mbox/", "series": [ { "id": 368803, "url": "http://patchwork.ozlabs.org/api/series/368803/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=368803", "date": "2023-08-14T21:54:40", "name": "Enable UFS on DragonBoard845c", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/368803/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/1821149/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1821149/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@legolas.ozlabs.org", "Authentication-Results": [ "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=<UNKNOWN>)", "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=C0QvKA6a;\n\tdkim-atps=neutral", "phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=linaro.org", "phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de", "phobos.denx.de;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.b=\"C0QvKA6a\";\n\tdkim-atps=neutral", "phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=linaro.org", "phobos.denx.de;\n spf=pass smtp.mailfrom=bhupesh.sharma@linaro.org" ], "Received": [ "from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature ECDSA (P-384))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4RPpCf0Dx9z1yfS\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 15 Aug 2023 07:57:18 +1000 (AEST)", "from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 7C4FF86989;\n\tMon, 14 Aug 2023 23:56:10 +0200 (CEST)", "by phobos.denx.de (Postfix, from userid 109)\n id EEC3F869B5; Mon, 14 Aug 2023 23:56:08 +0200 (CEST)", "from mail-pl1-x62e.google.com (mail-pl1-x62e.google.com\n [IPv6:2607:f8b0:4864:20::62e])\n (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 4658086993\n for <u-boot@lists.denx.de>; Mon, 14 Aug 2023 23:56:04 +0200 (CEST)", "by mail-pl1-x62e.google.com with SMTP id\n d9443c01a7336-1bdc19b782aso19536915ad.0\n for <u-boot@lists.denx.de>; Mon, 14 Aug 2023 14:56:04 -0700 (PDT)", "from localhost.localdomain\n ([2401:4900:1f3b:3924:6581:8508:2ecb:b5dd])\n by smtp.gmail.com with ESMTPSA id\n n4-20020a170903110400b001bba373919bsm9872075plh.261.2023.08.14.14.55.57\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Mon, 14 Aug 2023 14:56:01 -0700 (PDT)" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS\n autolearn=ham autolearn_force=no version=3.4.2", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1692050162; x=1692654962;\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=5aSajnqbX3WDsT8WQkNy5K1voHGzBm1yc0a5S/FNzLc=;\n b=C0QvKA6aoyoNZkapYjm4IM9Bc3CLcT9kgyja6tgYANkBoijZl8LzSkmy3qjN6abAmv\n BywLuQCwKE+oz7i5qFwfKDeuEwG/ecoS7PLHt7GzFJh/E1/L4sWD6CVmyOj7kAROLkts\n Ak6B4asGscFdRygi4DZhf4zZOSpNNDbGoxGfN8lbOG2E26w4XwbknqGyRjmN/CN047sL\n t1Zt3gytPYAkQiGpzpAMNwTrzBSvnTEJvA+ObryWor+zlqI8yOivVpc9CuEC6t1NX0gy\n Qb9xDEWEqeJmxHZGR1FpYlXWua6OxiyO3egvksj5PDU/O41nV63oWoie7Oh1gq1ljXx8\n 5WLQ==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20221208; t=1692050162; x=1692654962;\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=5aSajnqbX3WDsT8WQkNy5K1voHGzBm1yc0a5S/FNzLc=;\n b=bEvbMl/XlAVbv6Y5Y8uVoYYTE8Oaa3Zy3O+F7fGpSdtwAFNHeRCTNtcFSMJDSC5PZc\n CEJoHieZuZfX59fzTpoJhMcJNshrmEfZxKM3XFLU05sQBYwfsNIP6hhdoLoBdmfsFSwB\n W05xv8Dme3bMVhLxlTMtNbCNL63bruHsUYf990wUk3seWl8avidiqqQ5/8kf1HYBw1kd\n h9DXojjov3fjUONHs7L6hbwx3C6flkoHRpxl4Mo+BwvJMvrJQFfkNV/MPU8X+L+1YkZS\n GHDZ7U2S2xGtpYnX7msJHp613MOfJKq+gafGnUocW4mgyX/Oh0XXgC+xmeja9iYvB4Dx\n K2sQ==", "X-Gm-Message-State": "AOJu0YydTEeREovQgP4vQ4YIp8JfncSE34vYvvsshb0n/9WwjBt+HOtB\n 5Mjve0SGnSNQksZ2sOel1GxjoMoyKlhkUzIYHaQ=", "X-Google-Smtp-Source": "\n AGHT+IHCbNmgj4v9hnBYgrDZhiYuKUZRRbALJHyILdY40Z/S3QAtuOYUT6EBIJd+iqUilH6a/FFCsQ==", "X-Received": "by 2002:a17:902:d4cf:b0:1b8:9b1b:ae8e with SMTP id\n o15-20020a170902d4cf00b001b89b1bae8emr10260353plg.59.1692050161913;\n Mon, 14 Aug 2023 14:56:01 -0700 (PDT)", "From": "Bhupesh Sharma <bhupesh.sharma@linaro.org>", "To": "u-boot@lists.denx.de", "Cc": "sjg@chromium.org, trini@konsulko.com, bhupesh.sharma@linaro.org,\n bhupesh.linux@gmail.com, marek.vasut+renesas@mailbox.org,\n sumit.garg@linaro.org, rfried.dev@gmail.com, patrice.chotard@foss.st.com,\n jbx6244@gmail.com, kever.yang@rock-chips.com, eugen.hristev@collabora.com", "Subject": "[PATCH 12/17] ufs: Add Support for Qualcomm UFS HC driver", "Date": "Tue, 15 Aug 2023 03:24:52 +0530", "Message-Id": "<20230814215457.4075025-13-bhupesh.sharma@linaro.org>", "X-Mailer": "git-send-email 2.38.1", "In-Reply-To": "<20230814215457.4075025-1-bhupesh.sharma@linaro.org>", "References": "<20230814215457.4075025-1-bhupesh.sharma@linaro.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.39", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<https://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>", "X-Virus-Scanned": "clamav-milter 0.103.8 at phobos.denx.de", "X-Virus-Status": "Clean" }, "content": "Add Support for the Host Controller driver for UFS HC\npresent on Qualcomm Snapdragon SoCs.\n\nSigned-off-by: Bhupesh Sharma <bhupesh.sharma@linaro.org>\n---\n drivers/ufs/Kconfig | 7 +\n drivers/ufs/Makefile | 1 +\n drivers/ufs/qcom-ufshcd.c | 880 ++++++++++++++++++++++++++++++++++++++\n drivers/ufs/ufs-qcom.h | 275 ++++++++++++\n 4 files changed, 1163 insertions(+)\n create mode 100644 drivers/ufs/qcom-ufshcd.c\n create mode 100644 drivers/ufs/ufs-qcom.h", "diff": "diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig\nindex 69ea18edf8..5dfe8048a8 100644\n--- a/drivers/ufs/Kconfig\n+++ b/drivers/ufs/Kconfig\n@@ -15,6 +15,13 @@ config CADENCE_UFS\n \t This selects the platform driver for the Cadence UFS host\n \t controller present on present TI's J721e devices.\n \n+config QCOM_UFS\n+\tbool \"Qualcomm Host Controller driver for UFS\"\n+\tdepends on UFS && ARCH_SNAPDRAGON\n+ help\n+\t This selects the platform driver for the UFS host\n+\t controller present on Qualcomm Snapdragon SoCs.\n+\n config TI_J721E_UFS\n \tbool \"Glue Layer driver for UFS on TI J721E devices\"\n \thelp\ndiff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile\nindex 62ed016608..87944b1a7a 100644\n--- a/drivers/ufs/Makefile\n+++ b/drivers/ufs/Makefile\n@@ -5,4 +5,5 @@\n \n obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o\n obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o\n+obj-$(CONFIG_QCOM_UFS) += qcom-ufshcd.o\n obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o\ndiff --git a/drivers/ufs/qcom-ufshcd.c b/drivers/ufs/qcom-ufshcd.c\nnew file mode 100644\nindex 0000000000..ca55c3e8f5\n--- /dev/null\n+++ b/drivers/ufs/qcom-ufshcd.c\n@@ -0,0 +1,880 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/*\n+ * Copyright (C) 2023 Bhupesh Sharma <bhupesh.sharma@linaro.org>\n+ *\n+ * Based on Linux driver\n+ */\n+\n+#include <asm/io.h>\n+#include <clk.h>\n+#include <common.h>\n+#include <dm.h>\n+#include <dm/device_compat.h>\n+#include <generic-phy.h>\n+#include <ufs.h>\n+\n+#include <linux/bitops.h>\n+#include <linux/delay.h>\n+#include <linux/err.h>\n+\n+#include \"ufs.h\"\n+#include \"ufs-qcom.h\"\n+\n+#define MSEC_PER_SEC\t(1000L)\n+#define USEC_PER_SEC\t(1000000L)\n+#define NSEC_PER_SEC\t(1000000000L)\n+\n+static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,\n+\t\t\t\t\t\t u32 clk_cycles);\n+\n+static int ufs_qcom_clk_get(struct udevice *dev,\n+\t\tconst char *name, struct clk **clk_out, bool optional)\n+{\n+\tstruct clk *clk;\n+\tint err = 0;\n+\n+\tclk = devm_clk_get(dev, name);\n+\tif (!IS_ERR(clk)) {\n+\t\t*clk_out = clk;\n+\t\treturn 0;\n+\t}\n+\n+\terr = PTR_ERR(clk);\n+\n+\tif (optional && err == -ENOENT) {\n+\t\t*clk_out = NULL;\n+\t\treturn 0;\n+\t}\n+\n+\tif (err != -EPROBE_DEFER)\n+\t\tdev_err(dev, \"failed to get %s err %d\\n\", name, err);\n+\n+\treturn err;\n+}\n+\n+static int ufs_qcom_clk_enable(struct udevice *dev,\n+\t\tconst char *name, struct clk *clk)\n+{\n+\tint err = 0;\n+\n+\terr = clk_prepare_enable(clk);\n+\tif (err)\n+\t\tdev_err(dev, \"%s: %s enable failed %d\\n\", __func__, name, err);\n+\n+\treturn err;\n+}\n+\n+static int ufs_qcom_enable_lane_clks(struct ufs_qcom_priv *priv)\n+{\n+\tint err;\n+\tstruct udevice *dev = priv->hba->dev;\n+\n+\tif (priv->is_lane_clks_enabled)\n+\t\treturn 0;\n+\n+\terr = ufs_qcom_clk_enable(dev, \"rx_lane0_sync_clk\",\n+\t\tpriv->rx_l0_sync_clk);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ufs_qcom_clk_enable(dev, \"tx_lane0_sync_clk\",\n+\t\tpriv->tx_l0_sync_clk);\n+\tif (err)\n+\t\tgoto disable_rx_l0;\n+\n+\terr = ufs_qcom_clk_enable(dev, \"rx_lane1_sync_clk\",\n+\t\tpriv->rx_l1_sync_clk);\n+\tif (err)\n+\t\tgoto disable_tx_l0;\n+\n+\tpriv->is_lane_clks_enabled = true;\n+\n+\treturn 0;\n+\n+disable_tx_l0:\n+\tclk_disable_unprepare(priv->tx_l0_sync_clk);\n+disable_rx_l0:\n+\tclk_disable_unprepare(priv->rx_l0_sync_clk);\n+\n+\treturn err;\n+}\n+\n+static int ufs_qcom_init_lane_clks(struct ufs_qcom_priv *priv)\n+{\n+\tint err = 0;\n+\tstruct udevice *dev = priv->hba->dev;\n+\n+\terr = ufs_qcom_clk_get(dev, \"rx_lane0_sync_clk\",\n+\t\t\t\t\t&priv->rx_l0_sync_clk, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ufs_qcom_clk_get(dev, \"tx_lane0_sync_clk\",\n+\t\t\t\t\t&priv->tx_l0_sync_clk, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ufs_qcom_clk_get(dev, \"rx_lane1_sync_clk\",\n+\t\t\t\t\t&priv->rx_l1_sync_clk, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\treturn 0;\n+}\n+\n+static int ufs_qcom_enable_core_clks(struct ufs_qcom_priv *priv)\n+{\n+\tint err;\n+\tstruct udevice *dev = priv->hba->dev;\n+\n+\tif (priv->is_core_clks_enabled)\n+\t\treturn 0;\n+\n+\terr = ufs_qcom_clk_enable(dev, \"core_clk\", priv->core_clk);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ufs_qcom_clk_enable(dev, \"bus_aggr_clk\", priv->bus_aggr_clk);\n+\tif (err)\n+\t\tgoto disable_core_clk;\n+\n+\terr = ufs_qcom_clk_enable(dev, \"iface_clk\", priv->iface_clk);\n+\tif (err)\n+\t\tgoto disable_bus_aggr_clk;\n+\n+\terr = ufs_qcom_clk_enable(dev, \"core_clk_unipro\", priv->core_clk_unipro);\n+\tif (err)\n+\t\tgoto disable_iface_clk;\n+\n+\tpriv->is_core_clks_enabled = true;\n+\n+\treturn 0;\n+\n+disable_iface_clk:\n+\tclk_disable_unprepare(priv->iface_clk);\n+disable_bus_aggr_clk:\n+\tclk_disable_unprepare(priv->bus_aggr_clk);\n+disable_core_clk:\n+\tclk_disable_unprepare(priv->core_clk);\n+\n+\treturn err;\n+}\n+\n+static int ufs_qcom_init_core_clks(struct ufs_qcom_priv *priv)\n+{\n+\tint err = 0;\n+\tstruct udevice *dev = priv->hba->dev;\n+\n+\terr = ufs_qcom_clk_get(dev, \"core_clk\",\n+\t\t\t\t\t&priv->core_clk, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ufs_qcom_clk_get(dev, \"bus_aggr_clk\",\n+\t\t\t\t\t&priv->bus_aggr_clk, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ufs_qcom_clk_get(dev, \"iface_clk\", &priv->iface_clk, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = ufs_qcom_clk_get(dev, \"core_clk_unipro\", &priv->core_clk_unipro, false);\n+\tif (err)\n+\t\treturn err;\n+\n+\t/* ref_clk is optional */\n+\n+\treturn 0;\n+}\n+\n+static void ufs_qcom_select_unipro_mode(struct ufs_qcom_priv *priv)\n+{\n+\tufshcd_rmwl(priv->hba, QUNIPRO_SEL,\n+\t\t ufs_qcom_cap_qunipro(priv) ? QUNIPRO_SEL : 0,\n+\t\t REG_UFS_CFG1);\n+\n+\tif (priv->hw_ver.major == 0x05)\n+\t\tufshcd_rmwl(priv->hba, QUNIPRO_G4_SEL, 0, REG_UFS_CFG0);\n+\n+\t/* make sure above configuration is applied before we return */\n+\tmb();\n+}\n+\n+/*\n+ * ufs_qcom_reset - reset host controller and PHY\n+ */\n+static int ufs_qcom_reset(struct ufs_hba *hba)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\tint ret = 0;\n+\n+\tret = reset_assert(&priv->core_reset);\n+\tif (ret) {\n+\t\tdev_err(hba->dev, \"%s: core_reset assert failed, err = %d\\n\",\n+\t\t\t\t __func__, ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/*\n+\t * The hardware requirement for delay between assert/deassert\n+\t * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to\n+\t * ~125us (4/32768). To be on the safe side add 200us delay.\n+\t */\n+\tudelay(210);\n+\n+\tret = reset_deassert(&priv->core_reset);\n+\tif (ret)\n+\t\tdev_err(hba->dev, \"%s: core_reset deassert failed, err = %d\\n\",\n+\t\t\t\t __func__, ret);\n+\n+\tudelay(1100);\n+\n+\treturn 0;\n+}\n+\n+static void ufs_qcom_set_caps(struct ufs_hba *hba)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\n+\tif (priv->hw_ver.major >= 0x2) {\n+\t\tpriv->caps = UFS_QCOM_CAP_QUNIPRO |\n+\t\t\t UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE;\n+\t}\n+}\n+\n+/**\n+ * ufs_qcom_advertise_quirks - advertise the known QCOM UFS controller quirks\n+ * @hba: host controller instance\n+ *\n+ * QCOM UFS host controller might have some non standard behaviours (quirks)\n+ * than what is specified by UFSHCI specification. Advertise all such\n+ * quirks to standard UFS host controller driver so standard takes them into\n+ * account.\n+ */\n+static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\n+\tif (priv->hw_ver.major == 0x01) {\n+\t\thba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS\n+\t\t\t | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP\n+\t\t\t | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE;\n+\n+\t\tif (priv->hw_ver.minor == 0x0001 && priv->hw_ver.step == 0x0001)\n+\t\t\thba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR;\n+\n+\t\thba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;\n+\t}\n+\n+\tif (priv->hw_ver.major == 0x2) {\n+\t\thba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;\n+\n+\t\tif (!ufs_qcom_cap_qunipro(priv))\n+\t\t\t/* Legacy UniPro mode still need following quirks */\n+\t\t\thba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS\n+\t\t\t\t| UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE\n+\t\t\t\t| UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP);\n+\t}\n+\n+\tif (priv->hw_ver.major > 0x3)\n+\t\thba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH;\n+}\n+\n+static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_hba *hba, bool enable)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\n+\tif (priv->dev_ref_clk_ctrl_mmio &&\n+\t (enable ^ priv->is_dev_ref_clk_enabled)) {\n+\t\tu32 temp = readl_relaxed(priv->dev_ref_clk_ctrl_mmio);\n+\n+\t\tif (enable)\n+\t\t\ttemp |= priv->dev_ref_clk_en_mask;\n+\t\telse\n+\t\t\ttemp &= ~priv->dev_ref_clk_en_mask;\n+\n+\t\t/*\n+\t\t * If we are here to disable this clock it might be immediately\n+\t\t * after entering into hibern8 in which case we need to make\n+\t\t * sure that device ref_clk is active for specific time after\n+\t\t * hibern8 enter.\n+\t\t */\n+\t\tif (!enable)\n+\t\t\tudelay(10);\n+\n+\t\twritel_relaxed(temp, priv->dev_ref_clk_ctrl_mmio);\n+\n+\t\t/*\n+\t\t * Make sure the write to ref_clk reaches the destination and\n+\t\t * not stored in a Write Buffer (WB).\n+\t\t */\n+\t\treadl(priv->dev_ref_clk_ctrl_mmio);\n+\n+\t\t/*\n+\t\t * If we call hibern8 exit after this, we need to make sure that\n+\t\t * device ref_clk is stable for at least 1us before the hibern8\n+\t\t * exit command.\n+\t\t */\n+\t\tif (enable)\n+\t\t\tudelay(1);\n+\n+\t\tpriv->is_dev_ref_clk_enabled = enable;\n+\t}\n+}\n+\n+/**\n+ * ufs_qcom_setup_clocks - enables/disable clocks\n+ * @hba: host controller instance\n+ * @on: If true, enable clocks else disable them.\n+ * @status: PRE_CHANGE or POST_CHANGE notify\n+ *\n+ * Returns 0 on success, non-zero on failure.\n+ */\n+static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,\n+\t\t\t\t enum ufs_notify_change_status status)\n+{\n+\tswitch (status) {\n+\tcase PRE_CHANGE:\n+\t\tif (!on) {\n+\t\t\t/* disable device ref_clk */\n+\t\t\tufs_qcom_dev_ref_clk_ctrl(hba, false);\n+\t\t}\n+\t\tbreak;\n+\tcase POST_CHANGE:\n+\t\tif (on) {\n+\t\t\t/* enable the device ref clock for HS mode*/\n+\t\t\tufs_qcom_dev_ref_clk_ctrl(hba, true);\n+\t\t}\n+\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\tstruct phy phy;\n+\tint ret;\n+\n+\t/* Reset UFS Host Controller and PHY */\n+\tret = ufs_qcom_reset(hba);\n+\tif (ret)\n+\t\tdev_warn(hba->dev, \"%s: host reset returned %d\\n\",\n+\t\t\t\t __func__, ret);\n+\n+\t/* get phy */\n+\tret = generic_phy_get_by_name(hba->dev, \"ufsphy\", &phy);\n+\tif (ret) {\n+\t\tdev_warn(hba->dev, \"%s: Unable to get QMP ufs phy, ret = %d\\n\",\n+\t\t\t __func__, ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* phy initialization */\n+\tret = generic_phy_init(&phy);\n+\tif (ret) {\n+\t\tdev_err(hba->dev, \"%s: phy init failed, ret = %d\\n\",\n+\t\t\t__func__, ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* power on phy */\n+\tret = generic_phy_power_on(&phy);\n+\tif (ret) {\n+\t\tdev_err(hba->dev, \"%s: phy power on failed, ret = %d\\n\",\n+\t\t\t__func__, ret);\n+\t\tgoto out_disable_phy;\n+\t}\n+\n+\tufs_qcom_select_unipro_mode(priv);\n+\n+\treturn 0;\n+\n+out_disable_phy:\n+\tgeneric_phy_exit(&phy);\n+\n+\treturn ret;\n+}\n+\n+static int ufs_qcom_check_hibern8(struct ufs_hba *hba)\n+{\n+\tint err, retry_count = 50;\n+\tu32 tx_fsm_val = 0;\n+\n+\tdo {\n+\t\terr = ufshcd_dme_get(hba,\n+\t\t\t\tUIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,\n+\t\t\t\t\tUIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),\n+\t\t\t\t&tx_fsm_val);\n+\t\tif (err || tx_fsm_val == TX_FSM_HIBERN8)\n+\t\t\tbreak;\n+\n+\t\t/* max. 200us */\n+\t\tudelay(200);\n+\t\tretry_count--;\n+\t} while (retry_count != 0);\n+\n+\t/*\n+\t * check the state again.\n+\t */\n+\terr = ufshcd_dme_get(hba,\n+\t\t\tUIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,\n+\t\t\t\tUIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),\n+\t\t\t\t&tx_fsm_val);\n+\n+\tif (err) {\n+\t\tdev_err(hba->dev, \"%s: unable to get TX_FSM_STATE, err %d\\n\",\n+\t\t\t\t__func__, err);\n+\t} else if (tx_fsm_val != TX_FSM_HIBERN8) {\n+\t\terr = tx_fsm_val;\n+\t\tdev_err(hba->dev, \"%s: invalid TX_FSM_STATE = %d\\n\",\n+\t\t\t\t__func__, err);\n+\t}\n+\n+\treturn err;\n+}\n+\n+/*\n+ * The UTP controller has a number of internal clock gating cells (CGCs).\n+ * Internal hardware sub-modules within the UTP controller control the CGCs.\n+ * Hardware CGCs disable the clock to inactivate UTP sub-modules not involved\n+ * in a specific operation, UTP controller CGCs are by default disabled and\n+ * this function enables them (after every UFS link startup) to save some power\n+ * leakage.\n+ */\n+static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)\n+{\n+\tufshcd_writel(hba,\n+\t\tufshcd_readl(hba, REG_UFS_CFG2) | REG_UFS_CFG2_CGC_EN_ALL,\n+\t\tREG_UFS_CFG2);\n+\n+\t/* Ensure that HW clock gating is enabled before next operations */\n+\tmb();\n+}\n+\n+static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,\n+\t\t\t\t enum ufs_notify_change_status status)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\tint err = 0;\n+\n+\tswitch (status) {\n+\tcase PRE_CHANGE:\n+\t\tufs_qcom_power_up_sequence(hba);\n+\t\t/*\n+\t\t * The PHY PLL output is the source of tx/rx lane symbol\n+\t\t * clocks, hence, enable the lane clocks only after PHY\n+\t\t * is initialized.\n+\t\t */\n+\t\terr = ufs_qcom_enable_core_clks(priv);\n+\t\tif (err < 0)\n+\t\t\treturn err;\n+\n+\t\terr = ufs_qcom_enable_lane_clks(priv);\n+\t\tif (err < 0)\n+\t\t\treturn err;\n+\t\tbreak;\n+\tcase POST_CHANGE:\n+\t\t/* check if UFS PHY moved from DISABLED to HIBERN8 */\n+\t\terr = ufs_qcom_check_hibern8(hba);\n+\t\tufs_qcom_enable_hw_clk_gating(hba);\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_err(hba->dev, \"%s: invalid status %d\\n\", __func__, status);\n+\t\terr = -EINVAL;\n+\t\tbreak;\n+\t}\n+\n+\treturn err;\n+}\n+\n+/*\n+ * Returns zero for success and non-zero in case of a failure\n+ */\n+static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,\n+\t\t\t u32 hs, u32 rate, bool update_link_startup_timer)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\tu32 core_clk_period_in_ns;\n+\tu32 tx_clk_cycles_per_us = 0;\n+\tunsigned long core_clk_rate = 0;\n+\tu32 core_clk_cycles_per_us = 0;\n+\n+\tstatic u32 pwm_fr_table[][2] = {\n+\t\t{UFS_PWM_G1, 0x1},\n+\t\t{UFS_PWM_G2, 0x1},\n+\t\t{UFS_PWM_G3, 0x1},\n+\t\t{UFS_PWM_G4, 0x1},\n+\t};\n+\n+\tstatic u32 hs_fr_table_rA[][2] = {\n+\t\t{UFS_HS_G1, 0x1F},\n+\t\t{UFS_HS_G2, 0x3e},\n+\t\t{UFS_HS_G3, 0x7D},\n+\t};\n+\n+\tstatic u32 hs_fr_table_rB[][2] = {\n+\t\t{UFS_HS_G1, 0x24},\n+\t\t{UFS_HS_G2, 0x49},\n+\t\t{UFS_HS_G3, 0x92},\n+\t};\n+\n+\t/*\n+\t * The Qunipro controller does not use following registers:\n+\t * SYS1CLK_1US_REG, TX_SYMBOL_CLK_1US_REG, CLK_NS_REG &\n+\t * UFS_REG_PA_LINK_STARTUP_TIMER\n+\t * But UTP controller uses SYS1CLK_1US_REG register for Interrupt\n+\t * Aggregation logic.\n+\t*/\n+\tif (ufs_qcom_cap_qunipro(priv))\n+\t\treturn 0;\n+\n+\tif (gear == 0) {\n+\t\tdev_err(hba->dev, \"%s: invalid gear = %d\\n\", __func__, gear);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tcore_clk_rate = clk_get_rate(priv->core_clk);\n+\n+\t/* If frequency is smaller than 1MHz, set to 1MHz */\n+\tif (core_clk_rate < DEFAULT_CLK_RATE_HZ)\n+\t\tcore_clk_rate = DEFAULT_CLK_RATE_HZ;\n+\n+\tcore_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC;\n+\tif (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) {\n+\t\tufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);\n+\t\t/*\n+\t\t * make sure above write gets applied before we return from\n+\t\t * this function.\n+\t\t */\n+\t\tmb();\n+\t}\n+\n+\tif (ufs_qcom_cap_qunipro(priv))\n+\t\treturn 0;\n+\n+\tcore_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate;\n+\tcore_clk_period_in_ns <<= OFFSET_CLK_NS_REG;\n+\tcore_clk_period_in_ns &= MASK_CLK_NS_REG;\n+\n+\tswitch (hs) {\n+\tcase FASTAUTO_MODE:\n+\tcase FAST_MODE:\n+\t\tif (rate == PA_HS_MODE_A) {\n+\t\t\tif (gear > ARRAY_SIZE(hs_fr_table_rA)) {\n+\t\t\t\tdev_err(hba->dev,\n+\t\t\t\t\t\"%s: index %d exceeds table size %zu\\n\",\n+\t\t\t\t\t__func__, gear,\n+\t\t\t\t\tARRAY_SIZE(hs_fr_table_rA));\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\ttx_clk_cycles_per_us = hs_fr_table_rA[gear-1][1];\n+\t\t} else if (rate == PA_HS_MODE_B) {\n+\t\t\tif (gear > ARRAY_SIZE(hs_fr_table_rB)) {\n+\t\t\t\tdev_err(hba->dev,\n+\t\t\t\t\t\"%s: index %d exceeds table size %zu\\n\",\n+\t\t\t\t\t__func__, gear,\n+\t\t\t\t\tARRAY_SIZE(hs_fr_table_rB));\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\ttx_clk_cycles_per_us = hs_fr_table_rB[gear-1][1];\n+\t\t} else {\n+\t\t\tdev_err(hba->dev, \"%s: invalid rate = %d\\n\",\n+\t\t\t\t__func__, rate);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\tbreak;\n+\tcase SLOWAUTO_MODE:\n+\tcase SLOW_MODE:\n+\t\tif (gear > ARRAY_SIZE(pwm_fr_table)) {\n+\t\t\tdev_err(hba->dev,\n+\t\t\t\t\t\"%s: index %d exceeds table size %zu\\n\",\n+\t\t\t\t\t__func__, gear,\n+\t\t\t\t\tARRAY_SIZE(pwm_fr_table));\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t\ttx_clk_cycles_per_us = pwm_fr_table[gear-1][1];\n+\t\tbreak;\n+\tcase UNCHANGED:\n+\tdefault:\n+\t\tdev_err(hba->dev, \"%s: invalid mode = %d\\n\", __func__, hs);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) !=\n+\t (core_clk_period_in_ns | tx_clk_cycles_per_us)) {\n+\t\t/* this register 2 fields shall be written at once */\n+\t\tufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us,\n+\t\t\t REG_UFS_TX_SYMBOL_CLK_NS_US);\n+\t\t/*\n+\t\t * make sure above write gets applied before we return from\n+\t\t * this function.\n+\t\t */\n+\t\tmb();\n+\t}\n+\n+\tif (update_link_startup_timer && priv->hw_ver.major != 0x5) {\n+\t\tufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100),\n+\t\t\t REG_UFS_CFG0);\n+\t\t/*\n+\t\t * make sure that this configuration is applied before\n+\t\t * we return\n+\t\t */\n+\t\tmb();\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,\n+\t\t\t\t\t\t u32 clk_cycles)\n+{\n+\tint err;\n+\tu32 core_clk_ctrl_reg;\n+\n+\tif (clk_cycles > DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK)\n+\t\treturn -EINVAL;\n+\n+\terr = ufshcd_dme_get(hba,\n+\t\t\t UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),\n+\t\t\t &core_clk_ctrl_reg);\n+\tif (err)\n+\t\treturn err;\n+\n+\tcore_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK;\n+\tcore_clk_ctrl_reg |= clk_cycles;\n+\n+\t/* Clear CORE_CLK_DIV_EN */\n+\tcore_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;\n+\n+\treturn ufshcd_dme_set(hba,\n+\t\t\t UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),\n+\t\t\t core_clk_ctrl_reg);\n+}\n+\n+/* TBD: Move this to common framework layer */\n+u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)\n+{\n+\t/* HCI version 1.0 and 1.1 supports UniPro 1.41 */\n+\tswitch (hba->version) {\n+\tcase UFSHCI_VERSION_10:\n+\tcase UFSHCI_VERSION_11:\n+\t\treturn UFS_UNIPRO_VER_1_41;\n+\n+\tcase UFSHCI_VERSION_20:\n+\tcase UFSHCI_VERSION_21:\n+\tdefault:\n+\t\treturn UFS_UNIPRO_VER_1_6;\n+\t}\n+}\n+\n+static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,\n+\t\t\t\t\tenum ufs_notify_change_status status)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\tint err = 0;\n+\n+\tswitch (status) {\n+\tcase PRE_CHANGE:\n+\t\tif (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE,\n+\t\t\t\t\t0, true)) {\n+\t\t\tdev_err(hba->dev, \"%s: ufs_qcom_cfg_timers() failed\\n\",\n+\t\t\t\t__func__);\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (ufs_qcom_cap_qunipro(priv))\n+\t\t\t/*\n+\t\t\t * set unipro core clock cycles to 150 & clear clock\n+\t\t\t * divider\n+\t\t\t */\n+\t\t\terr = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba,\n+\t\t\t\t\t\t\t\t\t 150);\n+\n+\t\t/*\n+\t\t * Some UFS devices (and may be host) have issues if LCC is\n+\t\t * enabled. So we are setting PA_Local_TX_LCC_Enable to 0\n+\t\t * before link startup which will make sure that both host\n+\t\t * and device TX LCC are disabled once link startup is\n+\t\t * completed.\n+\t\t */\n+\t\tif (ufshcd_get_local_unipro_ver(hba) != UFS_UNIPRO_VER_1_41)\n+\t\t\terr = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0);\n+\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn err;\n+}\n+\n+/**\n+ * ufs_qcom_init - bind phy with controller\n+ * @hba: host controller instance\n+ *\n+ * Powers up PHY enabling clocks and regulators.\n+ *\n+ * Returns -EPROBE_DEFER if binding fails, returns negative error\n+ * on phy power up failure and returns zero on success.\n+ */\n+static int ufs_qcom_init(struct ufs_hba *hba)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\tint err;\n+\n+\tpriv->hba = hba;\n+\n+\t/* setup clocks */\n+\tufs_qcom_setup_clocks(hba, true, PRE_CHANGE);\n+\tufs_qcom_setup_clocks(hba, true, POST_CHANGE);\n+\n+\tufs_qcom_get_controller_revision(hba, &priv->hw_ver.major,\n+\t\t&priv->hw_ver.minor, &priv->hw_ver.step);\n+\tdev_info(hba->dev, \"Qcom UFS HC version: %d.%d.%d\\n\", priv->hw_ver.major,\n+\t\tpriv->hw_ver.minor, priv->hw_ver.step);\n+\n+\t/*\n+\t * for newer controllers, device reference clock control bit has\n+\t * moved inside UFS controller register address space itself.\n+\t */\n+\tif (priv->hw_ver.major >= 0x02) {\n+\t\tpriv->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1;\n+\t\tpriv->dev_ref_clk_en_mask = BIT(26);\n+\t}\n+\n+\terr = ufs_qcom_init_core_clks(priv);\n+\tif (err) {\n+\t\tdev_err(hba->dev, \"failed to initialize core clocks, err:%d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\terr = ufs_qcom_init_lane_clks(priv);\n+\tif (err) {\n+\t\tdev_err(hba->dev, \"failed to initialize lane clocks, err:%d\\n\", err);\n+\t\treturn err;\n+\t}\n+\n+\tufs_qcom_set_caps(hba);\n+\tufs_qcom_advertise_quirks(hba);\n+\tufs_qcom_setup_clocks(hba, true, POST_CHANGE);\n+\n+\t/* Power up the PHY using UFS_HS_G3. */\n+\tpriv->hs_gear = UFS_HS_G3;\n+\n+\treturn 0;\n+}\n+\n+static void ufshcd_print_clk_freqs(struct ufs_hba *hba)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\n+\tdev_info(hba->dev, \"clk: %s, rate: %lu\\n\", \"bus_aggr_clk\",\n+\t\t clk_get_rate(priv->bus_aggr_clk));\n+\tdev_info(hba->dev, \"clk: %s, rate: %lu\\n\", \"iface_clk\",\n+\t\t clk_get_rate(priv->iface_clk));\n+\tdev_info(hba->dev, \"clk: %s, rate: %lu\\n\", \"core_clk_unipro\",\n+\t\t clk_get_rate(priv->core_clk_unipro));\n+}\n+\n+static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)\n+{\n+\tu32 reg;\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(hba->dev);\n+\n+\tufshcd_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16 * 4,\n+\t\t\t \"HCI Vendor Specific Registers \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_UFS_DBG_RD_REG_OCSC);\n+\tufshcd_dump_regs(hba, reg, 44 * 4, \"UFS_UFS_DBG_RD_REG_OCSC \");\n+\n+\treg = ufshcd_readl(hba, REG_UFS_CFG1);\n+\treg |= UTP_DBG_RAMS_EN;\n+\tufshcd_writel(hba, reg, REG_UFS_CFG1);\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_UFS_DBG_RD_EDTL_RAM);\n+\tufshcd_dump_regs(hba, reg, 32 * 4, \"UFS_UFS_DBG_RD_EDTL_RAM \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_UFS_DBG_RD_DESC_RAM);\n+\tufshcd_dump_regs(hba, reg, 128 * 4, \"UFS_UFS_DBG_RD_DESC_RAM \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_UFS_DBG_RD_PRDT_RAM);\n+\tufshcd_dump_regs(hba, reg, 64 * 4, \"UFS_UFS_DBG_RD_PRDT_RAM \");\n+\n+\t/* clear bit 17 - UTP_DBG_RAMS_EN */\n+\tufshcd_rmwl(hba, UTP_DBG_RAMS_EN, 0, REG_UFS_CFG1);\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_DBG_RD_REG_UAWM);\n+\tufshcd_dump_regs(hba, reg, 4 * 4, \"UFS_DBG_RD_REG_UAWM \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_DBG_RD_REG_UARM);\n+\tufshcd_dump_regs(hba, reg, 4 * 4, \"UFS_DBG_RD_REG_UARM \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_DBG_RD_REG_TXUC);\n+\tufshcd_dump_regs(hba, reg, 48 * 4, \"UFS_DBG_RD_REG_TXUC \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_DBG_RD_REG_RXUC);\n+\tufshcd_dump_regs(hba, reg, 27 * 4, \"UFS_DBG_RD_REG_RXUC \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_DBG_RD_REG_DFC);\n+\tufshcd_dump_regs(hba, reg, 19 * 4, \"UFS_DBG_RD_REG_DFC \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_DBG_RD_REG_TRLUT);\n+\tufshcd_dump_regs(hba, reg, 34 * 4, \"UFS_DBG_RD_REG_TRLUT \");\n+\n+\treg = ufs_qcom_get_debug_reg_offset(priv, UFS_DBG_RD_REG_TMRLUT);\n+\tufshcd_dump_regs(hba, reg, 9 * 4, \"UFS_DBG_RD_REG_TMRLUT \");\n+\n+\tufshcd_print_clk_freqs(hba);\n+}\n+\n+static struct ufs_hba_ops ufs_qcom_hba_ops = {\n+\t.init\t\t\t= ufs_qcom_init,\n+\t.dbg_register_dump\t= ufs_qcom_dump_dbg_regs,\n+\t.hce_enable_notify\t= ufs_qcom_hce_enable_notify,\n+\t.link_startup_notify\t= ufs_qcom_link_startup_notify,\n+};\n+\n+static int ufs_qcom_probe(struct udevice *dev)\n+{\n+\tstruct ufs_qcom_priv *priv = dev_get_priv(dev);\n+\tint ret;\n+\n+\t/* get resets */\n+\tret = reset_get_by_name(dev, \"rst\", &priv->core_reset);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to get reset, ret:%d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = ufshcd_probe(dev, &ufs_qcom_hba_ops);\n+\tif (ret) {\n+\t\tdev_err(dev, \"ufshcd_probe() failed, ret:%d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int ufs_qcom_bind(struct udevice *dev)\n+{\n+\tstruct udevice *scsi_dev;\n+\n+\treturn ufs_scsi_bind(dev, &scsi_dev);\n+}\n+\n+static const struct udevice_id ufs_qcom_ids[] = {\n+\t{ .compatible = \"qcom,ufshc\" },\n+\t{},\n+};\n+\n+U_BOOT_DRIVER(qcom_ufshcd) = {\n+\t.name\t\t= \"qcom-ufshcd\",\n+\t.id\t\t= UCLASS_UFS,\n+\t.of_match\t= ufs_qcom_ids,\n+\t.probe\t\t= ufs_qcom_probe,\n+\t.bind\t\t= ufs_qcom_bind,\n+\t.priv_auto\t= sizeof(struct ufs_qcom_priv),\n+};\ndiff --git a/drivers/ufs/ufs-qcom.h b/drivers/ufs/ufs-qcom.h\nnew file mode 100644\nindex 0000000000..be5f558aef\n--- /dev/null\n+++ b/drivers/ufs/ufs-qcom.h\n@@ -0,0 +1,275 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.\n+ */\n+\n+#ifndef UFS_QCOM_H_\n+#define UFS_QCOM_H_\n+\n+#include <reset.h>\n+#include <linux/bitfield.h>\n+\n+#define MAX_UFS_QCOM_HOSTS\t1\n+#define MAX_U32 (~(u32)0)\n+#define MPHY_TX_FSM_STATE 0x41\n+#define TX_FSM_HIBERN8 0x1\n+#define HBRN8_POLL_TOUT_MS 100\n+#define DEFAULT_CLK_RATE_HZ 1000000\n+#define BUS_VECTOR_NAME_LEN 32\n+#define MAX_SUPP_MAC\t\t64\n+\n+#define UFS_HW_VER_MAJOR_MASK\tGENMASK(31, 28)\n+#define UFS_HW_VER_MINOR_MASK\tGENMASK(27, 16)\n+#define UFS_HW_VER_STEP_MASK\tGENMASK(15, 0)\n+\n+/* vendor specific pre-defined parameters */\n+#define SLOW 1\n+#define FAST 2\n+\n+#define UFS_QCOM_LIMIT_HS_RATE\t\tPA_HS_MODE_B\n+\n+/* QCOM UFS host controller vendor specific registers */\n+enum {\n+\tREG_UFS_SYS1CLK_1US = 0xC0,\n+\tREG_UFS_TX_SYMBOL_CLK_NS_US = 0xC4,\n+\tREG_UFS_LOCAL_PORT_ID_REG = 0xC8,\n+\tREG_UFS_PA_ERR_CODE = 0xCC,\n+\t/* On older UFS revisions, this register is called \"RETRY_TIMER_REG\" */\n+\tREG_UFS_PARAM0 = 0xD0,\n+\t/* On older UFS revisions, this register is called \"REG_UFS_PA_LINK_STARTUP_TIMER\" */\n+\tREG_UFS_CFG0 = 0xD8,\n+\tREG_UFS_CFG1 = 0xDC,\n+\tREG_UFS_CFG2 = 0xE0,\n+\tREG_UFS_HW_VERSION = 0xE4,\n+\n+\tUFS_TEST_BUS\t\t\t\t= 0xE8,\n+\tUFS_TEST_BUS_CTRL_0\t\t\t= 0xEC,\n+\tUFS_TEST_BUS_CTRL_1\t\t\t= 0xF0,\n+\tUFS_TEST_BUS_CTRL_2\t\t\t= 0xF4,\n+\tUFS_UNIPRO_CFG\t\t\t\t= 0xF8,\n+\n+\t/*\n+\t * QCOM UFS host controller vendor specific registers\n+\t * added in HW Version 3.0.0\n+\t */\n+\tUFS_AH8_CFG\t\t\t\t= 0xFC,\n+\n+\tREG_UFS_CFG3\t\t\t\t= 0x271C,\n+};\n+\n+/* QCOM UFS host controller vendor specific debug registers */\n+enum {\n+\tUFS_DBG_RD_REG_UAWM\t\t\t= 0x100,\n+\tUFS_DBG_RD_REG_UARM\t\t\t= 0x200,\n+\tUFS_DBG_RD_REG_TXUC\t\t\t= 0x300,\n+\tUFS_DBG_RD_REG_RXUC\t\t\t= 0x400,\n+\tUFS_DBG_RD_REG_DFC\t\t\t= 0x500,\n+\tUFS_DBG_RD_REG_TRLUT\t\t\t= 0x600,\n+\tUFS_DBG_RD_REG_TMRLUT\t\t\t= 0x700,\n+\tUFS_UFS_DBG_RD_REG_OCSC\t\t\t= 0x800,\n+\n+\tUFS_UFS_DBG_RD_DESC_RAM\t\t\t= 0x1500,\n+\tUFS_UFS_DBG_RD_PRDT_RAM\t\t\t= 0x1700,\n+\tUFS_UFS_DBG_RD_RESP_RAM\t\t\t= 0x1800,\n+\tUFS_UFS_DBG_RD_EDTL_RAM\t\t\t= 0x1900,\n+};\n+\n+enum {\n+\tUFS_MEM_CQIS_VS\t\t= 0x8,\n+};\n+\n+#define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x)\t(0x000 + x)\n+#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x)\t(0x400 + x)\n+\n+/* bit definitions for REG_UFS_CFG0 register */\n+#define QUNIPRO_G4_SEL\t\tBIT(5)\n+\n+/* bit definitions for REG_UFS_CFG1 register */\n+#define QUNIPRO_SEL\t\tBIT(0)\n+#define UFS_PHY_SOFT_RESET\tBIT(1)\n+#define UTP_DBG_RAMS_EN\t\tBIT(17)\n+#define TEST_BUS_EN\t\tBIT(18)\n+#define TEST_BUS_SEL\t\tGENMASK(22, 19)\n+#define UFS_REG_TEST_BUS_EN\tBIT(30)\n+\n+#define UFS_PHY_RESET_ENABLE\t1\n+#define UFS_PHY_RESET_DISABLE\t0\n+\n+/* bit definitions for REG_UFS_CFG2 register */\n+#define UAWM_HW_CGC_EN\t\tBIT(0)\n+#define UARM_HW_CGC_EN\t\tBIT(1)\n+#define TXUC_HW_CGC_EN\t\tBIT(2)\n+#define RXUC_HW_CGC_EN\t\tBIT(3)\n+#define DFC_HW_CGC_EN\t\tBIT(4)\n+#define TRLUT_HW_CGC_EN\t\tBIT(5)\n+#define TMRLUT_HW_CGC_EN\tBIT(6)\n+#define OCSC_HW_CGC_EN\t\tBIT(7)\n+\n+/* bit definitions for REG_UFS_PARAM0 */\n+#define MAX_HS_GEAR_MASK\tGENMASK(6, 4)\n+#define UFS_QCOM_MAX_GEAR(x)\tFIELD_GET(MAX_HS_GEAR_MASK, (x))\n+\n+/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */\n+#define TEST_BUS_SUB_SEL_MASK\tGENMASK(4, 0) /* All XXX_SEL fields are 5 bits wide */\n+\n+#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\\\n+\t\t\t\t TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\\\n+\t\t\t\t DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\\\n+\t\t\t\t TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN)\n+\n+/* bit offset */\n+#define OFFSET_CLK_NS_REG\t\t0xa\n+\n+/* bit masks */\n+#define MASK_TX_SYMBOL_CLK_1US_REG\tGENMASK(9, 0)\n+#define MASK_CLK_NS_REG\t\t\tGENMASK(23, 10)\n+\n+/* QUniPro Vendor specific attributes */\n+#define PA_VS_CONFIG_REG1\t0x9000\n+#define DME_VS_CORE_CLK_CTRL\t0xD002\n+/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */\n+#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT\t\tBIT(8)\n+#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK\t0xFF\n+\n+static inline void\n+ufs_qcom_get_controller_revision(struct ufs_hba *hba,\n+\t\t\t\t u8 *major, u16 *minor, u16 *step)\n+{\n+\tu32 ver = ufshcd_readl(hba, REG_UFS_HW_VERSION);\n+\n+\t*major = FIELD_GET(UFS_HW_VER_MAJOR_MASK, ver);\n+\t*minor = FIELD_GET(UFS_HW_VER_MINOR_MASK, ver);\n+\t*step = FIELD_GET(UFS_HW_VER_STEP_MASK, ver);\n+};\n+\n+static inline void ufs_qcom_assert_reset(struct ufs_hba *hba)\n+{\n+\tufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_ENABLE),\n+\t\t REG_UFS_CFG1);\n+\n+\t/*\n+\t * Make sure assertion of ufs phy reset is written to\n+\t * register before returning\n+\t */\n+\tmb();\n+}\n+\n+static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba)\n+{\n+\tufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_DISABLE),\n+\t\t REG_UFS_CFG1);\n+\n+\t/*\n+\t * Make sure de-assertion of ufs phy reset is written to\n+\t * register before returning\n+\t */\n+\tmb();\n+}\n+\n+/* Host controller hardware version: major.minor.step */\n+struct ufs_hw_version {\n+\tu16 step;\n+\tu16 minor;\n+\tu8 major;\n+};\n+\n+struct ufs_qcom_testbus {\n+\tu8 select_major;\n+\tu8 select_minor;\n+};\n+\n+struct gpio_desc;\n+\n+struct ufs_qcom_priv {\n+\t/*\n+\t * Set this capability if host controller supports the QUniPro mode\n+\t * and if driver wants the Host controller to operate in QUniPro mode.\n+\t * Note: By default this capability will be kept enabled if host\n+\t * controller supports the QUniPro mode.\n+\t */\n+\t#define UFS_QCOM_CAP_QUNIPRO\t0x1\n+\n+\t/*\n+\t * Set this capability if host controller can retain the secure\n+\t * configuration even after UFS controller core power collapse.\n+\t */\n+\t#define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE\t0x2\n+\tu32 caps;\n+\n+\tstruct phy *generic_phy;\n+\tstruct ufs_hba *hba;\n+\tstruct ufs_pa_layer_attr dev_req_params;\n+\n+\tstruct clk *core_clk;\n+\tstruct clk *bus_aggr_clk;\n+\tstruct clk *iface_clk;\n+\tstruct clk *core_clk_unipro;\n+\tstruct clk *ref_clk;\n+\tbool is_core_clks_enabled;\n+\n+\tstruct clk *rx_l0_sync_clk;\n+\tstruct clk *tx_l0_sync_clk;\n+\tstruct clk *rx_l1_sync_clk;\n+\tstruct clk *tx_l1_sync_clk;\n+\tbool is_lane_clks_enabled;\n+\n+\tstruct ufs_hw_version hw_ver;\n+\n+\t/* Reset control of HCI */\n+\tstruct reset_ctl core_reset;\n+\n+\tu32 hs_gear;\n+\n+\tint esi_base;\n+\tbool esi_enabled;\n+\n+\tvoid __iomem *dev_ref_clk_ctrl_mmio;\n+\tbool is_dev_ref_clk_enabled;\n+\n+\tu32 dev_ref_clk_en_mask;\n+};\n+\n+static inline u32\n+ufs_qcom_get_debug_reg_offset(struct ufs_qcom_priv *host, u32 reg)\n+{\n+\tif (host->hw_ver.major <= 0x02)\n+\t\treturn UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(reg);\n+\n+\treturn UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(reg);\n+};\n+\n+#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)\n+#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)\n+#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)\n+\n+int ufs_qcom_testbus_config(struct ufs_qcom_priv *host);\n+\n+static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_priv *host)\n+{\n+\treturn host->caps & UFS_QCOM_CAP_QUNIPRO;\n+}\n+\n+/* ufs-qcom-ice.c */\n+\n+#ifdef CONFIG_SCSI_UFS_CRYPTO\n+int ufs_qcom_ice_init(struct ufs_qcom_priv *host);\n+int ufs_qcom_ice_enable(struct ufs_qcom_priv *host);\n+int ufs_qcom_ice_resume(struct ufs_qcom_priv *host);\n+int ufs_qcom_ice_program_key(struct ufs_hba *hba,\n+\t\t\t const union ufs_crypto_cfg_entry *cfg, int slot);\n+#else\n+static inline int ufs_qcom_ice_init(struct ufs_qcom_priv *host)\n+{\n+\treturn 0;\n+}\n+static inline int ufs_qcom_ice_enable(struct ufs_qcom_priv *host)\n+{\n+\treturn 0;\n+}\n+static inline int ufs_qcom_ice_resume(struct ufs_qcom_priv *host)\n+{\n+\treturn 0;\n+}\n+#define ufs_qcom_ice_program_key NULL\n+#endif /* !CONFIG_SCSI_UFS_CRYPTO */\n+\n+#endif /* UFS_QCOM_H_ */\n", "prefixes": [ "12/17" ] }