From patchwork Wed Mar 21 08:03:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Zhu X-Patchwork-Id: 888629 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-ide-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=nxp.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=nxp.com header.i=@nxp.com header.b="SU8RQT99"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 405j8r5YN8z9s0v for ; Wed, 21 Mar 2018 19:07:56 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751823AbeCUIHz (ORCPT ); Wed, 21 Mar 2018 04:07:55 -0400 Received: from mail-eopbgr20056.outbound.protection.outlook.com ([40.107.2.56]:12236 "EHLO EUR02-VE1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751626AbeCUIHu (ORCPT ); Wed, 21 Mar 2018 04:07:50 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=hUpuuRe1R8iiEdDrpkyd+HuEIOVTPfdK7E/QBIQcihA=; b=SU8RQT99W3XOjvz0hWea/KUaHOwTGHpHZ6pYd5LljbjLDx2EWmHS6hlf4QAdD/QwRyqN4Gk/dn+4dQ6XzVE0twC6mjZ32OF4ngqEgzdbQuuYmmuqsd/FRDwNKHxDo4rimQJP5/cxCvAoEce6O4oNJ0XNB/G4puMQAF7rH/NCpmk= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=hongxing.zhu@nxp.com; Received: from shlinux2.ap.freescale.net (119.31.174.66) by HE1PR0402MB2860.eurprd04.prod.outlook.com (2603:10a6:3:d6::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.588.14; Wed, 21 Mar 2018 08:07:45 +0000 From: Richard Zhu To: tj@kernel.org, hdegoede@redhat.com Cc: linux-ide@vger.kernel.org, Richard Zhu Subject: [RFC] ahci: imx: add the imx8qm ahci sata support Date: Wed, 21 Mar 2018 16:03:42 +0800 Message-Id: <1521619422-345-1-git-send-email-hongxing.zhu@nxp.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 X-Originating-IP: [119.31.174.66] X-ClientProxiedBy: HK2PR02CA0154.apcprd02.prod.outlook.com (2603:1096:201:1f::14) To HE1PR0402MB2860.eurprd04.prod.outlook.com (2603:10a6:3:d6::17) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-HT: Tenant X-MS-Office365-Filtering-Correlation-Id: 1739358b-4c35-46a3-d7cd-08d58f02d52f X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(48565401081)(5600026)(4604075)(4534165)(4627221)(201703031133081)(201702281549075)(2017052603328)(7153060)(7193020); SRVR:HE1PR0402MB2860; X-Microsoft-Exchange-Diagnostics: 1; HE1PR0402MB2860; 3:p/ZAciSSbXHMwt/H8GBDSoGp+otzdIKNNdlmikG3xgjpvh1ibjMHjl/G8p/Bh/KPL+QgpQjE5WdwIIvo7THkCwO/PyC4k8g3rJXjtIz19ERxLVtdp0hgm8eUg24phT4LFfDVryqHA4SkMsVf3mCIkT/so73cbgKdPGjBbwAi51S82PsDZlWBsNZU3KWrC4eN57dy71pwaY8rGvtO1IgzDKCMFgz1wIxMMIqE0HPU4WwUSDjxgVNjIrs8QAAsSw5S; 25:qIV+sfhSdFAYi+gm/2Y51ru4SVh8osXz86U5hTjyLUcJenwno00b+BTSuEHLTHquy2KGjG5++Ri5GCZLW4lyRgbuM/ELb++scwOXcBaBRJoqNLyyxQVCBRIeJ8QxkP1h7k5UXHeKhE1jcvhJGxrSs/8sd18ha3RvSN5kANMPNIyoosghZpjAqnNUJGNJOZBTgeK+5UP1mEgvt0ypdSULin5AHlxTi6mdxS4Gu0Gur0hB8ZxKjVPRgIOis6MzsaYqPnF/SRiBuogPzybHZ3uWJXT1U1p47irYqXn2+I7FOQPMuHbm1FF5iidNKCkw8W1j1VqT70DGy6zZGaIA8SHe+Q==; 31:B1RvXXj0jXaKswn+zvJUbte238H/nEXU07x38g76AV22fsvFRrwwrMmhDXwqH0I0roFhxlMMS9C+UHlnj9lLK3wLQhV3yRkPGORRk1ABkM41piB2sa4hN4ueN5BGNDohEWer0IfGbeg494QyolU0qui+XsTpqE0c7Yw4GlMUl+UTfoabY1tTRZ7IdXzZvmltjfWnzbMSN0aeJ5o1DWugJ6OrVTOyT9JvuaeNiy7seLI= X-MS-TrafficTypeDiagnostic: HE1PR0402MB2860: X-Microsoft-Exchange-Diagnostics: 1; HE1PR0402MB2860; 20:VIaIJAKIcsHDFnsBkyx0KV3y+W+RAlGr3EIqMKbDV/QMGDrGuoMltdqdM4kyx0ZIEEasJ+rCwRbSoPNv7AC9/cBoyhGi2dhfKfksGCyWK0lelhDtukaXGPKQH6viBRD/zSdrGS6Y7oDnxmaVD8tcKJ7zIsNB6qwCCwvhiuFs11NYDrs+A65tY1SmBJObcFGBxvWk7px/CzwEULVFx0oaGIluXZFSJkCUPydhpwub7z3vU0PTSekgna3xi/VZxoQTky3QyMqju4FB6aVyJGA5LoeRen8v1VAmqUaS75fZUE0zJo49h6zty+N2qP/FmxlnUYxBCbU8Cgdmg79R44hBFbaHrHyq1DD+JDPfIDmZnA4OMQNiV/ccBaaIX/KnkwCAeKHnBlQGDNkUMhnITJlY3Rhrcrn4so3zm0ZigLKmLon0hBIvxwmQzlaiJXFvjRwL7wRVIqgzrmKbtY7Q4PVjYFj3JfehQrFU47GyfvPL5+DYNaW+yJzjJ7BD7BP07yrH; 4:U1EVQfxfGVlF/0eMQxu7yAJoUmQG+1IzBOXgjtQQitsZVskQE+D/k07Yjj4NE3/5FQDD4dX/fYWk84ueGLEhLkpzCURLTh8FhKgVq3IhNYox0UuzfPbx+xFpir8eEx3z4sEpdX6qVPk6n+gWgraxyPvs3BHMev8EtSBTz0DPf7HiZKsV0fsvABBFVQ7njrxRrLTTqtyDMT4acaaThnDbEyLEXHUfyvQikdYG3IuGbyAzFP4D2wpEmfbzYJzvKO3gFs8S0jCNBY0XxY4jJYscCHxnPYTOKVjSmzjpyTIggP4b/TKHn7Ty0UpeAdlG78Jk X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(185117386973197); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(10201501046)(3231221)(944501320)(52105095)(3002001)(93006095)(93001095)(6055026)(6041310)(20161123558120)(20161123562045)(20161123560045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123564045)(6072148)(201708071742011); SRVR:HE1PR0402MB2860; BCL:0; PCL:0; RULEID:; SRVR:HE1PR0402MB2860; X-Forefront-PRVS: 0618E4E7E1 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(346002)(366004)(376002)(396003)(39860400002)(39380400002)(199004)(189003)(6486002)(6116002)(36756003)(5660300001)(97736004)(6666003)(3846002)(50466002)(105586002)(48376002)(25786009)(16526019)(186003)(8676002)(106356001)(86362001)(6506007)(316002)(386003)(8936002)(6512007)(52116002)(2906002)(81156014)(81166006)(16586007)(47776003)(575784001)(59450400001)(305945005)(50226002)(26005)(68736007)(478600001)(53936002)(7736002)(4326008)(51416003)(66066001)(32563001); DIR:OUT; SFP:1101; SCL:1; SRVR:HE1PR0402MB2860; H:shlinux2.ap.freescale.net; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: nxp.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: 1; HE1PR0402MB2860; 23:9fBVnWR0P94RAbj1JGUXOTeBTeQMaIOGaFVEy+dNY4GIvmSMkI4lUW6asPfOnDRBx28YeddNWQX+uqUrfBjB4ZLbBifREOwZ5iKjUPznpsBQ5EwAoPxPmlwpuKeGhpFYCkKvWK7+XeHhGI9i1xzdENVWwKvKeTym+/hvA4eYjSJKLRCbdLFeiovJwbwUFAcIpO+t7+6tA2lgZ8Ue4e0s5FPg3nB1s1p0MOJfzZ4o8yk0iGfil0uPbGhGnTdKRPHyQGJaPFa2EbABLTiGni/eLlNgWC++wda3p1mGgdIJ+U9NhDlBBlrxYTN1XFgcGxjVk0lEtP4zABJ03+bxDzJ9BPEfm3a49cwUD5Y5jN3Ly49Cz5+kyLGmEs6+9w3dyjS0Hw5lJpaWl3sDL/eSiWV2Ee8hnVvfV2RKFUGRZ1BsYiptUqZQJjZRT/iEQ3yJCn3vCglaFayMwvONeYxBhN6kOB/BbOoBWzBNhq1YUMANZ3etNCW99OES8C3PItTt3uM+ouFBdXumBZ+jbSU2GqtcnkD29H0MnfkmYfKjOnD1uHX0XAxplbv2Blqw+JV3XSy6VOWNWqXCAmCIrqk/mrtzZqk70pcDw5qSd8ngdz7aMdc2JARL4l7AjjpdjQSkiBWpbSdzElkjS+WeKK3Sg6NenvBWRXl0d2MG0cCYWDg3aW4L7XSog1CIU8h9ZFUDD0OBVUlzLik4cFbMmVW3rM/AYm4sPRgyzaXsfACIEh64E1yVAMBfVV7nSfZwCLMm+OpgLFYZ7OPrF9WDkXOUQCHifk2W10Ee++RRqa4qZC7dSwNzEMHUW2WhWwjfuiU5kxdAKuEIxJAD+RTZ2aP3o+tWKS1oN/floPZsyRr2+vdS9U/+vVXzZP4W6nmYITAZXtX6EoLC44appmycy2ELl2TUNbH0/h8yN1GLRjT5HHMB5/pYGe0WEF5HCT3ha8sjZWvzsYr2Uti+Aeb+u09mXd5RBCF8O9jrGWrxcixM9G/dH4bS6SO3ZUStfZeV425U770/roUAIDlg9PEh+eGucNeTQAeefeoNP/JC2q/dhH6C8XMkGwlxzQymoO5iDTwK88+2AiIWAfbfYvnaE2TSBZgpIw== X-Microsoft-Antispam-Message-Info: IvK7PdIFs1yAIH+btl0q8qI8Wdu+75+1FE8bXmgEEL56DO/ASUmTGU/pfy10MiivD79gftd85Qrxky8USpzeI0PlQfIakOV1Sg0DS/NA77XrRnv+if4PslBCGIH/OjtyT0ZFy6hPATHj1/V4fV4/cnfnsnOxxqlIg9oJmS9kbMIAVKn7jXPHgow3b0RVAb2J X-Microsoft-Exchange-Diagnostics: 1; HE1PR0402MB2860; 6:Jspe+lVXOof0eeo+YV9DgphHjZVdYjsEyK4VAMUYWP50LlLHcC83afmjCQvMjJ84JbBobu8O45sjJ1yzRQtYLSvCxcgjK+UjzD/z1fBZztOwN1y7Z92d2er6rVz8Oa+G27OVysvq2qSgP7iegmAO+UOL7k0bOzuMRv8U4pth3xynEanHr0GlKwelYnBWX4XiPh9kcmlxlO8cKt0oPQlxhMR43laOswHAho5EAlOHCxGOgIRfQA6dG85ByQ638uwLIOeoPQBErHHXGiJmMfn0po0dMfRDRmTagL/DZPp725F6qvW+M80HGHNxNaAsYbQN72CRH0/MCHqn53l7czfEuN+7Ce+kjyas6S17mucNCws=; 5:LU06Ljrx5XcylHbq3hSK5anKrkc8hK9XHOviEwzR+7HMYlP3nLRWLGebvRQ4cWrIZrcD6xkJpT8d5aaJz49gM+J64fH+BInYAbGVJ7LlWmwKQ8rA49xqHKqsYUixlNTvbt5mQ068P1bwphHWqCMJMN6w3vRRc1Qe9tP908Qr8xA=; 24:h/VDJL7GharR0XXK1kOrW2J1B+qH2xsoELz7L9VzB4ylrfJXOdkur3c4YJdKAfOxRDuw4fB0sIZ+VmRUL7gK+IGtAIdUG6ANK2I8RK4WmrY=; 7:/5piCg/8nXYjqF1qH+e3/S2vJQhI8Yl6Qvq42q5YQB3r2+cTaL76U6UpNUW7K28+OoUBBEVfFFp0JZhyxAgHF/sCLPFZyWYLZ+Ye9DTVUDo3cmIIinID7+mp9Y4u4SAjtWTj0ilFEBTy+gE7f56GflNgDur9QZYyMCDYCjXmIa60vpQESq5Mdd6FK1oUq9ZxngdgR5yMOhK+KmqM25w7UO0+5+KDCa/i/JEmFwHaK/QD9+WXL46Sz7E2OimcbMX0 SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Mar 2018 08:07:45.4369 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 1739358b-4c35-46a3-d7cd-08d58f02d52f X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-Transport-CrossTenantHeadersStamped: HE1PR0402MB2860 Sender: linux-ide-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ide@vger.kernel.org - There are three PHY lanes on iMX8QM, and can be used in the following three cases 1. a two lanes PCIE_A, and a single lane SATA. 2. a single lane PCIE_A, a single lane PCIE_B and a single lane SATA. 3. a two lanes PCIE_A, and a single lane PCIE_B. The configuration of the iMX8QM AHCI SATA is relied on the usage of PCIE ports in the case 1 and 2. Use standalone iMX8 AHCI SATA probe and enable functions to enable iMX8QM AHCI SATA support. - To save power consumption, PHY CLKs can be gated off after the configurations are done. - The impedance ratio should be configured refer to differnet REXT values. 0x6c <--> REXT valuse is 85Ohms 0x80 (default value) <--> REXT value is 100Ohms. Signed-off-by: Richard Zhu --- drivers/ata/ahci_imx.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 1c69e88..cc83bea 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -53,12 +54,49 @@ enum { /* Clock Reset Register */ IMX_CLOCK_RESET = 0x7f3f, IMX_CLOCK_RESET_RESET = 1 << 0, + /* IMX8QM HSIO AHCI definitions */ + IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET = 0x03, + IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET = 0x09, + IMX8QM_SATA_PHY_IMPED_RATIO_85OHM = 0x6c, + IMX8QM_LPCG_PHYX2_OFFSET = 0x00000, + IMX8QM_CSR_PHYX2_OFFSET = 0x90000, + IMX8QM_CSR_PHYX1_OFFSET = 0xa0000, + IMX8QM_CSR_PHYX_STTS0_OFFSET = 0x4, + IMX8QM_CSR_PCIEA_OFFSET = 0xb0000, + IMX8QM_CSR_PCIEB_OFFSET = 0xc0000, + IMX8QM_CSR_SATA_OFFSET = 0xd0000, + IMX8QM_CSR_PCIE_CTRL2_OFFSET = 0x8, + IMX8QM_CSR_MISC_OFFSET = 0xe0000, + + IMX8QM_LPCG_PHYX2_PCLK0_MASK = (0x3 << 16), + IMX8QM_LPCG_PHYX2_PCLK1_MASK = (0x3 << 20), + IMX8QM_PHY_APB_RSTN_0 = BIT(0), + IMX8QM_PHY_MODE_SATA = BIT(19), + IMX8QM_PHY_MODE_MASK = (0xf << 17), + IMX8QM_PHY_PIPE_RSTN_0 = BIT(24), + IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0 = BIT(25), + IMX8QM_PHY_PIPE_RSTN_1 = BIT(26), + IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1 = BIT(27), + IMX8QM_STTS0_LANE0_TX_PLL_LOCK = BIT(4), + IMX8QM_MISC_IOB_RXENA = BIT(0), + IMX8QM_MISC_IOB_TXENA = BIT(1), + IMX8QM_MISC_PHYX1_EPCS_SEL = BIT(12), + IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 = BIT(24), + IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 = BIT(25), + IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 = BIT(28), + IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0 = BIT(29), + IMX8QM_SATA_CTRL_RESET_N = BIT(12), + IMX8QM_SATA_CTRL_EPCS_PHYRESET_N = BIT(7), + IMX8QM_CTRL_BUTTON_RST_N = BIT(21), + IMX8QM_CTRL_POWER_UP_RST_N = BIT(23), + IMX8QM_CTRL_LTSSM_ENABLE = BIT(4), }; enum ahci_imx_type { AHCI_IMX53, AHCI_IMX6Q, AHCI_IMX6QP, + AHCI_IMX8QM, }; struct imx_ahci_priv { @@ -67,10 +105,18 @@ struct imx_ahci_priv { struct clk *sata_clk; struct clk *sata_ref_clk; struct clk *ahb_clk; + struct clk *epcs_tx_clk; + struct clk *epcs_rx_clk; + struct clk *phy_apbclk; + struct clk *phy_pclk0; + struct clk *phy_pclk1; + void __iomem *phy_base; + int clkreq_gpio; struct regmap *gpr; bool no_device; bool first_time; u32 phy_params; + u32 imped_ratio; }; static int ahci_imx_hotplug; @@ -407,6 +453,207 @@ static ssize_t sata_ahci_show_temp(struct device *dev, }; ATTRIBUTE_GROUPS(fsl_sata_ahci); +static int imx8_sata_enable(struct ahci_host_priv *hpriv) +{ + u32 val, reg; + int i, ret; + struct imx_ahci_priv *imxpriv = hpriv->plat_data; + struct device *dev = &imxpriv->ahci_pdev->dev; + + /* configure the hsio for sata */ + ret = clk_prepare_enable(imxpriv->phy_pclk0); + if (ret < 0) { + dev_err(dev, "can't enable phy_pclk0.\n"); + return ret; + } + ret = clk_prepare_enable(imxpriv->phy_pclk1); + if (ret < 0) { + dev_err(dev, "can't enable phy_pclk1.\n"); + goto disable_phy_pclk0; + } + ret = clk_prepare_enable(imxpriv->epcs_tx_clk); + if (ret < 0) { + dev_err(dev, "can't enable epcs_tx_clk.\n"); + goto disable_phy_pclk1; + } + ret = clk_prepare_enable(imxpriv->epcs_rx_clk); + if (ret < 0) { + dev_err(dev, "can't enable epcs_rx_clk.\n"); + goto disable_epcs_tx_clk; + } + ret = clk_prepare_enable(imxpriv->phy_apbclk); + if (ret < 0) { + dev_err(dev, "can't enable phy_apbclk.\n"); + goto disable_epcs_rx_clk; + } + /* Configure PHYx2 PIPE_RSTN */ + regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEA_OFFSET + + IMX8QM_CSR_PCIE_CTRL2_OFFSET, &val); + if ((val & IMX8QM_CTRL_LTSSM_ENABLE) == 0) { + /* The link of the PCIEA of HSIO is down */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_PHYX2_OFFSET, + IMX8QM_PHY_PIPE_RSTN_0 + | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0, + IMX8QM_PHY_PIPE_RSTN_0 + | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0); + } + regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEB_OFFSET + + IMX8QM_CSR_PCIE_CTRL2_OFFSET, ®); + if ((reg & IMX8QM_CTRL_LTSSM_ENABLE) == 0) { + /* The link of the PCIEB of HSIO is down */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_PHYX2_OFFSET, + IMX8QM_PHY_PIPE_RSTN_1 + | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1, + IMX8QM_PHY_PIPE_RSTN_1 + | IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1); + } + if (((reg | val) & IMX8QM_CTRL_LTSSM_ENABLE) == 0) { + /* The links of both PCIA and PCIEB of HSIO are down */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_LPCG_PHYX2_OFFSET, + IMX8QM_LPCG_PHYX2_PCLK0_MASK + | IMX8QM_LPCG_PHYX2_PCLK1_MASK, + 0); + } + + /* set PWR_RST and BT_RST of csr_pciea */ + val = IMX8QM_CSR_PCIEA_OFFSET + IMX8QM_CSR_PCIE_CTRL2_OFFSET; + regmap_update_bits(imxpriv->gpr, + val, + IMX8QM_CTRL_BUTTON_RST_N, + IMX8QM_CTRL_BUTTON_RST_N); + regmap_update_bits(imxpriv->gpr, + val, + IMX8QM_CTRL_POWER_UP_RST_N, + IMX8QM_CTRL_POWER_UP_RST_N); + + /* PHYX1_MODE to SATA */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_PHYX1_OFFSET, + IMX8QM_PHY_MODE_MASK, + IMX8QM_PHY_MODE_SATA); + + /* + * BIT0 RXENA 1, BIT1 TXENA 0 + * BIT12 PHY_X1_EPCS_SEL 1. + */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_MISC_OFFSET, + IMX8QM_MISC_IOB_RXENA, + IMX8QM_MISC_IOB_RXENA); + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_MISC_OFFSET, + IMX8QM_MISC_IOB_TXENA, + 0); + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_MISC_OFFSET, + IMX8QM_MISC_PHYX1_EPCS_SEL, + IMX8QM_MISC_PHYX1_EPCS_SEL); + /* + * It is possible, for PCIe and SATA are sharing + * the same clock source, HPLL or external oscillator. + * When PCIe is in low power modes (L1.X or L2 etc), + * the clock source can be turned off. In this case, + * if this clock source is required to be toggling by + * SATA, then SATA functions will be abnormal. + * Set the override here to avoid it. + */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_MISC_OFFSET, + IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 + | IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 + | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 + | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0, + IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 + | IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 + | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 + | IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0); + + /* clear PHY RST, then set it */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_SATA_OFFSET, + IMX8QM_SATA_CTRL_EPCS_PHYRESET_N, + 0); + + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_SATA_OFFSET, + IMX8QM_SATA_CTRL_EPCS_PHYRESET_N, + IMX8QM_SATA_CTRL_EPCS_PHYRESET_N); + + /* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_SATA_OFFSET, + IMX8QM_SATA_CTRL_RESET_N, + IMX8QM_SATA_CTRL_RESET_N); + udelay(1); + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_SATA_OFFSET, + IMX8QM_SATA_CTRL_RESET_N, + 0); + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_SATA_OFFSET, + IMX8QM_SATA_CTRL_RESET_N, + IMX8QM_SATA_CTRL_RESET_N); + + /* APB reset */ + regmap_update_bits(imxpriv->gpr, + IMX8QM_CSR_PHYX1_OFFSET, + IMX8QM_PHY_APB_RSTN_0, + IMX8QM_PHY_APB_RSTN_0); + + for (i = 0; i < 100; i++) { + reg = IMX8QM_CSR_PHYX1_OFFSET + + IMX8QM_CSR_PHYX_STTS0_OFFSET; + regmap_read(imxpriv->gpr, reg, &val); + val &= IMX8QM_STTS0_LANE0_TX_PLL_LOCK; + if (val == IMX8QM_STTS0_LANE0_TX_PLL_LOCK) + break; + udelay(1); + } + + if (val != IMX8QM_STTS0_LANE0_TX_PLL_LOCK) { + dev_err(dev, "TX PLL of the PHY is not locked\n"); + ret = -ENODEV; + } else { + writeb(imxpriv->imped_ratio, imxpriv->phy_base + + IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET); + writeb(imxpriv->imped_ratio, imxpriv->phy_base + + IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET); + reg = readb(imxpriv->phy_base + + IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET); + if (unlikely(reg != imxpriv->imped_ratio)) + dev_info(dev, "Can't set PHY RX impedance ratio.\n"); + reg = readb(imxpriv->phy_base + + IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET); + if (unlikely(reg != imxpriv->imped_ratio)) + dev_info(dev, "Can't set PHY TX impedance ratio.\n"); + usleep_range(50, 100); + + /* + * To reduce the power consumption, gate off + * the PHY clks + */ + clk_disable_unprepare(imxpriv->phy_apbclk); + clk_disable_unprepare(imxpriv->phy_pclk1); + clk_disable_unprepare(imxpriv->phy_pclk0); + return ret; + } + + clk_disable_unprepare(imxpriv->phy_apbclk); +disable_epcs_rx_clk: + clk_disable_unprepare(imxpriv->epcs_rx_clk); +disable_epcs_tx_clk: + clk_disable_unprepare(imxpriv->epcs_tx_clk); +disable_phy_pclk1: + clk_disable_unprepare(imxpriv->phy_pclk1); +disable_phy_pclk0: + clk_disable_unprepare(imxpriv->phy_pclk0); + + return ret; +} + static int imx_sata_enable(struct ahci_host_priv *hpriv) { struct imx_ahci_priv *imxpriv = hpriv->plat_data; @@ -454,6 +701,8 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv) dev_err(dev, "failed to reset phy: %d\n", ret); goto disable_clk; } + } else if (imxpriv->type == AHCI_IMX8QM) { + ret = imx8_sata_enable(hpriv); } usleep_range(1000, 2000); @@ -491,6 +740,11 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv) !IMX6Q_GPR13_SATA_MPLL_CLK_EN); break; + case AHCI_IMX8QM: + clk_disable_unprepare(imxpriv->epcs_rx_clk); + clk_disable_unprepare(imxpriv->epcs_tx_clk); + break; + default: break; } @@ -567,6 +821,7 @@ static int ahci_imx_softreset(struct ata_link *link, unsigned int *class, { .compatible = "fsl,imx53-ahci", .data = (void *)AHCI_IMX53 }, { .compatible = "fsl,imx6q-ahci", .data = (void *)AHCI_IMX6Q }, { .compatible = "fsl,imx6qp-ahci", .data = (void *)AHCI_IMX6QP }, + { .compatible = "fsl,imx8qm-ahci", .data = (void *)AHCI_IMX8QM }, {}, }; MODULE_DEVICE_TABLE(of, imx_ahci_of_match); @@ -734,6 +989,79 @@ static u32 imx_ahci_parse_props(struct device *dev, AHCI_SHT(DRV_NAME), }; +static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv) +{ + int ret; + struct resource *phy_res; + struct platform_device *pdev = imxpriv->ahci_pdev; + struct device_node *np = dev->of_node; + + if (of_property_read_u32(np, "fsl,phy-imp", &imxpriv->imped_ratio)) + imxpriv->imped_ratio = IMX8QM_SATA_PHY_IMPED_RATIO_85OHM; + phy_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); + if (phy_res) { + imxpriv->phy_base = devm_ioremap(dev, phy_res->start, + resource_size(phy_res)); + if (!imxpriv->phy_base) { + dev_err(dev, "error with ioremap\n"); + return -ENOMEM; + } + } else { + dev_err(dev, "missing *phy* reg region.\n"); + return -ENOMEM; + } + imxpriv->gpr = + syscon_regmap_lookup_by_phandle(np, "hsio"); + if (IS_ERR(imxpriv->gpr)) { + dev_err(dev, "unable to find gpr registers\n"); + return PTR_ERR(imxpriv->gpr); + } + + imxpriv->epcs_tx_clk = devm_clk_get(dev, "epcs_tx"); + if (IS_ERR(imxpriv->epcs_tx_clk)) { + dev_err(dev, "can't get epcs_tx_clk clock.\n"); + return PTR_ERR(imxpriv->epcs_tx_clk); + } + imxpriv->epcs_rx_clk = devm_clk_get(dev, "epcs_rx"); + if (IS_ERR(imxpriv->epcs_rx_clk)) { + dev_err(dev, "can't get epcs_rx_clk clock.\n"); + return PTR_ERR(imxpriv->epcs_rx_clk); + } + imxpriv->phy_pclk0 = devm_clk_get(dev, "phy_pclk0"); + if (IS_ERR(imxpriv->phy_pclk0)) { + dev_err(dev, "can't get phy_pclk0 clock.\n"); + return PTR_ERR(imxpriv->phy_pclk0); + } + imxpriv->phy_pclk1 = devm_clk_get(dev, "phy_pclk1"); + if (IS_ERR(imxpriv->phy_pclk1)) { + dev_err(dev, "can't get phy_pclk1 clock.\n"); + return PTR_ERR(imxpriv->phy_pclk1); + } + imxpriv->phy_apbclk = devm_clk_get(dev, "phy_apbclk"); + if (IS_ERR(imxpriv->phy_apbclk)) { + dev_err(dev, "can't get phy_apbclk clock.\n"); + return PTR_ERR(imxpriv->phy_apbclk); + } + + /* Fetch GPIO, then enable the external OSC */ + imxpriv->clkreq_gpio = of_get_named_gpio(np, "clkreq-gpio", 0); + if (gpio_is_valid(imxpriv->clkreq_gpio)) { + ret = devm_gpio_request_one(dev, imxpriv->clkreq_gpio, + GPIOF_OUT_INIT_LOW, + "SATA CLKREQ"); + if (ret == -EBUSY) { + dev_info(dev, "clkreq had been initialized.\n"); + } else if (ret) { + dev_err(dev, "%d unable to get clkreq.\n", ret); + return ret; + } + } else if (imxpriv->clkreq_gpio == -EPROBE_DEFER) { + return imxpriv->clkreq_gpio; + } + + return 0; +} + static int imx_ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -793,6 +1121,10 @@ static int imx_ahci_probe(struct platform_device *pdev) IMX6Q_GPR13_SATA_RX_DPLL_MODE_2P_4F | IMX6Q_GPR13_SATA_SPD_MODE_3P0G | reg_value; + } else if (imxpriv->type == AHCI_IMX8QM) { + ret = imx8_sata_probe(dev, imxpriv); + if (ret) + return ret; } hpriv = ahci_platform_get_resources(pdev);