[COMMON] scsi: ufs: change some things to support various projects
authorKiwoong Kim <kwmad.kim@samsung.com>
Mon, 18 Sep 2017 04:47:16 +0000 (13:47 +0900)
committerJaeHun Jung <jh0801.jung@samsung.com>
Tue, 8 May 2018 08:21:47 +0000 (17:21 +0900)
1. build ufs driver in ww branch
2. choose ufs cal for each project
3. use regmap to access external regions
- phy isolcation
- io coherency
4. choose a way to do dvfs lock for ufs
- it's possible to lock INT domain
5. enumerate ufs clocks in order, not with name
- clock names are changing continously..

Change-Id: I29e807a66fedc86d979906c9ea7ed9b7fa546d85
Signed-off-by: Kiwoong Kim <kwmad.kim@samsung.com>
drivers/scsi/ufs/Makefile
drivers/scsi/ufs/ufs-exynos.c
drivers/scsi/ufs/ufs-exynos.h

index 35e29296ad1ee59857515839122aaf30ec8b0fbd..1b2ba71795d4d6082a4e5a690de7f2883509da37 100644 (file)
@@ -6,6 +6,8 @@ obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
 obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
 obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
 obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
-obj-$(CONFIG_SCSI_UFS_EXYNOS) += ufs-exynos.o ufs-exynos-dbg.o ufs-cal-9810.o
+obj-$(CONFIG_SCSI_UFS_EXYNOS) += ufs-exynos.o ufs-exynos-dbg.o
+obj-$(CONFIG_SOC_EXYNOS9810) += ufs-cal-9810.o
+obj-$(CONFIG_SOC_EXYNOS9610) += ufs-cal-9610.o
 obj-$(CONFIG_SCSI_UFS_EXYNOS_FMP) += ufs-exynos-fmp.o
 obj-$(CONFIG_SCSI_UFS_EXYNOS_SMU) += ufs-exynos-smu.o
index d77fd88ce844f810cc8e2cbf6802024902a71246..e1ed7fc7916409516492e5e2b5281fe35ed3d70e 100644 (file)
 
 #define IATOVAL_NSEC           20000   /* unit: ns */
 
-#if defined(CONFIG_SOC_EXYNOS9810)
-#define UFS_PHY_CONTROL_OFFSET 0x0724
-#endif
-
 /* UFS CAL interface */
 
 /*
@@ -244,15 +240,16 @@ unsigned long ufs_lld_calc_timeout(const unsigned int ms)
        return msecs_to_jiffies(ms);
 }
 
-
 static inline void exynos_ufs_ctrl_phy_pwr(struct exynos_ufs *ufs, bool en)
 {
        int ret = 0;
 
        if (en)
-               ret = regmap_update_bits(ufs->pmureg, UFS_PHY_CONTROL_OFFSET, 0x1, 1);
+               ret = regmap_update_bits(ufs->pmureg, ufs->cxt_iso.offset,
+                                       ufs->cxt_iso.mask, ufs->cxt_iso.val);
        else
-               ret = regmap_update_bits(ufs->pmureg, UFS_PHY_CONTROL_OFFSET, 0x1, 0);
+               ret = regmap_update_bits(ufs->pmureg, ufs->cxt_iso.offset,
+                                       ufs->cxt_iso.mask, 0);
 
        if (ret)
                dev_err(ufs->dev, "Unable to update PHY ISO control\n");
@@ -493,39 +490,29 @@ static void exynos_ufs_post_hibern8(struct ufs_hba *hba, u8 enter)
        }
 }
 
-static void exynos_ufs_modify_sysreg(struct exynos_ufs *ufs, int index)
-{
-       struct exynos_ufs_sys *sys = &ufs->sys;
-       void __iomem *reg_sys = sys->reg_sys[index];
-       const char *const name[NUM_OF_SYSREG] = {
-               "ufs-io-coherency",
-       };
-       u32 reg;
-
-       if (!of_get_child_by_name(ufs->dev->of_node, name[index]))
-               return;
-
-       reg = readl(reg_sys);
-       writel((reg & ~(sys->mask[index])) | sys->bits[index], reg_sys);
-}
-
 static int exynos_ufs_init_system(struct exynos_ufs *ufs)
 {
        struct device *dev = ufs->dev;
        int ret = 0;
+       bool is_io_coherency;
+       bool is_dma_coherent;
 
        /* PHY isolation bypass */
        exynos_ufs_ctrl_phy_pwr(ufs, true);
 
        /* IO cohernecy */
