From patchwork Thu Jul 9 18:11:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 11654877 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8EBC614E3 for ; Thu, 9 Jul 2020 18:11:31 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5AA78207DD for ; Thu, 9 Jul 2020 18:11:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="RT7KA2X4"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=amarulasolutions.com header.i=@amarulasolutions.com header.b="H4jwzU7h" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5AA78207DD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=amarulasolutions.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=tgNVCXWl/IR+QOh0v1Er6WwRQbWaW4K57C3oL+uTXL0=; b=RT7KA2X4v+nbFtR7nDnrHTImS 9w/+HU8EYHj3RpEyPONdfXfXn3X+DUgdCPs7AC4/8cMbMgxSiL9zw4OJNIPxb3SeSV03L/Pbg/4oE khszBV2tVUEQzc+gxHxxZhbVV1I8SEBK4WC5TOlVa2riTrrmw6D3UhJsY5tArCewa0BxIEYg8cWN9 AyZxkpCaVl/7+1YsgsjEl/pPpoazxoGYxa9OsDVoTX+0gJze1r2Z0O1O1MI6KYhQ2lvd/0XpXbDRv LUyWgVFJHdxpY4JRjcoIfCuJT8jAZS173QP0cQZmdciqgNG4o3Y/dkVLJm5/n72UUKrNKxWDw127q Ywme7BYxw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jtb15-0007xm-Qx; Thu, 09 Jul 2020 18:11:27 +0000 Received: from mail-pj1-x1042.google.com ([2607:f8b0:4864:20::1042]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jtb0z-0007vB-Th for linux-rockchip@lists.infradead.org; Thu, 09 Jul 2020 18:11:25 +0000 Received: by mail-pj1-x1042.google.com with SMTP id gc9so1478744pjb.2 for ; Thu, 09 Jul 2020 11:11:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amarulasolutions.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=4IOfXaDI/O3tgp4tPqfwUYM1F7Adj8fwjzislLLHnZ0=; b=H4jwzU7htGNbYk+T1DO6dCIV5VChwDyiQaNRAPq0qoGGOC2DtqLcwkraVzyhIEfn2V eSGsG8OpxnhgUY/Frrw5mP5zU3JGVdiih9XhV9h+g6Txb/wp1iWx0u2lpd5o3Vak4oK4 3agi45v7InDIC3jFB07YZydVqZVgHYTHe6KGQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=4IOfXaDI/O3tgp4tPqfwUYM1F7Adj8fwjzislLLHnZ0=; b=Xk2KYaupoSKkuIP6Ox0Mp5DW7yBYRrvzqpQKhnSe4gtwPXaU+dCuH/EOEqtgx2pY4K DkidGkCHTX5du9ziwAb/L7DkJKpt1TRvj5MZJWYJ5UbIJgt00FeOY2wANGrY3WJVBmZE mma/XZcdlZeWEitlcfyR9MLMbMU+sd4INNC4L5p3AYd7ocJB4g3ZCcL09qkIleUiRMjk QM+sfyvHgtvC2k39u0X810qqpRE/kBHBtZg6mlu/M0bNtl0uYTXvCTxxOz4JYxWp3GDd n8Lyt//e6KyOwYsu6kv4mUR3solqosMM+t7w3k5jtKazH68OV/aP3kIt3ljlZbmT+mzO hX3Q== X-Gm-Message-State: AOAM531huaYVnpbFavG1ShARYehVSoL30TiuCTdXw4aeCYsRIb57jGgh 3F3QFX/jcQPtJFpEjrH8AOV9yA== X-Google-Smtp-Source: ABdhPJxY/NyOUJOGyaDOfVa8ps8hoVVExnM34A82xdiGNGPVY4i6pWkDRwpTOYu7J0pm/jD7eyGARQ== X-Received: by 2002:a17:90a:254f:: with SMTP id j73mr1283176pje.16.1594318279751; Thu, 09 Jul 2020 11:11:19 -0700 (PDT) Received: from localhost.localdomain ([2405:201:c809:c7d5:a05e:bc35:5722:db76]) by smtp.gmail.com with ESMTPSA id x3sm3450696pfn.154.2020.07.09.11.11.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 09 Jul 2020 11:11:18 -0700 (PDT) From: Jagan Teki To: Kever Yang , Philipp Tomsich , Simon Glass , Shawn Lin Subject: [PATCH 1/3] phy: Add Rockchip PCIe PHY driver Date: Thu, 9 Jul 2020 23:41:01 +0530 Message-Id: <20200709181103.89870-2-jagan@amarulasolutions.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200709181103.89870-1-jagan@amarulasolutions.com> References: <20200709181103.89870-1-jagan@amarulasolutions.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200709_141122_011085_D9FD4DE1 X-CRM114-Status: GOOD ( 20.07 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:1042 listed in] [list.dnswl.org] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: U-Boot-Denx , linux-rockchip@lists.infradead.org, linux-amarula , Jagan Teki , Suniel Mahesh Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org Add the Rockchip PCIe PHY driver as part of Generic PHY framework. Signed-off-by: Jagan Teki Reviewed-by: Kever Yang --- drivers/phy/rockchip/Kconfig | 7 + drivers/phy/rockchip/Makefile | 1 + drivers/phy/rockchip/phy-rockchip-pcie.c | 271 +++++++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 drivers/phy/rockchip/phy-rockchip-pcie.c diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 84cc7c876d..2318e71f35 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -11,6 +11,13 @@ config PHY_ROCKCHIP_INNO_USB2 help Support for Rockchip USB2.0 PHY with Innosilicon IP block. +config PHY_ROCKCHIP_PCIE + bool "Rockchip PCIe PHY Driver" + depends on ARCH_ROCKCHIP + select PHY + help + Enable this to support the Rockchip PCIe PHY. + config PHY_ROCKCHIP_TYPEC bool "Rockchip TYPEC PHY Driver" depends on ARCH_ROCKCHIP diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile index 95b2f8a3c0..44049154f9 100644 --- a/drivers/phy/rockchip/Makefile +++ b/drivers/phy/rockchip/Makefile @@ -4,4 +4,5 @@ # obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o +obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c new file mode 100644 index 0000000000..83928cffe0 --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-pcie.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: (GPL-2.0-only) +/* + * Rockchip PCIe PHY driver + * + * Copyright (C) 2020 Amarula Solutions(India) + * Copyright (C) 2016 Shawn Lin + * Copyright (C) 2016 ROCKCHIP, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* + * The higher 16-bit of this register is used for write protection + * only if BIT(x + 16) set to 1 the BIT(x) can be written. + */ +#define HIWORD_UPDATE(val, mask, shift) \ + ((val) << (shift) | (mask) << ((shift) + 16)) + +#define PHY_MAX_LANE_NUM 4 +#define PHY_CFG_DATA_SHIFT 7 +#define PHY_CFG_ADDR_SHIFT 1 +#define PHY_CFG_DATA_MASK 0xf +#define PHY_CFG_ADDR_MASK 0x3f +#define PHY_CFG_RD_MASK 0x3ff +#define PHY_CFG_WR_ENABLE 1 +#define PHY_CFG_WR_DISABLE 1 +#define PHY_CFG_WR_SHIFT 0 +#define PHY_CFG_WR_MASK 1 +#define PHY_CFG_PLL_LOCK 0x10 +#define PHY_CFG_CLK_TEST 0x10 +#define PHY_CFG_CLK_SCC 0x12 +#define PHY_CFG_SEPE_RATE BIT(3) +#define PHY_CFG_PLL_100M BIT(3) +#define PHY_PLL_LOCKED BIT(9) +#define PHY_PLL_OUTPUT BIT(10) +#define PHY_LANE_RX_DET_SHIFT 11 +#define PHY_LANE_RX_DET_TH 0x1 +#define PHY_LANE_IDLE_OFF 0x1 +#define PHY_LANE_IDLE_MASK 0x1 +#define PHY_LANE_IDLE_A_SHIFT 3 +#define PHY_LANE_IDLE_B_SHIFT 4 +#define PHY_LANE_IDLE_C_SHIFT 5 +#define PHY_LANE_IDLE_D_SHIFT 6 + +struct rockchip_pcie_phy_data { + unsigned int pcie_conf; + unsigned int pcie_status; + unsigned int pcie_laneoff; +}; + +struct rockchip_pcie_phy { + void *reg_base; + struct clk refclk; + struct reset_ctl phy_rst; + const struct rockchip_pcie_phy_data *data; +}; + +static void phy_wr_cfg(struct rockchip_pcie_phy *priv, u32 addr, u32 data) +{ + u32 reg; + + reg = HIWORD_UPDATE(data, PHY_CFG_DATA_MASK, PHY_CFG_DATA_SHIFT); + reg |= HIWORD_UPDATE(addr, PHY_CFG_ADDR_MASK, PHY_CFG_ADDR_SHIFT); + writel(reg, priv->reg_base + priv->data->pcie_conf); + + udelay(1); + + reg = HIWORD_UPDATE(PHY_CFG_WR_ENABLE, + PHY_CFG_WR_MASK, + PHY_CFG_WR_SHIFT); + writel(reg, priv->reg_base + priv->data->pcie_conf); + + udelay(1); + + reg = HIWORD_UPDATE(PHY_CFG_WR_DISABLE, + PHY_CFG_WR_MASK, + PHY_CFG_WR_SHIFT); + writel(reg, priv->reg_base + priv->data->pcie_conf); +} + +static int rockchip_pcie_phy_power_on(struct phy *phy) +{ + struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev); + int ret = 0; + u32 reg, status; + + ret = reset_deassert(&priv->phy_rst); + if (ret) { + dev_err(dev, "failed to assert phy reset\n"); + return ret; + } + + reg = HIWORD_UPDATE(PHY_CFG_PLL_LOCK, + PHY_CFG_ADDR_MASK, + PHY_CFG_ADDR_SHIFT); + writel(reg, priv->reg_base + priv->data->pcie_conf); + + reg = HIWORD_UPDATE(!PHY_LANE_IDLE_OFF, + PHY_LANE_IDLE_MASK, + PHY_LANE_IDLE_A_SHIFT); + writel(reg, priv->reg_base + priv->data->pcie_laneoff); + + ret = -EINVAL; + ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status, + status, + status & PHY_PLL_LOCKED, + 20 * 1000, + 50); + if (ret) { + dev_err(&priv->dev, "pll lock timeout!\n"); + goto err_pll_lock; + } + + phy_wr_cfg(priv, PHY_CFG_CLK_TEST, PHY_CFG_SEPE_RATE); + phy_wr_cfg(priv, PHY_CFG_CLK_SCC, PHY_CFG_PLL_100M); + + ret = -ETIMEDOUT; + ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status, + status, + !(status & PHY_PLL_OUTPUT), + 20 * 1000, + 50); + if (ret) { + dev_err(&priv->dev, "pll output enable timeout!\n"); + goto err_pll_lock; + } + + reg = HIWORD_UPDATE(PHY_CFG_PLL_LOCK, + PHY_CFG_ADDR_MASK, + PHY_CFG_ADDR_SHIFT); + writel(reg, priv->reg_base + priv->data->pcie_conf); + + ret = -EINVAL; + ret = readl_poll_sleep_timeout(priv->reg_base + priv->data->pcie_status, + status, + status & PHY_PLL_LOCKED, + 20 * 1000, + 50); + if (ret) { + dev_err(&priv->dev, "pll relock timeout!\n"); + goto err_pll_lock; + } + + return 0; + +err_pll_lock: + reset_assert(&priv->phy_rst); + return ret; +} + +static int rockchip_pcie_phy_power_off(struct phy *phy) +{ + struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev); + int ret; + u32 reg; + + reg = HIWORD_UPDATE(PHY_LANE_IDLE_OFF, + PHY_LANE_IDLE_MASK, + PHY_LANE_IDLE_A_SHIFT); + writel(reg, priv->reg_base + priv->data->pcie_laneoff); + + ret = reset_assert(&priv->phy_rst); + if (ret) { + dev_err(dev, "failed to assert phy reset\n"); + return ret; + } + + return 0; +} + +static int rockchip_pcie_phy_init(struct phy *phy) +{ + struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev); + int ret; + + ret = clk_enable(&priv->refclk); + if (ret) { + dev_err(dev, "failed to enable refclk clock\n"); + return ret; + } + + ret = reset_assert(&priv->phy_rst); + if (ret) { + dev_err(dev, "failed to assert phy reset\n"); + goto err_reset; + } + + return 0; + +err_reset: + clk_disable(&priv->refclk); + return ret; +} + +static int rockchip_pcie_phy_exit(struct phy *phy) +{ + struct rockchip_pcie_phy *priv = dev_get_priv(phy->dev); + + clk_disable(&priv->refclk); + + return 0; +} + +static struct phy_ops rockchip_pcie_phy_ops = { + .init = rockchip_pcie_phy_init, + .power_on = rockchip_pcie_phy_power_on, + .power_off = rockchip_pcie_phy_power_off, + .exit = rockchip_pcie_phy_exit, +}; + +static int rockchip_pcie_phy_probe(struct udevice *dev) +{ + struct rockchip_pcie_phy *priv = dev_get_priv(dev); + int ret; + + priv->data = (const struct rockchip_pcie_phy_data *) + dev_get_driver_data(dev); + if (!priv->data) + return -EINVAL; + + priv->reg_base = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); + + ret = clk_get_by_name(dev, "refclk", &priv->refclk); + if (ret) { + dev_err(dev, "failed to get refclk clock phandle\n"); + return ret; + } + + ret = reset_get_by_name(dev, "phy", &priv->phy_rst); + if (ret) { + dev_err(dev, "failed to get phy reset phandle\n"); + return ret; + } + + return 0; +} + +static const struct rockchip_pcie_phy_data rk3399_pcie_data = { + .pcie_conf = 0xe220, + .pcie_status = 0xe2a4, + .pcie_laneoff = 0xe214, +}; + +static const struct udevice_id rockchip_pcie_phy_ids[] = { + { + .compatible = "rockchip,rk3399-pcie-phy", + .data = (ulong)&rk3399_pcie_data, + }, + { /* sentile */ } +}; + +U_BOOT_DRIVER(rockchip_pcie_phy) = { + .name = "rockchip_pcie_phy", + .id = UCLASS_PHY, + .of_match = rockchip_pcie_phy_ids, + .ops = &rockchip_pcie_phy_ops, + .probe = rockchip_pcie_phy_probe, + .priv_auto_alloc_size = sizeof(struct rockchip_pcie_phy), +};