Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / drivers / scsi / ufs / ufs-mediatek.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019 MediaTek Inc.
4  * Authors:
5  *      Stanley Chu <stanley.chu@mediatek.com>
6  *      Peter Wang <peter.wang@mediatek.com>
7  */
8
9 #include <linux/of.h>
10 #include <linux/of_address.h>
11 #include <linux/phy/phy.h>
12 #include <linux/platform_device.h>
13
14 #include "ufshcd.h"
15 #include "ufshcd-pltfrm.h"
16 #include "ufs_quirks.h"
17 #include "unipro.h"
18 #include "ufs-mediatek.h"
19
20 static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable)
21 {
22         u32 tmp;
23
24         if (enable) {
25                 ufshcd_dme_get(hba,
26                                UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
27                 tmp = tmp |
28                       (1 << RX_SYMBOL_CLK_GATE_EN) |
29                       (1 << SYS_CLK_GATE_EN) |
30                       (1 << TX_CLK_GATE_EN);
31                 ufshcd_dme_set(hba,
32                                UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
33
34                 ufshcd_dme_get(hba,
35                                UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
36                 tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE);
37                 ufshcd_dme_set(hba,
38                                UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
39         } else {
40                 ufshcd_dme_get(hba,
41                                UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
42                 tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) |
43                               (1 << SYS_CLK_GATE_EN) |
44                               (1 << TX_CLK_GATE_EN));
45                 ufshcd_dme_set(hba,
46                                UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
47
48                 ufshcd_dme_get(hba,
49                                UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp);
50                 tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE);
51                 ufshcd_dme_set(hba,
52                                UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp);
53         }
54 }
55
56 static int ufs_mtk_bind_mphy(struct ufs_hba *hba)
57 {
58         struct ufs_mtk_host *host = ufshcd_get_variant(hba);
59         struct device *dev = hba->dev;
60         struct device_node *np = dev->of_node;
61         int err = 0;
62
63         host->mphy = devm_of_phy_get_by_index(dev, np, 0);
64
65         if (host->mphy == ERR_PTR(-EPROBE_DEFER)) {
66                 /*
67                  * UFS driver might be probed before the phy driver does.
68                  * In that case we would like to return EPROBE_DEFER code.
69                  */
70                 err = -EPROBE_DEFER;
71                 dev_info(dev,
72                          "%s: required phy hasn't probed yet. err = %d\n",
73                         __func__, err);
74         } else if (IS_ERR(host->mphy)) {
75                 err = PTR_ERR(host->mphy);
76                 dev_info(dev, "%s: PHY get failed %d\n", __func__, err);
77         }
78
79         if (err)
80                 host->mphy = NULL;
81
82         return err;
83 }
84
85 /**
86  * ufs_mtk_setup_clocks - enables/disable clocks
87  * @hba: host controller instance
88  * @on: If true, enable clocks else disable them.
89  * @status: PRE_CHANGE or POST_CHANGE notify
90  *
91  * Returns 0 on success, non-zero on failure.
92  */
93 static int ufs_mtk_setup_clocks(struct ufs_hba *hba, bool on,
94                                 enum ufs_notify_change_status status)
95 {
96         struct ufs_mtk_host *host = ufshcd_get_variant(hba);
97         int ret = -EINVAL;
98
99         /*
100          * In case ufs_mtk_init() is not yet done, simply ignore.
101          * This ufs_mtk_setup_clocks() shall be called from
102          * ufs_mtk_init() after init is done.
103          */
104         if (!host)
105                 return 0;
106
107         switch (status) {
108         case PRE_CHANGE:
109                 if (!on)
110                         ret = phy_power_off(host->mphy);
111                 break;
112         case POST_CHANGE:
113                 if (on)
114                         ret = phy_power_on(host->mphy);
115                 break;
116         }
117
118         return ret;
119 }
120
121 /**
122  * ufs_mtk_init - find other essential mmio bases
123  * @hba: host controller instance
124  *
125  * Binds PHY with controller and powers up PHY enabling clocks
126  * and regulators.
127  *
128  * Returns -EPROBE_DEFER if binding fails, returns negative error
129  * on phy power up failure and returns zero on success.
130  */
131 static int ufs_mtk_init(struct ufs_hba *hba)
132 {
133         struct ufs_mtk_host *host;
134         struct device *dev = hba->dev;
135         int err = 0;
136
137         host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
138         if (!host) {
139                 err = -ENOMEM;
140                 dev_info(dev, "%s: no memory for mtk ufs host\n", __func__);
141                 goto out;
142         }
143
144         host->hba = hba;
145         ufshcd_set_variant(hba, host);
146
147         err = ufs_mtk_bind_mphy(hba);
148         if (err)
149                 goto out_variant_clear;
150
151         /*
152          * ufshcd_vops_init() is invoked after
153          * ufshcd_setup_clock(true) in ufshcd_hba_init() thus
154          * phy clock setup is skipped.
155          *
156          * Enable phy clocks specifically here.
157          */
158         ufs_mtk_setup_clocks(hba, true, POST_CHANGE);
159
160         goto out;
161
162 out_variant_clear:
163         ufshcd_set_variant(hba, NULL);
164 out:
165         return err;
166 }
167
168 static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba,
169                                   struct ufs_pa_layer_attr *dev_max_params,
170                                   struct ufs_pa_layer_attr *dev_req_params)
171 {
172         struct ufs_dev_params host_cap;
173         int ret;
174
175         host_cap.tx_lanes = UFS_MTK_LIMIT_NUM_LANES_TX;
176         host_cap.rx_lanes = UFS_MTK_LIMIT_NUM_LANES_RX;
177         host_cap.hs_rx_gear = UFS_MTK_LIMIT_HSGEAR_RX;
178         host_cap.hs_tx_gear = UFS_MTK_LIMIT_HSGEAR_TX;
179         host_cap.pwm_rx_gear = UFS_MTK_LIMIT_PWMGEAR_RX;
180         host_cap.pwm_tx_gear = UFS_MTK_LIMIT_PWMGEAR_TX;
181         host_cap.rx_pwr_pwm = UFS_MTK_LIMIT_RX_PWR_PWM;
182         host_cap.tx_pwr_pwm = UFS_MTK_LIMIT_TX_PWR_PWM;
183         host_cap.rx_pwr_hs = UFS_MTK_LIMIT_RX_PWR_HS;
184         host_cap.tx_pwr_hs = UFS_MTK_LIMIT_TX_PWR_HS;
185         host_cap.hs_rate = UFS_MTK_LIMIT_HS_RATE;
186         host_cap.desired_working_mode =
187                                 UFS_MTK_LIMIT_DESIRED_MODE;
188
189         ret = ufshcd_get_pwr_dev_param(&host_cap,
190                                        dev_max_params,
191                                        dev_req_params);
192         if (ret) {
193                 pr_info("%s: failed to determine capabilities\n",
194                         __func__);
195         }
196
197         return ret;
198 }
199
200 static int ufs_mtk_pwr_change_notify(struct ufs_hba *hba,
201                                      enum ufs_notify_change_status stage,
202                                      struct ufs_pa_layer_attr *dev_max_params,
203                                      struct ufs_pa_layer_attr *dev_req_params)
204 {
205         int ret = 0;
206
207         switch (stage) {
208         case PRE_CHANGE:
209                 ret = ufs_mtk_pre_pwr_change(hba, dev_max_params,
210                                              dev_req_params);
211                 break;
212         case POST_CHANGE:
213                 break;
214         default:
215                 ret = -EINVAL;
216                 break;
217         }
218
219         return ret;
220 }
221
222 static int ufs_mtk_pre_link(struct ufs_hba *hba)
223 {
224         int ret;
225         u32 tmp;
226
227         /* disable deep stall */
228         ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp);
229         if (ret)
230                 return ret;
231
232         tmp &= ~(1 << 6);
233
234         ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp);
235
236         return ret;
237 }
238
239 static int ufs_mtk_post_link(struct ufs_hba *hba)
240 {
241         /* disable device LCC */
242         ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0);
243
244         /* enable unipro clock gating feature */
245         ufs_mtk_cfg_unipro_cg(hba, true);
246
247         return 0;
248 }
249
250 static int ufs_mtk_link_startup_notify(struct ufs_hba *hba,
251                                        enum ufs_notify_change_status stage)
252 {
253         int ret = 0;
254
255         switch (stage) {
256         case PRE_CHANGE:
257                 ret = ufs_mtk_pre_link(hba);
258                 break;
259         case POST_CHANGE:
260                 ret = ufs_mtk_post_link(hba);
261                 break;
262         default:
263                 ret = -EINVAL;
264                 break;
265         }
266
267         return ret;
268 }
269
270 static int ufs_mtk_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
271 {
272         struct ufs_mtk_host *host = ufshcd_get_variant(hba);
273
274         if (ufshcd_is_link_hibern8(hba))
275                 phy_power_off(host->mphy);
276
277         return 0;
278 }
279
280 static int ufs_mtk_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
281 {
282         struct ufs_mtk_host *host = ufshcd_get_variant(hba);
283
284         if (ufshcd_is_link_hibern8(hba))
285                 phy_power_on(host->mphy);
286
287         return 0;
288 }
289
290 static int ufs_mtk_apply_dev_quirks(struct ufs_hba *hba,
291                                     struct ufs_dev_desc *card)
292 {
293         if (card->wmanufacturerid == UFS_VENDOR_SAMSUNG)
294                 ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE), 6);
295
296         return 0;
297 }
298
299 /**
300  * struct ufs_hba_mtk_vops - UFS MTK specific variant operations
301  *
302  * The variant operations configure the necessary controller and PHY
303  * handshake during initialization.
304  */
305 static struct ufs_hba_variant_ops ufs_hba_mtk_vops = {
306         .name                = "mediatek.ufshci",
307         .init                = ufs_mtk_init,
308         .setup_clocks        = ufs_mtk_setup_clocks,
309         .link_startup_notify = ufs_mtk_link_startup_notify,
310         .pwr_change_notify   = ufs_mtk_pwr_change_notify,
311         .apply_dev_quirks    = ufs_mtk_apply_dev_quirks,
312         .suspend             = ufs_mtk_suspend,
313         .resume              = ufs_mtk_resume,
314 };
315
316 /**
317  * ufs_mtk_probe - probe routine of the driver
318  * @pdev: pointer to Platform device handle
319  *
320  * Return zero for success and non-zero for failure
321  */
322 static int ufs_mtk_probe(struct platform_device *pdev)
323 {
324         int err;
325         struct device *dev = &pdev->dev;
326
327         /* perform generic probe */
328         err = ufshcd_pltfrm_init(pdev, &ufs_hba_mtk_vops);
329         if (err)
330                 dev_info(dev, "probe failed %d\n", err);
331
332         return err;
333 }
334
335 /**
336  * ufs_mtk_remove - set driver_data of the device to NULL
337  * @pdev: pointer to platform device handle
338  *
339  * Always return 0
340  */
341 static int ufs_mtk_remove(struct platform_device *pdev)
342 {
343         struct ufs_hba *hba =  platform_get_drvdata(pdev);
344
345         pm_runtime_get_sync(&(pdev)->dev);
346         ufshcd_remove(hba);
347         return 0;
348 }
349
350 static const struct of_device_id ufs_mtk_of_match[] = {
351         { .compatible = "mediatek,mt8183-ufshci"},
352         {},
353 };
354
355 static const struct dev_pm_ops ufs_mtk_pm_ops = {
356         .suspend         = ufshcd_pltfrm_suspend,
357         .resume          = ufshcd_pltfrm_resume,
358         .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
359         .runtime_resume  = ufshcd_pltfrm_runtime_resume,
360         .runtime_idle    = ufshcd_pltfrm_runtime_idle,
361 };
362
363 static struct platform_driver ufs_mtk_pltform = {
364         .probe      = ufs_mtk_probe,
365         .remove     = ufs_mtk_remove,
366         .shutdown   = ufshcd_pltfrm_shutdown,
367         .driver = {
368                 .name   = "ufshcd-mtk",
369                 .pm     = &ufs_mtk_pm_ops,
370                 .of_match_table = ufs_mtk_of_match,
371         },
372 };
373
374 MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>");
375 MODULE_AUTHOR("Peter Wang <peter.wang@mediatek.com>");
376 MODULE_DESCRIPTION("MediaTek UFS Host Driver");
377 MODULE_LICENSE("GPL v2");
378
379 module_platform_driver(ufs_mtk_pltform);