xref: /openbmc/linux/drivers/ufs/host/ufs-mediatek.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1dd11376bSBart Van Assche // SPDX-License-Identifier: GPL-2.0
2dd11376bSBart Van Assche /*
3dd11376bSBart Van Assche  * Copyright (C) 2019 MediaTek Inc.
4dd11376bSBart Van Assche  * Authors:
5dd11376bSBart Van Assche  *	Stanley Chu <stanley.chu@mediatek.com>
6dd11376bSBart Van Assche  *	Peter Wang <peter.wang@mediatek.com>
7dd11376bSBart Van Assche  */
8dd11376bSBart Van Assche 
9dd11376bSBart Van Assche #include <linux/arm-smccc.h>
10dd11376bSBart Van Assche #include <linux/bitfield.h>
11dd11376bSBart Van Assche #include <linux/clk.h>
12dd11376bSBart Van Assche #include <linux/delay.h>
13dd11376bSBart Van Assche #include <linux/module.h>
14dd11376bSBart Van Assche #include <linux/of.h>
15dd11376bSBart Van Assche #include <linux/of_address.h>
16dd11376bSBart Van Assche #include <linux/of_device.h>
17c2ab6660SRob Herring #include <linux/of_platform.h>
18dd11376bSBart Van Assche #include <linux/phy/phy.h>
19dd11376bSBart Van Assche #include <linux/platform_device.h>
20c64c487dSPeter Wang #include <linux/pm_qos.h>
21dd11376bSBart Van Assche #include <linux/regulator/consumer.h>
22dd11376bSBart Van Assche #include <linux/reset.h>
23dd11376bSBart Van Assche #include <linux/soc/mediatek/mtk_sip_svc.h>
24dd11376bSBart Van Assche 
25dd11376bSBart Van Assche #include <ufs/ufshcd.h>
26dd11376bSBart Van Assche #include "ufshcd-pltfrm.h"
27dd11376bSBart Van Assche #include <ufs/ufs_quirks.h>
28dd11376bSBart Van Assche #include <ufs/unipro.h>
29dd11376bSBart Van Assche #include "ufs-mediatek.h"
30dd11376bSBart Van Assche 
31e152a616SPo-Wen Kao static int  ufs_mtk_config_mcq(struct ufs_hba *hba, bool irq);
32e152a616SPo-Wen Kao 
33dd11376bSBart Van Assche #define CREATE_TRACE_POINTS
34dd11376bSBart Van Assche #include "ufs-mediatek-trace.h"
35e152a616SPo-Wen Kao #undef CREATE_TRACE_POINTS
36e152a616SPo-Wen Kao 
37e152a616SPo-Wen Kao #define MAX_SUPP_MAC 64
38e152a616SPo-Wen Kao #define MCQ_QUEUE_OFFSET(c) ((((c) >> 16) & 0xFF) * 0x200)
39dd11376bSBart Van Assche 
40dd11376bSBart Van Assche static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = {
41981b4ac0SPeter Wang 	{ .wmanufacturerid = UFS_ANY_VENDOR,
42dd11376bSBart Van Assche 	  .model = UFS_ANY_MODEL,
43981b4ac0SPeter Wang 	  .quirk = UFS_DEVICE_QUIRK_DELAY_AFTER_LPM |
44981b4ac0SPeter Wang 		UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM },
45dd11376bSBart Van Assche 	{ .wmanufacturerid = UFS_VENDOR_SKHYNIX,
46dd11376bSBart Van Assche 	  .model = "H9HQ21AFAMZDAR",
47dd11376bSBart Van Assche 	  .quirk = UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES },
48dd11376bSBart Van Assche 	{}
49dd11376bSBart Van Assche };
50dd11376bSBart Van Assche 
51dd11376bSBart Van Assche static const struct of_device_id ufs_mtk_of_match[] = {
52dd11376bSBart Van Assche 	{ .compatible = "mediatek,mt8183-ufshci" },
53dd11376bSBart Van Assche 	{},
54dd11376bSBart Van Assche };
55dd11376bSBart Van Assche 
564d869fe6SStanley Chu /*
574d869fe6SStanley Chu  * Details of UIC Errors
584d869fe6SStanley Chu  */
594d869fe6SStanley Chu static const char *const ufs_uic_err_str[] = {
604d869fe6SStanley Chu 	"PHY Adapter Layer",
614d869fe6SStanley Chu 	"Data Link Layer",
624d869fe6SStanley Chu 	"Network Link Layer",
634d869fe6SStanley Chu 	"Transport Link Layer",
644d869fe6SStanley Chu 	"DME"
654d869fe6SStanley Chu };
664d869fe6SStanley Chu 
674d869fe6SStanley Chu static const char *const ufs_uic_pa_err_str[] = {
684d869fe6SStanley Chu 	"PHY error on Lane 0",
694d869fe6SStanley Chu 	"PHY error on Lane 1",
704d869fe6SStanley Chu 	"PHY error on Lane 2",
714d869fe6SStanley Chu 	"PHY error on Lane 3",
724d869fe6SStanley Chu 	"Generic PHY Adapter Error. This should be the LINERESET indication"
734d869fe6SStanley Chu };
744d869fe6SStanley Chu 
754d869fe6SStanley Chu static const char *const ufs_uic_dl_err_str[] = {
764d869fe6SStanley Chu 	"NAC_RECEIVED",
774d869fe6SStanley Chu 	"TCx_REPLAY_TIMER_EXPIRED",
784d869fe6SStanley Chu 	"AFCx_REQUEST_TIMER_EXPIRED",
794d869fe6SStanley Chu 	"FCx_PROTECTION_TIMER_EXPIRED",
804d869fe6SStanley Chu 	"CRC_ERROR",
814d869fe6SStanley Chu 	"RX_BUFFER_OVERFLOW",
824d869fe6SStanley Chu 	"MAX_FRAME_LENGTH_EXCEEDED",
834d869fe6SStanley Chu 	"WRONG_SEQUENCE_NUMBER",
844d869fe6SStanley Chu 	"AFC_FRAME_SYNTAX_ERROR",
854d869fe6SStanley Chu 	"NAC_FRAME_SYNTAX_ERROR",
864d869fe6SStanley Chu 	"EOF_SYNTAX_ERROR",
874d869fe6SStanley Chu 	"FRAME_SYNTAX_ERROR",
884d869fe6SStanley Chu 	"BAD_CTRL_SYMBOL_TYPE",
894d869fe6SStanley Chu 	"PA_INIT_ERROR",
904d869fe6SStanley Chu 	"PA_ERROR_IND_RECEIVED",
914d869fe6SStanley Chu 	"PA_INIT"
924d869fe6SStanley Chu };
934d869fe6SStanley Chu 
ufs_mtk_is_boost_crypt_enabled(struct ufs_hba * hba)94dd11376bSBart Van Assche static bool ufs_mtk_is_boost_crypt_enabled(struct ufs_hba *hba)
95dd11376bSBart Van Assche {
96dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
97dd11376bSBart Van Assche 
98dd11376bSBart Van Assche 	return !!(host->caps & UFS_MTK_CAP_BOOST_CRYPT_ENGINE);
99dd11376bSBart Van Assche }
100dd11376bSBart Van Assche 
ufs_mtk_is_va09_supported(struct ufs_hba * hba)101dd11376bSBart Van Assche static bool ufs_mtk_is_va09_supported(struct ufs_hba *hba)
102dd11376bSBart Van Assche {
103dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
104dd11376bSBart Van Assche 
105dd11376bSBart Van Assche 	return !!(host->caps & UFS_MTK_CAP_VA09_PWR_CTRL);
106dd11376bSBart Van Assche }
107dd11376bSBart Van Assche 
ufs_mtk_is_broken_vcc(struct ufs_hba * hba)108dd11376bSBart Van Assche static bool ufs_mtk_is_broken_vcc(struct ufs_hba *hba)
109dd11376bSBart Van Assche {
110dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
111dd11376bSBart Van Assche 
112dd11376bSBart Van Assche 	return !!(host->caps & UFS_MTK_CAP_BROKEN_VCC);
113dd11376bSBart Van Assche }
114dd11376bSBart Van Assche 
ufs_mtk_is_pmc_via_fastauto(struct ufs_hba * hba)1153f9b6cecSCC Chou static bool ufs_mtk_is_pmc_via_fastauto(struct ufs_hba *hba)
1163f9b6cecSCC Chou {
1173f9b6cecSCC Chou 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
1183f9b6cecSCC Chou 
11996a2dfa1SChanWoo Lee 	return !!(host->caps & UFS_MTK_CAP_PMC_VIA_FASTAUTO);
1203f9b6cecSCC Chou }
1213f9b6cecSCC Chou 
ufs_mtk_cfg_unipro_cg(struct ufs_hba * hba,bool enable)122dd11376bSBart Van Assche static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
123dd11376bSBart Van Assche {
124dd11376bSBart Van Assche 	u32 tmp;
125dd11376bSBart Van Assche 
126dd11376bSBart Van Assche 	if (enable) {
127dd11376bSBart Van Assche 		ufshcd_dme_get(hba,
128dd11376bSBart Van Assche 			       UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
129dd11376bSBart Van Assche 		tmp = tmp |
130dd11376bSBart Van Assche 		      (1 << RX_SYMBOL_CLK_GATE_EN) |
131dd11376bSBart Van Assche 		      (1 << SYS_CLK_GATE_EN) |
132dd11376bSBart Van Assche 		      (1 << TX_CLK_GATE_EN);
133dd11376bSBart Van Assche 		ufshcd_dme_set(hba,
134dd11376bSBart Van Assche 			       UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
135dd11376bSBart Van Assche 
136dd11376bSBart Van Assche 		ufshcd_dme_get(hba,
137dd11376bSBart Van Assche 			       UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
138dd11376bSBart Van Assche 		tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE);
139dd11376bSBart Van Assche 		ufshcd_dme_set(hba,
140dd11376bSBart Van Assche 			       UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
141dd11376bSBart Van Assche 	} else {
142dd11376bSBart Van Assche 		ufshcd_dme_get(hba,
143dd11376bSBart Van Assche 			       UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
144dd11376bSBart Van Assche 		tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) |
145dd11376bSBart Van Assche 			      (1 << SYS_CLK_GATE_EN) |
146dd11376bSBart Van Assche 			      (1 << TX_CLK_GATE_EN));
147dd11376bSBart Van Assche 		ufshcd_dme_set(hba,
148dd11376bSBart Van Assche 			       UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
149dd11376bSBart Van Assche 
150dd11376bSBart Van Assche 		ufshcd_dme_get(hba,
151dd11376bSBart Van Assche 			       UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
152dd11376bSBart Van Assche 		tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE);
153dd11376bSBart Van Assche 		ufshcd_dme_set(hba,
154dd11376bSBart Van Assche 			       UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
155dd11376bSBart Van Assche 	}
156dd11376bSBart Van Assche }
157dd11376bSBart Van Assche 
ufs_mtk_crypto_enable(struct ufs_hba * hba)158dd11376bSBart Van Assche static void ufs_mtk_crypto_enable(struct ufs_hba *hba)
159dd11376bSBart Van Assche {
160dd11376bSBart Van Assche 	struct arm_smccc_res res;
161dd11376bSBart Van Assche 
162dd11376bSBart Van Assche 	ufs_mtk_crypto_ctrl(res, 1);
163dd11376bSBart Van Assche 	if (res.a0) {
164dd11376bSBart Van Assche 		dev_info(hba->dev, "%s: crypto enable failed, err: %lu\n",
165dd11376bSBart Van Assche 			 __func__, res.a0);
166dd11376bSBart Van Assche 		hba->caps &= ~UFSHCD_CAP_CRYPTO;
167dd11376bSBart Van Assche 	}
168dd11376bSBart Van Assche }
169dd11376bSBart Van Assche 
ufs_mtk_host_reset(struct ufs_hba * hba)170dd11376bSBart Van Assche static void ufs_mtk_host_reset(struct ufs_hba *hba)
171dd11376bSBart Van Assche {
172dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
173dd11376bSBart Van Assche 
174dd11376bSBart Van Assche 	reset_control_assert(host->hci_reset);
175dd11376bSBart Van Assche 	reset_control_assert(host->crypto_reset);
176dd11376bSBart Van Assche 	reset_control_assert(host->unipro_reset);
177dd11376bSBart Van Assche 
178dd11376bSBart Van Assche 	usleep_range(100, 110);
179dd11376bSBart Van Assche 
180dd11376bSBart Van Assche 	reset_control_deassert(host->unipro_reset);
181dd11376bSBart Van Assche 	reset_control_deassert(host->crypto_reset);
182dd11376bSBart Van Assche 	reset_control_deassert(host->hci_reset);
183dd11376bSBart Van Assche }
184dd11376bSBart Van Assche 
ufs_mtk_init_reset_control(struct ufs_hba * hba,struct reset_control ** rc,char * str)185dd11376bSBart Van Assche static void ufs_mtk_init_reset_control(struct ufs_hba *hba,
186dd11376bSBart Van Assche 				       struct reset_control **rc,
187dd11376bSBart Van Assche 				       char *str)
188dd11376bSBart Van Assche {
189dd11376bSBart Van Assche 	*rc = devm_reset_control_get(hba->dev, str);
190dd11376bSBart Van Assche 	if (IS_ERR(*rc)) {
191dd11376bSBart Van Assche 		dev_info(hba->dev, "Failed to get reset control %s: %ld\n",
192dd11376bSBart Van Assche 			 str, PTR_ERR(*rc));
193dd11376bSBart Van Assche 		*rc = NULL;
194dd11376bSBart Van Assche 	}
195dd11376bSBart Van Assche }
196dd11376bSBart Van Assche 
ufs_mtk_init_reset(struct ufs_hba * hba)197dd11376bSBart Van Assche static void ufs_mtk_init_reset(struct ufs_hba *hba)
198dd11376bSBart Van Assche {
199dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
200dd11376bSBart Van Assche 
201dd11376bSBart Van Assche 	ufs_mtk_init_reset_control(hba, &host->hci_reset,
202dd11376bSBart Van Assche 				   "hci_rst");
203dd11376bSBart Van Assche 	ufs_mtk_init_reset_control(hba, &host->unipro_reset,
204dd11376bSBart Van Assche 				   "unipro_rst");
205dd11376bSBart Van Assche 	ufs_mtk_init_reset_control(hba, &host->crypto_reset,
206dd11376bSBart Van Assche 				   "crypto_rst");
207dd11376bSBart Van Assche }
208dd11376bSBart Van Assche 
ufs_mtk_hce_enable_notify(struct ufs_hba * hba,enum ufs_notify_change_status status)209dd11376bSBart Van Assche static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba,
210dd11376bSBart Van Assche 				     enum ufs_notify_change_status status)
211dd11376bSBart Van Assche {
212dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
213dd11376bSBart Van Assche 
214dd11376bSBart Van Assche 	if (status == PRE_CHANGE) {
215dd11376bSBart Van Assche 		if (host->unipro_lpm) {
216dd11376bSBart Van Assche 			hba->vps->hba_enable_delay_us = 0;
217dd11376bSBart Van Assche 		} else {
218dd11376bSBart Van Assche 			hba->vps->hba_enable_delay_us = 600;
219dd11376bSBart Van Assche 			ufs_mtk_host_reset(hba);
220dd11376bSBart Van Assche 		}
221dd11376bSBart Van Assche 
222dd11376bSBart Van Assche 		if (hba->caps & UFSHCD_CAP_CRYPTO)
223dd11376bSBart Van Assche 			ufs_mtk_crypto_enable(hba);
224dd11376bSBart Van Assche 
225dd11376bSBart Van Assche 		if (host->caps & UFS_MTK_CAP_DISABLE_AH8) {
226dd11376bSBart Van Assche 			ufshcd_writel(hba, 0,
227dd11376bSBart Van Assche 				      REG_AUTO_HIBERNATE_IDLE_TIMER);
228dd11376bSBart Van Assche 			hba->capabilities &= ~MASK_AUTO_HIBERN8_SUPPORT;
229dd11376bSBart Van Assche 			hba->ahit = 0;
230dd11376bSBart Van Assche 		}
2312bae03a6SPeter Wang 
2322bae03a6SPeter Wang 		/*
2332bae03a6SPeter Wang 		 * Turn on CLK_CG early to bypass abnormal ERR_CHK signal
2342bae03a6SPeter Wang 		 * to prevent host hang issue
2352bae03a6SPeter Wang 		 */
2362bae03a6SPeter Wang 		ufshcd_writel(hba,
2372bae03a6SPeter Wang 			      ufshcd_readl(hba, REG_UFS_XOUFS_CTRL) | 0x80,
2382bae03a6SPeter Wang 			      REG_UFS_XOUFS_CTRL);
239dd11376bSBart Van Assche 	}
240dd11376bSBart Van Assche 
241dd11376bSBart Van Assche 	return 0;
242dd11376bSBart Van Assche }
243dd11376bSBart Van Assche 
ufs_mtk_bind_mphy(struct ufs_hba * hba)244dd11376bSBart Van Assche static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
245dd11376bSBart Van Assche {
246dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
247dd11376bSBart Van Assche 	struct device *dev = hba->dev;
248dd11376bSBart Van Assche 	struct device_node *np = dev->of_node;
249dd11376bSBart Van Assche 	int err = 0;
250dd11376bSBart Van Assche 
251dd11376bSBart Van Assche 	host->mphy = devm_of_phy_get_by_index(dev, np, 0);
252dd11376bSBart Van Assche 
253dd11376bSBart Van Assche 	if (host->mphy == ERR_PTR(-EPROBE_DEFER)) {
254dd11376bSBart Van Assche 		/*
255dd11376bSBart Van Assche 		 * UFS driver might be probed before the phy driver does.
256dd11376bSBart Van Assche 		 * In that case we would like to return EPROBE_DEFER code.
257dd11376bSBart Van Assche 		 */
258dd11376bSBart Van Assche 		err = -EPROBE_DEFER;
259dd11376bSBart Van Assche 		dev_info(dev,
260dd11376bSBart Van Assche 			 "%s: required phy hasn't probed yet. err = %d\n",
261dd11376bSBart Van Assche 			__func__, err);
262dd11376bSBart Van Assche 	} else if (IS_ERR(host->mphy)) {
263dd11376bSBart Van Assche 		err = PTR_ERR(host->mphy);
264dd11376bSBart Van Assche 		if (err != -ENODEV) {
265dd11376bSBart Van Assche 			dev_info(dev, "%s: PHY get failed %d\n", __func__,
266dd11376bSBart Van Assche 				 err);
267dd11376bSBart Van Assche 		}
268dd11376bSBart Van Assche 	}
269dd11376bSBart Van Assche 
270dd11376bSBart Van Assche 	if (err)
271dd11376bSBart Van Assche 		host->mphy = NULL;
272dd11376bSBart Van Assche 	/*
273dd11376bSBart Van Assche 	 * Allow unbound mphy because not every platform needs specific
274dd11376bSBart Van Assche 	 * mphy control.
275dd11376bSBart Van Assche 	 */
276dd11376bSBart Van Assche 	if (err == -ENODEV)
277dd11376bSBart Van Assche 		err = 0;
278dd11376bSBart Van Assche 
279dd11376bSBart Van Assche 	return err;
280dd11376bSBart Van Assche }
281dd11376bSBart Van Assche 
ufs_mtk_setup_ref_clk(struct ufs_hba * hba,bool on)282dd11376bSBart Van Assche static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on)
283dd11376bSBart Van Assche {
284dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
285dd11376bSBart Van Assche 	struct arm_smccc_res res;
286dd11376bSBart Van Assche 	ktime_t timeout, time_checked;
287dd11376bSBart Van Assche 	u32 value;
288dd11376bSBart Van Assche 
289dd11376bSBart Van Assche 	if (host->ref_clk_enabled == on)
290dd11376bSBart Van Assche 		return 0;
291dd11376bSBart Van Assche 
292f53f1913SPeter Wang 	ufs_mtk_ref_clk_notify(on, PRE_CHANGE, res);
293f53f1913SPeter Wang 
294dd11376bSBart Van Assche 	if (on) {
295dd11376bSBart Van Assche 		ufshcd_writel(hba, REFCLK_REQUEST, REG_UFS_REFCLK_CTRL);
296dd11376bSBart Van Assche 	} else {
297dd11376bSBart Van Assche 		ufshcd_delay_us(host->ref_clk_gating_wait_us, 10);
298dd11376bSBart Van Assche 		ufshcd_writel(hba, REFCLK_RELEASE, REG_UFS_REFCLK_CTRL);
299dd11376bSBart Van Assche 	}
300dd11376bSBart Van Assche 
301dd11376bSBart Van Assche 	/* Wait for ack */
302dd11376bSBart Van Assche 	timeout = ktime_add_us(ktime_get(), REFCLK_REQ_TIMEOUT_US);
303dd11376bSBart Van Assche 	do {
304dd11376bSBart Van Assche 		time_checked = ktime_get();
305dd11376bSBart Van Assche 		value = ufshcd_readl(hba, REG_UFS_REFCLK_CTRL);
306dd11376bSBart Van Assche 
307dd11376bSBart Van Assche 		/* Wait until ack bit equals to req bit */
308dd11376bSBart Van Assche 		if (((value & REFCLK_ACK) >> 1) == (value & REFCLK_REQUEST))
309dd11376bSBart Van Assche 			goto out;
310dd11376bSBart Van Assche 
311dd11376bSBart Van Assche 		usleep_range(100, 200);
312dd11376bSBart Van Assche 	} while (ktime_before(time_checked, timeout));
313dd11376bSBart Van Assche 
314dd11376bSBart Van Assche 	dev_err(hba->dev, "missing ack of refclk req, reg: 0x%x\n", value);
315dd11376bSBart Van Assche 
316f53f1913SPeter Wang 	ufs_mtk_ref_clk_notify(host->ref_clk_enabled, POST_CHANGE, res);
317dd11376bSBart Van Assche 
318dd11376bSBart Van Assche 	return -ETIMEDOUT;
319dd11376bSBart Van Assche 
320dd11376bSBart Van Assche out:
321dd11376bSBart Van Assche 	host->ref_clk_enabled = on;
322dd11376bSBart Van Assche 	if (on)
323dd11376bSBart Van Assche 		ufshcd_delay_us(host->ref_clk_ungating_wait_us, 10);
324f53f1913SPeter Wang 
325f53f1913SPeter Wang 	ufs_mtk_ref_clk_notify(on, POST_CHANGE, res);
326dd11376bSBart Van Assche 
327dd11376bSBart Van Assche 	return 0;
328dd11376bSBart Van Assche }
329dd11376bSBart Van Assche 
ufs_mtk_setup_ref_clk_wait_us(struct ufs_hba * hba,u16 gating_us)330dd11376bSBart Van Assche static void ufs_mtk_setup_ref_clk_wait_us(struct ufs_hba *hba,
331dd11376bSBart Van Assche 					  u16 gating_us)
332dd11376bSBart Van Assche {
333dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
334dd11376bSBart Van Assche 
335dd11376bSBart Van Assche 	if (hba->dev_info.clk_gating_wait_us) {
336dd11376bSBart Van Assche 		host->ref_clk_gating_wait_us =
337dd11376bSBart Van Assche 			hba->dev_info.clk_gating_wait_us;
338dd11376bSBart Van Assche 	} else {
339dd11376bSBart Van Assche 		host->ref_clk_gating_wait_us = gating_us;
340dd11376bSBart Van Assche 	}
341dd11376bSBart Van Assche 
342dd11376bSBart Van Assche 	host->ref_clk_ungating_wait_us = REFCLK_DEFAULT_WAIT_US;
343dd11376bSBart Van Assche }
344dd11376bSBart Van Assche 
ufs_mtk_dbg_sel(struct ufs_hba * hba)345dd11376bSBart Van Assche static void ufs_mtk_dbg_sel(struct ufs_hba *hba)
346dd11376bSBart Van Assche {
347dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
348dd11376bSBart Van Assche 
349dd11376bSBart Van Assche 	if (((host->ip_ver >> 16) & 0xFF) >= 0x36) {
350dd11376bSBart Van Assche 		ufshcd_writel(hba, 0x820820, REG_UFS_DEBUG_SEL);
351dd11376bSBart Van Assche 		ufshcd_writel(hba, 0x0, REG_UFS_DEBUG_SEL_B0);
352dd11376bSBart Van Assche 		ufshcd_writel(hba, 0x55555555, REG_UFS_DEBUG_SEL_B1);
353dd11376bSBart Van Assche 		ufshcd_writel(hba, 0xaaaaaaaa, REG_UFS_DEBUG_SEL_B2);
354dd11376bSBart Van Assche 		ufshcd_writel(hba, 0xffffffff, REG_UFS_DEBUG_SEL_B3);
355dd11376bSBart Van Assche 	} else {
356dd11376bSBart Van Assche 		ufshcd_writel(hba, 0x20, REG_UFS_DEBUG_SEL);
357dd11376bSBart Van Assche 	}
358dd11376bSBart Van Assche }
359dd11376bSBart Van Assche 
ufs_mtk_wait_idle_state(struct ufs_hba * hba,unsigned long retry_ms)360dd11376bSBart Van Assche static void ufs_mtk_wait_idle_state(struct ufs_hba *hba,
361dd11376bSBart Van Assche 			    unsigned long retry_ms)
362dd11376bSBart Van Assche {
363dd11376bSBart Van Assche 	u64 timeout, time_checked;
364dd11376bSBart Van Assche 	u32 val, sm;
365dd11376bSBart Van Assche 	bool wait_idle;
366dd11376bSBart Van Assche 
367dd11376bSBart Van Assche 	/* cannot use plain ktime_get() in suspend */
368dd11376bSBart Van Assche 	timeout = ktime_get_mono_fast_ns() + retry_ms * 1000000UL;
369dd11376bSBart Van Assche 
370dd11376bSBart Van Assche 	/* wait a specific time after check base */
371dd11376bSBart Van Assche 	udelay(10);
372dd11376bSBart Van Assche 	wait_idle = false;
373dd11376bSBart Van Assche 
374dd11376bSBart Van Assche 	do {
375dd11376bSBart Van Assche 		time_checked = ktime_get_mono_fast_ns();
376dd11376bSBart Van Assche 		ufs_mtk_dbg_sel(hba);
377dd11376bSBart Van Assche 		val = ufshcd_readl(hba, REG_UFS_PROBE);
378dd11376bSBart Van Assche 
379dd11376bSBart Van Assche 		sm = val & 0x1f;
380dd11376bSBart Van Assche 
381dd11376bSBart Van Assche 		/*
382dd11376bSBart Van Assche 		 * if state is in H8 enter and H8 enter confirm
383dd11376bSBart Van Assche 		 * wait until return to idle state.
384dd11376bSBart Van Assche 		 */
385dd11376bSBart Van Assche 		if ((sm >= VS_HIB_ENTER) && (sm <= VS_HIB_EXIT)) {
386dd11376bSBart Van Assche 			wait_idle = true;
387dd11376bSBart Van Assche 			udelay(50);
388dd11376bSBart Van Assche 			continue;
389dd11376bSBart Van Assche 		} else if (!wait_idle)
390dd11376bSBart Van Assche 			break;
391dd11376bSBart Van Assche 
392dd11376bSBart Van Assche 		if (wait_idle && (sm == VS_HCE_BASE))
393dd11376bSBart Van Assche 			break;
394dd11376bSBart Van Assche 	} while (time_checked < timeout);
395dd11376bSBart Van Assche 
396dd11376bSBart Van Assche 	if (wait_idle && sm != VS_HCE_BASE)
397dd11376bSBart Van Assche 		dev_info(hba->dev, "wait idle tmo: 0x%x\n", val);
398dd11376bSBart Van Assche }
399dd11376bSBart Van Assche 
ufs_mtk_wait_link_state(struct ufs_hba * hba,u32 state,unsigned long max_wait_ms)400dd11376bSBart Van Assche static int ufs_mtk_wait_link_state(struct ufs_hba *hba, u32 state,
401dd11376bSBart Van Assche 				   unsigned long max_wait_ms)
402dd11376bSBart Van Assche {
403dd11376bSBart Van Assche 	ktime_t timeout, time_checked;
404dd11376bSBart Van Assche 	u32 val;
405dd11376bSBart Van Assche 
406dd11376bSBart Van Assche 	timeout = ktime_add_ms(ktime_get(), max_wait_ms);
407dd11376bSBart Van Assche 	do {
408dd11376bSBart Van Assche 		time_checked = ktime_get();
409dd11376bSBart Van Assche 		ufs_mtk_dbg_sel(hba);
410dd11376bSBart Van Assche 		val = ufshcd_readl(hba, REG_UFS_PROBE);
411dd11376bSBart Van Assche 		val = val >> 28;
412dd11376bSBart Van Assche 
413dd11376bSBart Van Assche 		if (val == state)
414dd11376bSBart Van Assche 			return 0;
415dd11376bSBart Van Assche 
416dd11376bSBart Van Assche 		/* Sleep for max. 200us */
417dd11376bSBart Van Assche 		usleep_range(100, 200);
418dd11376bSBart Van Assche 	} while (ktime_before(time_checked, timeout));
419dd11376bSBart Van Assche 
420dd11376bSBart Van Assche 	return -ETIMEDOUT;
421dd11376bSBart Van Assche }
422dd11376bSBart Van Assche 
ufs_mtk_mphy_power_on(struct ufs_hba * hba,bool on)423dd11376bSBart Van Assche static int ufs_mtk_mphy_power_on(struct ufs_hba *hba, bool on)
424dd11376bSBart Van Assche {
425dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
426dd11376bSBart Van Assche 	struct phy *mphy = host->mphy;
427dd11376bSBart Van Assche 	struct arm_smccc_res res;
428dd11376bSBart Van Assche 	int ret = 0;
429dd11376bSBart Van Assche 
430dd11376bSBart Van Assche 	if (!mphy || !(on ^ host->mphy_powered_on))
431dd11376bSBart Van Assche 		return 0;
432dd11376bSBart Van Assche 
433dd11376bSBart Van Assche 	if (on) {
434dd11376bSBart Van Assche 		if (ufs_mtk_is_va09_supported(hba)) {
435dd11376bSBart Van Assche 			ret = regulator_enable(host->reg_va09);
436dd11376bSBart Van Assche 			if (ret < 0)
437dd11376bSBart Van Assche 				goto out;
438dd11376bSBart Van Assche 			/* wait 200 us to stablize VA09 */
439dd11376bSBart Van Assche 			usleep_range(200, 210);
440dd11376bSBart Van Assche 			ufs_mtk_va09_pwr_ctrl(res, 1);
441dd11376bSBart Van Assche 		}
442dd11376bSBart Van Assche 		phy_power_on(mphy);
443dd11376bSBart Van Assche 	} else {
444dd11376bSBart Van Assche 		phy_power_off(mphy);
445dd11376bSBart Van Assche 		if (ufs_mtk_is_va09_supported(hba)) {
446dd11376bSBart Van Assche 			ufs_mtk_va09_pwr_ctrl(res, 0);
447dd11376bSBart Van Assche 			ret = regulator_disable(host->reg_va09);
448dd11376bSBart Van Assche 		}
449dd11376bSBart Van Assche 	}
450dd11376bSBart Van Assche out:
451dd11376bSBart Van Assche 	if (ret) {
452dd11376bSBart Van Assche 		dev_info(hba->dev,
453dd11376bSBart Van Assche 			 "failed to %s va09: %d\n",
454dd11376bSBart Van Assche 			 on ? "enable" : "disable",
455dd11376bSBart Van Assche 			 ret);
456dd11376bSBart Van Assche 	} else {
457dd11376bSBart Van Assche 		host->mphy_powered_on = on;
458dd11376bSBart Van Assche 	}
459dd11376bSBart Van Assche 
460dd11376bSBart Van Assche 	return ret;
461dd11376bSBart Van Assche }
462dd11376bSBart Van Assche 
ufs_mtk_get_host_clk(struct device * dev,const char * name,struct clk ** clk_out)463dd11376bSBart Van Assche static int ufs_mtk_get_host_clk(struct device *dev, const char *name,
464dd11376bSBart Van Assche 				struct clk **clk_out)
465dd11376bSBart Van Assche {
466dd11376bSBart Van Assche 	struct clk *clk;
467dd11376bSBart Van Assche 	int err = 0;
468dd11376bSBart Van Assche 
469dd11376bSBart Van Assche 	clk = devm_clk_get(dev, name);
470dd11376bSBart Van Assche 	if (IS_ERR(clk))
471dd11376bSBart Van Assche 		err = PTR_ERR(clk);
472dd11376bSBart Van Assche 	else
473dd11376bSBart Van Assche 		*clk_out = clk;
474dd11376bSBart Van Assche 
475dd11376bSBart Van Assche 	return err;
476dd11376bSBart Van Assche }
477dd11376bSBart Van Assche 
ufs_mtk_boost_crypt(struct ufs_hba * hba,bool boost)478dd11376bSBart Van Assche static void ufs_mtk_boost_crypt(struct ufs_hba *hba, bool boost)
479dd11376bSBart Van Assche {
480dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
481dd11376bSBart Van Assche 	struct ufs_mtk_crypt_cfg *cfg;
482dd11376bSBart Van Assche 	struct regulator *reg;
483dd11376bSBart Van Assche 	int volt, ret;
484dd11376bSBart Van Assche 
485dd11376bSBart Van Assche 	if (!ufs_mtk_is_boost_crypt_enabled(hba))
486dd11376bSBart Van Assche 		return;
487dd11376bSBart Van Assche 
488dd11376bSBart Van Assche 	cfg = host->crypt;
489dd11376bSBart Van Assche 	volt = cfg->vcore_volt;
490dd11376bSBart Van Assche 	reg = cfg->reg_vcore;
491dd11376bSBart Van Assche 
492dd11376bSBart Van Assche 	ret = clk_prepare_enable(cfg->clk_crypt_mux);
493dd11376bSBart Van Assche 	if (ret) {
494dd11376bSBart Van Assche 		dev_info(hba->dev, "clk_prepare_enable(): %d\n",
495dd11376bSBart Van Assche 			 ret);
496dd11376bSBart Van Assche 		return;
497dd11376bSBart Van Assche 	}
498dd11376bSBart Van Assche 
499dd11376bSBart Van Assche 	if (boost) {
500dd11376bSBart Van Assche 		ret = regulator_set_voltage(reg, volt, INT_MAX);
501dd11376bSBart Van Assche 		if (ret) {
502dd11376bSBart Van Assche 			dev_info(hba->dev,
503dd11376bSBart Van Assche 				 "failed to set vcore to %d\n", volt);
504dd11376bSBart Van Assche 			goto out;
505dd11376bSBart Van Assche 		}
506dd11376bSBart Van Assche 
507dd11376bSBart Van Assche 		ret = clk_set_parent(cfg->clk_crypt_mux,
508dd11376bSBart Van Assche 				     cfg->clk_crypt_perf);
509dd11376bSBart Van Assche 		if (ret) {
510dd11376bSBart Van Assche 			dev_info(hba->dev,
511dd11376bSBart Van Assche 				 "failed to set clk_crypt_perf\n");
512dd11376bSBart Van Assche 			regulator_set_voltage(reg, 0, INT_MAX);
513dd11376bSBart Van Assche 			goto out;
514dd11376bSBart Van Assche 		}
515dd11376bSBart Van Assche 	} else {
516dd11376bSBart Van Assche 		ret = clk_set_parent(cfg->clk_crypt_mux,
517dd11376bSBart Van Assche 				     cfg->clk_crypt_lp);
518dd11376bSBart Van Assche 		if (ret) {
519dd11376bSBart Van Assche 			dev_info(hba->dev,
520dd11376bSBart Van Assche 				 "failed to set clk_crypt_lp\n");
521dd11376bSBart Van Assche 			goto out;
522dd11376bSBart Van Assche 		}
523dd11376bSBart Van Assche 
524dd11376bSBart Van Assche 		ret = regulator_set_voltage(reg, 0, INT_MAX);
525dd11376bSBart Van Assche 		if (ret) {
526dd11376bSBart Van Assche 			dev_info(hba->dev,
527dd11376bSBart Van Assche 				 "failed to set vcore to MIN\n");
528dd11376bSBart Van Assche 		}
529dd11376bSBart Van Assche 	}
530dd11376bSBart Van Assche out:
531dd11376bSBart Van Assche 	clk_disable_unprepare(cfg->clk_crypt_mux);
532dd11376bSBart Van Assche }
533dd11376bSBart Van Assche 
ufs_mtk_init_host_clk(struct ufs_hba * hba,const char * name,struct clk ** clk)534dd11376bSBart Van Assche static int ufs_mtk_init_host_clk(struct ufs_hba *hba, const char *name,
535dd11376bSBart Van Assche 				 struct clk **clk)
536dd11376bSBart Van Assche {
537dd11376bSBart Van Assche 	int ret;
538dd11376bSBart Van Assche 
539dd11376bSBart Van Assche 	ret = ufs_mtk_get_host_clk(hba->dev, name, clk);
540dd11376bSBart Van Assche 	if (ret) {
541dd11376bSBart Van Assche 		dev_info(hba->dev, "%s: failed to get %s: %d", __func__,
542dd11376bSBart Van Assche 			 name, ret);
543dd11376bSBart Van Assche 	}
544dd11376bSBart Van Assche 
545dd11376bSBart Van Assche 	return ret;
546dd11376bSBart Van Assche }
547dd11376bSBart Van Assche 
ufs_mtk_init_boost_crypt(struct ufs_hba * hba)548dd11376bSBart Van Assche static void ufs_mtk_init_boost_crypt(struct ufs_hba *hba)
549dd11376bSBart Van Assche {
550dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
551dd11376bSBart Van Assche 	struct ufs_mtk_crypt_cfg *cfg;
552dd11376bSBart Van Assche 	struct device *dev = hba->dev;
553dd11376bSBart Van Assche 	struct regulator *reg;
554dd11376bSBart Van Assche 	u32 volt;
555dd11376bSBart Van Assche 
556dd11376bSBart Van Assche 	host->crypt = devm_kzalloc(dev, sizeof(*(host->crypt)),
557dd11376bSBart Van Assche 				   GFP_KERNEL);
558dd11376bSBart Van Assche 	if (!host->crypt)
559dd11376bSBart Van Assche 		goto disable_caps;
560dd11376bSBart Van Assche 
561dd11376bSBart Van Assche 	reg = devm_regulator_get_optional(dev, "dvfsrc-vcore");
562dd11376bSBart Van Assche 	if (IS_ERR(reg)) {
563dd11376bSBart Van Assche 		dev_info(dev, "failed to get dvfsrc-vcore: %ld",
564dd11376bSBart Van Assche 			 PTR_ERR(reg));
565dd11376bSBart Van Assche 		goto disable_caps;
566dd11376bSBart Van Assche 	}
567dd11376bSBart Van Assche 
568dd11376bSBart Van Assche 	if (of_property_read_u32(dev->of_node, "boost-crypt-vcore-min",
569dd11376bSBart Van Assche 				 &volt)) {
570dd11376bSBart Van Assche 		dev_info(dev, "failed to get boost-crypt-vcore-min");
571dd11376bSBart Van Assche 		goto disable_caps;
572dd11376bSBart Van Assche 	}
573dd11376bSBart Van Assche 
574dd11376bSBart Van Assche 	cfg = host->crypt;
575dd11376bSBart Van Assche 	if (ufs_mtk_init_host_clk(hba, "crypt_mux",
576dd11376bSBart Van Assche 				  &cfg->clk_crypt_mux))
577dd11376bSBart Van Assche 		goto disable_caps;
578dd11376bSBart Van Assche 
579dd11376bSBart Van Assche 	if (ufs_mtk_init_host_clk(hba, "crypt_lp",
580dd11376bSBart Van Assche 				  &cfg->clk_crypt_lp))
581dd11376bSBart Van Assche 		goto disable_caps;
582dd11376bSBart Van Assche 
583dd11376bSBart Van Assche 	if (ufs_mtk_init_host_clk(hba, "crypt_perf",
584dd11376bSBart Van Assche 				  &cfg->clk_crypt_perf))
585dd11376bSBart Van Assche 		goto disable_caps;
586dd11376bSBart Van Assche 
587dd11376bSBart Van Assche 	cfg->reg_vcore = reg;
588dd11376bSBart Van Assche 	cfg->vcore_volt = volt;
589dd11376bSBart Van Assche 	host->caps |= UFS_MTK_CAP_BOOST_CRYPT_ENGINE;
590dd11376bSBart Van Assche 
591dd11376bSBart Van Assche disable_caps:
592dd11376bSBart Van Assche 	return;
593dd11376bSBart Van Assche }
594dd11376bSBart Van Assche 
ufs_mtk_init_va09_pwr_ctrl(struct ufs_hba * hba)595dd11376bSBart Van Assche static void ufs_mtk_init_va09_pwr_ctrl(struct ufs_hba *hba)
596dd11376bSBart Van Assche {
597dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
598dd11376bSBart Van Assche 
599dd11376bSBart Van Assche 	host->reg_va09 = regulator_get(hba->dev, "va09");
600dd11376bSBart Van Assche 	if (IS_ERR(host->reg_va09))
601dd11376bSBart Van Assche 		dev_info(hba->dev, "failed to get va09");
602dd11376bSBart Van Assche 	else
603dd11376bSBart Van Assche 		host->caps |= UFS_MTK_CAP_VA09_PWR_CTRL;
604dd11376bSBart Van Assche }
605dd11376bSBart Van Assche 
ufs_mtk_init_host_caps(struct ufs_hba * hba)606dd11376bSBart Van Assche static void ufs_mtk_init_host_caps(struct ufs_hba *hba)
607dd11376bSBart Van Assche {
608dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
609dd11376bSBart Van Assche 	struct device_node *np = hba->dev->of_node;
610dd11376bSBart Van Assche 
611dd11376bSBart Van Assche 	if (of_property_read_bool(np, "mediatek,ufs-boost-crypt"))
612dd11376bSBart Van Assche 		ufs_mtk_init_boost_crypt(hba);
613dd11376bSBart Van Assche 
614dd11376bSBart Van Assche 	if (of_property_read_bool(np, "mediatek,ufs-support-va09"))
615dd11376bSBart Van Assche 		ufs_mtk_init_va09_pwr_ctrl(hba);
616dd11376bSBart Van Assche 
617dd11376bSBart Van Assche 	if (of_property_read_bool(np, "mediatek,ufs-disable-ah8"))
618dd11376bSBart Van Assche 		host->caps |= UFS_MTK_CAP_DISABLE_AH8;
619dd11376bSBart Van Assche 
620dd11376bSBart Van Assche 	if (of_property_read_bool(np, "mediatek,ufs-broken-vcc"))
621dd11376bSBart Van Assche 		host->caps |= UFS_MTK_CAP_BROKEN_VCC;
622dd11376bSBart Van Assche 
6233f9b6cecSCC Chou 	if (of_property_read_bool(np, "mediatek,ufs-pmc-via-fastauto"))
6243f9b6cecSCC Chou 		host->caps |= UFS_MTK_CAP_PMC_VIA_FASTAUTO;
6253f9b6cecSCC Chou 
626dd11376bSBart Van Assche 	dev_info(hba->dev, "caps: 0x%x", host->caps);
627dd11376bSBart Van Assche }
628dd11376bSBart Van Assche 
ufs_mtk_boost_pm_qos(struct ufs_hba * hba,bool boost)629c64c487dSPeter Wang static void ufs_mtk_boost_pm_qos(struct ufs_hba *hba, bool boost)
630dd11376bSBart Van Assche {
631dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
632dd11376bSBart Van Assche 
633c64c487dSPeter Wang 	if (!host || !host->pm_qos_init)
634c64c487dSPeter Wang 		return;
635dd11376bSBart Van Assche 
636c64c487dSPeter Wang 	cpu_latency_qos_update_request(&host->pm_qos_req,
637c64c487dSPeter Wang 				       boost ? 0 : PM_QOS_DEFAULT_VALUE);
638c64c487dSPeter Wang }
639c64c487dSPeter Wang 
ufs_mtk_scale_perf(struct ufs_hba * hba,bool scale_up)6402873e045SPeter Wang static void ufs_mtk_scale_perf(struct ufs_hba *hba, bool scale_up)
6412873e045SPeter Wang {
6422873e045SPeter Wang 	ufs_mtk_boost_crypt(hba, scale_up);
6432873e045SPeter Wang 	ufs_mtk_boost_pm_qos(hba, scale_up);
6442873e045SPeter Wang }
6452873e045SPeter Wang 
ufs_mtk_pwr_ctrl(struct ufs_hba * hba,bool on)646c64c487dSPeter Wang static void ufs_mtk_pwr_ctrl(struct ufs_hba *hba, bool on)
647c64c487dSPeter Wang {
648c64c487dSPeter Wang 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
649c64c487dSPeter Wang 
650c64c487dSPeter Wang 	if (on) {
651dd11376bSBart Van Assche 		phy_power_on(host->mphy);
652c64c487dSPeter Wang 		ufs_mtk_setup_ref_clk(hba, on);
6532873e045SPeter Wang 		if (!ufshcd_is_clkscaling_supported(hba))
6542873e045SPeter Wang 			ufs_mtk_scale_perf(hba, on);
655c64c487dSPeter Wang 	} else {
6562873e045SPeter Wang 		if (!ufshcd_is_clkscaling_supported(hba))
6572873e045SPeter Wang 			ufs_mtk_scale_perf(hba, on);
658c64c487dSPeter Wang 		ufs_mtk_setup_ref_clk(hba, on);
659dd11376bSBart Van Assche 		phy_power_off(host->mphy);
660dd11376bSBart Van Assche 	}
661c64c487dSPeter Wang }
662dd11376bSBart Van Assche 
663dd11376bSBart Van Assche /**
664dd11376bSBart Van Assche  * ufs_mtk_setup_clocks - enables/disable clocks
665dd11376bSBart Van Assche  * @hba: host controller instance
666dd11376bSBart Van Assche  * @on: If true, enable clocks else disable them.
667dd11376bSBart Van Assche  * @status: PRE_CHANGE or POST_CHANGE notify
668dd11376bSBart Van Assche  *
669*3a17fefeSBart Van Assche  * Return: 0 on success, non-zero on failure.
670dd11376bSBart Van Assche  */
ufs_mtk_setup_clocks(struct ufs_hba * hba,bool on,enum ufs_notify_change_status status)671dd11376bSBart Van Assche static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
672dd11376bSBart Van Assche 				enum ufs_notify_change_status status)
673dd11376bSBart Van Assche {
674dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
675dd11376bSBart Van Assche 	bool clk_pwr_off = false;
676dd11376bSBart Van Assche 	int ret = 0;
677dd11376bSBart Van Assche 
678dd11376bSBart Van Assche 	/*
679dd11376bSBart Van Assche 	 * In case ufs_mtk_init() is not yet done, simply ignore.
680dd11376bSBart Van Assche 	 * This ufs_mtk_setup_clocks() shall be called from
681dd11376bSBart Van Assche 	 * ufs_mtk_init() after init is done.
682dd11376bSBart Van Assche 	 */
683dd11376bSBart Van Assche 	if (!host)
684dd11376bSBart Van Assche 		return 0;
685dd11376bSBart Van Assche 
686dd11376bSBart Van Assche 	if (!on && status == PRE_CHANGE) {
687dd11376bSBart Van Assche 		if (ufshcd_is_link_off(hba)) {
688dd11376bSBart Van Assche 			clk_pwr_off = true;
689dd11376bSBart Van Assche 		} else if (ufshcd_is_link_hibern8(hba) ||
690dd11376bSBart Van Assche 			 (!ufshcd_can_hibern8_during_gating(hba) &&
691dd11376bSBart Van Assche 			 ufshcd_is_auto_hibern8_enabled(hba))) {
692dd11376bSBart Van Assche 			/*
693dd11376bSBart Van Assche 			 * Gate ref-clk and poweroff mphy if link state is in
694dd11376bSBart Van Assche 			 * OFF or Hibern8 by either Auto-Hibern8 or
695dd11376bSBart Van Assche 			 * ufshcd_link_state_transition().
696dd11376bSBart Van Assche 			 */
697dd11376bSBart Van Assche 			ret = ufs_mtk_wait_link_state(hba,
698dd11376bSBart Van Assche 						      VS_LINK_HIBERN8,
699dd11376bSBart Van Assche 						      15);
700dd11376bSBart Van Assche 			if (!ret)
701dd11376bSBart Van Assche 				clk_pwr_off = true;
702dd11376bSBart Van Assche 		}
703dd11376bSBart Van Assche 
704dd11376bSBart Van Assche 		if (clk_pwr_off)
705c64c487dSPeter Wang 			ufs_mtk_pwr_ctrl(hba, false);
706dd11376bSBart Van Assche 	} else if (on && status == POST_CHANGE) {
707c64c487dSPeter Wang 		ufs_mtk_pwr_ctrl(hba, true);
708dd11376bSBart Van Assche 	}
709dd11376bSBart Van Assche 
710dd11376bSBart Van Assche 	return ret;
711dd11376bSBart Van Assche }
712dd11376bSBart Van Assche 
ufs_mtk_get_controller_version(struct ufs_hba * hba)713dd11376bSBart Van Assche static void ufs_mtk_get_controller_version(struct ufs_hba *hba)
714dd11376bSBart Van Assche {
715dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
716dd11376bSBart Van Assche 	int ret, ver = 0;
717dd11376bSBart Van Assche 
718dd11376bSBart Van Assche 	if (host->hw_ver.major)
719dd11376bSBart Van Assche 		return;
720dd11376bSBart Van Assche 
721dd11376bSBart Van Assche 	/* Set default (minimum) version anyway */
722dd11376bSBart Van Assche 	host->hw_ver.major = 2;
723dd11376bSBart Van Assche 
724dd11376bSBart Van Assche 	ret = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_LOCALVERINFO), &ver);
725dd11376bSBart Van Assche 	if (!ret) {
726dd11376bSBart Van Assche 		if (ver >= UFS_UNIPRO_VER_1_8) {
727dd11376bSBart Van Assche 			host->hw_ver.major = 3;
728dd11376bSBart Van Assche 			/*
729dd11376bSBart Van Assche 			 * Fix HCI version for some platforms with
730dd11376bSBart Van Assche 			 * incorrect version
731dd11376bSBart Van Assche 			 */
732dd11376bSBart Van Assche 			if (hba->ufs_version < ufshci_version(3, 0))
733dd11376bSBart Van Assche 				hba->ufs_version = ufshci_version(3, 0);
734dd11376bSBart Van Assche 		}
735dd11376bSBart Van Assche 	}
736dd11376bSBart Van Assche }
737dd11376bSBart Van Assche 
ufs_mtk_get_ufs_hci_version(struct ufs_hba * hba)738dd11376bSBart Van Assche static u32 ufs_mtk_get_ufs_hci_version(struct ufs_hba *hba)
739dd11376bSBart Van Assche {
740dd11376bSBart Van Assche 	return hba->ufs_version;
741dd11376bSBart Van Assche }
742dd11376bSBart Van Assche 
743b7dbc686SPo-Wen Kao /**
744b7dbc686SPo-Wen Kao  * ufs_mtk_init_clocks - Init mtk driver private clocks
745b7dbc686SPo-Wen Kao  *
746b7dbc686SPo-Wen Kao  * @hba: per adapter instance
747b7dbc686SPo-Wen Kao  */
ufs_mtk_init_clocks(struct ufs_hba * hba)748b7dbc686SPo-Wen Kao static void ufs_mtk_init_clocks(struct ufs_hba *hba)
749b7dbc686SPo-Wen Kao {
750b7dbc686SPo-Wen Kao 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
751b7dbc686SPo-Wen Kao 	struct list_head *head = &hba->clk_list_head;
752b7dbc686SPo-Wen Kao 	struct ufs_mtk_clk *mclk = &host->mclk;
753b7dbc686SPo-Wen Kao 	struct ufs_clk_info *clki, *clki_tmp;
754b7dbc686SPo-Wen Kao 
755b7dbc686SPo-Wen Kao 	/*
756b7dbc686SPo-Wen Kao 	 * Find private clocks and store them in struct ufs_mtk_clk.
757b7dbc686SPo-Wen Kao 	 * Remove "ufs_sel_min_src" and "ufs_sel_min_src" from list to avoid
758b7dbc686SPo-Wen Kao 	 * being switched on/off in clock gating.
759b7dbc686SPo-Wen Kao 	 */
760b7dbc686SPo-Wen Kao 	list_for_each_entry_safe(clki, clki_tmp, head, list) {
761b7dbc686SPo-Wen Kao 		if (!strcmp(clki->name, "ufs_sel")) {
762b7dbc686SPo-Wen Kao 			host->mclk.ufs_sel_clki = clki;
763b7dbc686SPo-Wen Kao 		} else if (!strcmp(clki->name, "ufs_sel_max_src")) {
764b7dbc686SPo-Wen Kao 			host->mclk.ufs_sel_max_clki = clki;
765b7dbc686SPo-Wen Kao 			clk_disable_unprepare(clki->clk);
766b7dbc686SPo-Wen Kao 			list_del(&clki->list);
767b7dbc686SPo-Wen Kao 		} else if (!strcmp(clki->name, "ufs_sel_min_src")) {
768b7dbc686SPo-Wen Kao 			host->mclk.ufs_sel_min_clki = clki;
769b7dbc686SPo-Wen Kao 			clk_disable_unprepare(clki->clk);
770b7dbc686SPo-Wen Kao 			list_del(&clki->list);
771b7dbc686SPo-Wen Kao 		}
772b7dbc686SPo-Wen Kao 	}
773b7dbc686SPo-Wen Kao 
774b7dbc686SPo-Wen Kao 	if (!mclk->ufs_sel_clki || !mclk->ufs_sel_max_clki ||
775b7dbc686SPo-Wen Kao 	    !mclk->ufs_sel_min_clki) {
776b7dbc686SPo-Wen Kao 		hba->caps &= ~UFSHCD_CAP_CLK_SCALING;
777b7dbc686SPo-Wen Kao 		dev_info(hba->dev,
778b7dbc686SPo-Wen Kao 			 "%s: Clk-scaling not ready. Feature disabled.",
779b7dbc686SPo-Wen Kao 			 __func__);
780b7dbc686SPo-Wen Kao 	}
781b7dbc686SPo-Wen Kao }
782b7dbc686SPo-Wen Kao 
783ece418d0SStanley Chu #define MAX_VCC_NAME 30
ufs_mtk_vreg_fix_vcc(struct ufs_hba * hba)784ece418d0SStanley Chu static int ufs_mtk_vreg_fix_vcc(struct ufs_hba *hba)
785ece418d0SStanley Chu {
786ece418d0SStanley Chu 	struct ufs_vreg_info *info = &hba->vreg_info;
787ece418d0SStanley Chu 	struct device_node *np = hba->dev->of_node;
788ece418d0SStanley Chu 	struct device *dev = hba->dev;
789ece418d0SStanley Chu 	char vcc_name[MAX_VCC_NAME];
790ece418d0SStanley Chu 	struct arm_smccc_res res;
791ece418d0SStanley Chu 	int err, ver;
792ece418d0SStanley Chu 
793ece418d0SStanley Chu 	if (hba->vreg_info.vcc)
794ece418d0SStanley Chu 		return 0;
795ece418d0SStanley Chu 
796ece418d0SStanley Chu 	if (of_property_read_bool(np, "mediatek,ufs-vcc-by-num")) {
797ece418d0SStanley Chu 		ufs_mtk_get_vcc_num(res);
798ece418d0SStanley Chu 		if (res.a1 > UFS_VCC_NONE && res.a1 < UFS_VCC_MAX)
799f54912b2SRen Zhijie 			snprintf(vcc_name, MAX_VCC_NAME, "vcc-opt%lu", res.a1);
800ece418d0SStanley Chu 		else
801ece418d0SStanley Chu 			return -ENODEV;
802ece418d0SStanley Chu 	} else if (of_property_read_bool(np, "mediatek,ufs-vcc-by-ver")) {
803ece418d0SStanley Chu 		ver = (hba->dev_info.wspecversion & 0xF00) >> 8;
804ece418d0SStanley Chu 		snprintf(vcc_name, MAX_VCC_NAME, "vcc-ufs%u", ver);
805ece418d0SStanley Chu 	} else {
806ece418d0SStanley Chu 		return 0;
807ece418d0SStanley Chu 	}
808ece418d0SStanley Chu 
809ece418d0SStanley Chu 	err = ufshcd_populate_vreg(dev, vcc_name, &info->vcc);
810ece418d0SStanley Chu 	if (err)
811ece418d0SStanley Chu 		return err;
812ece418d0SStanley Chu 
813ece418d0SStanley Chu 	err = ufshcd_get_vreg(dev, info->vcc);
814ece418d0SStanley Chu 	if (err)
815ece418d0SStanley Chu 		return err;
816ece418d0SStanley Chu 
817ece418d0SStanley Chu 	err = regulator_enable(info->vcc->reg);
818ece418d0SStanley Chu 	if (!err) {
819ece418d0SStanley Chu 		info->vcc->enabled = true;
820ece418d0SStanley Chu 		dev_info(dev, "%s: %s enabled\n", __func__, vcc_name);
821ece418d0SStanley Chu 	}
822ece418d0SStanley Chu 
823ece418d0SStanley Chu 	return err;
824ece418d0SStanley Chu }
825ece418d0SStanley Chu 
ufs_mtk_vreg_fix_vccqx(struct ufs_hba * hba)826cb142b6dSStanley Chu static void ufs_mtk_vreg_fix_vccqx(struct ufs_hba *hba)
827cb142b6dSStanley Chu {
828cb142b6dSStanley Chu 	struct ufs_vreg_info *info = &hba->vreg_info;
829cb142b6dSStanley Chu 	struct ufs_vreg **vreg_on, **vreg_off;
830cb142b6dSStanley Chu 
831cb142b6dSStanley Chu 	if (hba->dev_info.wspecversion >= 0x0300) {
832cb142b6dSStanley Chu 		vreg_on = &info->vccq;
833cb142b6dSStanley Chu 		vreg_off = &info->vccq2;
834cb142b6dSStanley Chu 	} else {
835cb142b6dSStanley Chu 		vreg_on = &info->vccq2;
836cb142b6dSStanley Chu 		vreg_off = &info->vccq;
837cb142b6dSStanley Chu 	}
838cb142b6dSStanley Chu 
839cb142b6dSStanley Chu 	if (*vreg_on)
840cb142b6dSStanley Chu 		(*vreg_on)->always_on = true;
841cb142b6dSStanley Chu 
842cb142b6dSStanley Chu 	if (*vreg_off) {
843cb142b6dSStanley Chu 		regulator_disable((*vreg_off)->reg);
844cb142b6dSStanley Chu 		devm_kfree(hba->dev, (*vreg_off)->name);
845cb142b6dSStanley Chu 		devm_kfree(hba->dev, *vreg_off);
846df1ea242SAlice Chao 		*vreg_off = NULL;
847cb142b6dSStanley Chu 	}
848cb142b6dSStanley Chu }
849cb142b6dSStanley Chu 
ufs_mtk_init_mcq_irq(struct ufs_hba * hba)850e152a616SPo-Wen Kao static void ufs_mtk_init_mcq_irq(struct ufs_hba *hba)
851e152a616SPo-Wen Kao {
852e152a616SPo-Wen Kao 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
853e152a616SPo-Wen Kao 	struct platform_device *pdev;
854e152a616SPo-Wen Kao 	int i;
855e152a616SPo-Wen Kao 	int irq;
856e152a616SPo-Wen Kao 
857e152a616SPo-Wen Kao 	host->mcq_nr_intr = UFSHCD_MAX_Q_NR;
858e152a616SPo-Wen Kao 	pdev = container_of(hba->dev, struct platform_device, dev);
859e152a616SPo-Wen Kao 
860e152a616SPo-Wen Kao 	for (i = 0; i < host->mcq_nr_intr; i++) {
861e152a616SPo-Wen Kao 		/* irq index 0 is legacy irq, sq/cq irq start from index 1 */
862e152a616SPo-Wen Kao 		irq = platform_get_irq(pdev, i + 1);
863e152a616SPo-Wen Kao 		if (irq < 0) {
864e152a616SPo-Wen Kao 			host->mcq_intr_info[i].irq = MTK_MCQ_INVALID_IRQ;
865e152a616SPo-Wen Kao 			goto failed;
866e152a616SPo-Wen Kao 		}
867e152a616SPo-Wen Kao 		host->mcq_intr_info[i].hba = hba;
868e152a616SPo-Wen Kao 		host->mcq_intr_info[i].irq = irq;
869e152a616SPo-Wen Kao 		dev_info(hba->dev, "get platform mcq irq: %d, %d\n", i, irq);
870e152a616SPo-Wen Kao 	}
871e152a616SPo-Wen Kao 
872e152a616SPo-Wen Kao 	return;
873e152a616SPo-Wen Kao failed:
874e152a616SPo-Wen Kao        /* invalidate irq info */
875e152a616SPo-Wen Kao 	for (i = 0; i < host->mcq_nr_intr; i++)
876e152a616SPo-Wen Kao 		host->mcq_intr_info[i].irq = MTK_MCQ_INVALID_IRQ;
877e152a616SPo-Wen Kao 
878e152a616SPo-Wen Kao 	host->mcq_nr_intr = 0;
879e152a616SPo-Wen Kao }
880e152a616SPo-Wen Kao 
881dd11376bSBart Van Assche /**
882dd11376bSBart Van Assche  * ufs_mtk_init - find other essential mmio bases
883dd11376bSBart Van Assche  * @hba: host controller instance
884dd11376bSBart Van Assche  *
885dd11376bSBart Van Assche  * Binds PHY with controller and powers up PHY enabling clocks
886dd11376bSBart Van Assche  * and regulators.
887dd11376bSBart Van Assche  *
888*3a17fefeSBart Van Assche  * Return: -EPROBE_DEFER if binding fails, returns negative error
889dd11376bSBart Van Assche  * on phy power up failure and returns zero on success.
890dd11376bSBart Van Assche  */
ufs_mtk_init(struct ufs_hba * hba)891dd11376bSBart Van Assche static int ufs_mtk_init(struct ufs_hba *hba)
892dd11376bSBart Van Assche {
893dd11376bSBart Van Assche 	const struct of_device_id *id;
894dd11376bSBart Van Assche 	struct device *dev = hba->dev;
895dd11376bSBart Van Assche 	struct ufs_mtk_host *host;
896dd11376bSBart Van Assche 	int err = 0;
897dd11376bSBart Van Assche 
898dd11376bSBart Van Assche 	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
899dd11376bSBart Van Assche 	if (!host) {
900dd11376bSBart Van Assche 		err = -ENOMEM;
901dd11376bSBart Van Assche 		dev_info(dev, "%s: no memory for mtk ufs host\n", __func__);
902dd11376bSBart Van Assche 		goto out;
903dd11376bSBart Van Assche 	}
904dd11376bSBart Van Assche 
905dd11376bSBart Van Assche 	host->hba = hba;
906dd11376bSBart Van Assche 	ufshcd_set_variant(hba, host);
907dd11376bSBart Van Assche 
908dd11376bSBart Van Assche 	id = of_match_device(ufs_mtk_of_match, dev);
909dd11376bSBart Van Assche 	if (!id) {
910dd11376bSBart Van Assche 		err = -EINVAL;
911dd11376bSBart Van Assche 		goto out;
912dd11376bSBart Van Assche 	}
913dd11376bSBart Van Assche 
914dd11376bSBart Van Assche 	/* Initialize host capability */
915dd11376bSBart Van Assche 	ufs_mtk_init_host_caps(hba);
916dd11376bSBart Van Assche 
917e152a616SPo-Wen Kao 	ufs_mtk_init_mcq_irq(hba);
918e152a616SPo-Wen Kao 
919dd11376bSBart Van Assche 	err = ufs_mtk_bind_mphy(hba);
920dd11376bSBart Van Assche 	if (err)
921dd11376bSBart Van Assche 		goto out_variant_clear;
922dd11376bSBart Van Assche 
923dd11376bSBart Van Assche 	ufs_mtk_init_reset(hba);
924dd11376bSBart Van Assche 
925dd11376bSBart Van Assche 	/* Enable runtime autosuspend */
926dd11376bSBart Van Assche 	hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND;
927dd11376bSBart Van Assche 
928dd11376bSBart Van Assche 	/* Enable clock-gating */
929dd11376bSBart Van Assche 	hba->caps |= UFSHCD_CAP_CLK_GATING;
930dd11376bSBart Van Assche 
931dd11376bSBart Van Assche 	/* Enable inline encryption */
932dd11376bSBart Van Assche 	hba->caps |= UFSHCD_CAP_CRYPTO;
933dd11376bSBart Van Assche 
934dd11376bSBart Van Assche 	/* Enable WriteBooster */
935dd11376bSBart Van Assche 	hba->caps |= UFSHCD_CAP_WB_EN;
936b7dbc686SPo-Wen Kao 
937b7dbc686SPo-Wen Kao 	/* Enable clk scaling*/
938b7dbc686SPo-Wen Kao 	hba->caps |= UFSHCD_CAP_CLK_SCALING;
939b7dbc686SPo-Wen Kao 
940dd11376bSBart Van Assche 	hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL;
94195cd364cSPo-Wen Kao 	hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_INTR;
9423c9b49beSPo-Wen Kao 	hba->quirks |= UFSHCD_QUIRK_MCQ_BROKEN_RTC;
943dd11376bSBart Van Assche 	hba->vps->wb_flush_threshold = UFS_WB_BUF_REMAIN_PERCENT(80);
944dd11376bSBart Van Assche 
945dd11376bSBart Van Assche 	if (host->caps & UFS_MTK_CAP_DISABLE_AH8)
946dd11376bSBart Van Assche 		hba->caps |= UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
947dd11376bSBart Van Assche 
948b7dbc686SPo-Wen Kao 	ufs_mtk_init_clocks(hba);
949b7dbc686SPo-Wen Kao 
950dd11376bSBart Van Assche 	/*
951dd11376bSBart Van Assche 	 * ufshcd_vops_init() is invoked after
952dd11376bSBart Van Assche 	 * ufshcd_setup_clock(true) in ufshcd_hba_init() thus
953dd11376bSBart Van Assche 	 * phy clock setup is skipped.
954dd11376bSBart Van Assche 	 *
955dd11376bSBart Van Assche 	 * Enable phy clocks specifically here.
956dd11376bSBart Van Assche 	 */
957dd11376bSBart Van Assche 	ufs_mtk_mphy_power_on(hba, true);
958dd11376bSBart Van Assche 	ufs_mtk_setup_clocks(hba, true, POST_CHANGE);
959dd11376bSBart Van Assche 
960dd11376bSBart Van Assche 	host->ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER);
961dd11376bSBart Van Assche 
9622873e045SPeter Wang 	/* Initialize pm-qos request */
9632873e045SPeter Wang 	cpu_latency_qos_add_request(&host->pm_qos_req, PM_QOS_DEFAULT_VALUE);
9642873e045SPeter Wang 	host->pm_qos_init = true;
9652873e045SPeter Wang 
966dd11376bSBart Van Assche 	goto out;
967dd11376bSBart Van Assche 
968dd11376bSBart Van Assche out_variant_clear:
969dd11376bSBart Van Assche 	ufshcd_set_variant(hba, NULL);
970dd11376bSBart Van Assche out:
971dd11376bSBart Van Assche 	return err;
972dd11376bSBart Van Assche }
973dd11376bSBart Van Assche 
ufs_mtk_pmc_via_fastauto(struct ufs_hba * hba,struct ufs_pa_layer_attr * dev_req_params)9743f9b6cecSCC Chou static bool ufs_mtk_pmc_via_fastauto(struct ufs_hba *hba,
9753f9b6cecSCC Chou 				     struct ufs_pa_layer_attr *dev_req_params)
9763f9b6cecSCC Chou {
9773f9b6cecSCC Chou 	if (!ufs_mtk_is_pmc_via_fastauto(hba))
9783f9b6cecSCC Chou 		return false;
9793f9b6cecSCC Chou 
9803f9b6cecSCC Chou 	if (dev_req_params->hs_rate == hba->pwr_info.hs_rate)
9813f9b6cecSCC Chou 		return false;
9823f9b6cecSCC Chou 
9833f9b6cecSCC Chou 	if (dev_req_params->pwr_tx != FAST_MODE &&
9843f9b6cecSCC Chou 	    dev_req_params->gear_tx < UFS_HS_G4)
9853f9b6cecSCC Chou 		return false;
9863f9b6cecSCC Chou 
9873f9b6cecSCC Chou 	if (dev_req_params->pwr_rx != FAST_MODE &&
9883f9b6cecSCC Chou 	    dev_req_params->gear_rx < UFS_HS_G4)
9893f9b6cecSCC Chou 		return false;
9903f9b6cecSCC Chou 
9913f9b6cecSCC Chou 	return true;
9923f9b6cecSCC Chou }
9933f9b6cecSCC Chou 
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)994dd11376bSBart Van Assche static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
995dd11376bSBart Van Assche 				  struct ufs_pa_layer_attr *dev_max_params,
996dd11376bSBart Van Assche 				  struct ufs_pa_layer_attr *dev_req_params)
997dd11376bSBart Van Assche {
998dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
999dd11376bSBart Van Assche 	struct ufs_dev_params host_cap;
1000dd11376bSBart Van Assche 	int ret;
1001dd11376bSBart Van Assche 
1002dd11376bSBart Van Assche 	ufshcd_init_pwr_dev_param(&host_cap);
10033f9b6cecSCC Chou 	host_cap.hs_rx_gear = UFS_HS_G5;
10043f9b6cecSCC Chou 	host_cap.hs_tx_gear = UFS_HS_G5;
1005dd11376bSBart Van Assche 
1006dd11376bSBart Van Assche 	ret = ufshcd_get_pwr_dev_param(&host_cap,
1007dd11376bSBart Van Assche 				       dev_max_params,
1008dd11376bSBart Van Assche 				       dev_req_params);
1009dd11376bSBart Van Assche 	if (ret) {
1010dd11376bSBart Van Assche 		pr_info("%s: failed to determine capabilities\n",
1011dd11376bSBart Van Assche 			__func__);
1012dd11376bSBart Van Assche 	}
1013dd11376bSBart Van Assche 
10143f9b6cecSCC Chou 	if (ufs_mtk_pmc_via_fastauto(hba, dev_req_params)) {
10153f9b6cecSCC Chou 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), true);
10163f9b6cecSCC Chou 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), UFS_HS_G1);
10173f9b6cecSCC Chou 
10183f9b6cecSCC Chou 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), true);
10193f9b6cecSCC Chou 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), UFS_HS_G1);
10203f9b6cecSCC Chou 
10213f9b6cecSCC Chou 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
10223f9b6cecSCC Chou 			       dev_req_params->lane_tx);
10233f9b6cecSCC Chou 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES),
10243f9b6cecSCC Chou 			       dev_req_params->lane_rx);
10253f9b6cecSCC Chou 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES),
10263f9b6cecSCC Chou 			       dev_req_params->hs_rate);
10273f9b6cecSCC Chou 
10283f9b6cecSCC Chou 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE),
10293f9b6cecSCC Chou 			       PA_NO_ADAPT);
10303f9b6cecSCC Chou 
10313f9b6cecSCC Chou 		ret = ufshcd_uic_change_pwr_mode(hba,
10323f9b6cecSCC Chou 					FASTAUTO_MODE << 4 | FASTAUTO_MODE);
10333f9b6cecSCC Chou 
10343f9b6cecSCC Chou 		if (ret) {
10353f9b6cecSCC Chou 			dev_err(hba->dev, "%s: HSG1B FASTAUTO failed ret=%d\n",
10363f9b6cecSCC Chou 				__func__, ret);
10373f9b6cecSCC Chou 		}
10383f9b6cecSCC Chou 	}
10393f9b6cecSCC Chou 
1040dd11376bSBart Van Assche 	if (host->hw_ver.major >= 3) {
1041dd11376bSBart Van Assche 		ret = ufshcd_dme_configure_adapt(hba,
1042dd11376bSBart Van Assche 					   dev_req_params->gear_tx,
1043dd11376bSBart Van Assche 					   PA_INITIAL_ADAPT);
1044dd11376bSBart Van Assche 	}
1045dd11376bSBart Van Assche 
1046dd11376bSBart Van Assche 	return ret;
1047dd11376bSBart Van Assche }
1048dd11376bSBart Van Assche 
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)1049dd11376bSBart Van Assche static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba,
1050dd11376bSBart Van Assche 				     enum ufs_notify_change_status stage,
1051dd11376bSBart Van Assche 				     struct ufs_pa_layer_attr *dev_max_params,
1052dd11376bSBart Van Assche 				     struct ufs_pa_layer_attr *dev_req_params)
1053dd11376bSBart Van Assche {
1054dd11376bSBart Van Assche 	int ret = 0;
1055dd11376bSBart Van Assche 
1056dd11376bSBart Van Assche 	switch (stage) {
1057dd11376bSBart Van Assche 	case PRE_CHANGE:
1058dd11376bSBart Van Assche 		ret = ufs_mtk_pre_pwr_change(hba, dev_max_params,
1059dd11376bSBart Van Assche 					     dev_req_params);
1060dd11376bSBart Van Assche 		break;
1061dd11376bSBart Van Assche 	case POST_CHANGE:
1062dd11376bSBart Van Assche 		break;
1063dd11376bSBart Van Assche 	default:
1064dd11376bSBart Van Assche 		ret = -EINVAL;
1065dd11376bSBart Van Assche 		break;
1066dd11376bSBart Van Assche 	}
1067dd11376bSBart Van Assche 
1068dd11376bSBart Van Assche 	return ret;
1069dd11376bSBart Van Assche }
1070dd11376bSBart Van Assche 
ufs_mtk_unipro_set_lpm(struct ufs_hba * hba,bool lpm)1071dd11376bSBart Van Assche static int ufs_mtk_unipro_set_lpm(struct ufs_hba *hba, bool lpm)
1072dd11376bSBart Van Assche {
1073dd11376bSBart Van Assche 	int ret;
1074dd11376bSBart Van Assche 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
1075dd11376bSBart Van Assche 
1076dd11376bSBart Van Assche 	ret = ufshcd_dme_set(hba,
1077dd11376bSBart Van Assche 			     UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0),
1078dd11376bSBart Van Assche 			     lpm ? 1 : 0);
1079dd11376bSBart Van Assche 	if (!ret || !lpm) {
1080dd11376bSBart Van Assche 		/*
1081dd11376bSBart Van Assche 		 * Forcibly set as non-LPM mode if UIC commands is failed
1082dd11376bSBart Van Assche 		 * to use default hba_enable_delay_us value for re-enabling
1083dd11376bSBart Van Assche 		 * the host.
1084dd11376bSBart Van Assche 		 */
1085dd11376bSBart Van Assche 		host->unipro_lpm = lpm;
1086dd11376bSBart Van Assche 	}
1087dd11376bSBart Van Assche 
1088dd11376bSBart Van Assche 	return ret;
1089dd11376bSBart Van Assche }
1090dd11376bSBart Van Assche 
ufs_mtk_pre_link(struct ufs_hba * hba)1091dd11376bSBart Van Assche static int ufs_mtk_pre_link(struct ufs_hba *hba)
1092dd11376bSBart Van Assche {
1093dd11376bSBart Van Assche 	int ret;
1094dd11376bSBart Van Assche 	u32 tmp;
1095dd11376bSBart Van Assche 
1096dd11376bSBart Van Assche 	ufs_mtk_get_controller_version(hba);
1097dd11376bSBart Van Assche 
1098dd11376bSBart Van Assche 	ret = ufs_mtk_unipro_set_lpm(hba, false);
1099dd11376bSBart Van Assche 	if (ret)
1100dd11376bSBart Van Assche 		return ret;
1101dd11376bSBart Van Assche 
1102dd11376bSBart Van Assche 	/*
1103dd11376bSBart Van Assche 	 * Setting PA_Local_TX_LCC_Enable to 0 before link startup
1104dd11376bSBart Van Assche 	 * to make sure that both host and device TX LCC are disabled
1105dd11376bSBart Van Assche 	 * once link startup is completed.
1106dd11376bSBart Van Assche 	 */
1107dd11376bSBart Van Assche 	ret = ufshcd_disable_host_tx_lcc(hba);
1108dd11376bSBart Van Assche 	if (ret)
1109dd11376bSBart Van Assche 		return ret;
1110dd11376bSBart Van Assche 
1111dd11376bSBart Van Assche 	/* disable deep stall */
1112dd11376bSBart Van Assche 	ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
1113dd11376bSBart Van Assche 	if (ret)
1114dd11376bSBart Van Assche 		return ret;
1115dd11376bSBart Van Assche 
1116dd11376bSBart Van Assche 	tmp &= ~(1 << 6);
1117dd11376bSBart Van Assche 
1118dd11376bSBart Van Assche 	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
1119dd11376bSBart Van Assche 
1120dd11376bSBart Van Assche 	return ret;
1121dd11376bSBart Van Assche }
1122dd11376bSBart Van Assche 
ufs_mtk_setup_clk_gating(struct ufs_hba * hba)1123dd11376bSBart Van Assche static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
1124dd11376bSBart Van Assche {
1125dd11376bSBart Van Assche 	u32 ah_ms;
1126dd11376bSBart Van Assche 
1127dd11376bSBart Van Assche 	if (ufshcd_is_clkgating_allowed(hba)) {
1128dd11376bSBart Van Assche 		if (ufshcd_is_auto_hibern8_supported(hba) && hba->ahit)
1129dd11376bSBart Van Assche 			ah_ms = FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK,
1130dd11376bSBart Van Assche 					  hba->ahit);
1131dd11376bSBart Van Assche 		else
1132dd11376bSBart Van Assche 			ah_ms = 10;
1133dd11376bSBart Van Assche 		ufshcd_clkgate_delay_set(hba->dev, ah_ms + 5);
1134dd11376bSBart Van Assche 	}
1135dd11376bSBart Van Assche }
1136dd11376bSBart Van Assche 
ufs_mtk_post_link(struct ufs_hba * hba)1137d29c32efSChanWoo Lee static void ufs_mtk_post_link(struct ufs_hba *hba)
1138dd11376bSBart Van Assche {
1139dd11376bSBart Van Assche 	/* enable unipro clock gating feature */
1140dd11376bSBart Van Assche 	ufs_mtk_cfg_unipro_cg(hba, true);
1141dd11376bSBart Van Assche 
1142dd11376bSBart Van Assche 	/* will be configured during probe hba */
1143dd11376bSBart Van Assche 	if (ufshcd_is_auto_hibern8_supported(hba))
1144dd11376bSBart Van Assche 		hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 10) |
1145dd11376bSBart Van Assche 			FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3);
1146dd11376bSBart Van Assche 
1147dd11376bSBart Van Assche 	ufs_mtk_setup_clk_gating(hba);
1148dd11376bSBart Van Assche }
1149dd11376bSBart Van Assche 
ufs_mtk_link_startup_notify(struct ufs_hba * hba,enum ufs_notify_change_status stage)1150dd11376bSBart Van Assche static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
1151dd11376bSBart Van Assche 				       enum ufs_notify_change_status stage)
1152dd11376bSBart Van Assche {
1153dd11376bSBart Van Assche 	int ret = 0;
1154dd11376bSBart Van Assche 
1155dd11376bSBart Van Assche 	switch (stage) {
1156dd11376bSBart Van Assche 	case PRE_CHANGE:
1157dd11376bSBart Van Assche 		ret = ufs_mtk_pre_link(hba);
1158dd11376bSBart Van Assche 		break;
1159dd11376bSBart Van Assche 	case POST_CHANGE:
1160d29c32efSChanWoo Lee 		ufs_mtk_post_link(hba);
1161dd11376bSBart Van Assche 		break;
1162dd11376bSBart Van Assche 	default:
1163dd11376bSBart Van Assche 		ret = -EINVAL;
1164dd11376bSBart Van Assche 		break;
1165dd11376bSBart Van Assche 	}
1166dd11376bSBart Van Assche 
1167dd11376bSBart Van Assche 	return ret;
1168dd11376bSBart Van Assche }
1169dd11376bSBart Van Assche 
ufs_mtk_device_reset(struct ufs_hba * hba)1170dd11376bSBart Van Assche static int ufs_mtk_device_reset(struct ufs_hba *hba)
1171dd11376bSBart Van Assche {
1172dd11376bSBart Van Assche 	struct arm_smccc_res res;
1173dd11376bSBart Van Assche 
1174dd11376bSBart Van Assche 	/* disable hba before device reset */
1175dd11376bSBart Van Assche 	ufshcd_hba_stop(hba);
1176dd11376bSBart Van Assche 
1177dd11376bSBart Van Assche 	ufs_mtk_device_reset_ctrl(0, res);
1178dd11376bSBart Van Assche 
1179dd11376bSBart Van Assche 	/*
1180dd11376bSBart Van Assche 	 * The reset signal is active low. UFS devices shall detect
1181dd11376bSBart Van Assche 	 * more than or equal to 1us of positive or negative RST_n
1182dd11376bSBart Van Assche 	 * pulse width.
1183dd11376bSBart Van Assche 	 *
1184dd11376bSBart Van Assche 	 * To be on safe side, keep the reset low for at least 10us.
1185dd11376bSBart Van Assche 	 */
1186dd11376bSBart Van Assche 	usleep_range(10, 15);
1187dd11376bSBart Van Assche 
1188dd11376bSBart Van Assche 	ufs_mtk_device_reset_ctrl(1, res);
1189dd11376bSBart Van Assche 
1190dd11376bSBart Van Assche 	/* Some devices may need time to respond to rst_n */
1191dd11376bSBart Van Assche 	usleep_range(10000, 15000);
1192dd11376bSBart Van Assche 
1193dd11376bSBart Van Assche 	dev_info(hba->dev, "device reset done\n");
1194dd11376bSBart Van Assche 
1195dd11376bSBart Van Assche 	return 0;
1196dd11376bSBart Van Assche }
1197dd11376bSBart Van Assche 
ufs_mtk_link_set_hpm(struct ufs_hba * hba)1198dd11376bSBart Van Assche static int ufs_mtk_link_set_hpm(struct ufs_hba *hba)
1199dd11376bSBart Van Assche {
1200dd11376bSBart Van Assche 	int err;
1201dd11376bSBart Van Assche 
1202dd11376bSBart Van Assche 	err = ufshcd_hba_enable(hba);
1203dd11376bSBart Van Assche 	if (err)
1204dd11376bSBart Van Assche 		return err;
1205dd11376bSBart Van Assche 
1206dd11376bSBart Van Assche 	err = ufs_mtk_unipro_set_lpm(hba, false);
1207dd11376bSBart Van Assche 	if (err)
1208dd11376bSBart Van Assche 		return err;
1209dd11376bSBart Van Assche 
1210dd11376bSBart Van Assche 	err = ufshcd_uic_hibern8_exit(hba);
1211dd11376bSBart Van Assche 	if (!err)
1212dd11376bSBart Van Assche 		ufshcd_set_link_active(hba);
1213dd11376bSBart Van Assche 	else
1214dd11376bSBart Van Assche 		return err;
1215dd11376bSBart Van Assche 
1216e152a616SPo-Wen Kao 	if (!hba->mcq_enabled) {
1217dd11376bSBart Van Assche 		err = ufshcd_make_hba_operational(hba);
1218e152a616SPo-Wen Kao 	} else {
1219e152a616SPo-Wen Kao 		ufs_mtk_config_mcq(hba, false);
1220e152a616SPo-Wen Kao 		ufshcd_mcq_make_queues_operational(hba);
1221e152a616SPo-Wen Kao 		ufshcd_mcq_config_mac(hba, hba->nutrs);
1222e152a616SPo-Wen Kao 		/* Enable MCQ mode */
1223e152a616SPo-Wen Kao 		ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x1,
1224e152a616SPo-Wen Kao 			      REG_UFS_MEM_CFG);
1225e152a616SPo-Wen Kao 	}
1226e152a616SPo-Wen Kao 
1227dd11376bSBart Van Assche 	if (err)
1228dd11376bSBart Van Assche 		return err;
1229dd11376bSBart Van Assche 
1230dd11376bSBart Van Assche 	return 0;
1231dd11376bSBart Van Assche }
1232dd11376bSBart Van Assche 
ufs_mtk_link_set_lpm(struct ufs_hba * hba)1233dd11376bSBart Van Assche static int ufs_mtk_link_set_lpm(struct ufs_hba *hba)
1234dd11376bSBart Van Assche {
1235dd11376bSBart Van Assche 	int err;
1236dd11376bSBart Van Assche 
12374918694cSPo-Wen Kao 	/* Disable reset confirm feature by UniPro */
12384918694cSPo-Wen Kao 	ufshcd_writel(hba,
12394918694cSPo-Wen Kao 		      (ufshcd_readl(hba, REG_UFS_XOUFS_CTRL) & ~0x100),
12404918694cSPo-Wen Kao 		      REG_UFS_XOUFS_CTRL);
12414918694cSPo-Wen Kao 
1242dd11376bSBart Van Assche 	err = ufs_mtk_unipro_set_lpm(hba, true);
1243dd11376bSBart Van Assche 	if (err) {
1244dd11376bSBart Van Assche 		/* Resume UniPro state for following error recovery */
1245dd11376bSBart Van Assche 		ufs_mtk_unipro_set_lpm(hba, false);
1246dd11376bSBart Van Assche 		return err;
1247dd11376bSBart Van Assche 	}
1248dd11376bSBart Van Assche 
1249dd11376bSBart Van Assche 	return 0;
1250dd11376bSBart Van Assche }
1251dd11376bSBart Van Assche 
ufs_mtk_vccqx_set_lpm(struct ufs_hba * hba,bool lpm)125242b19283SStanley Chu static void ufs_mtk_vccqx_set_lpm(struct ufs_hba *hba, bool lpm)
1253dd11376bSBart Van Assche {
12540836cc25SPeter Wang 	struct ufs_vreg *vccqx = NULL;
12550836cc25SPeter Wang 
125642b19283SStanley Chu 	if (hba->vreg_info.vccq)
125742b19283SStanley Chu 		vccqx = hba->vreg_info.vccq;
125842b19283SStanley Chu 	else
125942b19283SStanley Chu 		vccqx = hba->vreg_info.vccq2;
126042b19283SStanley Chu 
126142b19283SStanley Chu 	regulator_set_mode(vccqx->reg,
126242b19283SStanley Chu 			   lpm ? REGULATOR_MODE_IDLE : REGULATOR_MODE_NORMAL);
126342b19283SStanley Chu }
126442b19283SStanley Chu 
ufs_mtk_vsx_set_lpm(struct ufs_hba * hba,bool lpm)126542b19283SStanley Chu static void ufs_mtk_vsx_set_lpm(struct ufs_hba *hba, bool lpm)
126642b19283SStanley Chu {
126742b19283SStanley Chu 	struct arm_smccc_res res;
126842b19283SStanley Chu 
126942b19283SStanley Chu 	ufs_mtk_device_pwr_ctrl(!lpm,
127042b19283SStanley Chu 				(unsigned long)hba->dev_info.wspecversion,
127142b19283SStanley Chu 				res);
127242b19283SStanley Chu }
127342b19283SStanley Chu 
ufs_mtk_dev_vreg_set_lpm(struct ufs_hba * hba,bool lpm)127442b19283SStanley Chu static void ufs_mtk_dev_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
127542b19283SStanley Chu {
12760836cc25SPeter Wang 	if (!hba->vreg_info.vccq && !hba->vreg_info.vccq2)
12770836cc25SPeter Wang 		return;
12780836cc25SPeter Wang 
12790836cc25SPeter Wang 	/* Skip if VCC is assumed always-on */
12800836cc25SPeter Wang 	if (!hba->vreg_info.vcc)
1281dd11376bSBart Van Assche 		return;
1282dd11376bSBart Van Assche 
1283005ffdf0SPo-Wen Kao 	/* Bypass LPM when device is still active */
1284005ffdf0SPo-Wen Kao 	if (lpm && ufshcd_is_ufs_dev_active(hba))
1285005ffdf0SPo-Wen Kao 		return;
1286005ffdf0SPo-Wen Kao 
1287005ffdf0SPo-Wen Kao 	/* Bypass LPM if VCC is enabled */
1288005ffdf0SPo-Wen Kao 	if (lpm && hba->vreg_info.vcc->enabled)
1289005ffdf0SPo-Wen Kao 		return;
1290005ffdf0SPo-Wen Kao 
129142b19283SStanley Chu 	if (lpm) {
129242b19283SStanley Chu 		ufs_mtk_vccqx_set_lpm(hba, lpm);
129342b19283SStanley Chu 		ufs_mtk_vsx_set_lpm(hba, lpm);
129442b19283SStanley Chu 	} else {
129542b19283SStanley Chu 		ufs_mtk_vsx_set_lpm(hba, lpm);
129642b19283SStanley Chu 		ufs_mtk_vccqx_set_lpm(hba, lpm);
129742b19283SStanley Chu 	}
1298dd11376bSBart Van Assche }
1299dd11376bSBart Van Assche 
ufs_mtk_auto_hibern8_disable(struct ufs_hba * hba)1300dd11376bSBart Van Assche static void ufs_mtk_auto_hibern8_disable(struct ufs_hba *hba)
1301dd11376bSBart Van Assche {
1302dd11376bSBart Van Assche 	int ret;
1303dd11376bSBart Van Assche 
1304dd11376bSBart Van Assche 	/* disable auto-hibern8 */
1305dd11376bSBart Van Assche 	ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER);
1306dd11376bSBart Van Assche 
1307dd11376bSBart Van Assche 	/* wait host return to idle state when auto-hibern8 off */
1308dd11376bSBart Van Assche 	ufs_mtk_wait_idle_state(hba, 5);
1309dd11376bSBart Van Assche 
1310dd11376bSBart Van Assche 	ret = ufs_mtk_wait_link_state(hba, VS_LINK_UP, 100);
1311dd11376bSBart Van Assche 	if (ret)
1312dd11376bSBart Van Assche 		dev_warn(hba->dev, "exit h8 state fail, ret=%d\n", ret);
1313dd11376bSBart Van Assche }
1314dd11376bSBart Van Assche 
ufs_mtk_suspend(struct ufs_hba * hba,enum ufs_pm_op pm_op,enum ufs_notify_change_status status)1315dd11376bSBart Van Assche static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
1316dd11376bSBart Van Assche 	enum ufs_notify_change_status status)
1317dd11376bSBart Van Assche {
1318dd11376bSBart Van Assche 	int err;
1319dd11376bSBart Van Assche 	struct arm_smccc_res res;
1320dd11376bSBart Van Assche 
1321dd11376bSBart Van Assche 	if (status == PRE_CHANGE) {
1322d29c32efSChanWoo Lee 		if (ufshcd_is_auto_hibern8_supported(hba))
1323dd11376bSBart Van Assche 			ufs_mtk_auto_hibern8_disable(hba);
1324dd11376bSBart Van Assche 		return 0;
1325dd11376bSBart Van Assche 	}
1326dd11376bSBart Van Assche 
1327dd11376bSBart Van Assche 	if (ufshcd_is_link_hibern8(hba)) {
1328dd11376bSBart Van Assche 		err = ufs_mtk_link_set_lpm(hba);
1329dd11376bSBart Van Assche 		if (err)
1330dd11376bSBart Van Assche 			goto fail;
1331dd11376bSBart Van Assche 	}
1332dd11376bSBart Van Assche 
1333dd11376bSBart Van Assche 	if (!ufshcd_is_link_active(hba)) {
1334dd11376bSBart Van Assche 		/*
1335dd11376bSBart Van Assche 		 * Make sure no error will be returned to prevent
1336dd11376bSBart Van Assche 		 * ufshcd_suspend() re-enabling regulators while vreg is still
1337dd11376bSBart Van Assche 		 * in low-power mode.
1338dd11376bSBart Van Assche 		 */
1339dd11376bSBart Van Assche 		err = ufs_mtk_mphy_power_on(hba, false);
1340dd11376bSBart Van Assche 		if (err)
1341dd11376bSBart Van Assche 			goto fail;
1342dd11376bSBart Van Assche 	}
1343dd11376bSBart Van Assche 
1344dd11376bSBart Van Assche 	if (ufshcd_is_link_off(hba))
1345dd11376bSBart Van Assche 		ufs_mtk_device_reset_ctrl(0, res);
1346dd11376bSBart Van Assche 
13472cf5cb2bSPo-Wen Kao 	ufs_mtk_host_pwr_ctrl(HOST_PWR_HCI, false, res);
13482cf5cb2bSPo-Wen Kao 
1349dd11376bSBart Van Assche 	return 0;
1350dd11376bSBart Van Assche fail:
1351dd11376bSBart Van Assche 	/*
1352dd11376bSBart Van Assche 	 * Set link as off state enforcedly to trigger
1353dd11376bSBart Van Assche 	 * ufshcd_host_reset_and_restore() in ufshcd_suspend()
1354dd11376bSBart Van Assche 	 * for completed host reset.
1355dd11376bSBart Van Assche 	 */
1356dd11376bSBart Van Assche 	ufshcd_set_link_off(hba);
1357dd11376bSBart Van Assche 	return -EAGAIN;
1358dd11376bSBart Van Assche }
1359dd11376bSBart Van Assche 
ufs_mtk_resume(struct ufs_hba * hba,enum ufs_pm_op pm_op)1360dd11376bSBart Van Assche static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
1361dd11376bSBart Van Assche {
1362dd11376bSBart Van Assche 	int err;
13632cf5cb2bSPo-Wen Kao 	struct arm_smccc_res res;
1364dd11376bSBart Van Assche 
13653fd23b8dSPo-Wen Kao 	if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL)
136642b19283SStanley Chu 		ufs_mtk_dev_vreg_set_lpm(hba, false);
13673fd23b8dSPo-Wen Kao 
13682cf5cb2bSPo-Wen Kao 	ufs_mtk_host_pwr_ctrl(HOST_PWR_HCI, true, res);
13692cf5cb2bSPo-Wen Kao 
1370dd11376bSBart Van Assche 	err = ufs_mtk_mphy_power_on(hba, true);
1371dd11376bSBart Van Assche 	if (err)
1372dd11376bSBart Van Assche 		goto fail;
1373dd11376bSBart Van Assche 
1374dd11376bSBart Van Assche 	if (ufshcd_is_link_hibern8(hba)) {
1375dd11376bSBart Van Assche 		err = ufs_mtk_link_set_hpm(hba);
1376dd11376bSBart Van Assche 		if (err)
1377dd11376bSBart Van Assche 			goto fail;
1378dd11376bSBart Van Assche 	}
1379dd11376bSBart Van Assche 
1380dd11376bSBart Van Assche 	return 0;
1381dd11376bSBart Van Assche fail:
1382dd11376bSBart Van Assche 	return ufshcd_link_recovery(hba);
1383dd11376bSBart Van Assche }
1384dd11376bSBart Van Assche 
ufs_mtk_dbg_register_dump(struct ufs_hba * hba)1385dd11376bSBart Van Assche static void ufs_mtk_dbg_register_dump(struct ufs_hba *hba)
1386dd11376bSBart Van Assche {
138736489357SPeter Wang 	/* Dump ufshci register 0x140 ~ 0x14C */
138836489357SPeter Wang 	ufshcd_dump_regs(hba, REG_UFS_XOUFS_CTRL, 0x10,
138936489357SPeter Wang 			 "XOUFS Ctrl (0x140): ");
1390dd11376bSBart Van Assche 
1391dd11376bSBart Van Assche 	ufshcd_dump_regs(hba, REG_UFS_EXTREG, 0x4, "Ext Reg ");
1392dd11376bSBart Van Assche 
139336489357SPeter Wang 	/* Dump ufshci register 0x2200 ~ 0x22AC */
1394dd11376bSBart Van Assche 	ufshcd_dump_regs(hba, REG_UFS_MPHYCTRL,
1395dd11376bSBart Van Assche 			 REG_UFS_REJECT_MON - REG_UFS_MPHYCTRL + 4,
139636489357SPeter Wang 			 "MPHY Ctrl (0x2200): ");
1397dd11376bSBart Van Assche 
1398dd11376bSBart Van Assche 	/* Direct debugging information to REG_MTK_PROBE */
1399dd11376bSBart Van Assche 	ufs_mtk_dbg_sel(hba);
1400dd11376bSBart Van Assche 	ufshcd_dump_regs(hba, REG_UFS_PROBE, 0x4, "Debug Probe ");
1401dd11376bSBart Van Assche }
1402dd11376bSBart Van Assche 
ufs_mtk_apply_dev_quirks(struct ufs_hba * hba)1403dd11376bSBart Van Assche static int ufs_mtk_apply_dev_quirks(struct ufs_hba *hba)
1404dd11376bSBart Van Assche {
1405dd11376bSBart Van Assche 	struct ufs_dev_info *dev_info = &hba->dev_info;
1406dd11376bSBart Van Assche 	u16 mid = dev_info->wmanufacturerid;
1407dd11376bSBart Van Assche 
1408c64c487dSPeter Wang 	if (mid == UFS_VENDOR_SAMSUNG) {
1409dd11376bSBart Van Assche 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 6);
1410c64c487dSPeter Wang 		ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME), 10);
1411c64c487dSPeter Wang 	}
1412dd11376bSBart Van Assche 
1413dd11376bSBart Van Assche 	/*
1414dd11376bSBart Van Assche 	 * Decide waiting time before gating reference clock and
1415dd11376bSBart Van Assche 	 * after ungating reference clock according to vendors'
1416dd11376bSBart Van Assche 	 * requirements.
1417dd11376bSBart Van Assche 	 */
1418dd11376bSBart Van Assche 	if (mid == UFS_VENDOR_SAMSUNG)
1419dd11376bSBart Van Assche 		ufs_mtk_setup_ref_clk_wait_us(hba, 1);
1420dd11376bSBart Van Assche 	else if (mid == UFS_VENDOR_SKHYNIX)
1421dd11376bSBart Van Assche 		ufs_mtk_setup_ref_clk_wait_us(hba, 30);
1422dd11376bSBart Van Assche 	else if (mid == UFS_VENDOR_TOSHIBA)
1423dd11376bSBart Van Assche 		ufs_mtk_setup_ref_clk_wait_us(hba, 100);
1424dd11376bSBart Van Assche 	else
1425dd11376bSBart Van Assche 		ufs_mtk_setup_ref_clk_wait_us(hba,
1426dd11376bSBart Van Assche 					      REFCLK_DEFAULT_WAIT_US);
1427dd11376bSBart Van Assche 	return 0;
1428dd11376bSBart Van Assche }
1429dd11376bSBart Van Assche 
ufs_mtk_fixup_dev_quirks(struct ufs_hba * hba)1430dd11376bSBart Van Assche static void ufs_mtk_fixup_dev_quirks(struct ufs_hba *hba)
1431dd11376bSBart Van Assche {
1432dd11376bSBart Van Assche 	ufshcd_fixup_dev_quirks(hba, ufs_mtk_dev_fixups);
1433dd11376bSBart Van Assche 
1434dd11376bSBart Van Assche 	if (ufs_mtk_is_broken_vcc(hba) && hba->vreg_info.vcc &&
1435dd11376bSBart Van Assche 	    (hba->dev_quirks & UFS_DEVICE_QUIRK_DELAY_AFTER_LPM)) {
1436dd11376bSBart Van Assche 		hba->vreg_info.vcc->always_on = true;
1437dd11376bSBart Van Assche 		/*
1438dd11376bSBart Van Assche 		 * VCC will be kept always-on thus we don't
1439dd11376bSBart Van Assche 		 * need any delay during regulator operations
1440dd11376bSBart Van Assche 		 */
1441dd11376bSBart Van Assche 		hba->dev_quirks &= ~(UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
1442dd11376bSBart Van Assche 			UFS_DEVICE_QUIRK_DELAY_AFTER_LPM);
1443dd11376bSBart Van Assche 	}
1444ece418d0SStanley Chu 
1445ece418d0SStanley Chu 	ufs_mtk_vreg_fix_vcc(hba);
1446cb142b6dSStanley Chu 	ufs_mtk_vreg_fix_vccqx(hba);
1447dd11376bSBart Van Assche }
1448dd11376bSBart Van Assche 
ufs_mtk_event_notify(struct ufs_hba * hba,enum ufs_event_type evt,void * data)1449dd11376bSBart Van Assche static void ufs_mtk_event_notify(struct ufs_hba *hba,
1450dd11376bSBart Van Assche 				 enum ufs_event_type evt, void *data)
1451dd11376bSBart Van Assche {
1452dd11376bSBart Van Assche 	unsigned int val = *(u32 *)data;
14534d869fe6SStanley Chu 	unsigned long reg;
14544d869fe6SStanley Chu 	u8 bit;
1455dd11376bSBart Van Assche 
1456dd11376bSBart Van Assche 	trace_ufs_mtk_event(evt, val);
14574d869fe6SStanley Chu 
14584d869fe6SStanley Chu 	/* Print details of UIC Errors */
14594d869fe6SStanley Chu 	if (evt <= UFS_EVT_DME_ERR) {
14604d869fe6SStanley Chu 		dev_info(hba->dev,
14614d869fe6SStanley Chu 			 "Host UIC Error Code (%s): %08x\n",
14624d869fe6SStanley Chu 			 ufs_uic_err_str[evt], val);
14634d869fe6SStanley Chu 		reg = val;
14644d869fe6SStanley Chu 	}
14654d869fe6SStanley Chu 
14664d869fe6SStanley Chu 	if (evt == UFS_EVT_PA_ERR) {
14674d869fe6SStanley Chu 		for_each_set_bit(bit, &reg, ARRAY_SIZE(ufs_uic_pa_err_str))
14684d869fe6SStanley Chu 			dev_info(hba->dev, "%s\n", ufs_uic_pa_err_str[bit]);
14694d869fe6SStanley Chu 	}
14704d869fe6SStanley Chu 
14714d869fe6SStanley Chu 	if (evt == UFS_EVT_DL_ERR) {
14724d869fe6SStanley Chu 		for_each_set_bit(bit, &reg, ARRAY_SIZE(ufs_uic_dl_err_str))
14734d869fe6SStanley Chu 			dev_info(hba->dev, "%s\n", ufs_uic_dl_err_str[bit]);
14744d869fe6SStanley Chu 	}
1475dd11376bSBart Van Assche }
1476dd11376bSBart Van Assche 
ufs_mtk_config_scaling_param(struct ufs_hba * hba,struct devfreq_dev_profile * profile,struct devfreq_simple_ondemand_data * data)1477b7dbc686SPo-Wen Kao static void ufs_mtk_config_scaling_param(struct ufs_hba *hba,
1478b7dbc686SPo-Wen Kao 				struct devfreq_dev_profile *profile,
1479b7dbc686SPo-Wen Kao 				struct devfreq_simple_ondemand_data *data)
1480b7dbc686SPo-Wen Kao {
1481b7dbc686SPo-Wen Kao 	/* Customize min gear in clk scaling */
1482b7dbc686SPo-Wen Kao 	hba->clk_scaling.min_gear = UFS_HS_G4;
1483b7dbc686SPo-Wen Kao 
1484b7dbc686SPo-Wen Kao 	hba->vps->devfreq_profile.polling_ms = 200;
1485b7dbc686SPo-Wen Kao 	hba->vps->ondemand_data.upthreshold = 50;
1486b7dbc686SPo-Wen Kao 	hba->vps->ondemand_data.downdifferential = 20;
1487b7dbc686SPo-Wen Kao }
1488b7dbc686SPo-Wen Kao 
1489b7dbc686SPo-Wen Kao /**
1490b7dbc686SPo-Wen Kao  * ufs_mtk_clk_scale - Internal clk scaling operation
1491b7dbc686SPo-Wen Kao  *
1492b7dbc686SPo-Wen Kao  * MTK platform supports clk scaling by switching parent of ufs_sel(mux).
1493b7dbc686SPo-Wen Kao  * The ufs_sel downstream to ufs_ck which feeds directly to UFS hardware.
1494b7dbc686SPo-Wen Kao  * Max and min clocks rate of ufs_sel defined in dts should match rate of
1495b7dbc686SPo-Wen Kao  * "ufs_sel_max_src" and "ufs_sel_min_src" respectively.
1496b7dbc686SPo-Wen Kao  * This prevent changing rate of pll clock that is shared between modules.
1497b7dbc686SPo-Wen Kao  *
1498b7dbc686SPo-Wen Kao  * @hba: per adapter instance
1499b7dbc686SPo-Wen Kao  * @scale_up: True for scaling up and false for scaling down
1500b7dbc686SPo-Wen Kao  */
ufs_mtk_clk_scale(struct ufs_hba * hba,bool scale_up)1501b7dbc686SPo-Wen Kao static void ufs_mtk_clk_scale(struct ufs_hba *hba, bool scale_up)
1502b7dbc686SPo-Wen Kao {
1503b7dbc686SPo-Wen Kao 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
1504b7dbc686SPo-Wen Kao 	struct ufs_mtk_clk *mclk = &host->mclk;
1505b7dbc686SPo-Wen Kao 	struct ufs_clk_info *clki = mclk->ufs_sel_clki;
1506b7dbc686SPo-Wen Kao 	int ret = 0;
1507b7dbc686SPo-Wen Kao 
1508b7dbc686SPo-Wen Kao 	ret = clk_prepare_enable(clki->clk);
1509b7dbc686SPo-Wen Kao 	if (ret) {
1510b7dbc686SPo-Wen Kao 		dev_info(hba->dev,
1511b7dbc686SPo-Wen Kao 			 "clk_prepare_enable() fail, ret: %d\n", ret);
1512b7dbc686SPo-Wen Kao 		return;
1513b7dbc686SPo-Wen Kao 	}
1514b7dbc686SPo-Wen Kao 
1515b7dbc686SPo-Wen Kao 	if (scale_up) {
1516b7dbc686SPo-Wen Kao 		ret = clk_set_parent(clki->clk, mclk->ufs_sel_max_clki->clk);
1517b7dbc686SPo-Wen Kao 		clki->curr_freq = clki->max_freq;
1518b7dbc686SPo-Wen Kao 	} else {
1519b7dbc686SPo-Wen Kao 		ret = clk_set_parent(clki->clk, mclk->ufs_sel_min_clki->clk);
1520b7dbc686SPo-Wen Kao 		clki->curr_freq = clki->min_freq;
1521b7dbc686SPo-Wen Kao 	}
1522b7dbc686SPo-Wen Kao 
1523b7dbc686SPo-Wen Kao 	if (ret) {
1524b7dbc686SPo-Wen Kao 		dev_info(hba->dev,
1525b7dbc686SPo-Wen Kao 			 "Failed to set ufs_sel_clki, ret: %d\n", ret);
1526b7dbc686SPo-Wen Kao 	}
1527b7dbc686SPo-Wen Kao 
1528b7dbc686SPo-Wen Kao 	clk_disable_unprepare(clki->clk);
1529b7dbc686SPo-Wen Kao 
1530b7dbc686SPo-Wen Kao 	trace_ufs_mtk_clk_scale(clki->name, scale_up, clk_get_rate(clki->clk));
1531b7dbc686SPo-Wen Kao }
1532b7dbc686SPo-Wen Kao 
ufs_mtk_clk_scale_notify(struct ufs_hba * hba,bool scale_up,enum ufs_notify_change_status status)1533b7dbc686SPo-Wen Kao static int ufs_mtk_clk_scale_notify(struct ufs_hba *hba, bool scale_up,
1534b7dbc686SPo-Wen Kao 				    enum ufs_notify_change_status status)
1535b7dbc686SPo-Wen Kao {
1536b7dbc686SPo-Wen Kao 	if (!ufshcd_is_clkscaling_supported(hba))
1537b7dbc686SPo-Wen Kao 		return 0;
1538b7dbc686SPo-Wen Kao 
1539b7dbc686SPo-Wen Kao 	if (status == PRE_CHANGE) {
1540b7dbc686SPo-Wen Kao 		/* Switch parent before clk_set_rate() */
1541b7dbc686SPo-Wen Kao 		ufs_mtk_clk_scale(hba, scale_up);
1542b7dbc686SPo-Wen Kao 	} else {
1543b7dbc686SPo-Wen Kao 		/* Request interrupt latency QoS accordingly */
1544b7dbc686SPo-Wen Kao 		ufs_mtk_scale_perf(hba, scale_up);
1545b7dbc686SPo-Wen Kao 	}
1546b7dbc686SPo-Wen Kao 
1547b7dbc686SPo-Wen Kao 	return 0;
1548b7dbc686SPo-Wen Kao }
1549b7dbc686SPo-Wen Kao 
ufs_mtk_get_hba_mac(struct ufs_hba * hba)1550e152a616SPo-Wen Kao static int ufs_mtk_get_hba_mac(struct ufs_hba *hba)
1551e152a616SPo-Wen Kao {
1552e152a616SPo-Wen Kao 	return MAX_SUPP_MAC;
1553e152a616SPo-Wen Kao }
1554e152a616SPo-Wen Kao 
ufs_mtk_op_runtime_config(struct ufs_hba * hba)1555e152a616SPo-Wen Kao static int ufs_mtk_op_runtime_config(struct ufs_hba *hba)
1556e152a616SPo-Wen Kao {
1557e152a616SPo-Wen Kao 	struct ufshcd_mcq_opr_info_t *opr;
1558e152a616SPo-Wen Kao 	int i;
1559e152a616SPo-Wen Kao 
1560e152a616SPo-Wen Kao 	hba->mcq_opr[OPR_SQD].offset = REG_UFS_MTK_SQD;
1561e152a616SPo-Wen Kao 	hba->mcq_opr[OPR_SQIS].offset = REG_UFS_MTK_SQIS;
1562e152a616SPo-Wen Kao 	hba->mcq_opr[OPR_CQD].offset = REG_UFS_MTK_CQD;
1563e152a616SPo-Wen Kao 	hba->mcq_opr[OPR_CQIS].offset = REG_UFS_MTK_CQIS;
1564e152a616SPo-Wen Kao 
1565e152a616SPo-Wen Kao 	for (i = 0; i < OPR_MAX; i++) {
1566e152a616SPo-Wen Kao 		opr = &hba->mcq_opr[i];
1567e152a616SPo-Wen Kao 		opr->stride = REG_UFS_MCQ_STRIDE;
1568e152a616SPo-Wen Kao 		opr->base = hba->mmio_base + opr->offset;
1569e152a616SPo-Wen Kao 	}
1570e152a616SPo-Wen Kao 
1571e152a616SPo-Wen Kao 	return 0;
1572e152a616SPo-Wen Kao }
1573e152a616SPo-Wen Kao 
ufs_mtk_mcq_config_resource(struct ufs_hba * hba)1574e152a616SPo-Wen Kao static int ufs_mtk_mcq_config_resource(struct ufs_hba *hba)
1575e152a616SPo-Wen Kao {
1576e152a616SPo-Wen Kao 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
1577e152a616SPo-Wen Kao 
1578e152a616SPo-Wen Kao 	/* fail mcq initialization if interrupt is not filled properly */
1579e152a616SPo-Wen Kao 	if (!host->mcq_nr_intr) {
1580e152a616SPo-Wen Kao 		dev_info(hba->dev, "IRQs not ready. MCQ disabled.");
1581e152a616SPo-Wen Kao 		return -EINVAL;
1582e152a616SPo-Wen Kao 	}
1583e152a616SPo-Wen Kao 
1584e152a616SPo-Wen Kao 	hba->mcq_base = hba->mmio_base + MCQ_QUEUE_OFFSET(hba->mcq_capabilities);
1585e152a616SPo-Wen Kao 	return 0;
1586e152a616SPo-Wen Kao }
1587e152a616SPo-Wen Kao 
ufs_mtk_mcq_intr(int irq,void * __intr_info)1588e152a616SPo-Wen Kao static irqreturn_t ufs_mtk_mcq_intr(int irq, void *__intr_info)
1589e152a616SPo-Wen Kao {
1590e152a616SPo-Wen Kao 	struct ufs_mtk_mcq_intr_info *mcq_intr_info = __intr_info;
1591e152a616SPo-Wen Kao 	struct ufs_hba *hba = mcq_intr_info->hba;
1592e152a616SPo-Wen Kao 	struct ufs_hw_queue *hwq;
1593e152a616SPo-Wen Kao 	u32 events;
1594e152a616SPo-Wen Kao 	int qid = mcq_intr_info->qid;
1595e152a616SPo-Wen Kao 
1596e152a616SPo-Wen Kao 	hwq = &hba->uhq[qid];
1597e152a616SPo-Wen Kao 
1598e152a616SPo-Wen Kao 	events = ufshcd_mcq_read_cqis(hba, qid);
1599e152a616SPo-Wen Kao 	if (events)
1600e152a616SPo-Wen Kao 		ufshcd_mcq_write_cqis(hba, events, qid);
1601e152a616SPo-Wen Kao 
1602e152a616SPo-Wen Kao 	if (events & UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS)
1603e152a616SPo-Wen Kao 		ufshcd_mcq_poll_cqe_lock(hba, hwq);
1604e152a616SPo-Wen Kao 
1605e152a616SPo-Wen Kao 	return IRQ_HANDLED;
1606e152a616SPo-Wen Kao }
1607e152a616SPo-Wen Kao 
ufs_mtk_config_mcq_irq(struct ufs_hba * hba)1608e152a616SPo-Wen Kao static int ufs_mtk_config_mcq_irq(struct ufs_hba *hba)
1609e152a616SPo-Wen Kao {
1610e152a616SPo-Wen Kao 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
1611e152a616SPo-Wen Kao 	u32 irq, i;
1612e152a616SPo-Wen Kao 	int ret;
1613e152a616SPo-Wen Kao 
1614e152a616SPo-Wen Kao 	for (i = 0; i < host->mcq_nr_intr; i++) {
1615e152a616SPo-Wen Kao 		irq = host->mcq_intr_info[i].irq;
1616e152a616SPo-Wen Kao 		if (irq == MTK_MCQ_INVALID_IRQ) {
1617e152a616SPo-Wen Kao 			dev_err(hba->dev, "invalid irq. %d\n", i);
1618e152a616SPo-Wen Kao 			return -ENOPARAM;
1619e152a616SPo-Wen Kao 		}
1620e152a616SPo-Wen Kao 
1621e152a616SPo-Wen Kao 		host->mcq_intr_info[i].qid = i;
1622e152a616SPo-Wen Kao 		ret = devm_request_irq(hba->dev, irq, ufs_mtk_mcq_intr, 0, UFSHCD,
1623e152a616SPo-Wen Kao 				       &host->mcq_intr_info[i]);
1624e152a616SPo-Wen Kao 
1625e152a616SPo-Wen Kao 		dev_dbg(hba->dev, "request irq %d intr %s\n", irq, ret ? "failed" : "");
1626e152a616SPo-Wen Kao 
1627e152a616SPo-Wen Kao 		if (ret) {
1628e152a616SPo-Wen Kao 			dev_err(hba->dev, "Cannot request irq %d\n", ret);
1629e152a616SPo-Wen Kao 			return ret;
1630e152a616SPo-Wen Kao 		}
1631e152a616SPo-Wen Kao 	}
1632e152a616SPo-Wen Kao 
1633e152a616SPo-Wen Kao 	return 0;
1634e152a616SPo-Wen Kao }
1635e152a616SPo-Wen Kao 
ufs_mtk_config_mcq(struct ufs_hba * hba,bool irq)1636e152a616SPo-Wen Kao static int ufs_mtk_config_mcq(struct ufs_hba *hba, bool irq)
1637e152a616SPo-Wen Kao {
1638e152a616SPo-Wen Kao 	struct ufs_mtk_host *host = ufshcd_get_variant(hba);
1639e152a616SPo-Wen Kao 	int ret = 0;
1640e152a616SPo-Wen Kao 
1641e152a616SPo-Wen Kao 	if (!host->mcq_set_intr) {
1642e152a616SPo-Wen Kao 		/* Disable irq option register */
1643e152a616SPo-Wen Kao 		ufshcd_rmwl(hba, MCQ_INTR_EN_MSK, 0, REG_UFS_MMIO_OPT_CTRL_0);
1644e152a616SPo-Wen Kao 
1645e152a616SPo-Wen Kao 		if (irq) {
1646e152a616SPo-Wen Kao 			ret = ufs_mtk_config_mcq_irq(hba);
1647e152a616SPo-Wen Kao 			if (ret)
1648e152a616SPo-Wen Kao 				return ret;
1649e152a616SPo-Wen Kao 		}
1650e152a616SPo-Wen Kao 
1651e152a616SPo-Wen Kao 		host->mcq_set_intr = true;
1652e152a616SPo-Wen Kao 	}
1653e152a616SPo-Wen Kao 
1654e152a616SPo-Wen Kao 	ufshcd_rmwl(hba, MCQ_AH8, MCQ_AH8, REG_UFS_MMIO_OPT_CTRL_0);
1655e152a616SPo-Wen Kao 	ufshcd_rmwl(hba, MCQ_INTR_EN_MSK, MCQ_MULTI_INTR_EN, REG_UFS_MMIO_OPT_CTRL_0);
1656e152a616SPo-Wen Kao 
1657e152a616SPo-Wen Kao 	return 0;
1658e152a616SPo-Wen Kao }
1659e152a616SPo-Wen Kao 
ufs_mtk_config_esi(struct ufs_hba * hba)1660e152a616SPo-Wen Kao static int ufs_mtk_config_esi(struct ufs_hba *hba)
1661e152a616SPo-Wen Kao {
1662e152a616SPo-Wen Kao 	return ufs_mtk_config_mcq(hba, true);
1663e152a616SPo-Wen Kao }
1664e152a616SPo-Wen Kao 
1665dd11376bSBart Van Assche /*
1666dd11376bSBart Van Assche  * struct ufs_hba_mtk_vops - UFS MTK specific variant operations
1667dd11376bSBart Van Assche  *
1668dd11376bSBart Van Assche  * The variant operations configure the necessary controller and PHY
1669dd11376bSBart Van Assche  * handshake during initialization.
1670dd11376bSBart Van Assche  */
1671dd11376bSBart Van Assche static const struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
1672dd11376bSBart Van Assche 	.name                = "mediatek.ufshci",
1673dd11376bSBart Van Assche 	.init                = ufs_mtk_init,
1674dd11376bSBart Van Assche 	.get_ufs_hci_version = ufs_mtk_get_ufs_hci_version,
1675dd11376bSBart Van Assche 	.setup_clocks        = ufs_mtk_setup_clocks,
1676dd11376bSBart Van Assche 	.hce_enable_notify   = ufs_mtk_hce_enable_notify,
1677dd11376bSBart Van Assche 	.link_startup_notify = ufs_mtk_link_startup_notify,
1678dd11376bSBart Van Assche 	.pwr_change_notify   = ufs_mtk_pwr_change_notify,
1679dd11376bSBart Van Assche 	.apply_dev_quirks    = ufs_mtk_apply_dev_quirks,
1680dd11376bSBart Van Assche 	.fixup_dev_quirks    = ufs_mtk_fixup_dev_quirks,
1681dd11376bSBart Van Assche 	.suspend             = ufs_mtk_suspend,
1682dd11376bSBart Van Assche 	.resume              = ufs_mtk_resume,
1683dd11376bSBart Van Assche 	.dbg_register_dump   = ufs_mtk_dbg_register_dump,
1684dd11376bSBart Van Assche 	.device_reset        = ufs_mtk_device_reset,
1685dd11376bSBart Van Assche 	.event_notify        = ufs_mtk_event_notify,
1686b7dbc686SPo-Wen Kao 	.config_scaling_param = ufs_mtk_config_scaling_param,
1687b7dbc686SPo-Wen Kao 	.clk_scale_notify    = ufs_mtk_clk_scale_notify,
1688e152a616SPo-Wen Kao 	/* mcq vops */
1689e152a616SPo-Wen Kao 	.get_hba_mac         = ufs_mtk_get_hba_mac,
1690e152a616SPo-Wen Kao 	.op_runtime_config   = ufs_mtk_op_runtime_config,
1691e152a616SPo-Wen Kao 	.mcq_config_resource = ufs_mtk_mcq_config_resource,
1692e152a616SPo-Wen Kao 	.config_esi          = ufs_mtk_config_esi,
1693dd11376bSBart Van Assche };
1694dd11376bSBart Van Assche 
1695dd11376bSBart Van Assche /**
1696dd11376bSBart Van Assche  * ufs_mtk_probe - probe routine of the driver
1697dd11376bSBart Van Assche  * @pdev: pointer to Platform device handle
1698dd11376bSBart Van Assche  *
1699*3a17fefeSBart Van Assche  * Return: zero for success and non-zero for failure.
1700dd11376bSBart Van Assche  */
ufs_mtk_probe(struct platform_device * pdev)1701dd11376bSBart Van Assche static int ufs_mtk_probe(struct platform_device *pdev)
1702dd11376bSBart Van Assche {
1703dd11376bSBart Van Assche 	int err;
1704dd11376bSBart Van Assche 	struct device *dev = &pdev->dev;
1705dd11376bSBart Van Assche 	struct device_node *reset_node;
1706dd11376bSBart Van Assche 	struct platform_device *reset_pdev;
1707dd11376bSBart Van Assche 	struct device_link *link;
1708dd11376bSBart Van Assche 
1709dd11376bSBart Van Assche 	reset_node = of_find_compatible_node(NULL, NULL,
1710dd11376bSBart Van Assche 					     "ti,syscon-reset");
1711dd11376bSBart Van Assche 	if (!reset_node) {
1712dd11376bSBart Van Assche 		dev_notice(dev, "find ti,syscon-reset fail\n");
1713dd11376bSBart Van Assche 		goto skip_reset;
1714dd11376bSBart Van Assche 	}
1715dd11376bSBart Van Assche 	reset_pdev = of_find_device_by_node(reset_node);
1716dd11376bSBart Van Assche 	if (!reset_pdev) {
1717dd11376bSBart Van Assche 		dev_notice(dev, "find reset_pdev fail\n");
1718dd11376bSBart Van Assche 		goto skip_reset;
1719dd11376bSBart Van Assche 	}
1720dd11376bSBart Van Assche 	link = device_link_add(dev, &reset_pdev->dev,
1721dd11376bSBart Van Assche 		DL_FLAG_AUTOPROBE_CONSUMER);
1722dd11376bSBart Van Assche 	put_device(&reset_pdev->dev);
1723dd11376bSBart Van Assche 	if (!link) {
1724dd11376bSBart Van Assche 		dev_notice(dev, "add reset device_link fail\n");
1725dd11376bSBart Van Assche 		goto skip_reset;
1726dd11376bSBart Van Assche 	}
1727dd11376bSBart Van Assche 	/* supplier is not probed */
1728dd11376bSBart Van Assche 	if (link->status == DL_STATE_DORMANT) {
1729dd11376bSBart Van Assche 		err = -EPROBE_DEFER;
1730dd11376bSBart Van Assche 		goto out;
1731dd11376bSBart Van Assche 	}
1732dd11376bSBart Van Assche 
1733dd11376bSBart Van Assche skip_reset:
1734dd11376bSBart Van Assche 	/* perform generic probe */
1735dd11376bSBart Van Assche 	err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
1736dd11376bSBart Van Assche 
1737dd11376bSBart Van Assche out:
1738dd11376bSBart Van Assche 	if (err)
1739e152a616SPo-Wen Kao 		dev_err(dev, "probe failed %d\n", err);
1740dd11376bSBart Van Assche 
1741dd11376bSBart Van Assche 	of_node_put(reset_node);
1742dd11376bSBart Van Assche 	return err;
1743dd11376bSBart Van Assche }
1744dd11376bSBart Van Assche 
1745dd11376bSBart Van Assche /**
1746dd11376bSBart Van Assche  * ufs_mtk_remove - set driver_data of the device to NULL
1747dd11376bSBart Van Assche  * @pdev: pointer to platform device handle
1748dd11376bSBart Van Assche  *
1749dd11376bSBart Van Assche  * Always return 0
1750dd11376bSBart Van Assche  */
ufs_mtk_remove(struct platform_device * pdev)1751dd11376bSBart Van Assche static int ufs_mtk_remove(struct platform_device *pdev)
1752dd11376bSBart Van Assche {
1753dd11376bSBart Van Assche 	struct ufs_hba *hba =  platform_get_drvdata(pdev);
1754dd11376bSBart Van Assche 
1755dd11376bSBart Van Assche 	pm_runtime_get_sync(&(pdev)->dev);
1756dd11376bSBart Van Assche 	ufshcd_remove(hba);
1757dd11376bSBart Van Assche 	return 0;
1758dd11376bSBart Van Assche }
1759dd11376bSBart Van Assche 
1760f54912b2SRen Zhijie #ifdef CONFIG_PM_SLEEP
ufs_mtk_system_suspend(struct device * dev)1761e7bf1d50SStanley Chu static int ufs_mtk_system_suspend(struct device *dev)
17623fd23b8dSPo-Wen Kao {
17633fd23b8dSPo-Wen Kao 	struct ufs_hba *hba = dev_get_drvdata(dev);
17643fd23b8dSPo-Wen Kao 	int ret;
17653fd23b8dSPo-Wen Kao 
17663fd23b8dSPo-Wen Kao 	ret = ufshcd_system_suspend(dev);
17673fd23b8dSPo-Wen Kao 	if (ret)
17683fd23b8dSPo-Wen Kao 		return ret;
17693fd23b8dSPo-Wen Kao 
177042b19283SStanley Chu 	ufs_mtk_dev_vreg_set_lpm(hba, true);
17713fd23b8dSPo-Wen Kao 
17723fd23b8dSPo-Wen Kao 	return 0;
17733fd23b8dSPo-Wen Kao }
17743fd23b8dSPo-Wen Kao 
ufs_mtk_system_resume(struct device * dev)1775e7bf1d50SStanley Chu static int ufs_mtk_system_resume(struct device *dev)
17763fd23b8dSPo-Wen Kao {
17773fd23b8dSPo-Wen Kao 	struct ufs_hba *hba = dev_get_drvdata(dev);
17783fd23b8dSPo-Wen Kao 
177942b19283SStanley Chu 	ufs_mtk_dev_vreg_set_lpm(hba, false);
17803fd23b8dSPo-Wen Kao 
17813fd23b8dSPo-Wen Kao 	return ufshcd_system_resume(dev);
17823fd23b8dSPo-Wen Kao }
1783f54912b2SRen Zhijie #endif
17843fd23b8dSPo-Wen Kao 
178519873b03SYangtao Li #ifdef CONFIG_PM
ufs_mtk_runtime_suspend(struct device * dev)1786e7bf1d50SStanley Chu static int ufs_mtk_runtime_suspend(struct device *dev)
17873fd23b8dSPo-Wen Kao {
17883fd23b8dSPo-Wen Kao 	struct ufs_hba *hba = dev_get_drvdata(dev);
17893fd23b8dSPo-Wen Kao 	int ret = 0;
17903fd23b8dSPo-Wen Kao 
17913fd23b8dSPo-Wen Kao 	ret = ufshcd_runtime_suspend(dev);
17923fd23b8dSPo-Wen Kao 	if (ret)
17933fd23b8dSPo-Wen Kao 		return ret;
17943fd23b8dSPo-Wen Kao 
179542b19283SStanley Chu 	ufs_mtk_dev_vreg_set_lpm(hba, true);
17963fd23b8dSPo-Wen Kao 
17973fd23b8dSPo-Wen Kao 	return 0;
17983fd23b8dSPo-Wen Kao }
17993fd23b8dSPo-Wen Kao 
ufs_mtk_runtime_resume(struct device * dev)1800e7bf1d50SStanley Chu static int ufs_mtk_runtime_resume(struct device *dev)
18013fd23b8dSPo-Wen Kao {
18023fd23b8dSPo-Wen Kao 	struct ufs_hba *hba = dev_get_drvdata(dev);
18033fd23b8dSPo-Wen Kao 
180442b19283SStanley Chu 	ufs_mtk_dev_vreg_set_lpm(hba, false);
18053fd23b8dSPo-Wen Kao 
18063fd23b8dSPo-Wen Kao 	return ufshcd_runtime_resume(dev);
18073fd23b8dSPo-Wen Kao }
180819873b03SYangtao Li #endif
18093fd23b8dSPo-Wen Kao 
1810dd11376bSBart Van Assche static const struct dev_pm_ops ufs_mtk_pm_ops = {
18113fd23b8dSPo-Wen Kao 	SET_SYSTEM_SLEEP_PM_OPS(ufs_mtk_system_suspend,
18123fd23b8dSPo-Wen Kao 				ufs_mtk_system_resume)
18133fd23b8dSPo-Wen Kao 	SET_RUNTIME_PM_OPS(ufs_mtk_runtime_suspend,
18143fd23b8dSPo-Wen Kao 			   ufs_mtk_runtime_resume, NULL)
1815dd11376bSBart Van Assche 	.prepare	 = ufshcd_suspend_prepare,
1816dd11376bSBart Van Assche 	.complete	 = ufshcd_resume_complete,
1817dd11376bSBart Van Assche };
1818dd11376bSBart Van Assche 
1819dd11376bSBart Van Assche static struct platform_driver ufs_mtk_pltform = {
1820dd11376bSBart Van Assche 	.probe      = ufs_mtk_probe,
1821dd11376bSBart Van Assche 	.remove     = ufs_mtk_remove,
1822dd11376bSBart Van Assche 	.driver = {
1823dd11376bSBart Van Assche 		.name   = "ufshcd-mtk",
1824dd11376bSBart Van Assche 		.pm     = &ufs_mtk_pm_ops,
1825dd11376bSBart Van Assche 		.of_match_table = ufs_mtk_of_match,
1826dd11376bSBart Van Assche 	},
1827dd11376bSBart Van Assche };
1828dd11376bSBart Van Assche 
1829dd11376bSBart Van Assche MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>");
1830dd11376bSBart Van Assche MODULE_AUTHOR("Peter Wang <peter.wang@mediatek.com>");
1831dd11376bSBart Van Assche MODULE_DESCRIPTION("MediaTek UFS Host Driver");
1832dd11376bSBart Van Assche MODULE_LICENSE("GPL v2");
1833dd11376bSBart Van Assche 
1834dd11376bSBart Van Assche module_platform_driver(ufs_mtk_pltform);
1835