-       if (!of_get_child_by_name(dev->of_node, "ufs-io-coherency")) {
-               dev_err(dev, "Not configured to use IO coherency\n");
-       } else {
-               if (!of_find_property(dev->of_node, "dma-coherent", NULL))
-                       BUG();
+       is_io_coherency = !IS_ERR(ufs->sysreg);
+       is_dma_coherent = !!of_find_property(dev->of_node,
+                                               "dma-coherent", NULL);
 
-               exynos_ufs_modify_sysreg(ufs, 0);
-       }
+       if (is_io_coherency != is_dma_coherent)
+               BUG();
+
+       if (!is_io_coherency)
+               dev_err(dev, "Not configured to use IO coherency\n");
+       else
+               ret = regmap_update_bits(ufs->sysreg, ufs->cxt_coherency.offset,
+                       ufs->cxt_coherency.mask, ufs->cxt_coherency.val);
 
        return ret;
 }
@@ -535,6 +522,7 @@ static int exynos_ufs_get_clks(struct ufs_hba *hba)
        struct exynos_ufs *ufs = to_exynos_ufs(hba);
        struct list_head *head = &hba->clk_list_head;
        struct ufs_clk_info *clki;
+       int i = 0;
 
        ufs_host_backup[ufs_host_index++] = ufs;
        ufs->debug.std_sfr = ufs_log_std_sfr;
@@ -543,13 +531,15 @@ static int exynos_ufs_get_clks(struct ufs_hba *hba)
                goto out;
 
        list_for_each_entry(clki, head, list) {
-               if (!IS_ERR_OR_NULL(clki->clk)) {
-                       if (!strcmp(clki->name, "GATE_UFS_EMBD"))
-                               ufs->clk_hci = clki->clk;
-                       if (!strcmp(clki->name, "UFS_EMBD")) {
-                               ufs->clk_unipro = clki->clk;
-                       }
-               }
+               /*
+                * get clock with an order listed in device tree
+                */
+               if (i == 0)
+                       ufs->clk_hci = clki->clk;
+               else if (i == 1)
+                       ufs->clk_unipro = clki->clk;
+
+               i++;
        }
 out:
        if (!ufs->clk_hci || !ufs->clk_unipro)
@@ -681,7 +671,7 @@ static void exynos_ufs_tcxo_ctrl(struct exynos_ufs *ufs, bool tcxo_on)
        unsigned int val;
        int ret;
 
-       ret = regmap_read(ufs->pmureg , UFS_PHY_CONTROL_OFFSET , &val);
+       ret = regmap_read(ufs->pmureg, ufs->cxt_iso.offset, &val);
 
        if (tcxo_on == true)
                val |= (1 << 16);
@@ -689,7 +679,7 @@ static void exynos_ufs_tcxo_ctrl(struct exynos_ufs *ufs, bool tcxo_on)
                val &= ~(1 << 16);
 
        if (!ret)
-               ret = regmap_write(ufs->pmureg , UFS_PHY_CONTROL_OFFSET , val);
+               ret = regmap_write(ufs->pmureg, ufs->cxt_iso.offset, val);
 
        if (ret)
                dev_err(ufs->dev, "Unable to access the pmureg using regmap\n");
@@ -724,10 +714,12 @@ static int exynos_ufs_pre_setup_clocks(struct ufs_hba *hba, bool on)
                exynos_update_ip_idle_status(ufs->idle_ip_index, 0);
 #endif
 
