From patchwork Mon Feb 25 09:24:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanley Chu X-Patchwork-Id: 10828373 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 22E92922 for ; Mon, 25 Feb 2019 09:24:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0E77A2AACE for ; Mon, 25 Feb 2019 09:24:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 028102AC27; Mon, 25 Feb 2019 09:24:51 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham 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 6A97C2ABF0 for ; Mon, 25 Feb 2019 09:24:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726523AbfBYJYu (ORCPT ); Mon, 25 Feb 2019 04:24:50 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:56086 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726388AbfBYJYu (ORCPT ); Mon, 25 Feb 2019 04:24:50 -0500 X-UUID: a07e0282b98e47af81542e76029519ca-20190225 X-UUID: a07e0282b98e47af81542e76029519ca-20190225 Received: from mtkcas09.mediatek.inc [(172.21.101.178)] by mailgw02.mediatek.com (envelope-from ) (mhqrelay.mediatek.com ESMTP with TLS) with ESMTP id 1946197070; Mon, 25 Feb 2019 17:24:38 +0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs02n2.mediatek.inc (172.21.101.101) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 25 Feb 2019 17:24:36 +0800 Received: from mtkswgap22.mediatek.inc (172.21.77.33) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 25 Feb 2019 17:24:36 +0800 From: To: , , , , , , , , , , CC: , , , , , , , , Stanley Chu Subject: [PATCH v2 1/6] scsi: ufs: Introduce ufshcd_get_pwr_dev_param Date: Mon, 25 Feb 2019 17:24:10 +0800 Message-ID: <1551086655-5029-3-git-send-email-stanley.chu@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> References: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> MIME-Version: 1.0 X-TM-SNTS-SMTP: F5D2D8FD66A3567D6C9B230E82D279BDD4CC999A893EBC3D614636E8587055612000:8 X-MTK: N Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Stanley Chu ufshcd_get_pwr_dev_param is for vendors to decide finally agreed attributes for power mode change if vendors define their host capability in struct ufs_dev_params. This api is using by both ufs-qcom and ufs-hisi now. Simply re-factor it and then every vendors can reuse it. Signed-off-by: Stanley Chu Reviewed-by: Avri Altman --- drivers/scsi/ufs/ufshcd-pltfrm.c | 98 ++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd-pltfrm.h | 21 +++++++ 2 files changed, 119 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 895a9b5ac989..508c561c9a62 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -39,6 +39,7 @@ #include "ufshcd.h" #include "ufshcd-pltfrm.h" +#include "unipro.h" #define UFSHCD_DEFAULT_LANES_PER_DIRECTION 2 @@ -289,6 +290,103 @@ static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba) } } +/** + * ufshcd_get_pwr_dev_param - get finally agreed attributes for + * power mode change + * @pltfrm_param: pointer to platform parameters + * @dev_max: pointer to device attributes + * @agreed_pwr: returned agreed attributes + * + * Returns 0 on success, non-zero value on failure + */ +int ufshcd_get_pwr_dev_param(struct ufs_dev_params *pltfrm_param, + struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr) +{ + int min_pltfrm_gear; + int min_dev_gear; + bool is_dev_sup_hs = false; + bool is_pltfrm_max_hs = false; + + if (dev_max->pwr_rx == FAST_MODE) + is_dev_sup_hs = true; + + if (pltfrm_param->desired_working_mode == UFS_HS_MODE) { + is_pltfrm_max_hs = true; + min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear, + pltfrm_param->hs_tx_gear); + } else { + min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear, + pltfrm_param->pwm_tx_gear); + } + + /* + * device doesn't support HS but + * pltfrm_param->desired_working_mode is HS, + * thus device and pltfrm_param don't agree + */ + if (!is_dev_sup_hs && is_pltfrm_max_hs) { + pr_info("%s: device doesn't support HS\n", + __func__); + return -ENOTSUPP; + } else if (is_dev_sup_hs && is_pltfrm_max_hs) { + /* + * since device supports HS, it supports FAST_MODE. + * since pltfrm_param->desired_working_mode is also HS + * then final decision (FAST/FASTAUTO) is done according + * to pltfrm_params as it is the restricting factor + */ + agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs; + agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; + } else { + /* + * here pltfrm_param->desired_working_mode is PWM. + * it doesn't matter whether device supports HS or PWM, + * in both cases pltfrm_param->desired_working_mode will + * determine the mode + */ + agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm; + agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; + } + + /* + * we would like tx to work in the minimum number of lanes + * between device capability and vendor preferences. + * the same decision will be made for rx + */ + agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, + pltfrm_param->tx_lanes); + agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, + pltfrm_param->rx_lanes); + + /* device maximum gear is the minimum between device rx and tx gears */ + min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); + + /* + * if both device capabilities and vendor pre-defined preferences are + * both HS or both PWM then set the minimum gear to be the chosen + * working gear. + * if one is PWM and one is HS then the one that is PWM get to decide + * what is the gear, as it is the one that also decided previously what + * pwr the device will be configured to. + */ + if ((is_dev_sup_hs && is_pltfrm_max_hs) || + (!is_dev_sup_hs && !is_pltfrm_max_hs)) { + agreed_pwr->gear_rx = + min_t(u32, min_dev_gear, min_pltfrm_gear); + } else if (!is_dev_sup_hs) { + agreed_pwr->gear_rx = min_dev_gear; + } else { + agreed_pwr->gear_rx = min_pltfrm_gear; + } + agreed_pwr->gear_tx = agreed_pwr->gear_rx; + + agreed_pwr->hs_rate = pltfrm_param->hs_rate; + + return 0; +} +EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); + /** * ufshcd_pltfrm_init - probe routine of the driver * @pdev: pointer to Platform device handle diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h index df64c4180340..d3ba62269be6 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.h +++ b/drivers/scsi/ufs/ufshcd-pltfrm.h @@ -16,6 +16,27 @@ #include "ufshcd.h" +#define UFS_PWM_MODE 1 +#define UFS_HS_MODE 2 + +struct ufs_dev_params { + u32 pwm_rx_gear; /* pwm rx gear to work in */ + u32 pwm_tx_gear; /* pwm tx gear to work in */ + u32 hs_rx_gear; /* hs rx gear to work in */ + u32 hs_tx_gear; /* hs tx gear to work in */ + u32 rx_lanes; /* number of rx lanes */ + u32 tx_lanes; /* number of tx lanes */ + u32 rx_pwr_pwm; /* rx pwm working pwr */ + u32 tx_pwr_pwm; /* tx pwm working pwr */ + u32 rx_pwr_hs; /* rx hs working pwr */ + u32 tx_pwr_hs; /* tx hs working pwr */ + u32 hs_rate; /* rate A/B to work in HS */ + u32 desired_working_mode; +}; + +int ufshcd_get_pwr_dev_param(struct ufs_dev_params *dev_param, + struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr); int ufshcd_pltfrm_init(struct platform_device *pdev, struct ufs_hba_variant_ops *vops); void ufshcd_pltfrm_shutdown(struct platform_device *pdev); From patchwork Mon Feb 25 09:24:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanley Chu X-Patchwork-Id: 10828375 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9C4CF1390 for ; Mon, 25 Feb 2019 09:24:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8D9CC2AACE for ; Mon, 25 Feb 2019 09:24:51 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 818962AC2A; Mon, 25 Feb 2019 09:24:51 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham 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 0A2002AACE for ; Mon, 25 Feb 2019 09:24:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726518AbfBYJYt (ORCPT ); Mon, 25 Feb 2019 04:24:49 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:38747 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726509AbfBYJYs (ORCPT ); Mon, 25 Feb 2019 04:24:48 -0500 X-UUID: d6d826419975484997836e253b94f230-20190225 X-UUID: d6d826419975484997836e253b94f230-20190225 Received: from mtkcas07.mediatek.inc [(172.21.101.84)] by mailgw02.mediatek.com (envelope-from ) (mhqrelay.mediatek.com ESMTP with TLS) with ESMTP id 1831202984; Mon, 25 Feb 2019 17:24:43 +0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs02n1.mediatek.inc (172.21.101.77) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 25 Feb 2019 17:24:36 +0800 Received: from mtkswgap22.mediatek.inc (172.21.77.33) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 25 Feb 2019 17:24:37 +0800 From: To: , , , , , , , , , , CC: , , , , , , , , Stanley Chu Subject: [PATCH v2 2/6] scsi: ufs-qcom: Re-factor ufshcd_get_pwr_dev_param Date: Mon, 25 Feb 2019 17:24:11 +0800 Message-ID: <1551086655-5029-4-git-send-email-stanley.chu@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> References: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> MIME-Version: 1.0 X-MTK: N Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Stanley Chu ufshcd_get_pwr_dev_param function and ufs_dev_params struct are re-factored to ufs common driver thus change the way this driver used. Signed-off-by: Stanley Chu Reviewed-by: Avri Altman --- drivers/scsi/ufs/ufs-qcom.c | 106 ++---------------------------------- 1 file changed, 4 insertions(+), 102 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 3aeadb14aae1..a6b6f6eb9061 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -595,104 +595,6 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) return err; } -struct ufs_qcom_dev_params { - u32 pwm_rx_gear; /* pwm rx gear to work in */ - u32 pwm_tx_gear; /* pwm tx gear to work in */ - u32 hs_rx_gear; /* hs rx gear to work in */ - u32 hs_tx_gear; /* hs tx gear to work in */ - u32 rx_lanes; /* number of rx lanes */ - u32 tx_lanes; /* number of tx lanes */ - u32 rx_pwr_pwm; /* rx pwm working pwr */ - u32 tx_pwr_pwm; /* tx pwm working pwr */ - u32 rx_pwr_hs; /* rx hs working pwr */ - u32 tx_pwr_hs; /* tx hs working pwr */ - u32 hs_rate; /* rate A/B to work in HS */ - u32 desired_working_mode; -}; - -static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, - struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr) -{ - int min_qcom_gear; - int min_dev_gear; - bool is_dev_sup_hs = false; - bool is_qcom_max_hs = false; - - if (dev_max->pwr_rx == FAST_MODE) - is_dev_sup_hs = true; - - if (qcom_param->desired_working_mode == FAST) { - is_qcom_max_hs = true; - min_qcom_gear = min_t(u32, qcom_param->hs_rx_gear, - qcom_param->hs_tx_gear); - } else { - min_qcom_gear = min_t(u32, qcom_param->pwm_rx_gear, - qcom_param->pwm_tx_gear); - } - - /* - * device doesn't support HS but qcom_param->desired_working_mode is - * HS, thus device and qcom_param don't agree - */ - if (!is_dev_sup_hs && is_qcom_max_hs) { - pr_err("%s: failed to agree on power mode (device doesn't support HS but requested power is HS)\n", - __func__); - return -ENOTSUPP; - } else if (is_dev_sup_hs && is_qcom_max_hs) { - /* - * since device supports HS, it supports FAST_MODE. - * since qcom_param->desired_working_mode is also HS - * then final decision (FAST/FASTAUTO) is done according - * to qcom_params as it is the restricting factor - */ - agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = - qcom_param->rx_pwr_hs; - } else { - /* - * here qcom_param->desired_working_mode is PWM. - * it doesn't matter whether device supports HS or PWM, - * in both cases qcom_param->desired_working_mode will - * determine the mode - */ - agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = - qcom_param->rx_pwr_pwm; - } - - /* - * we would like tx to work in the minimum number of lanes - * between device capability and vendor preferences. - * the same decision will be made for rx - */ - agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, - qcom_param->tx_lanes); - agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, - qcom_param->rx_lanes); - - /* device maximum gear is the minimum between device rx and tx gears */ - min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); - - /* - * if both device capabilities and vendor pre-defined preferences are - * both HS or both PWM then set the minimum gear to be the chosen - * working gear. - * if one is PWM and one is HS then the one that is PWM get to decide - * what is the gear, as it is the one that also decided previously what - * pwr the device will be configured to. - */ - if ((is_dev_sup_hs && is_qcom_max_hs) || - (!is_dev_sup_hs && !is_qcom_max_hs)) - agreed_pwr->gear_rx = agreed_pwr->gear_tx = - min_t(u32, min_dev_gear, min_qcom_gear); - else if (!is_dev_sup_hs) - agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_dev_gear; - else - agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_qcom_gear; - - agreed_pwr->hs_rate = qcom_param->hs_rate; - return 0; -} - #ifdef CONFIG_MSM_BUS_SCALING static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, const char *speed_mode) @@ -920,7 +822,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, { u32 val; struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_qcom_dev_params ufs_qcom_cap; + struct ufs_dev_params ufs_qcom_cap; int ret = 0; if (!dev_req_params) { @@ -959,9 +861,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, ufs_qcom_cap.hs_rx_gear = UFS_HS_G2; } - ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap, - dev_max_params, - dev_req_params); + ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap, + dev_max_params, + dev_req_params); if (ret) { pr_err("%s: failed to determine capabilities\n", __func__); From patchwork Mon Feb 25 09:24:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanley Chu X-Patchwork-Id: 10828365 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5DAD413B5 for ; Mon, 25 Feb 2019 09:24:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4F1F52AACE for ; Mon, 25 Feb 2019 09:24:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 42B4A2ABEC; Mon, 25 Feb 2019 09:24:46 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham 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 BD6F22AAD1 for ; Mon, 25 Feb 2019 09:24:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726504AbfBYJYo (ORCPT ); Mon, 25 Feb 2019 04:24:44 -0500 Received: from mailgw01.mediatek.com ([210.61.82.183]:5229 "EHLO mailgw01.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726490AbfBYJYn (ORCPT ); Mon, 25 Feb 2019 04:24:43 -0500 X-UUID: 6c855ab8be204fabbba49548e69232a8-20190225 X-UUID: 6c855ab8be204fabbba49548e69232a8-20190225 Received: from mtkcas09.mediatek.inc [(172.21.101.178)] by mailgw01.mediatek.com (envelope-from ) (mhqrelay.mediatek.com ESMTP with TLS) with ESMTP id 993937738; Mon, 25 Feb 2019 17:24:38 +0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs01n1.mediatek.inc (172.21.101.68) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 25 Feb 2019 17:24:37 +0800 Received: from mtkswgap22.mediatek.inc (172.21.77.33) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 25 Feb 2019 17:24:37 +0800 From: To: , , , , , , , , , , CC: , , , , , , , , Stanley Chu Subject: [PATCH v2 3/6] scsi: ufs-hisi: Re-factor ufshcd_get_pwr_dev_param Date: Mon, 25 Feb 2019 17:24:12 +0800 Message-ID: <1551086655-5029-5-git-send-email-stanley.chu@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> References: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> MIME-Version: 1.0 X-MTK: N Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Stanley Chu ufshcd_get_pwr_dev_param function and ufs_dev_params struct are re-factored to ufs common driver thus change the way this driver used. Signed-off-by: Stanley Chu Reviewed-by: Avri Altman --- drivers/scsi/ufs/ufs-hisi.c | 109 ++---------------------------------- 1 file changed, 4 insertions(+), 105 deletions(-) diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c index 452e19f8fb47..01faad26ec26 100644 --- a/drivers/scsi/ufs/ufs-hisi.c +++ b/drivers/scsi/ufs/ufs-hisi.c @@ -272,108 +272,7 @@ static int ufs_hi3660_link_startup_notify(struct ufs_hba *hba, return err; } -struct ufs_hisi_dev_params { - u32 pwm_rx_gear; /* pwm rx gear to work in */ - u32 pwm_tx_gear; /* pwm tx gear to work in */ - u32 hs_rx_gear; /* hs rx gear to work in */ - u32 hs_tx_gear; /* hs tx gear to work in */ - u32 rx_lanes; /* number of rx lanes */ - u32 tx_lanes; /* number of tx lanes */ - u32 rx_pwr_pwm; /* rx pwm working pwr */ - u32 tx_pwr_pwm; /* tx pwm working pwr */ - u32 rx_pwr_hs; /* rx hs working pwr */ - u32 tx_pwr_hs; /* tx hs working pwr */ - u32 hs_rate; /* rate A/B to work in HS */ - u32 desired_working_mode; -}; - -static int ufs_hisi_get_pwr_dev_param( - struct ufs_hisi_dev_params *hisi_param, - struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr) -{ - int min_hisi_gear; - int min_dev_gear; - bool is_dev_sup_hs = false; - bool is_hisi_max_hs = false; - - if (dev_max->pwr_rx == FASTAUTO_MODE || dev_max->pwr_rx == FAST_MODE) - is_dev_sup_hs = true; - - if (hisi_param->desired_working_mode == FAST) { - is_hisi_max_hs = true; - min_hisi_gear = min_t(u32, hisi_param->hs_rx_gear, - hisi_param->hs_tx_gear); - } else { - min_hisi_gear = min_t(u32, hisi_param->pwm_rx_gear, - hisi_param->pwm_tx_gear); - } - - /* - * device doesn't support HS but - * hisi_param->desired_working_mode is HS, - * thus device and hisi_param don't agree - */ - if (!is_dev_sup_hs && is_hisi_max_hs) { - pr_err("%s: device not support HS\n", __func__); - return -ENOTSUPP; - } else if (is_dev_sup_hs && is_hisi_max_hs) { - /* - * since device supports HS, it supports FAST_MODE. - * since hisi_param->desired_working_mode is also HS - * then final decision (FAST/FASTAUTO) is done according - * to hisi_params as it is the restricting factor - */ - agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = - hisi_param->rx_pwr_hs; - } else { - /* - * here hisi_param->desired_working_mode is PWM. - * it doesn't matter whether device supports HS or PWM, - * in both cases hisi_param->desired_working_mode will - * determine the mode - */ - agreed_pwr->pwr_rx = agreed_pwr->pwr_tx = - hisi_param->rx_pwr_pwm; - } - - /* - * we would like tx to work in the minimum number of lanes - * between device capability and vendor preferences. - * the same decision will be made for rx - */ - agreed_pwr->lane_tx = - min_t(u32, dev_max->lane_tx, hisi_param->tx_lanes); - agreed_pwr->lane_rx = - min_t(u32, dev_max->lane_rx, hisi_param->rx_lanes); - - /* device maximum gear is the minimum between device rx and tx gears */ - min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); - - /* - * if both device capabilities and vendor pre-defined preferences are - * both HS or both PWM then set the minimum gear to be the chosen - * working gear. - * if one is PWM and one is HS then the one that is PWM get to decide - * what is the gear, as it is the one that also decided previously what - * pwr the device will be configured to. - */ - if ((is_dev_sup_hs && is_hisi_max_hs) || - (!is_dev_sup_hs && !is_hisi_max_hs)) - agreed_pwr->gear_rx = agreed_pwr->gear_tx = - min_t(u32, min_dev_gear, min_hisi_gear); - else - agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_hisi_gear; - - agreed_pwr->hs_rate = hisi_param->hs_rate; - - pr_info("ufs final power mode: gear = %d, lane = %d, pwr = %d, rate = %d\n", - agreed_pwr->gear_rx, agreed_pwr->lane_rx, agreed_pwr->pwr_rx, - agreed_pwr->hs_rate); - return 0; -} - -static void ufs_hisi_set_dev_cap(struct ufs_hisi_dev_params *hisi_param) +static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param) { hisi_param->rx_lanes = UFS_HISI_LIMIT_NUM_LANES_RX; hisi_param->tx_lanes = UFS_HISI_LIMIT_NUM_LANES_TX; @@ -434,7 +333,7 @@ static int ufs_hi3660_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { - struct ufs_hisi_dev_params ufs_hisi_cap; + struct ufs_dev_params ufs_hisi_cap; int ret = 0; if (!dev_req_params) { @@ -447,8 +346,8 @@ static int ufs_hi3660_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: ufs_hisi_set_dev_cap(&ufs_hisi_cap); - ret = ufs_hisi_get_pwr_dev_param( - &ufs_hisi_cap, dev_max_params, dev_req_params); + ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap, + dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); From patchwork Mon Feb 25 09:24:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanley Chu X-Patchwork-Id: 10828371 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A4E961390 for ; Mon, 25 Feb 2019 09:24:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 925442AAD1 for ; Mon, 25 Feb 2019 09:24:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 860782ABEC; Mon, 25 Feb 2019 09:24:50 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham 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 1DABE2AAD1 for ; Mon, 25 Feb 2019 09:24:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726521AbfBYJYt (ORCPT ); Mon, 25 Feb 2019 04:24:49 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:57018 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726480AbfBYJYt (ORCPT ); Mon, 25 Feb 2019 04:24:49 -0500 X-UUID: 68209fb9717744b68a8a4e119bc6d3a5-20190225 X-UUID: 68209fb9717744b68a8a4e119bc6d3a5-20190225 Received: from mtkcas09.mediatek.inc [(172.21.101.178)] by mailgw02.mediatek.com (envelope-from ) (mhqrelay.mediatek.com ESMTP with TLS) with ESMTP id 637926081; Mon, 25 Feb 2019 17:24:38 +0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs02n2.mediatek.inc (172.21.101.101) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 25 Feb 2019 17:24:37 +0800 Received: from mtkswgap22.mediatek.inc (172.21.77.33) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 25 Feb 2019 17:24:37 +0800 From: To: , , , , , , , , , , CC: , , , , , , , , Stanley Chu Subject: [PATCH v2 4/6] dt-bindings: scsi: ufs: Add document for ufs-mediatek Date: Mon, 25 Feb 2019 17:24:13 +0800 Message-ID: <1551086655-5029-6-git-send-email-stanley.chu@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> References: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> MIME-Version: 1.0 X-TM-SNTS-SMTP: 8AAE95325725A3A413C9E91E1F6B23F0AF75B897BAF10258411EC160D7C29FD92000:8 X-MTK: N Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Stanley Chu Add UFS and UFS PHY node document for Mediatek SoC chips. Signed-off-by: Stanley Chu --- .../devicetree/bindings/ufs/ufs-mediatek.txt | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Documentation/devicetree/bindings/ufs/ufs-mediatek.txt diff --git a/Documentation/devicetree/bindings/ufs/ufs-mediatek.txt b/Documentation/devicetree/bindings/ufs/ufs-mediatek.txt new file mode 100644 index 000000000000..d73804687095 --- /dev/null +++ b/Documentation/devicetree/bindings/ufs/ufs-mediatek.txt @@ -0,0 +1,75 @@ +* Mediatek Universal Flash Storage (UFS) Host Controller + +UFS nodes are defined to describe on-chip UFS hardware macro. +Each UFS Host Controller should have its own node. + +UFS PHY nodes are defined to describe on-chip UFS PHY hardware macro. +Each UFS PHY node should have its own node. + +Required properties for UFS PHY nodes: +- compatible : Compatible list, contains the following controller: + "mediatek,ufs-mphy-12nm" +- reg : Address and length of the UFS PHY register set. +- reg-names : indicates various resources passed to driver (via reg proptery) by name. + Required "reg-names" is "ufs_mphy". +- #phy-cells : This property shall be set to 0 +- clocks : List of phandle and clock specifier pairs. +- clock-names : List of clock input name strings sorted in the same + order as the clocks property. "ufs0-unipro-clk" and + "ufs0-mp-clk" are mandatory. + +Required properties for UFS nodes: +- compatible : Compatible list, contains the following controller: + "mediatek,ufshci" +- reg : Address and length of the UFS register set. +- interrupt-parent : interrupt device. +- phys : PHandle to phy. +- phy-names : Name of phy. + Required "phy-name" is "ufsphy". +- clocks : List of phandle and clock specifier pairs. +- clock-names : List of clock input name strings sorted in the same + order as the clocks property. "ufs0-clock" is mandatory. +- freq-table-hz : Array of operating frequencies stored in the same + order as the clocks property. If this property is not + defined or a value in the array is "0" then it is assumed + that the frequency is set by the parent clock or a + fixed rate clock source. +- vcc-supply : Power to the UFS device. +- vcc-fixed-regulator: Specify that vcc-supply is a fixed regulator. +- lanes-per-direction: Number of lanes available per direction. Shall be 1. + +Example: + + ufs_mphy: ufs_mphy@11fa0000 { + compatible = "mediatek,ufs-mphy-12nm"; + reg = <0 0x11fa0000 0 0xc000>; + reg-names = "ufs_mphy"; + #phy-cells = <0>; + + clocks = + <&infracfg_ao INFRACFG_AO_UNIPRO_SCK_CG>, + <&infracfg_ao INFRACFG_AO_UFS_MP_SAP_BCLK_CG>; + clock-names = + "ufs0-unipro-clk", + "ufs0-mp-clk"; + }; + + ufshci:ufshci@11270000 { + compatible = "mediatek,ufshci"; + reg = <0 0x11270000 0 0x2300>; + interrupts = ; + phys = <&ufs_mphy>; + phy-names = "ufsphy"; + + clocks = + <&infracfg_ao INFRACFG_AO_UFS_CG>; + clock-names = + "ufs0-clock"; + freq-table-hz = + <0 0>; + + vcc-supply = <&mt_pmic_vemc_ldo_reg>; + vcc-fixed-regulator; + + lanes-per-direction = <1>; + }; From patchwork Mon Feb 25 09:24:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanley Chu X-Patchwork-Id: 10828369 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B7331922 for ; Mon, 25 Feb 2019 09:24:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A13F02AAD1 for ; Mon, 25 Feb 2019 09:24:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 94EA92ABF0; Mon, 25 Feb 2019 09:24:49 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham 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 53C942AAD1 for ; Mon, 25 Feb 2019 09:24:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726508AbfBYJYr (ORCPT ); Mon, 25 Feb 2019 04:24:47 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:59096 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726388AbfBYJYr (ORCPT ); Mon, 25 Feb 2019 04:24:47 -0500 X-UUID: d6aa8db25dad49c2a38c8eb7ec6400a7-20190225 X-UUID: d6aa8db25dad49c2a38c8eb7ec6400a7-20190225 Received: from mtkmrs01.mediatek.inc [(172.21.131.159)] by mailgw02.mediatek.com (envelope-from ) (mhqrelay.mediatek.com ESMTP with TLS) with ESMTP id 1949989532; Mon, 25 Feb 2019 17:24:38 +0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs03n1.mediatek.inc (172.21.101.181) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 25 Feb 2019 17:24:37 +0800 Received: from mtkswgap22.mediatek.inc (172.21.77.33) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 25 Feb 2019 17:24:37 +0800 From: To: , , , , , , , , , , CC: , , , , , , , , Stanley Chu Subject: [PATCH v2 5/6] phy: mediatek: Add UFS M-PHY driver Date: Mon, 25 Feb 2019 17:24:14 +0800 Message-ID: <1551086655-5029-7-git-send-email-stanley.chu@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> References: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> MIME-Version: 1.0 X-MTK: N Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Stanley Chu Add UFS M-PHY driver on Mediatek chipsets. Signed-off-by: Stanley Chu --- drivers/phy/mediatek/Kconfig | 29 ++-- drivers/phy/mediatek/Makefile | 2 + drivers/phy/mediatek/phy-mtk-ufs-12nm.c | 151 +++++++++++++++++++ drivers/phy/mediatek/phy-mtk-ufs-12nm.h | 52 +++++++ drivers/phy/mediatek/phy-mtk-ufs.c | 189 ++++++++++++++++++++++++ drivers/phy/mediatek/phy-mtk-ufs.h | 76 ++++++++++ 6 files changed, 489 insertions(+), 10 deletions(-) create mode 100644 drivers/phy/mediatek/phy-mtk-ufs-12nm.c create mode 100644 drivers/phy/mediatek/phy-mtk-ufs-12nm.h create mode 100644 drivers/phy/mediatek/phy-mtk-ufs.c create mode 100644 drivers/phy/mediatek/phy-mtk-ufs.h diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig index 8857d00b3c65..38c41836ef46 100644 --- a/drivers/phy/mediatek/Kconfig +++ b/drivers/phy/mediatek/Kconfig @@ -2,22 +2,31 @@ # Phy drivers for Mediatek devices # config PHY_MTK_TPHY - tristate "MediaTek T-PHY Driver" - depends on ARCH_MEDIATEK && OF - select GENERIC_PHY - help - Say 'Y' here to add support for MediaTek T-PHY driver, - it supports multiple usb2.0, usb3.0 ports, PCIe and + tristate "MediaTek T-PHY Driver" + depends on ARCH_MEDIATEK && OF + select GENERIC_PHY + help + Say 'Y' here to add support for MediaTek T-PHY driver, + it supports multiple usb2.0, usb3.0 ports, PCIe and SATA, and meanwhile supports two version T-PHY which have different banks layout, the T-PHY with shared banks between multi-ports is first version, otherwise is second veriosn, so you can easily distinguish them by banks layout. config PHY_MTK_XSPHY - tristate "MediaTek XS-PHY Driver" - depends on ARCH_MEDIATEK && OF - select GENERIC_PHY - help + tristate "MediaTek XS-PHY Driver" + depends on ARCH_MEDIATEK && OF + select GENERIC_PHY + help Enable this to support the SuperSpeedPlus XS-PHY transceiver for USB3.1 GEN2 controllers on MediaTek chips. The driver supports multiple USB2.0, USB3.1 GEN2 ports. + +config PHY_MTK_UFS + tristate "Mediatek UFS M-PHY driver" + depends on ARCH_MEDIATEK && OF + select GENERIC_PHY + help + Support for UFS M-PHY on MediaTek chipsets. Enable this to provide + vendor-specific initialization, power on and off flow of specified + M-PHYs. diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index ee49edc97ee9..e29b56b29d21 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile @@ -5,3 +5,5 @@ obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o +obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o +obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs-12nm.o diff --git a/drivers/phy/mediatek/phy-mtk-ufs-12nm.c b/drivers/phy/mediatek/phy-mtk-ufs-12nm.c new file mode 100644 index 000000000000..7ddcaaceafbd --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-ufs-12nm.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 MediaTek Inc. + * 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include +#include +#include +#include +#include +#include +#include "phy-mtk-ufs.h" +#include "phy-mtk-ufs-12nm.h" + +#define MPHY_NAME "ufs_phy_mtk_12nm" + +static void ufs_mtk_phy_12nm_power_on(struct ufs_mtk_phy *phy) +{ + /* release DA_MP_PLL_PWR_ON */ + mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); + mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + + /* release DA_MP_PLL_ISO_EN */ + mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); + mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + + /* release DA_MP_CDR_PWR_ON */ + mphy_set_bit(phy, MP_LN_RX_44, CDR_PWR_ON); + mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); + + /* release DA_MP_CDR_ISO_EN */ + mphy_clr_bit(phy, MP_LN_RX_44, CDR_ISO_EN); + mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); + + /* release DA_MP_RX0_SQ_EN */ + mphy_set_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); + mphy_clr_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + + /* delay 1us to wait DIFZ stable */ + udelay(1); + + /* release DIFZ */ + mphy_clr_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); +} + +static void ufs_mtk_phy_12nm_power_off(struct ufs_mtk_phy *phy) +{ + /* force DIFZ */ + mphy_set_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); + + /* force DA_MP_RX0_SQ_EN */ + mphy_set_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + mphy_clr_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); + + /* force DA_MP_CDR_ISO_EN */ + mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); + mphy_set_bit(phy, MP_LN_RX_44, CDR_ISO_EN); + + /* force DA_MP_CDR_PWR_ON */ + mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); + mphy_clr_bit(phy, MP_LN_RX_44, CDR_PWR_ON); + + /* force DA_MP_PLL_ISO_EN */ + mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); + + /* force DA_MP_PLL_PWR_ON */ + mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); +} + +static void ufs_mtk_phy_12nm_power_control(struct ufs_mtk_phy *phy, bool on) +{ + if (on) + ufs_mtk_phy_12nm_power_on(phy); + else + ufs_mtk_phy_12nm_power_off(phy); +} + +static const struct phy_ops ufs_mtk_phy_12nm_phy_ops = { + .power_on = ufs_mtk_phy_power_on, + .power_off = ufs_mtk_phy_power_off, + .owner = THIS_MODULE, +}; + +static struct ufs_mtk_phy_specific_ops phy_12nm_ops = { + .power_control = ufs_mtk_phy_12nm_power_control, +}; + +static int ufs_mtk_phy_12nm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy *generic_phy; + struct ufs_mtk_phy_12nm *phy; + int err = 0; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + err = -ENOMEM; + goto out; + } + + generic_phy = ufs_mtk_phy_generic_probe(pdev, &phy->common_cfg, + &ufs_mtk_phy_12nm_phy_ops, + &phy_12nm_ops); + + if (!generic_phy) { + dev_info(dev, "%s: ufs_mtk_phy_generic_probe() failed\n", + __func__); + err = -EIO; + goto out; + } + + phy_set_drvdata(generic_phy, phy); + + strlcpy(phy->common_cfg.name, MPHY_NAME, + sizeof(phy->common_cfg.name)); + + err = ufs_mtk_phy_init_clks(generic_phy, &phy->common_cfg); + if (err) { + dev_info(dev, + "%s: ufs_mtk_phy_init_clks() failed %d\n", + __func__, err); + } +out: + return err; +} + +static const struct of_device_id ufs_mtk_phy_12nm_of_match[] = { + {.compatible = "mediatek,ufs-mphy-12nm"}, + {}, +}; +MODULE_DEVICE_TABLE(of, ufs_mtk_phy_12nm_of_match); + +static struct platform_driver ufs_mtk_phy_12nm_driver = { + .probe = ufs_mtk_phy_12nm_probe, + .driver = { + .of_match_table = ufs_mtk_phy_12nm_of_match, + .name = "ufs_mtk_phy_12nm", + }, +}; +module_platform_driver(ufs_mtk_phy_12nm_driver); + +MODULE_DESCRIPTION("Universal Flash Storage (UFS) Mediatek MPHY 12nm"); diff --git a/drivers/phy/mediatek/phy-mtk-ufs-12nm.h b/drivers/phy/mediatek/phy-mtk-ufs-12nm.h new file mode 100644 index 000000000000..5ebcdbd8ec4d --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-ufs-12nm.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 MediaTek Inc. + * 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef UFS_MTK_PHY_12NM_H_ +#define UFS_MTK_PHY_12NM_H_ + +#include "phy-mtk-ufs.h" + +/* + * MPHY register and offsets + */ +#define MP_GLB_DIG_8C 0x008C +#define FRC_PLL_ISO_EN 0x00000100 +#define PLL_ISO_EN 0x00000200 +#define FRC_FRC_PWR_ON 0x00000400 +#define PLL_PWR_ON 0x00000800 + +#define MP_LN_DIG_RX_9C 0xA09C +#define FSM_DIFZ_FRC 0x00040000 + +#define MP_LN_DIG_RX_AC 0xA0AC +#define FRC_RX_SQ_EN 0x00000001 +#define RX_SQ_EN 0x00000002 + +#define MP_LN_RX_44 0xB044 +#define FRC_CDR_PWR_ON 0x00020000 +#define CDR_PWR_ON 0x00040000 +#define FRC_CDR_ISO_EN 0x00080000 +#define CDR_ISO_EN 0x00100000 + +/* + * This structure represents the 12nm specific phy. + * common_cfg MUST remain the first field in this structure + * in case extra fields are added. This way, when calling + * get_ufs_mtk_phy() of generic phy, we can extract the + * common phy structure (struct ufs_mtk_phy) out of it + * regardless of the relevant specific phy. + */ +struct ufs_mtk_phy_12nm { + struct ufs_mtk_phy common_cfg; +}; + +#endif diff --git a/drivers/phy/mediatek/phy-mtk-ufs.c b/drivers/phy/mediatek/phy-mtk-ufs.c new file mode 100644 index 000000000000..68ed27eaf195 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-ufs.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 MediaTek Inc. + * 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include +#include +#include +#include +#include +#include "phy-mtk-ufs.h" + +static int ufs_mtk_phy_base_init(struct platform_device *pdev, + struct ufs_mtk_phy *phy); + +struct phy +*ufs_mtk_phy_generic_probe(struct platform_device *pdev, + struct ufs_mtk_phy *common_cfg, + const struct phy_ops *ufs_mtk_phy_gen_ops, + struct ufs_mtk_phy_specific_ops *phy_spec_ops) +{ + int err; + struct device *dev = &pdev->dev; + struct phy *generic_phy = NULL; + struct phy_provider *phy_provider; + + err = ufs_mtk_phy_base_init(pdev, common_cfg); + if (err) { + dev_info(dev, "%s: phy base init failed %d\n", __func__, err); + goto out; + } + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + err = PTR_ERR(phy_provider); + dev_info(dev, "%s: failed to register phy %d\n", __func__, err); + goto out; + } + + generic_phy = devm_phy_create(dev, NULL, ufs_mtk_phy_gen_ops); + if (IS_ERR(generic_phy)) { + err = PTR_ERR(generic_phy); + dev_info(dev, "%s: failed to create phy %d\n", __func__, err); + generic_phy = NULL; + goto out; + } + + common_cfg->phy_spec_ops = phy_spec_ops; + common_cfg->dev = dev; + +out: + return generic_phy; +} +EXPORT_SYMBOL_GPL(ufs_mtk_phy_generic_probe); + +/* + * This assumes the embedded phy structure inside generic_phy is of type + * struct ufs_mtk_phy. In order to function properly it's crucial + * to keep the embedded struct "struct ufs_mtk_phy common_cfg" + * as the first inside generic_phy. + */ +struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) +{ + return (struct ufs_mtk_phy *)phy_get_drvdata(generic_phy); +} +EXPORT_SYMBOL_GPL(get_ufs_mtk_phy); + +static int ufs_mtk_phy_ctl_clk(struct ufs_mtk_phy *phy, + struct clk *clk, + bool on) +{ + int ret = 0; + + if (on) { + ret = clk_prepare_enable(clk); + if (ret) { + dev_info(phy->dev, + "%s: mp_clk enable failed %d\n", + __func__, ret); + goto out; + } + } else { + clk_disable_unprepare(clk); + } +out: + return ret; +} + +static int ufs_mtk_phy_ctl_clks(struct phy *generic_phy, bool on) +{ + struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); + int ret; + + ret = ufs_mtk_phy_ctl_clk(phy, phy->unipro_clk, on); + if (ret) + goto out; + + ret = ufs_mtk_phy_ctl_clk(phy, phy->mp_clk, on); +out: + return ret; +} +EXPORT_SYMBOL_GPL(ufs_mtk_phy_ctl_clks); + +static int ufs_mtk_phy_base_init(struct platform_device *pdev, + struct ufs_mtk_phy *phy) +{ + struct device *dev = &pdev->dev; + struct resource *res; + int err = 0; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ufs_mphy"); + phy->mmio = devm_ioremap_resource(dev, res); + if (IS_ERR((void const *)phy->mmio)) { + err = PTR_ERR((void const *)phy->mmio); + phy->mmio = NULL; + dev_info(dev, "%s: ioremap for ufs_mphy resource failed %d\n", + __func__, err); + return err; + } + + return 0; +} + +static +int ufs_mtk_phy_clk_get(struct phy *phy, + const char *name, struct clk **clk_out) +{ + struct clk *clk; + int err = 0; + struct ufs_mtk_phy *ufs_mtk_phy = get_ufs_mtk_phy(phy); + struct device *dev = ufs_mtk_phy->dev; + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + err = PTR_ERR(clk); + dev_info(dev, "failed to get %s err %d", name, err); + } else { + *clk_out = clk; + } + + return err; +} + +int ufs_mtk_phy_init_clks(struct phy *generic_phy, + struct ufs_mtk_phy *phy) +{ + int err; + + err = ufs_mtk_phy_clk_get(generic_phy, "ufs0-unipro-clk", + &phy->unipro_clk); + if (err) + goto out; + + err = ufs_mtk_phy_clk_get(generic_phy, "ufs0-mp-clk", + &phy->mp_clk); +out: + return err; +} +EXPORT_SYMBOL_GPL(ufs_mtk_phy_init_clks); + +int ufs_mtk_phy_power_on(struct phy *generic_phy) +{ + struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); + + ufs_mtk_phy_ctl_clks(generic_phy, true); + phy->phy_spec_ops->power_control(phy, true); + + return 0; +} +EXPORT_SYMBOL_GPL(ufs_mtk_phy_power_on); + +int ufs_mtk_phy_power_off(struct phy *generic_phy) +{ + struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); + + phy->phy_spec_ops->power_control(phy, false); + ufs_mtk_phy_ctl_clks(generic_phy, false); + + return 0; +} +EXPORT_SYMBOL_GPL(ufs_mtk_phy_power_off); + diff --git a/drivers/phy/mediatek/phy-mtk-ufs.h b/drivers/phy/mediatek/phy-mtk-ufs.h new file mode 100644 index 000000000000..7163aae2b56b --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-ufs.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 MediaTek Inc. + * 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef UFS_MTK_PHY_H_ +#define UFS_MTK_PHY_H_ + +#include +#include +#include +#include +#include + +#define UFS_MTK_PHY_NAME_LEN 30 + +#define mphy_readl(phy, ofs) readl((phy)->mmio + (ofs)) +#define mphy_writel(phy, val, ofs) writel((val), (phy)->mmio + (ofs)) + +#define mphy_set_bit(phy, reg, ofs) \ +do { \ + u32 val; \ + u32 _reg = (reg); \ + struct ufs_mtk_phy *_phy = (phy); \ + val = mphy_readl(_phy, _reg); \ + val = val | (ofs); \ + mphy_writel(_phy, val, _reg); \ +} while (0) + +#define mphy_clr_bit(phy, reg, ofs) \ +do { \ + u32 val; \ + u32 _reg = (reg); \ + struct ufs_mtk_phy *_phy = (phy); \ + val = mphy_readl(_phy, _reg); \ + val = val & ~(ofs); \ + mphy_writel(_phy, val, _reg); \ +} while (0) + +struct ufs_mtk_phy { + struct device *dev; + void __iomem *mmio; + struct clk *mp_clk; + struct clk *unipro_clk; + char name[UFS_MTK_PHY_NAME_LEN]; + struct ufs_mtk_phy_specific_ops *phy_spec_ops; +}; + +/** + * struct ufs_mtk_phy_specific_ops - set of pointers to functions which have a + * specific implementation per phy. Each UFS phy, should implement + * those functions according to its spec and requirements + * @power_control: Control power on/off flow of phy. + */ +struct ufs_mtk_phy_specific_ops { + void (*power_control)(struct ufs_mtk_phy *phy, bool on); +}; + +struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy); +int ufs_mtk_phy_power_on(struct phy *generic_phy); +int ufs_mtk_phy_power_off(struct phy *generic_phy); +int ufs_mtk_phy_init_clks(struct phy *generic_phy, + struct ufs_mtk_phy *phy_common); +struct phy +*ufs_mtk_phy_generic_probe(struct platform_device *pdev, + struct ufs_mtk_phy *common_cfg, + const struct phy_ops *ufs_mtk_phy_gen_ops, + struct ufs_mtk_phy_specific_ops *phy_spec_ops); +#endif From patchwork Mon Feb 25 09:24:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanley Chu X-Patchwork-Id: 10828377 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 762F81390 for ; Mon, 25 Feb 2019 09:24:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 60EB42ABF0 for ; Mon, 25 Feb 2019 09:24:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 54D3C2AC2A; Mon, 25 Feb 2019 09:24:54 +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=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY autolearn=ham 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 63B282ABF0 for ; Mon, 25 Feb 2019 09:24:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726527AbfBYJYw (ORCPT ); Mon, 25 Feb 2019 04:24:52 -0500 Received: from mailgw02.mediatek.com ([210.61.82.184]:38747 "EHLO mailgw02.mediatek.com" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726514AbfBYJYw (ORCPT ); Mon, 25 Feb 2019 04:24:52 -0500 X-UUID: b7f369a210de496585002e53a59eb878-20190225 X-UUID: b7f369a210de496585002e53a59eb878-20190225 Received: from mtkcas06.mediatek.inc [(172.21.101.30)] by mailgw02.mediatek.com (envelope-from ) (mhqrelay.mediatek.com ESMTP with TLS) with ESMTP id 429969470; Mon, 25 Feb 2019 17:24:39 +0800 Received: from mtkcas08.mediatek.inc (172.21.101.126) by mtkmbs08n1.mediatek.inc (172.21.101.55) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Mon, 25 Feb 2019 17:24:37 +0800 Received: from mtkswgap22.mediatek.inc (172.21.77.33) by mtkcas08.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1395.4 via Frontend Transport; Mon, 25 Feb 2019 17:24:37 +0800 From: To: , , , , , , , , , , CC: , , , , , , , , Stanley Chu Subject: [PATCH v2 6/6] scsi: ufs-mediatek: Add UFS support for Mediatek SoC chips Date: Mon, 25 Feb 2019 17:24:15 +0800 Message-ID: <1551086655-5029-8-git-send-email-stanley.chu@mediatek.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> References: <1551086655-5029-1-git-send-email-stanley.chu@mediatek.com> MIME-Version: 1.0 X-MTK: N Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Stanley Chu This patch adds UFS support for Mediatek SoC chips. Signed-off-by: Stanley Chu Reviewed-by: Avri Altman --- drivers/scsi/ufs/Kconfig | 14 ++ drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/ufs-mediatek.c | 377 ++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-mediatek.h | 61 ++++++ 4 files changed, 453 insertions(+) create mode 100644 drivers/scsi/ufs/ufs-mediatek.c create mode 100644 drivers/scsi/ufs/ufs-mediatek.h diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 2ddbb26d9c26..58e5a9c8eb5d 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -109,6 +109,20 @@ config SCSI_UFS_QCOM Select this if you have UFS controller on QCOM chipset. If unsure, say N. +config SCSI_UFS_MEDIATEK + tristate "Mediatek specific hooks to UFS controller platform driver" + depends on SCSI_UFSHCD_PLATFORM && ARCH_MEDIATEK + select PHY_MTK_UFS + help + This selects the Mediatek specific additions to UFSHCD platform driver. + UFS host on Mediatek needs some vendor specific configuration before + accessing the hardware which includes PHY configuration and vendor + specific registers. + + Select this if you have UFS controller on Mediatek chipset. + + If unsure, say N. + config SCSI_UFS_HISI tristate "Hisilicon specific hooks to UFS controller platform driver" depends on (ARCH_HISI || COMPILE_TEST) && SCSI_UFSHCD_PLATFORM diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index a3bd70c3652c..2a9097939bcb 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -10,3 +10,4 @@ ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o +obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c new file mode 100644 index 000000000000..ce633dff5888 --- /dev/null +++ b/drivers/scsi/ufs/ufs-mediatek.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Authors: + * Stanley Chu + * Peter Wang + * + * Copyright (C) 2019 MediaTek Inc. + * 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include +#include +#include +#include + +#include "ufshcd.h" +#include "ufshcd-pltfrm.h" +#include "unipro.h" +#include "ufs-mediatek.h" + +void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) +{ + u32 tmp; + + if (enable) { + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + tmp = tmp | + (1 << RX_SYMBOL_CLK_GATE_EN) | + (1 << SYS_CLK_GATE_EN) | + (1 << TX_CLK_GATE_EN); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp); + tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp); + } else { + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) | + (1 << SYS_CLK_GATE_EN) | + (1 << TX_CLK_GATE_EN)); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp); + tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp); + } +} + +int ufs_mtk_bind_mphy(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + struct device *dev = hba->dev; + int err = 0; + + host->mphy = devm_phy_get(dev, "ufsphy"); + + if (host->mphy == ERR_PTR(-EPROBE_DEFER)) { + /* + * UFS driver might be probed before the phy driver does. + * In that case we would like to return EPROBE_DEFER code. + */ + err = -EPROBE_DEFER; + dev_info(dev, + "%s: required phy hasn't probed yet. err = %d\n", + __func__, err); + } else if (IS_ERR(host->mphy)) { + err = PTR_ERR(host->mphy); + dev_info(dev, "%s: PHY get failed %d\n", __func__, err); + } + + if (err) + host->mphy = NULL; + + return err; +} + +/** + * ufs_mtk_setup_clocks - enables/disable clocks + * @hba: host controller instance + * @on: If true, enable clocks else disable them. + * @status: PRE_CHANGE or POST_CHANGE notify + * + * Returns 0 on success, non-zero on failure. + */ +static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on, + enum ufs_notify_change_status status) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + int ret; + + /* + * In case ufs_mtk_init() is not yet done, simply ignore. + * This ufs_mtk_setup_clocks() shall be called from + * ufs_mtk_init() after init is done. + */ + if (!host) + return 0; + + switch (status) { + case PRE_CHANGE: + if (!on) + ret = phy_power_off(host->mphy); + break; + case POST_CHANGE: + if (on) { + pr_info("%s: phy_power_on\n", __func__); + ret = phy_power_on(host->mphy); + } + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * ufs_mtk_init - find other essential mmio bases + * @hba: host controller instance + * + * Binds PHY with controller and powers up PHY enabling clocks + * and regulators. + * + * Returns -EPROBE_DEFER if binding fails, returns negative error + * on phy power up failure and returns zero on success. + */ +static int ufs_mtk_init(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host; + struct device *dev = hba->dev; + int err = 0; + + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) { + err = -ENOMEM; + dev_info(dev, "%s: no memory for mtk ufs host\n", __func__); + goto out; + } + + host->hba = hba; + ufshcd_set_variant(hba, host); + + err = ufs_mtk_bind_mphy(hba); + if (err) + goto out_variant_clear; + + /* + * ufshcd_vops_init() is invoked after + * ufshcd_setup_clock(true) in ufshcd_hba_init() thus + * phy clock setup is skipped. + * + * Enable phy clocks specifically here. + */ + ufs_mtk_setup_clocks(hba, true, POST_CHANGE); + + goto out; + +out_variant_clear: + ufshcd_set_variant(hba, NULL); +out: + return err; +} + +static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, + struct ufs_pa_layer_attr *dev_max_params, + struct ufs_pa_layer_attr *dev_req_params) +{ + struct ufs_dev_params host_cap; + int ret; + + host_cap.tx_lanes = UFS_MTK_LIMIT_NUM_LANES_TX; + host_cap.rx_lanes = UFS_MTK_LIMIT_NUM_LANES_RX; + host_cap.hs_rx_gear = UFS_MTK_LIMIT_HSGEAR_RX; + host_cap.hs_tx_gear = UFS_MTK_LIMIT_HSGEAR_TX; + host_cap.pwm_rx_gear = UFS_MTK_LIMIT_PWMGEAR_RX; + host_cap.pwm_tx_gear = UFS_MTK_LIMIT_PWMGEAR_TX; + host_cap.rx_pwr_pwm = UFS_MTK_LIMIT_RX_PWR_PWM; + host_cap.tx_pwr_pwm = UFS_MTK_LIMIT_TX_PWR_PWM; + host_cap.rx_pwr_hs = UFS_MTK_LIMIT_RX_PWR_HS; + host_cap.tx_pwr_hs = UFS_MTK_LIMIT_TX_PWR_HS; + host_cap.hs_rate = UFS_MTK_LIMIT_HS_RATE; + host_cap.desired_working_mode = + UFS_MTK_LIMIT_DESIRED_MODE; + + ret = ufshcd_get_pwr_dev_param(&host_cap, + dev_max_params, + dev_req_params); + if (ret) { + pr_info("%s: failed to determine capabilities\n", + __func__); + } + + return ret; +} + +static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba, + enum ufs_notify_change_status stage, + struct ufs_pa_layer_attr *dev_max_params, + struct ufs_pa_layer_attr *dev_req_params) +{ + int ret = 0; + + switch (stage) { + case PRE_CHANGE: + ret = ufs_mtk_pre_pwr_change(hba, dev_max_params, + dev_req_params); + break; + case POST_CHANGE: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ufs_mtk_pre_link(struct ufs_hba *hba) +{ + int ret; + u32 tmp; + + /* disable deep stall */ + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + if (ret) + return ret; + + tmp &= ~(1 << 6); + + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + + return ret; +} + +static int ufs_mtk_post_link(struct ufs_hba *hba) +{ + /* disable device LCC */ + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); + + /* enable unipro clock gating feature */ + ufs_mtk_cfg_unipro_cg(hba, true); + + return 0; +} + +static int ufs_mtk_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status stage) +{ + int ret = 0; + + switch (stage) { + case PRE_CHANGE: + ret = ufs_mtk_pre_link(hba); + break; + case POST_CHANGE: + ret = ufs_mtk_post_link(hba); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + if (ufshcd_is_link_hibern8(hba)) + phy_power_off(host->mphy); + + return 0; +} + +static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct ufs_mtk_host *host = ufshcd_get_variant(hba); + + if (ufshcd_is_link_hibern8(hba)) + phy_power_on(host->mphy); + + return 0; +} + +/** + * struct ufs_hba_mtk_vops - UFS MTK specific variant operations + * + * The variant operations configure the necessary controller and PHY + * handshake during initialization. + */ +static struct ufs_hba_variant_ops ufs_hba_mtk_vops = { + .name = "mediatek.ufshci", + .init = ufs_mtk_init, + .setup_clocks = ufs_mtk_setup_clocks, + .link_startup_notify = ufs_mtk_link_startup_notify, + .pwr_change_notify = ufs_mtk_pwr_change_notify, + .suspend = ufs_mtk_suspend, + .resume = ufs_mtk_resume, +}; + +/** + * ufs_mtk_probe - probe routine of the driver + * @pdev: pointer to Platform device handle + * + * Return zero for success and non-zero for failure + */ +static int ufs_mtk_probe(struct platform_device *pdev) +{ + int err; + struct device *dev = &pdev->dev; + + /* perform generic probe */ + err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops); + if (err) + dev_info(dev, "probe failed %d\n", err); + + return err; +} + +/** + * ufs_mtk_remove - set driver_data of the device to NULL + * @pdev: pointer to platform device handle + * + * Always return 0 + */ +static int ufs_mtk_remove(struct platform_device *pdev) +{ + struct ufs_hba *hba = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&(pdev)->dev); + ufshcd_remove(hba); + return 0; +} + +const struct of_device_id ufs_mtk_of_match[] = { + { .compatible = "mediatek,ufshci"}, + {}, +}; + +static const struct dev_pm_ops ufs_mtk_pm_ops = { + .suspend = ufshcd_pltfrm_suspend, + .resume = ufshcd_pltfrm_resume, + .runtime_suspend = ufshcd_pltfrm_runtime_suspend, + .runtime_resume = ufshcd_pltfrm_runtime_resume, + .runtime_idle = ufshcd_pltfrm_runtime_idle, +}; + +static struct platform_driver ufs_mtk_pltform = { + .probe = ufs_mtk_probe, + .remove = ufs_mtk_remove, + .shutdown = ufshcd_pltfrm_shutdown, + .driver = { + .name = "ufshcd-mtk", + .owner = THIS_MODULE, + .pm = &ufs_mtk_pm_ops, + .of_match_table = ufs_mtk_of_match, + }, +}; + +module_platform_driver(ufs_mtk_pltform); + diff --git a/drivers/scsi/ufs/ufs-mediatek.h b/drivers/scsi/ufs/ufs-mediatek.h new file mode 100644 index 000000000000..3c964e5d9077 --- /dev/null +++ b/drivers/scsi/ufs/ufs-mediatek.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 MediaTek Inc. + * 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. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _UFS_MEDIATEK_H +#define _UFS_MEDIATEK_H + +/* + * Vendor specific pre-defined parameters + */ +#define UFS_MTK_LIMIT_NUM_LANES_RX 1 +#define UFS_MTK_LIMIT_NUM_LANES_TX 1 +#define UFS_MTK_LIMIT_HSGEAR_RX UFS_HS_G3 +#define UFS_MTK_LIMIT_HSGEAR_TX UFS_HS_G3 +#define UFS_MTK_LIMIT_PWMGEAR_RX UFS_PWM_G4 +#define UFS_MTK_LIMIT_PWMGEAR_TX UFS_PWM_G4 +#define UFS_MTK_LIMIT_RX_PWR_PWM SLOW_MODE +#define UFS_MTK_LIMIT_TX_PWR_PWM SLOW_MODE +#define UFS_MTK_LIMIT_RX_PWR_HS FAST_MODE +#define UFS_MTK_LIMIT_TX_PWR_HS FAST_MODE +#define UFS_MTK_LIMIT_HS_RATE PA_HS_MODE_B +#define UFS_MTK_LIMIT_DESIRED_MODE UFS_HS_MODE + +/* + * Other attributes + */ +#define VS_DEBUGCLOCKENABLE 0xD0A1 +#define VS_SAVEPOWERCONTROL 0xD0A6 +#define VS_UNIPROPOWERDOWNCONTROL 0xD0A8 + +/* + * VS_DEBUGCLOCKENABLE + */ +enum { + TX_SYMBOL_CLK_REQ_FORCE = 5, +}; + +/* + * VS_SAVEPOWERCONTROL + */ +enum { + RX_SYMBOL_CLK_GATE_EN = 0, + SYS_CLK_GATE_EN = 2, + TX_CLK_GATE_EN = 3, +}; + +struct ufs_mtk_host { + struct ufs_hba *hba; + struct phy *mphy; +}; + +#endif /* !_UFS_MEDIATEK_H */ +