uboot/drivers/ufs/cdns-platform.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/**
   3 * cdns-platform.c - Platform driver for Cadence UFSHCI device
   4 *
   5 * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
   6 */
   7
   8#include <clk.h>
   9#include <common.h>
  10#include <dm.h>
  11#include <ufs.h>
  12#include <asm/io.h>
  13#include <dm/device_compat.h>
  14#include <linux/bitops.h>
  15#include <linux/err.h>
  16
  17#include "ufs.h"
  18
  19#define USEC_PER_SEC    1000000L
  20
  21#define CDNS_UFS_REG_HCLKDIV    0xFC
  22#define CDNS_UFS_REG_PHY_XCFGD1 0x113C
  23
  24static int cdns_ufs_link_startup_notify(struct ufs_hba *hba,
  25                                        enum ufs_notify_change_status status)
  26{
  27        hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
  28        switch (status) {
  29        case PRE_CHANGE:
  30                return ufshcd_dme_set(hba,
  31                                      UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE),
  32                                      0);
  33        case POST_CHANGE:
  34        ;
  35        }
  36
  37        return 0;
  38}
  39
  40static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba)
  41{
  42        struct clk clk;
  43        unsigned long core_clk_rate = 0;
  44        u32 core_clk_div = 0;
  45        int ret;
  46
  47        ret = clk_get_by_name(hba->dev, "core_clk", &clk);
  48        if (ret) {
  49                dev_err(hba->dev, "failed to get core_clk clock\n");
  50                return ret;
  51        }
  52
  53        core_clk_rate = clk_get_rate(&clk);
  54        if (IS_ERR_VALUE(core_clk_rate)) {
  55                dev_err(hba->dev, "%s: unable to find core_clk rate\n",
  56                        __func__);
  57                return core_clk_rate;
  58        }
  59
  60        core_clk_div = core_clk_rate / USEC_PER_SEC;
  61        ufshcd_writel(hba, core_clk_div, CDNS_UFS_REG_HCLKDIV);
  62
  63        return 0;
  64}
  65
  66static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba,
  67                                      enum ufs_notify_change_status status)
  68{
  69        switch (status) {
  70        case PRE_CHANGE:
  71                return cdns_ufs_set_hclkdiv(hba);
  72        case POST_CHANGE:
  73        ;
  74        }
  75
  76        return 0;
  77}
  78
  79static int cdns_ufs_init(struct ufs_hba *hba)
  80{
  81        u32 data;
  82
  83        /* Increase RX_Advanced_Min_ActivateTime_Capability */
  84        data = ufshcd_readl(hba, CDNS_UFS_REG_PHY_XCFGD1);
  85        data |= BIT(24);
  86        ufshcd_writel(hba, data, CDNS_UFS_REG_PHY_XCFGD1);
  87
  88        return 0;
  89}
  90
  91static struct ufs_hba_ops cdns_pltfm_hba_ops = {
  92        .init = cdns_ufs_init,
  93        .hce_enable_notify = cdns_ufs_hce_enable_notify,
  94        .link_startup_notify = cdns_ufs_link_startup_notify,
  95};
  96
  97static int cdns_ufs_pltfm_probe(struct udevice *dev)
  98{
  99        int err = ufshcd_probe(dev, &cdns_pltfm_hba_ops);
 100        if (err)
 101                dev_err(dev, "ufshcd_probe() failed %d\n", err);
 102
 103        return err;
 104}
 105
 106static int cdns_ufs_pltfm_bind(struct udevice *dev)
 107{
 108        struct udevice *scsi_dev;
 109
 110        return ufs_scsi_bind(dev, &scsi_dev);
 111}
 112
 113static const struct udevice_id cdns_ufs_pltfm_ids[] = {
 114        {
 115                .compatible = "cdns,ufshc-m31-16nm",
 116        },
 117        {},
 118};
 119
 120U_BOOT_DRIVER(cdns_ufs_pltfm) = {
 121        .name           = "cdns-ufs-pltfm",
 122        .id             =  UCLASS_UFS,
 123        .of_match       = cdns_ufs_pltfm_ids,
 124        .probe          = cdns_ufs_pltfm_probe,
 125        .bind           = cdns_ufs_pltfm_bind,
 126};
 127