From patchwork Mon Feb 13 08:26:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jaehoon Chung X-Patchwork-Id: 9569003 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 08D5760572 for ; Mon, 13 Feb 2017 08:26:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EBC2627FAE for ; Mon, 13 Feb 2017 08:26:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E056628047; Mon, 13 Feb 2017 08:26:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1BE1427FC0 for ; Mon, 13 Feb 2017 08:26:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752543AbdBMI03 (ORCPT ); Mon, 13 Feb 2017 03:26:29 -0500 Received: from mailout3.samsung.com ([203.254.224.33]:53151 "EHLO mailout3.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752297AbdBMI0U (ORCPT ); Mon, 13 Feb 2017 03:26:20 -0500 Received: from epcas1p3.samsung.com (unknown [182.195.41.47]) by mailout3.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0OLB02UWA0RSIM30@mailout3.samsung.com>; Mon, 13 Feb 2017 17:26:16 +0900 (KST) Received: from epsmges5p2.samsung.com (unknown [182.195.40.65]) by epcas1p1.samsung.com (KnoxPortal) with ESMTP id 20170213082616epcas1p17d9b180f95117a3d7e48c637fe90ec15~iy1EimDVS0193601936epcas1p1W; Mon, 13 Feb 2017 08:26:16 +0000 (GMT) Received: from epcas5p4.samsung.com ( [182.195.41.42]) by epsmges5p2.samsung.com (EPCPMTA) with SMTP id 28.1C.05006.8AD61A85; Mon, 13 Feb 2017 17:26:16 +0900 (KST) Received: from epcpsbgm2new.samsung.com (u27.gpu120.samsung.co.kr [203.254.230.27]) by epcas5p2.samsung.com (KnoxPortal) with ESMTP id 20170213082615epcas5p2d6bc5521e68adf71bb64d9eb8262274d~iy1Dzmd1S1265012650epcas5p2V; Mon, 13 Feb 2017 08:26:15 +0000 (GMT) X-AuditID: b6c32a2d-f79836d00000138e-a8-58a16da833e2 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm2new.samsung.com (EPCPMTA) with SMTP id 1A.E2.06428.7AD61A85; Mon, 13 Feb 2017 17:26:15 +0900 (KST) Received: from localhost.localdomain ([10.113.62.216]) by mmp1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OLB000LO0RQDO60@mmp1.samsung.com>; Mon, 13 Feb 2017 17:26:15 +0900 (KST) From: Jaehoon Chung To: linux-pci@vger.kernel.org Cc: bhelgaas@google.com, krzk@kernel.org, linux-kernel@vger.kernel.org, jingoohan1@gmail.com, javier@osg.samsung.com, kgene@kernel.org, linux-samsung-soc@vger.kernel.org, cpgs@samsung.com, niyas.ahmed@samsung.com, alim.akhtar@samsung.com, pankaj.dubey@samsung.com, kishon@ti.com, devicetree@vger.kernel.org, mark.rutland@arm.com, vivek.gautam@codeaurora.org, robh+dt@kernel.org, Jaehoon Chung Subject: [PATCH V3 2/4] phy: phy-exynos-pcie: Add support for Exynos PCIe phy Date: Mon, 13 Feb 2017 17:26:11 +0900 Message-id: <20170213082613.19628-3-jh80.chung@samsung.com> X-Mailer: git-send-email 2.10.2 In-reply-to: <20170213082613.19628-1-jh80.chung@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupgk+LIzCtJLcpLzFFi42LZdlhTS3dF7sIIg3Nr+S0ezNvGZrGkKcPi 5SFNi/lHzrFavHm7hsnixq82VosVX2ayW/Q/fs1sceFpD5vF+fMb2C0u75rDZnF23nE2ixnn 9zFZLL1+kcniyZRHrBaLtn5ht2jde4Td4sTPHcwOQh5r5q1h9Ljc18vksXPWXXaPBZtKPTat 6mTz2NIP5PVtWcXocfzGdiaPz5vkAjijUm0yUhNTUosUUvOS81My89JtlbyD453jTc0MDHUN LS3MlRTyEnNTbZVcfAJ03TJzgN5RUihLzCkFCgUkFhcr6dvZFOWXlqQqZOQXl9gqRRsaGukZ GpjrGRkZ6ZkYx1oZmQKVJKRmbDx9h6ngV0LFyxufGRsYtwd3MXJwSAiYSOx4ad7FyAlkiklc uLeeDcQWEljKKHHpexiE3c4ksWJTLkSNicTh+zdZuhi5gOLLGSVOn++Ccn4wSnTt+88OUsUm oCOx/dtxJhBbREBW4uPlPWwgRcwCa5klPn7cBLZCWMBfYvP9bSwgNouAqsTa5VfA4rwC1hKf fnUzQqyTl1h4/gjYIE4BG4lN8w8ygQySELjHLvHkwX5GiBdkJTYdYIaod5E4cuEoVK+wxKvj W9ghbGmJv0tvMUL0djNK/PuykQ3C6WGUuLV1NRNElbHE/Qf3wCYxC/BJ9P5+wgSxgFeio00I osRD4tqJJqhyR4mZP64wQrzfzyhxpHUi0wRGmQWMDKsYxVILinPTU4tNC4z0ihNzi0vz0vWS 83M3MYJToZbuDsYvC7wPMQpwMCrx8BpcWxAhxJpYVlyZe4hRgoNZSYT3T+bCCCHelMTKqtSi /Pii0pzU4kOMpsCAmsgsJZqcD0zTeSXxhiZmhiZGlkBobmiuJM4bZTAxQkggPbEkNTs1tSC1 CKaPiYNTqoGRdcerrZ3fplj1rLj7urDmu53H3t/X3tk9veLiclTO7KTq3qS8r+zNole5J1ux PjH+qBn6xcB+spG5zg1zVd9l4a8O8OVlTlZ7uvotn/wNYU2pMBu9zqU/vmcaTplz57D9A/XA 8qT3Qo0JLUcy1Rerpr837Yh/tHOCfl0jx8oTj5fqT590KyZAiaU4I9FQi7moOBEATVyer5sD AAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrGIsWRmVeSWpSXmKPExsVy+t9jAd3luQsjDJ5dlbV4MG8bm8WSpgyL l4c0LeYfOcdq8ebtGiaLG7/aWC1WfJnJbtH/+DWzxYWnPWwW589vYLe4vGsOm8XZecfZLGac 38dksfT6RSaLJ1MesVos2vqF3aJ17xF2ixM/dzA7CHmsmbeG0eNyXy+Tx85Zd9k9Fmwq9di0 qpPNY0s/kNe3ZRWjx/Eb25k8Pm+SC+CMcrPJSE1MSS1SSM1Lzk/JzEu3VQoNcdO1UFLIS8xN tVWK0PUNCVJSKEvMKQXyjAzQgINzgHuwkr5dglvGxtN3mAp+JVS8vPGZsYFxe3AXIyeHhICJ xOH7N1kgbDGJC/fWs3UxcnEICSxllLj7YC8jhPODUeLlvZesIFVsAjoS278dZwKxRQRkJT5e 3gPWwSywmlli75TDzCAJYQFfibbHG8AaWARUJdYuv8IGYvMKWEt8+tXNCLFOXmLh+SNggzgF bCQ2zT8IZgsB1RxdNZt5AiPvAkaGVYwSqQXJBcVJ6blGeanlesWJucWleel6yfm5mxjBcfZM egfj4V3uhxgFOBiVeHh/vF8QIcSaWFZcmXuIUYKDWUmE90/mwggh3pTEyqrUovz4otKc1OJD jKZAh01klhJNzgemgLySeEMTcxNzYwMLc0tLEyMlcd7G2c/ChQTSE0tSs1NTC1KLYPqYODil GhgPR8/uervIJ8Pz2rTkHF1fNa6Db/fU+KRyLDzqNNM5dYaBs0qESIrRw8JVFfwTDr9+JZR3 YJ3e/Ycp6vk9l7/cuOy4RDrPyq9tn2Efv5qTws8URRWPcMHnz/r2PvUJ/fipjLXaimVj3uYb DFGGBXuuHVL3+fnX9ULchZ0X4naufl9h4jVh8SYlluKMREMt5qLiRABMKRotyQIAAA== X-MTR: 20000000000000000@CPGS X-CMS-MailID: 20170213082615epcas5p2d6bc5521e68adf71bb64d9eb8262274d X-Msg-Generator: CA X-Sender-IP: 203.254.230.27 X-Local-Sender: =?UTF-8?B?7KCV7J6s7ZuIG1RpemVuIFBsYXRmb3JtIExhYihTL1fshLw=?= =?UTF-8?B?7YSwKRvsgrzshLHsoITsnpAbUzUo7LGF7J6EKS/ssYXsnoQ=?= X-Global-Sender: =?UTF-8?B?SmFlaG9vbiBDaHVuZxtUaXplbiBQbGF0Zm9ybSBMYWIuG1Nh?= =?UTF-8?B?bXN1bmcgRWxlY3Ryb25pY3MbUzUvU2VuaW9yIEVuZ2luZWVy?= X-Sender-Code: =?UTF-8?B?QzEwG1NUQUYbQzEwVjgxMTE=?= CMS-TYPE: 105P DLP-Filter: Pass X-CFilter-Loop: Reflected X-HopCount: 7 X-CMS-RootMailID: 20170213082615epcas5p2d6bc5521e68adf71bb64d9eb8262274d X-RootMTR: 20170213082615epcas5p2d6bc5521e68adf71bb64d9eb8262274d References: <20170213082613.19628-1-jh80.chung@samsung.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support for Generic PHY framework about Exynos SoCs. Current Exynos PCIe driver doesn't use the PHY framework. It's making a difficult to upstream the other Exynos variants because of different PHY registers. Move the codes relevant to PHY from Exnyos PCIe driver to PHY Exynos PCIe driver. Signed-off-by: Jaehoon Chung Acked-by: Krzysztof Kozlowski Reviewed-by: Jingoo Han Reviewed-by: Pankaj Dubey Reviewed-by: Vivek Gautam --- Changelog on V3: - Remove the dependency abot PCI_EXYNOS - Adds a depends on COMPILE_TEST - Use the readl_poll_timeout() instead of while() - Fixes const type - Adds MODULE_DESCRIPTION()/LICENCSE()/AUTHOR() - Changes commit message Changelog on V2: - Not include the codes relevant to pci-exynos. - Remove the getting child node. drivers/phy/Kconfig | 8 ++ drivers/phy/Makefile | 1 + drivers/phy/phy-exynos-pcie.c | 285 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 294 insertions(+) create mode 100644 drivers/phy/phy-exynos-pcie.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e8eb7f2..8659f38 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -331,6 +331,14 @@ config PHY_EXYNOS5_USBDRD This driver provides PHY interface for USB 3.0 DRD controller present on Exynos5 SoC series. +config PHY_EXYNOS_PCIE + bool "Exynos PCIe PHY driver" + depends on (ARCH_EXYNOS && OF) || COMPILE_TEST + select GENERIC_PHY + help + Enable PCIe PHY support for Exynos SoC series. + This driver provides PHY interface for Exynos PCIe controller. + config PHY_PISTACHIO_USB tristate "IMG Pistachio USB2.0 PHY driver" depends on MACH_PISTACHIO diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 65eb2f4..081aeb4 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -37,6 +37,7 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o +obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o diff --git a/drivers/phy/phy-exynos-pcie.c b/drivers/phy/phy-exynos-pcie.c new file mode 100644 index 0000000..9ec1855 --- /dev/null +++ b/drivers/phy/phy-exynos-pcie.c @@ -0,0 +1,285 @@ +/* + * Samsung EXYNOS SoC series PCIe PHY driver + * + * Phy provider for PCIe controller on Exynos SoC series + * + * Copyright (C) 2016 Samsung Electronics Co., Ltd. + * Jaehoon Chung + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PCIe Purple registers */ +#define PCIE_PHY_GLOBAL_RESET 0x000 +#define PCIE_PHY_COMMON_RESET 0x004 +#define PCIE_PHY_CMN_REG 0x008 +#define PCIE_PHY_MAC_RESET 0x00c +#define PCIE_PHY_PLL_LOCKED 0x010 +#define PCIE_PHY_TRSVREG_RESET 0x020 +#define PCIE_PHY_TRSV_RESET 0x024 + +/* PCIe PHY registers */ +#define PCIE_PHY_IMPEDANCE 0x004 +#define PCIE_PHY_PLL_DIV_0 0x008 +#define PCIE_PHY_PLL_BIAS 0x00c +#define PCIE_PHY_DCC_FEEDBACK 0x014 +#define PCIE_PHY_PLL_DIV_1 0x05c +#define PCIE_PHY_COMMON_POWER 0x064 +#define PCIE_PHY_COMMON_PD_CMN BIT(3) +#define PCIE_PHY_TRSV0_EMP_LVL 0x084 +#define PCIE_PHY_TRSV0_DRV_LVL 0x088 +#define PCIE_PHY_TRSV0_RXCDR 0x0ac +#define PCIE_PHY_TRSV0_POWER 0x0c4 +#define PCIE_PHY_TRSV0_PD_TSV BIT(7) +#define PCIE_PHY_TRSV0_LVCC 0x0dc +#define PCIE_PHY_TRSV1_EMP_LVL 0x144 +#define PCIE_PHY_TRSV1_RXCDR 0x16c +#define PCIE_PHY_TRSV1_POWER 0x184 +#define PCIE_PHY_TRSV1_PD_TSV BIT(7) +#define PCIE_PHY_TRSV1_LVCC 0x19c +#define PCIE_PHY_TRSV2_EMP_LVL 0x204 +#define PCIE_PHY_TRSV2_RXCDR 0x22c +#define PCIE_PHY_TRSV2_POWER 0x244 +#define PCIE_PHY_TRSV2_PD_TSV BIT(7) +#define PCIE_PHY_TRSV2_LVCC 0x25c +#define PCIE_PHY_TRSV3_EMP_LVL 0x2c4 +#define PCIE_PHY_TRSV3_RXCDR 0x2ec +#define PCIE_PHY_TRSV3_POWER 0x304 +#define PCIE_PHY_TRSV3_PD_TSV BIT(7) +#define PCIE_PHY_TRSV3_LVCC 0x31c + +struct exynos_pcie_phy_data { + const struct phy_ops *ops; +}; + +/* For Exynos pcie phy */ +struct exynos_pcie_phy { + const struct exynos_pcie_phy_data *drv_data; + void __iomem *phy_base; + void __iomem *blk_base; /* For exynos5440 */ +}; + +static void exynos_pcie_phy_writel(void __iomem *base, u32 val, u32 offset) +{ + writel(val, base + offset); +} + +static u32 exynos_pcie_phy_readl(void __iomem *base, u32 offset) +{ + return readl(base + offset); +} + +/* For Exynos5440 specific functions */ +static int exynos5440_pcie_phy_init(struct phy *phy) +{ + struct exynos_pcie_phy *ep = phy_get_drvdata(phy); + + /* DCC feedback control off */ + exynos_pcie_phy_writel(ep->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK); + + /* set TX/RX impedance */ + exynos_pcie_phy_writel(ep->phy_base, 0xd5, PCIE_PHY_IMPEDANCE); + + /* set 50Mhz PHY clock */ + exynos_pcie_phy_writel(ep->phy_base, 0x14, PCIE_PHY_PLL_DIV_0); + exynos_pcie_phy_writel(ep->phy_base, 0x12, PCIE_PHY_PLL_DIV_1); + + /* set TX Differential output for lane 0 */ + exynos_pcie_phy_writel(ep->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL); + + /* set TX Pre-emphasis Level Control for lane 0 to minimum */ + exynos_pcie_phy_writel(ep->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL); + + /* set RX clock and data recovery bandwidth */ + exynos_pcie_phy_writel(ep->phy_base, 0xe7, PCIE_PHY_PLL_BIAS); + exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR); + exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR); + exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR); + exynos_pcie_phy_writel(ep->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR); + + /* change TX Pre-emphasis Level Control for lanes */ + exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL); + exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL); + exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL); + exynos_pcie_phy_writel(ep->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL); + + /* set LVCC */ + exynos_pcie_phy_writel(ep->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC); + exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC); + exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC); + exynos_pcie_phy_writel(ep->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC); + + /* pulse for common reset */ + exynos_pcie_phy_writel(ep->blk_base, 1, PCIE_PHY_COMMON_RESET); + udelay(500); + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_COMMON_RESET); + + return 0; +} + +static int exynos5440_pcie_phy_power_on(struct phy *phy) +{ + struct exynos_pcie_phy *ep = phy_get_drvdata(phy); + u32 val; + + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_COMMON_RESET); + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_CMN_REG); + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_TRSVREG_RESET); + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_TRSV_RESET); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_COMMON_POWER); + val &= ~PCIE_PHY_COMMON_PD_CMN; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER); + val &= ~PCIE_PHY_TRSV0_PD_TSV; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER); + val &= ~PCIE_PHY_TRSV1_PD_TSV; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER); + val &= ~PCIE_PHY_TRSV2_PD_TSV; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER); + val &= ~PCIE_PHY_TRSV3_PD_TSV; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER); + + return 0; +} + +static int exynos5440_pcie_phy_power_off(struct phy *phy) +{ + struct exynos_pcie_phy *ep = phy_get_drvdata(phy); + u32 val; + + if (readl_poll_timeout(ep->phy_base + PCIE_PHY_PLL_LOCKED, val, + (val != 0), 1, 500)) { + dev_err(&phy->dev, "PLL Locked: 0x%x\n", val); + return -ETIMEDOUT; + } + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_COMMON_POWER); + val |= PCIE_PHY_COMMON_PD_CMN; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_COMMON_POWER); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV0_POWER); + val |= PCIE_PHY_TRSV0_PD_TSV; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV0_POWER); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV1_POWER); + val |= PCIE_PHY_TRSV1_PD_TSV; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV1_POWER); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV2_POWER); + val |= PCIE_PHY_TRSV2_PD_TSV; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV2_POWER); + + val = exynos_pcie_phy_readl(ep->phy_base, PCIE_PHY_TRSV3_POWER); + val |= PCIE_PHY_TRSV3_PD_TSV; + exynos_pcie_phy_writel(ep->phy_base, val, PCIE_PHY_TRSV3_POWER); + + return 0; +} + +static int exynos5440_pcie_phy_reset(struct phy *phy) +{ + struct exynos_pcie_phy *ep = phy_get_drvdata(phy); + + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_MAC_RESET); + exynos_pcie_phy_writel(ep->blk_base, 1, PCIE_PHY_GLOBAL_RESET); + exynos_pcie_phy_writel(ep->blk_base, 0, PCIE_PHY_GLOBAL_RESET); + + return 0; +} + +static const struct phy_ops exynos5440_phy_ops = { + .init = exynos5440_pcie_phy_init, + .power_on = exynos5440_pcie_phy_power_on, + .power_off = exynos5440_pcie_phy_power_off, + .reset = exynos5440_pcie_phy_reset, + .owner = THIS_MODULE, +}; + +static const struct exynos_pcie_phy_data exynos5440_pcie_phy_data = { + .ops = &exynos5440_phy_ops, +}; + +static const struct of_device_id exynos_pcie_phy_match[] = { + { + .compatible = "samsung,exynos5440-pcie-phy", + .data = &exynos5440_pcie_phy_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_pcie_phy_match); + +static int exynos_pcie_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct exynos_pcie_phy *exynos_phy; + struct phy *generic_phy; + struct phy_provider *phy_provider; + struct resource *res; + const struct exynos_pcie_phy_data *drv_data; + + drv_data = of_device_get_match_data(dev); + if (!drv_data) + return -ENODEV; + + exynos_phy = devm_kzalloc(dev, sizeof(*exynos_phy), GFP_KERNEL); + if (!exynos_phy) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + exynos_phy->phy_base = devm_ioremap_resource(dev, res); + if (IS_ERR(exynos_phy->phy_base)) + return PTR_ERR(exynos_phy->phy_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + exynos_phy->blk_base = devm_ioremap_resource(dev, res); + if (IS_ERR(exynos_phy->phy_base)) + return PTR_ERR(exynos_phy->phy_base); + + exynos_phy->drv_data = drv_data; + + generic_phy = devm_phy_create(dev, dev->of_node, drv_data->ops); + if (IS_ERR(generic_phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(generic_phy); + } + + phy_set_drvdata(generic_phy, exynos_phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static struct platform_driver exynos_pcie_phy_driver = { + .probe = exynos_pcie_phy_probe, + .driver = { + .of_match_table = exynos_pcie_phy_match, + .name = "exynos_pcie_phy", + } +}; +module_platform_driver(exynos_pcie_phy_driver); + +MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC PCIe PHY driver"); +MODULE_AUTHOR("Jaehoon Chung "); +MODULE_LICENSE("GPL v2");