1*df7320baSZhe Wang // SPDX-License-Identifier: GPL-2.0-only
2*df7320baSZhe Wang /*
3*df7320baSZhe Wang * UNISOC UFS Host Controller driver
4*df7320baSZhe Wang *
5*df7320baSZhe Wang * Copyright (C) 2022 Unisoc, Inc.
6*df7320baSZhe Wang * Author: Zhe Wang <zhe.wang1@unisoc.com>
7*df7320baSZhe Wang */
8*df7320baSZhe Wang
9*df7320baSZhe Wang #include <linux/arm-smccc.h>
10*df7320baSZhe Wang #include <linux/mfd/syscon.h>
11*df7320baSZhe Wang #include <linux/of.h>
12*df7320baSZhe Wang #include <linux/platform_device.h>
13*df7320baSZhe Wang #include <linux/regmap.h>
14*df7320baSZhe Wang #include <linux/reset.h>
15*df7320baSZhe Wang #include <linux/regulator/consumer.h>
16*df7320baSZhe Wang
17*df7320baSZhe Wang #include <ufs/ufshcd.h>
18*df7320baSZhe Wang #include "ufshcd-pltfrm.h"
19*df7320baSZhe Wang #include "ufs-sprd.h"
20*df7320baSZhe Wang
21*df7320baSZhe Wang static const struct of_device_id ufs_sprd_of_match[];
22*df7320baSZhe Wang
ufs_sprd_get_priv_data(struct ufs_hba * hba)23*df7320baSZhe Wang static struct ufs_sprd_priv *ufs_sprd_get_priv_data(struct ufs_hba *hba)
24*df7320baSZhe Wang {
25*df7320baSZhe Wang struct ufs_sprd_host *host = ufshcd_get_variant(hba);
26*df7320baSZhe Wang
27*df7320baSZhe Wang WARN_ON(!host->priv);
28*df7320baSZhe Wang return host->priv;
29*df7320baSZhe Wang }
30*df7320baSZhe Wang
ufs_sprd_regmap_update(struct ufs_sprd_priv * priv,unsigned int index,unsigned int reg,unsigned int bits,unsigned int val)31*df7320baSZhe Wang static void ufs_sprd_regmap_update(struct ufs_sprd_priv *priv, unsigned int index,
32*df7320baSZhe Wang unsigned int reg, unsigned int bits, unsigned int val)
33*df7320baSZhe Wang {
34*df7320baSZhe Wang regmap_update_bits(priv->sysci[index].regmap, reg, bits, val);
35*df7320baSZhe Wang }
36*df7320baSZhe Wang
ufs_sprd_regmap_read(struct ufs_sprd_priv * priv,unsigned int index,unsigned int reg,unsigned int * val)37*df7320baSZhe Wang static void ufs_sprd_regmap_read(struct ufs_sprd_priv *priv, unsigned int index,
38*df7320baSZhe Wang unsigned int reg, unsigned int *val)
39*df7320baSZhe Wang {
40*df7320baSZhe Wang regmap_read(priv->sysci[index].regmap, reg, val);
41*df7320baSZhe Wang }
42*df7320baSZhe Wang
ufs_sprd_get_unipro_ver(struct ufs_hba * hba)43*df7320baSZhe Wang static void ufs_sprd_get_unipro_ver(struct ufs_hba *hba)
44*df7320baSZhe Wang {
45*df7320baSZhe Wang struct ufs_sprd_host *host = ufshcd_get_variant(hba);
46*df7320baSZhe Wang
47*df7320baSZhe Wang if (ufshcd_dme_get(hba, UIC_ARG_MIB(PA_LOCALVERINFO), &host->unipro_ver))
48*df7320baSZhe Wang host->unipro_ver = 0;
49*df7320baSZhe Wang }
50*df7320baSZhe Wang
ufs_sprd_ctrl_uic_compl(struct ufs_hba * hba,bool enable)51*df7320baSZhe Wang static void ufs_sprd_ctrl_uic_compl(struct ufs_hba *hba, bool enable)
52*df7320baSZhe Wang {
53*df7320baSZhe Wang u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
54*df7320baSZhe Wang
55*df7320baSZhe Wang if (enable == true)
56*df7320baSZhe Wang set |= UIC_COMMAND_COMPL;
57*df7320baSZhe Wang else
58*df7320baSZhe Wang set &= ~UIC_COMMAND_COMPL;
59*df7320baSZhe Wang ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE);
60*df7320baSZhe Wang }
61*df7320baSZhe Wang
ufs_sprd_get_reset_ctrl(struct device * dev,struct ufs_sprd_rst * rci)62*df7320baSZhe Wang static int ufs_sprd_get_reset_ctrl(struct device *dev, struct ufs_sprd_rst *rci)
63*df7320baSZhe Wang {
64*df7320baSZhe Wang rci->rc = devm_reset_control_get(dev, rci->name);
65*df7320baSZhe Wang if (IS_ERR(rci->rc)) {
66*df7320baSZhe Wang dev_err(dev, "failed to get reset ctrl:%s\n", rci->name);
67*df7320baSZhe Wang return PTR_ERR(rci->rc);
68*df7320baSZhe Wang }
69*df7320baSZhe Wang
70*df7320baSZhe Wang return 0;
71*df7320baSZhe Wang }
72*df7320baSZhe Wang
ufs_sprd_get_syscon_reg(struct device * dev,struct ufs_sprd_syscon * sysci)73*df7320baSZhe Wang static int ufs_sprd_get_syscon_reg(struct device *dev, struct ufs_sprd_syscon *sysci)
74*df7320baSZhe Wang {
75*df7320baSZhe Wang sysci->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, sysci->name);
76*df7320baSZhe Wang if (IS_ERR(sysci->regmap)) {
77*df7320baSZhe Wang dev_err(dev, "failed to get ufs syscon:%s\n", sysci->name);
78*df7320baSZhe Wang return PTR_ERR(sysci->regmap);
79*df7320baSZhe Wang }
80*df7320baSZhe Wang
81*df7320baSZhe Wang return 0;
82*df7320baSZhe Wang }
83*df7320baSZhe Wang
ufs_sprd_get_vreg(struct device * dev,struct ufs_sprd_vreg * vregi)84*df7320baSZhe Wang static int ufs_sprd_get_vreg(struct device *dev, struct ufs_sprd_vreg *vregi)
85*df7320baSZhe Wang {
86*df7320baSZhe Wang vregi->vreg = devm_regulator_get(dev, vregi->name);
87*df7320baSZhe Wang if (IS_ERR(vregi->vreg)) {
88*df7320baSZhe Wang dev_err(dev, "failed to get vreg:%s\n", vregi->name);
89*df7320baSZhe Wang return PTR_ERR(vregi->vreg);
90*df7320baSZhe Wang }
91*df7320baSZhe Wang
92*df7320baSZhe Wang return 0;
93*df7320baSZhe Wang }
94*df7320baSZhe Wang
ufs_sprd_parse_dt(struct device * dev,struct ufs_hba * hba,struct ufs_sprd_host * host)95*df7320baSZhe Wang static int ufs_sprd_parse_dt(struct device *dev, struct ufs_hba *hba, struct ufs_sprd_host *host)
96*df7320baSZhe Wang {
97*df7320baSZhe Wang u32 i;
98*df7320baSZhe Wang struct ufs_sprd_priv *priv = host->priv;
99*df7320baSZhe Wang int ret = 0;
100*df7320baSZhe Wang
101*df7320baSZhe Wang /* Parse UFS reset ctrl info */
102*df7320baSZhe Wang for (i = 0; i < SPRD_UFS_RST_MAX; i++) {
103*df7320baSZhe Wang if (!priv->rci[i].name)
104*df7320baSZhe Wang continue;
105*df7320baSZhe Wang ret = ufs_sprd_get_reset_ctrl(dev, &priv->rci[i]);
106*df7320baSZhe Wang if (ret)
107*df7320baSZhe Wang goto out;
108*df7320baSZhe Wang }
109*df7320baSZhe Wang
110*df7320baSZhe Wang /* Parse UFS syscon reg info */
111*df7320baSZhe Wang for (i = 0; i < SPRD_UFS_SYSCON_MAX; i++) {
112*df7320baSZhe Wang if (!priv->sysci[i].name)
113*df7320baSZhe Wang continue;
114*df7320baSZhe Wang ret = ufs_sprd_get_syscon_reg(dev, &priv->sysci[i]);
115*df7320baSZhe Wang if (ret)
116*df7320baSZhe Wang goto out;
117*df7320baSZhe Wang }
118*df7320baSZhe Wang
119*df7320baSZhe Wang /* Parse UFS vreg info */
120*df7320baSZhe Wang for (i = 0; i < SPRD_UFS_VREG_MAX; i++) {
121*df7320baSZhe Wang if (!priv->vregi[i].name)
122*df7320baSZhe Wang continue;
123*df7320baSZhe Wang ret = ufs_sprd_get_vreg(dev, &priv->vregi[i]);
124*df7320baSZhe Wang if (ret)
125*df7320baSZhe Wang goto out;
126*df7320baSZhe Wang }
127*df7320baSZhe Wang
128*df7320baSZhe Wang out:
129*df7320baSZhe Wang return ret;
130*df7320baSZhe Wang }
131*df7320baSZhe Wang
ufs_sprd_common_init(struct ufs_hba * hba)132*df7320baSZhe Wang static int ufs_sprd_common_init(struct ufs_hba *hba)
133*df7320baSZhe Wang {
134*df7320baSZhe Wang struct device *dev = hba->dev;
135*df7320baSZhe Wang struct ufs_sprd_host *host;
136*df7320baSZhe Wang struct platform_device __maybe_unused *pdev = to_platform_device(dev);
137*df7320baSZhe Wang const struct of_device_id *of_id;
138*df7320baSZhe Wang int ret = 0;
139*df7320baSZhe Wang
140*df7320baSZhe Wang host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
141*df7320baSZhe Wang if (!host)
142*df7320baSZhe Wang return -ENOMEM;
143*df7320baSZhe Wang
144*df7320baSZhe Wang of_id = of_match_node(ufs_sprd_of_match, pdev->dev.of_node);
145*df7320baSZhe Wang if (of_id->data != NULL)
146*df7320baSZhe Wang host->priv = container_of(of_id->data, struct ufs_sprd_priv,
147*df7320baSZhe Wang ufs_hba_sprd_vops);
148*df7320baSZhe Wang
149*df7320baSZhe Wang host->hba = hba;
150*df7320baSZhe Wang ufshcd_set_variant(hba, host);
151*df7320baSZhe Wang
152*df7320baSZhe Wang hba->caps |= UFSHCD_CAP_CLK_GATING |
153*df7320baSZhe Wang UFSHCD_CAP_CRYPTO |
154*df7320baSZhe Wang UFSHCD_CAP_WB_EN;
155*df7320baSZhe Wang hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS;
156*df7320baSZhe Wang
157*df7320baSZhe Wang ret = ufs_sprd_parse_dt(dev, hba, host);
158*df7320baSZhe Wang
159*df7320baSZhe Wang return ret;
160*df7320baSZhe Wang }
161*df7320baSZhe Wang
sprd_ufs_pwr_change_notify(struct ufs_hba * hba,enum ufs_notify_change_status status,struct ufs_pa_layer_attr * dev_max_params,struct ufs_pa_layer_attr * dev_req_params)162*df7320baSZhe Wang static int sprd_ufs_pwr_change_notify(struct ufs_hba *hba,
163*df7320baSZhe Wang enum ufs_notify_change_status status,
164*df7320baSZhe Wang struct ufs_pa_layer_attr *dev_max_params,
165*df7320baSZhe Wang struct ufs_pa_layer_attr *dev_req_params)
166*df7320baSZhe Wang {
167*df7320baSZhe Wang struct ufs_sprd_host *host = ufshcd_get_variant(hba);
168*df7320baSZhe Wang
169*df7320baSZhe Wang if (status == PRE_CHANGE) {
170*df7320baSZhe Wang memcpy(dev_req_params, dev_max_params,
171*df7320baSZhe Wang sizeof(struct ufs_pa_layer_attr));
172*df7320baSZhe Wang if (host->unipro_ver >= UFS_UNIPRO_VER_1_8)
173*df7320baSZhe Wang ufshcd_dme_configure_adapt(hba, dev_req_params->gear_tx,
174*df7320baSZhe Wang PA_INITIAL_ADAPT);
175*df7320baSZhe Wang }
176*df7320baSZhe Wang
177*df7320baSZhe Wang return 0;
178*df7320baSZhe Wang }
179*df7320baSZhe Wang
ufs_sprd_suspend(struct ufs_hba * hba,enum ufs_pm_op pm_op,enum ufs_notify_change_status status)180*df7320baSZhe Wang static int ufs_sprd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op,
181*df7320baSZhe Wang enum ufs_notify_change_status status)
182*df7320baSZhe Wang {
183*df7320baSZhe Wang unsigned long flags;
184*df7320baSZhe Wang
185*df7320baSZhe Wang if (status == PRE_CHANGE) {
186*df7320baSZhe Wang if (ufshcd_is_auto_hibern8_supported(hba)) {
187*df7320baSZhe Wang spin_lock_irqsave(hba->host->host_lock, flags);
188*df7320baSZhe Wang ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER);
189*df7320baSZhe Wang spin_unlock_irqrestore(hba->host->host_lock, flags);
190*df7320baSZhe Wang }
191*df7320baSZhe Wang }
192*df7320baSZhe Wang
193*df7320baSZhe Wang return 0;
194*df7320baSZhe Wang }
195*df7320baSZhe Wang
ufs_sprd_n6_host_reset(struct ufs_hba * hba)196*df7320baSZhe Wang static void ufs_sprd_n6_host_reset(struct ufs_hba *hba)
197*df7320baSZhe Wang {
198*df7320baSZhe Wang struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
199*df7320baSZhe Wang
200*df7320baSZhe Wang dev_info(hba->dev, "ufs host reset!\n");
201*df7320baSZhe Wang
202*df7320baSZhe Wang reset_control_assert(priv->rci[SPRD_UFSHCI_SOFT_RST].rc);
203*df7320baSZhe Wang usleep_range(1000, 1100);
204*df7320baSZhe Wang reset_control_deassert(priv->rci[SPRD_UFSHCI_SOFT_RST].rc);
205*df7320baSZhe Wang }
206*df7320baSZhe Wang
ufs_sprd_n6_device_reset(struct ufs_hba * hba)207*df7320baSZhe Wang static int ufs_sprd_n6_device_reset(struct ufs_hba *hba)
208*df7320baSZhe Wang {
209*df7320baSZhe Wang struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
210*df7320baSZhe Wang
211*df7320baSZhe Wang dev_info(hba->dev, "ufs device reset!\n");
212*df7320baSZhe Wang
213*df7320baSZhe Wang reset_control_assert(priv->rci[SPRD_UFS_DEV_RST].rc);
214*df7320baSZhe Wang usleep_range(1000, 1100);
215*df7320baSZhe Wang reset_control_deassert(priv->rci[SPRD_UFS_DEV_RST].rc);
216*df7320baSZhe Wang
217*df7320baSZhe Wang return 0;
218*df7320baSZhe Wang }
219*df7320baSZhe Wang
ufs_sprd_n6_key_acc_enable(struct ufs_hba * hba)220*df7320baSZhe Wang static void ufs_sprd_n6_key_acc_enable(struct ufs_hba *hba)
221*df7320baSZhe Wang {
222*df7320baSZhe Wang u32 val;
223*df7320baSZhe Wang u32 retry = 10;
224*df7320baSZhe Wang struct arm_smccc_res res;
225*df7320baSZhe Wang
226*df7320baSZhe Wang check_hce:
227*df7320baSZhe Wang /* Key access only can be enabled under HCE enable */
228*df7320baSZhe Wang val = ufshcd_readl(hba, REG_CONTROLLER_ENABLE);
229*df7320baSZhe Wang if (!(val & CONTROLLER_ENABLE)) {
230*df7320baSZhe Wang ufs_sprd_n6_host_reset(hba);
231*df7320baSZhe Wang val |= CONTROLLER_ENABLE;
232*df7320baSZhe Wang ufshcd_writel(hba, val, REG_CONTROLLER_ENABLE);
233*df7320baSZhe Wang usleep_range(1000, 1100);
234*df7320baSZhe Wang if (retry) {
235*df7320baSZhe Wang retry--;
236*df7320baSZhe Wang goto check_hce;
237*df7320baSZhe Wang }
238*df7320baSZhe Wang goto disable_crypto;
239*df7320baSZhe Wang }
240*df7320baSZhe Wang
241*df7320baSZhe Wang arm_smccc_smc(SPRD_SIP_SVC_STORAGE_UFS_CRYPTO_ENABLE,
242*df7320baSZhe Wang 0, 0, 0, 0, 0, 0, 0, &res);
243*df7320baSZhe Wang if (!res.a0)
244*df7320baSZhe Wang return;
245*df7320baSZhe Wang
246*df7320baSZhe Wang disable_crypto:
247*df7320baSZhe Wang dev_err(hba->dev, "key reg access enable fail, disable crypto\n");
248*df7320baSZhe Wang hba->caps &= ~UFSHCD_CAP_CRYPTO;
249*df7320baSZhe Wang }
250*df7320baSZhe Wang
ufs_sprd_n6_init(struct ufs_hba * hba)251*df7320baSZhe Wang static int ufs_sprd_n6_init(struct ufs_hba *hba)
252*df7320baSZhe Wang {
253*df7320baSZhe Wang struct ufs_sprd_priv *priv;
254*df7320baSZhe Wang int ret = 0;
255*df7320baSZhe Wang
256*df7320baSZhe Wang ret = ufs_sprd_common_init(hba);
257*df7320baSZhe Wang if (ret != 0)
258*df7320baSZhe Wang return ret;
259*df7320baSZhe Wang
260*df7320baSZhe Wang priv = ufs_sprd_get_priv_data(hba);
261*df7320baSZhe Wang
262*df7320baSZhe Wang ret = regulator_enable(priv->vregi[SPRD_UFS_VDD_MPHY].vreg);
263*df7320baSZhe Wang if (ret)
264*df7320baSZhe Wang return -ENODEV;
265*df7320baSZhe Wang
266*df7320baSZhe Wang if (hba->caps & UFSHCD_CAP_CRYPTO)
267*df7320baSZhe Wang ufs_sprd_n6_key_acc_enable(hba);
268*df7320baSZhe Wang
269*df7320baSZhe Wang return 0;
270*df7320baSZhe Wang }
271*df7320baSZhe Wang
ufs_sprd_n6_phy_init(struct ufs_hba * hba)272*df7320baSZhe Wang static int ufs_sprd_n6_phy_init(struct ufs_hba *hba)
273*df7320baSZhe Wang {
274*df7320baSZhe Wang int ret = 0;
275*df7320baSZhe Wang uint32_t val = 0;
276*df7320baSZhe Wang uint32_t retry = 10;
277*df7320baSZhe Wang uint32_t offset;
278*df7320baSZhe Wang struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
279*df7320baSZhe Wang
280*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(CBREFCLKCTRL2), 0x90);
281*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(CBCRCTRL), 0x01);
282*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RXSQCONTROL,
283*df7320baSZhe Wang UIC_ARG_MPHY_RX_GEN_SEL_INDEX(0)), 0x01);
284*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(RXSQCONTROL,
285*df7320baSZhe Wang UIC_ARG_MPHY_RX_GEN_SEL_INDEX(1)), 0x01);
286*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
287*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(CBRATESEL), 0x01);
288*df7320baSZhe Wang
289*df7320baSZhe Wang do {
290*df7320baSZhe Wang /* phy_sram_init_done */
291*df7320baSZhe Wang ufs_sprd_regmap_read(priv, SPRD_UFS_ANLG, 0xc, &val);
292*df7320baSZhe Wang if ((val & 0x1) == 0x1) {
293*df7320baSZhe Wang for (offset = 0x40; offset < 0x42; offset++) {
294*df7320baSZhe Wang /* Lane afe calibration */
295*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGADDRLSB), 0x1c);
296*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGADDRMSB), offset);
297*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGWRLSB), 0x04);
298*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGWRMSB), 0x00);
299*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(CBCREGRDWRSEL), 0x01);
300*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
301*df7320baSZhe Wang }
302*df7320baSZhe Wang
303*df7320baSZhe Wang goto update_phy;
304*df7320baSZhe Wang }
305*df7320baSZhe Wang udelay(1000);
306*df7320baSZhe Wang retry--;
307*df7320baSZhe Wang } while (retry > 0);
308*df7320baSZhe Wang
309*df7320baSZhe Wang ret = -ETIMEDOUT;
310*df7320baSZhe Wang goto out;
311*df7320baSZhe Wang
312*df7320baSZhe Wang update_phy:
313*df7320baSZhe Wang /* phy_sram_ext_ld_done */
314*df7320baSZhe Wang ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x2, 0);
315*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYCFGUPDT), 0x01);
316*df7320baSZhe Wang ufshcd_dme_set(hba, UIC_ARG_MIB(VS_MPHYDISABLE), 0x0);
317*df7320baSZhe Wang out:
318*df7320baSZhe Wang return ret;
319*df7320baSZhe Wang }
320*df7320baSZhe Wang
321*df7320baSZhe Wang
sprd_ufs_n6_hce_enable_notify(struct ufs_hba * hba,enum ufs_notify_change_status status)322*df7320baSZhe Wang static int sprd_ufs_n6_hce_enable_notify(struct ufs_hba *hba,
323*df7320baSZhe Wang enum ufs_notify_change_status status)
324*df7320baSZhe Wang {
325*df7320baSZhe Wang int err = 0;
326*df7320baSZhe Wang struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
327*df7320baSZhe Wang
328*df7320baSZhe Wang if (status == PRE_CHANGE) {
329*df7320baSZhe Wang /* phy_sram_ext_ld_done */
330*df7320baSZhe Wang ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x2, 0x2);
331*df7320baSZhe Wang /* phy_sram_bypass */
332*df7320baSZhe Wang ufs_sprd_regmap_update(priv, SPRD_UFS_ANLG, 0xc, 0x4, 0x4);
333*df7320baSZhe Wang
334*df7320baSZhe Wang ufs_sprd_n6_host_reset(hba);
335*df7320baSZhe Wang
336*df7320baSZhe Wang if (hba->caps & UFSHCD_CAP_CRYPTO)
337*df7320baSZhe Wang ufs_sprd_n6_key_acc_enable(hba);
338*df7320baSZhe Wang }
339*df7320baSZhe Wang
340*df7320baSZhe Wang if (status == POST_CHANGE) {
341*df7320baSZhe Wang err = ufs_sprd_n6_phy_init(hba);
342*df7320baSZhe Wang if (err) {
343*df7320baSZhe Wang dev_err(hba->dev, "Phy setup failed (%d)\n", err);
344*df7320baSZhe Wang goto out;
345*df7320baSZhe Wang }
346*df7320baSZhe Wang
347*df7320baSZhe Wang ufs_sprd_get_unipro_ver(hba);
348*df7320baSZhe Wang }
349*df7320baSZhe Wang out:
350*df7320baSZhe Wang return err;
351*df7320baSZhe Wang }
352*df7320baSZhe Wang
sprd_ufs_n6_h8_notify(struct ufs_hba * hba,enum uic_cmd_dme cmd,enum ufs_notify_change_status status)353*df7320baSZhe Wang static void sprd_ufs_n6_h8_notify(struct ufs_hba *hba,
354*df7320baSZhe Wang enum uic_cmd_dme cmd,
355*df7320baSZhe Wang enum ufs_notify_change_status status)
356*df7320baSZhe Wang {
357*df7320baSZhe Wang struct ufs_sprd_priv *priv = ufs_sprd_get_priv_data(hba);
358*df7320baSZhe Wang
359*df7320baSZhe Wang if (status == PRE_CHANGE) {
360*df7320baSZhe Wang if (cmd == UIC_CMD_DME_HIBER_ENTER)
361*df7320baSZhe Wang /*
362*df7320baSZhe Wang * Disable UIC COMPL INTR to prevent access to UFSHCI after
363*df7320baSZhe Wang * checking HCS.UPMCRS
364*df7320baSZhe Wang */
365*df7320baSZhe Wang ufs_sprd_ctrl_uic_compl(hba, false);
366*df7320baSZhe Wang
367*df7320baSZhe Wang if (cmd == UIC_CMD_DME_HIBER_EXIT) {
368*df7320baSZhe Wang ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_UFSDEV_REG,
369*df7320baSZhe Wang APB_UFSDEV_REFCLK_EN, APB_UFSDEV_REFCLK_EN);
370*df7320baSZhe Wang ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_USB31PLL_CTRL,
371*df7320baSZhe Wang APB_USB31PLLV_REF2MPHY, APB_USB31PLLV_REF2MPHY);
372*df7320baSZhe Wang }
373*df7320baSZhe Wang }
374*df7320baSZhe Wang
375*df7320baSZhe Wang if (status == POST_CHANGE) {
376*df7320baSZhe Wang if (cmd == UIC_CMD_DME_HIBER_EXIT)
377*df7320baSZhe Wang ufs_sprd_ctrl_uic_compl(hba, true);
378*df7320baSZhe Wang
379*df7320baSZhe Wang if (cmd == UIC_CMD_DME_HIBER_ENTER) {
380*df7320baSZhe Wang ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_UFSDEV_REG,
381*df7320baSZhe Wang APB_UFSDEV_REFCLK_EN, 0);
382*df7320baSZhe Wang ufs_sprd_regmap_update(priv, SPRD_UFS_AON_APB, APB_USB31PLL_CTRL,
383*df7320baSZhe Wang APB_USB31PLLV_REF2MPHY, 0);
384*df7320baSZhe Wang }
385*df7320baSZhe Wang }
386*df7320baSZhe Wang }
387*df7320baSZhe Wang
388*df7320baSZhe Wang static struct ufs_sprd_priv n6_ufs = {
389*df7320baSZhe Wang .rci[SPRD_UFSHCI_SOFT_RST] = { .name = "controller", },
390*df7320baSZhe Wang .rci[SPRD_UFS_DEV_RST] = { .name = "device", },
391*df7320baSZhe Wang
392*df7320baSZhe Wang .sysci[SPRD_UFS_ANLG] = { .name = "sprd,ufs-anlg-syscon", },
393*df7320baSZhe Wang .sysci[SPRD_UFS_AON_APB] = { .name = "sprd,aon-apb-syscon", },
394*df7320baSZhe Wang
395*df7320baSZhe Wang .vregi[SPRD_UFS_VDD_MPHY] = { .name = "vdd-mphy", },
396*df7320baSZhe Wang
397*df7320baSZhe Wang .ufs_hba_sprd_vops = {
398*df7320baSZhe Wang .name = "sprd,ums9620-ufs",
399*df7320baSZhe Wang .init = ufs_sprd_n6_init,
400*df7320baSZhe Wang .hce_enable_notify = sprd_ufs_n6_hce_enable_notify,
401*df7320baSZhe Wang .pwr_change_notify = sprd_ufs_pwr_change_notify,
402*df7320baSZhe Wang .hibern8_notify = sprd_ufs_n6_h8_notify,
403*df7320baSZhe Wang .device_reset = ufs_sprd_n6_device_reset,
404*df7320baSZhe Wang .suspend = ufs_sprd_suspend,
405*df7320baSZhe Wang },
406*df7320baSZhe Wang };
407*df7320baSZhe Wang
408*df7320baSZhe Wang static const struct of_device_id __maybe_unused ufs_sprd_of_match[] = {
409*df7320baSZhe Wang { .compatible = "sprd,ums9620-ufs", .data = &n6_ufs.ufs_hba_sprd_vops},
410*df7320baSZhe Wang {},
411*df7320baSZhe Wang };
412*df7320baSZhe Wang MODULE_DEVICE_TABLE(of, ufs_sprd_of_match);
413*df7320baSZhe Wang
ufs_sprd_probe(struct platform_device * pdev)414*df7320baSZhe Wang static int ufs_sprd_probe(struct platform_device *pdev)
415*df7320baSZhe Wang {
416*df7320baSZhe Wang int err;
417*df7320baSZhe Wang struct device *dev = &pdev->dev;
418*df7320baSZhe Wang const struct of_device_id *of_id;
419*df7320baSZhe Wang
420*df7320baSZhe Wang of_id = of_match_node(ufs_sprd_of_match, dev->of_node);
421*df7320baSZhe Wang err = ufshcd_pltfrm_init(pdev, of_id->data);
422*df7320baSZhe Wang if (err)
423*df7320baSZhe Wang dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
424*df7320baSZhe Wang
425*df7320baSZhe Wang return err;
426*df7320baSZhe Wang }
427*df7320baSZhe Wang
ufs_sprd_remove(struct platform_device * pdev)428*df7320baSZhe Wang static int ufs_sprd_remove(struct platform_device *pdev)
429*df7320baSZhe Wang {
430*df7320baSZhe Wang struct ufs_hba *hba = platform_get_drvdata(pdev);
431*df7320baSZhe Wang
432*df7320baSZhe Wang pm_runtime_get_sync(&(pdev)->dev);
433*df7320baSZhe Wang ufshcd_remove(hba);
434*df7320baSZhe Wang return 0;
435*df7320baSZhe Wang }
436*df7320baSZhe Wang
437*df7320baSZhe Wang static const struct dev_pm_ops ufs_sprd_pm_ops = {
438*df7320baSZhe Wang SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume)
439*df7320baSZhe Wang SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL)
440*df7320baSZhe Wang .prepare = ufshcd_suspend_prepare,
441*df7320baSZhe Wang .complete = ufshcd_resume_complete,
442*df7320baSZhe Wang };
443*df7320baSZhe Wang
444*df7320baSZhe Wang static struct platform_driver ufs_sprd_pltform = {
445*df7320baSZhe Wang .probe = ufs_sprd_probe,
446*df7320baSZhe Wang .remove = ufs_sprd_remove,
447*df7320baSZhe Wang .driver = {
448*df7320baSZhe Wang .name = "ufshcd-sprd",
449*df7320baSZhe Wang .pm = &ufs_sprd_pm_ops,
450*df7320baSZhe Wang .of_match_table = of_match_ptr(ufs_sprd_of_match),
451*df7320baSZhe Wang },
452*df7320baSZhe Wang };
453*df7320baSZhe Wang module_platform_driver(ufs_sprd_pltform);
454*df7320baSZhe Wang
455*df7320baSZhe Wang MODULE_AUTHOR("Zhe Wang <zhe.wang1@unisoc.com>");
456*df7320baSZhe Wang MODULE_DESCRIPTION("Unisoc UFS Host Driver");
457*df7320baSZhe Wang MODULE_LICENSE("GPL v2");
458