-               spin_lock_irqsave(&fsys0_tcxo_lock, flags);
-               if (exynos_use_shared_resource(OWNER_FIRST, on) == !on)
-                       exynos_ufs_tcxo_ctrl(ufs, true);
-               spin_unlock_irqrestore(&fsys0_tcxo_lock, flags);
+               if (ufs->tcxo_ex_ctrl) {
+                       spin_lock_irqsave(&fsys0_tcxo_lock, flags);
+                       if (exynos_use_shared_resource(OWNER_FIRST, on) == !on)
+                               exynos_ufs_tcxo_ctrl(ufs, true);
+                       spin_unlock_irqrestore(&fsys0_tcxo_lock, flags);
+               }
 
                /*
                 * Now all used blocks would not be turned off in a host.
@@ -738,7 +730,8 @@ static int exynos_ufs_pre_setup_clocks(struct ufs_hba *hba, bool on)
                /* HWAGC disable */
                exynos_ufs_set_hwacg_control(ufs, false);
        } else {
-               pm_qos_update_request(&ufs->pm_qos_fsys0, 0);
+               pm_qos_update_request(&ufs->pm_qos_int, 0);
+//             pm_qos_update_request(&ufs->pm_qos_fsys0, 0);
 
                /*
                 * BG/SQ off
@@ -761,22 +754,25 @@ static int exynos_ufs_setup_clocks(struct ufs_hba *hba, bool on)
                 */
                ret = ufs_pre_h8_exit(ufs);
 
-               pm_qos_update_request(&ufs->pm_qos_fsys0, ufs->pm_qos_fsys0_value);
+               pm_qos_update_request(&ufs->pm_qos_int, ufs->pm_qos_int_value);
+//             pm_qos_update_request(&ufs->pm_qos_fsys0, ufs->pm_qos_fsys0_value);
 
        } else {
                /*
                 * Now all used blocks would be turned off in a host.
                 */
-               exynos_ufs_gate_clk(ufs, true);
+               //exynos_ufs_gate_clk(ufs, true);
                exynos_ufs_ctrl_auto_hci_clk(ufs, true);
 
                /* HWAGC enable */
                exynos_ufs_set_hwacg_control(ufs, true);
 
-               spin_lock_irqsave(&fsys0_tcxo_lock, flags);
-               if (exynos_use_shared_resource(OWNER_FIRST, on) == on)
-                       exynos_ufs_tcxo_ctrl(ufs, false);
-               spin_unlock_irqrestore(&fsys0_tcxo_lock, flags);
+               if (ufs->tcxo_ex_ctrl) {
+                       spin_lock_irqsave(&fsys0_tcxo_lock, flags);
+                       if (exynos_use_shared_resource(OWNER_FIRST, on) == on)
+                               exynos_ufs_tcxo_ctrl(ufs, false);
+                       spin_unlock_irqrestore(&fsys0_tcxo_lock, flags);
+               }
 
 
 #ifdef CONFIG_CPU_IDLE
@@ -928,7 +924,8 @@ static int __exynos_ufs_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 {
        struct exynos_ufs *ufs = to_exynos_ufs(hba);
 
-       pm_qos_update_request(&ufs->pm_qos_fsys0, 0);
+       pm_qos_update_request(&ufs->pm_qos_int, 0);
+//     pm_qos_update_request(&ufs->pm_qos_fsys0, 0);
 
        exynos_ufs_dev_reset_ctrl(ufs, false);
 
@@ -1022,99 +1019,129 @@ static struct ufs_hba_variant_ops exynos_ufs_ops = {
        .access_control_abort = exynos_ufs_access_control_abort,
 };
 
-static int exynos_ufs_populate_dt_sys_per_feature(struct device *dev,
-                               struct exynos_ufs *ufs, int index)
+static int exynos_ufs_populate_dt_phy(struct device *dev, struct exynos_ufs *ufs)
 {
-       struct device_node *np;
-       struct exynos_ufs_sys *sys = &ufs->sys;
+       struct device_node *ufs_phy;
+       struct exynos_ufs_phy *phy = &ufs->phy;
        struct resource io_res;
        int ret;
-       const char *const name[NUM_OF_SYSREG] = {
-               "ufs-io-coherency",
-       };
 
-       np = of_get_child_by_name(dev->of_node, name[index]);
-       if (!np) {
-               dev_err(dev, "failed to get ufs-sys node\n");
+       ufs_phy = of_get_child_by_name(dev->of_node, "ufs-phy");
+       if (!ufs_phy) {
+               dev_err(dev, "failed to get ufs-phy node\n");
                return -ENODEV;
        }
 
-       ret = of_address_to_resource(np, 0, &io_res);
+       ret = of_address_to_resource(ufs_phy, 0, &io_res);
        if (ret) {
-               dev_err(dev, "failed to get i/o address %s\n", name[index]);
-               if (ret == -EINVAL)
-                       ret = 0;
-       } else {
-               sys->reg_sys[index] = devm_ioremap_resource(dev, &io_res);
-               if (IS_ERR(sys->reg_sys[index])) {
-                       dev_err(dev, "failed to ioremap sysreg\n");
-                       ret = -ENOMEM;
-               } else {
-                       ret = of_property_read_u32(np, "mask",
-                                               &sys->mask[index]);
-                       ret = of_property_read_u32(np, "bits",
-                                               &sys->bits[index]);
-                       if (ret)
-                               ret = -EINVAL;
-               }
+               dev_err(dev, "failed to get i/o address phy pma\n");
+               goto err_0;
        }
 
-       of_node_put(np);
+       phy->reg_pma = devm_ioremap_resource(dev, &io_res);
+       if (!phy->reg_pma) {
+               dev_err(dev, "failed to ioremap for phy pma\n");
+               ret = -ENOMEM;
+               goto err_0;
+       }
+
+err_0:
+       of_node_put(ufs_phy);
 
        return ret;
 }
 
-static int exynos_ufs_populate_dt_sys(struct device *dev, struct exynos_ufs *ufs)
+/*
+ * This function is to define offset, mask and shift to access somewhere.
+ */
+static int exynos_ufs_set_context_for_access(struct device *dev,
+                               const char *name, struct exynos_access_cxt *cxt)
 {
-       int i = 0;
+       struct device_node *np;
        int ret;
 
-       for (i = 0 ; i < NUM_OF_SYSREG ; i++) {
-               ret = exynos_ufs_populate_dt_sys_per_feature(dev, ufs, i);
-               if (ret && ret != -ENODEV)
-                       break;
+       np = of_get_child_by_name(dev->of_node, name);
+       if (!np) {
+               dev_err(dev, "failed to get node(%s)\n", name);
+               return 1;
        }
 
-       return ret;
+       ret = of_property_read_u32(np, "offset", &cxt->offset);
+       if (IS_ERR(&cxt->offset)) {
+               dev_err(dev, "failed to set cxt(%s) offset\n", name);
+               return cxt->offset;
+       }
+
+       ret = of_property_read_u32(np, "mask", &cxt->mask);
+       if (IS_ERR(&cxt->mask)) {
+               dev_err(dev, "failed to set cxt(%s) mask\n", name);
+               return cxt->mask;
+       }
+
+       ret = of_property_read_u32(np, "val", &cxt->val);
+       if (IS_ERR(&cxt->val)) {
+               dev_err(dev, "failed to set cxt(%s) val\n", name);
+               return cxt->val;
+       }
+
+       return 0;
 }
 
-static int exynos_ufs_populate_dt_phy(struct device *dev, struct exynos_ufs *ufs)
+static int exynos_ufs_populate_dt_system(struct device *dev, struct exynos_ufs *ufs)
 {
-       struct device_node *ufs_phy;
-       struct exynos_ufs_phy *phy = &ufs->phy;
-       struct resource io_res;
-       struct device_node *phy_sys = dev->of_node;
+       struct device_node *np = dev->of_node;
        int ret;
 
-       ufs_phy = of_get_child_by_name(dev->of_node, "ufs-phy");
-       if (!ufs_phy) {
-               dev_err(dev, "failed to get ufs-phy node\n");
-               return -ENODEV;
+       /* regmap pmureg */
+       ufs->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                        "samsung,pmu-phandle");
+       if (IS_ERR(ufs->pmureg)) {
+               /*
+                * phy isolation should be available.
+                * so this case need to be failed.
+                */
+               dev_err(dev, "pmu regmap lookup failed.\n");
+               return PTR_ERR(ufs->pmureg);
        }
 
-       ret = of_address_to_resource(ufs_phy, 0, &io_res);
-       if (ret) {
-               dev_err(dev, "failed to get i/o address phy pma\n");
-               goto err_0;
+       /* Set access context for phy isolation bypass */
+       ret = exynos_ufs_set_context_for_access(dev, "ufs-phy-iso",
+                                                       &ufs->cxt_iso);
+       if (ret == 1) {
+               /* no device node, default */
+               ufs->cxt_iso.offset = 0x0724;
+               ufs->cxt_iso.mask = 0x1;
+               ufs->cxt_iso.val = 0x1;
+               ret = 0;
        }
 
-       phy->reg_pma = devm_ioremap_resource(dev, &io_res);
-       if (!phy->reg_pma) {
-               dev_err(dev, "failed to ioremap for phy pma\n");
-               ret = -ENOMEM;
-               goto err_0;
+       /* regmap sysreg */
+       ufs->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                        "samsung,sysreg-fsys-phandle");
+       if (IS_ERR(ufs->sysreg)) {
+               /*
+                * Currently, ufs driver gets sysreg for io coherency.
+                * Some architecture might not support this feature.
+                * So the device node might not exist.
+                */
+               dev_err(dev, "sysreg regmap lookup failed.\n");
+               return 0;
        }
 
-       /* regmap pmureg*/
-       ufs->pmureg = syscon_regmap_lookup_by_phandle(phy_sys,
-                                        "samsung,pmu-phandle");
-       if (IS_ERR(ufs->pmureg)) {
-                        dev_err(dev, "syscon regmap lookup failed.\n");
-                        return PTR_ERR(ufs->pmureg);
-        }
+       /* Set access context for io coherency */
+       ret = exynos_ufs_set_context_for_access(dev, "ufs-dma-coherency",
+                                                       &ufs->cxt_coherency);
+       if (ret == 1) {
+               /* no device node, default */
+               ufs->cxt_coherency.offset = 0x0700;
+               ufs->cxt_coherency.mask = 0x300;        /* bit 8,9 */
+               ufs->cxt_coherency.val = 0x3;
+               ret = 0;
+       }
 
-err_0:
-       of_node_put(ufs_phy);
+       /* TCXO exclusive control */
+       if (of_property_read_u32(np, "tcxo-ex-ctrl", &ufs->tcxo_ex_ctrl))
+               ufs->tcxo_ex_ctrl = 1;
 
        return ret;
 }
@@ -1152,9 +1179,11 @@ static int exynos_ufs_populate_dt(struct device *dev, struct exynos_ufs *ufs)
                goto out;
        }
 
-       ret = exynos_ufs_populate_dt_sys(dev, ufs);
-       if (ret)
-               dev_err(dev, "failed to populate ufs-sys\n");
+       ret = exynos_ufs_populate_dt_system(dev, ufs);
+       if (ret) {
+               dev_err(dev, "failed to populate dt-pmu\n");
+               goto out;
+       }
 
        exynos_ufs_get_pwr_mode(np, ufs);
 
@@ -1247,14 +1276,19 @@ static int exynos_ufs_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ufs->tcxo_nb.notifier_call = exynos_ufs_lp_event;
-       ufs->tcxo_nb.next = NULL;
-       ufs->tcxo_nb.priority = 0;
-
-       ret = exynos_fsys0_tcxo_register_notifier(&ufs->tcxo_nb);
-       if (ret) {
-               dev_err(dev, "failed to register fsys0 txco notifier\n");
-               return ret;
+       /*
+        * pmu node and txco syscon node should be exclusive
+        */
+       if (ufs->tcxo_ex_ctrl) {
+               ufs->tcxo_nb.notifier_call = exynos_ufs_lp_event;
+               ufs->tcxo_nb.next = NULL;
+               ufs->tcxo_nb.priority = 0;
+
+               ret = exynos_fsys0_tcxo_register_notifier(&ufs->tcxo_nb);
+               if (ret) {
+                       dev_err(dev, "failed to register fsys0 txco notifier\n");
+                       return ret;
+               }
        }
 #ifdef CONFIG_CPU_IDLE
        ufs->idle_ip_index = exynos_get_idle_ip_index(dev_name(&pdev->dev));
@@ -1265,8 +1299,11 @@ static int exynos_ufs_probe(struct platform_device *pdev)
        dev->platform_data = ufs;
        dev->dma_mask = &exynos_ufs_dma_mask;
 
-       pm_qos_add_request(&ufs->pm_qos_fsys0, PM_QOS_FSYS0_THROUGHPUT, 0);
-       spin_lock_init(&fsys0_tcxo_lock);
+
+       pm_qos_add_request(&ufs->pm_qos_int, PM_QOS_DEVICE_THROUGHPUT, 0);
+//     pm_qos_add_request(&ufs->pm_qos_fsys0, PM_QOS_FSYS0_THROUGHPUT, 0);
+       if (ufs->tcxo_ex_ctrl)
+               spin_lock_init(&fsys0_tcxo_lock);
 
        ret = ufshcd_pltfrm_init(pdev, &exynos_ufs_ops);
 
index dd9714e217f19cb9a0c6329d536f66f0ae3119c7..f58f0bf692559b58996a33007b34505f1aa5e46d 100644 (file)
@@ -458,32 +458,8 @@ struct ufs_phy_cfg {
        u32 lyr;
 };
 
-struct exynos_ufs_soc {
-       struct ufs_phy_cfg *tbl_phy_init;
-       struct ufs_phy_cfg *tbl_post_phy_init;
-       struct ufs_phy_cfg *tbl_calib_of_pwm;
-       struct ufs_phy_cfg *tbl_calib_of_hs_rate_a;
-       struct ufs_phy_cfg *tbl_calib_of_hs_rate_b;
-       struct ufs_phy_cfg *tbl_post_calib_of_pwm;
-       struct ufs_phy_cfg *tbl_post_calib_of_hs_rate_a;
-       struct ufs_phy_cfg *tbl_post_calib_of_hs_rate_b;
-       struct ufs_phy_cfg *tbl_lpa_restore;
-       struct ufs_phy_cfg *tbl_pre_clk_off;
-       struct ufs_phy_cfg *tbl_post_clk_on;
-       struct ufs_phy_cfg *tbl_lane1_sq_off;
-};
-
 struct exynos_ufs_phy {
        void __iomem *reg_pma;
-       void __iomem *reg_pmu;
-       struct exynos_ufs_soc *soc;
-};
-
-#define NUM_OF_SYSREG 1
-struct exynos_ufs_sys {
-       void __iomem *reg_sys[NUM_OF_SYSREG];
-       u32 mask[NUM_OF_SYSREG];
-       u32 bits[NUM_OF_SYSREG];
 };
 
 struct exynos_ufs_clk_info {
@@ -532,6 +508,12 @@ struct exynos_fmp_data {
        struct platform_device *pdev;
 };
 
+struct exynos_access_cxt {
+       u32 offset;
+       u32 mask;
+       u32 val;
+};
+
 struct exynos_ufs {
        struct device *dev;
        struct ufs_hba *hba;
@@ -541,6 +523,7 @@ struct exynos_ufs {
        void __iomem *reg_ufsp;
 
        struct regmap *pmureg;
+       struct regmap *sysreg;
 
        struct clk *clk_hci;
        struct clk *pclk;
@@ -555,7 +538,6 @@ struct exynos_ufs {
        int num_tx_lanes;
 
        struct exynos_ufs_phy phy;
-       struct exynos_ufs_sys sys;
        struct notifier_block tcxo_nb;
        struct uic_pwr_mode req_pmd_parm;
        struct uic_pwr_mode act_pmd_parm;
@@ -580,6 +562,10 @@ struct exynos_ufs {
 
        u32 hw_rev;
 
+       u32 tcxo_ex_ctrl;                       /* TCXO exclusive control */
+       struct exynos_access_cxt cxt_iso;       /* phy isolation */
+       struct exynos_access_cxt cxt_coherency; /* io coherency */
+
        struct pm_qos_request   pm_qos_int;
        s32                     pm_qos_int_value;
        struct pm_qos_request   pm_qos_fsys0;