root/drivers/scsi/ufs/ufs-mediatek.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ufs_mtk_cfg_unipro_cg
  2. ufs_mtk_bind_mphy
  3. ufs_mtk_setup_clocks
  4. ufs_mtk_init
  5. ufs_mtk_pre_pwr_change
  6. ufs_mtk_pwr_change_notify
  7. ufs_mtk_pre_link
  8. ufs_mtk_post_link
  9. ufs_mtk_link_startup_notify
  10. ufs_mtk_suspend
  11. ufs_mtk_resume
  12. ufs_mtk_apply_dev_quirks
  13. ufs_mtk_probe
  14. ufs_mtk_remove

   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);

/* [<][>][^][v][top][bottom][index][help] */