Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Synopsys G210 Test Chip driver
0004  *
0005  * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
0006  *
0007  * Authors: Joao Pinto <jpinto@synopsys.com>
0008  */
0009 
0010 #include <ufs/ufshcd.h>
0011 #include "ufshcd-dwc.h"
0012 #include "tc-dwc-g210.h"
0013 
0014 #include <linux/module.h>
0015 #include <linux/pci.h>
0016 #include <linux/pm_runtime.h>
0017 
0018 /* Test Chip type expected values */
0019 #define TC_G210_20BIT 20
0020 #define TC_G210_40BIT 40
0021 #define TC_G210_INV 0
0022 
0023 static int tc_type = TC_G210_INV;
0024 module_param(tc_type, int, 0);
0025 MODULE_PARM_DESC(tc_type, "Test Chip Type (20 = 20-bit, 40 = 40-bit)");
0026 
0027 /*
0028  * struct ufs_hba_dwc_vops - UFS DWC specific variant operations
0029  */
0030 static struct ufs_hba_variant_ops tc_dwc_g210_pci_hba_vops = {
0031     .name                   = "tc-dwc-g210-pci",
0032     .link_startup_notify    = ufshcd_dwc_link_startup_notify,
0033 };
0034 
0035 /**
0036  * tc_dwc_g210_pci_shutdown - main function to put the controller in reset state
0037  * @pdev: pointer to PCI device handle
0038  */
0039 static void tc_dwc_g210_pci_shutdown(struct pci_dev *pdev)
0040 {
0041     ufshcd_shutdown((struct ufs_hba *)pci_get_drvdata(pdev));
0042 }
0043 
0044 /**
0045  * tc_dwc_g210_pci_remove - de-allocate PCI/SCSI host and host memory space
0046  *      data structure memory
0047  * @pdev: pointer to PCI handle
0048  */
0049 static void tc_dwc_g210_pci_remove(struct pci_dev *pdev)
0050 {
0051     struct ufs_hba *hba = pci_get_drvdata(pdev);
0052 
0053     pm_runtime_forbid(&pdev->dev);
0054     pm_runtime_get_noresume(&pdev->dev);
0055     ufshcd_remove(hba);
0056 }
0057 
0058 /**
0059  * tc_dwc_g210_pci_probe - probe routine of the driver
0060  * @pdev: pointer to PCI device handle
0061  * @id: PCI device id
0062  *
0063  * Returns 0 on success, non-zero value on failure
0064  */
0065 static int
0066 tc_dwc_g210_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
0067 {
0068     struct ufs_hba *hba;
0069     void __iomem *mmio_base;
0070     int err;
0071 
0072     /* Check Test Chip type and set the specific setup routine */
0073     if (tc_type == TC_G210_20BIT) {
0074         tc_dwc_g210_pci_hba_vops.phy_initialization =
0075                         tc_dwc_g210_config_20_bit;
0076     } else if (tc_type == TC_G210_40BIT) {
0077         tc_dwc_g210_pci_hba_vops.phy_initialization =
0078                         tc_dwc_g210_config_40_bit;
0079     } else {
0080         dev_err(&pdev->dev, "test chip version not specified\n");
0081         return -EPERM;
0082     }
0083 
0084     err = pcim_enable_device(pdev);
0085     if (err) {
0086         dev_err(&pdev->dev, "pcim_enable_device failed\n");
0087         return err;
0088     }
0089 
0090     pci_set_master(pdev);
0091 
0092     err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD);
0093     if (err < 0) {
0094         dev_err(&pdev->dev, "request and iomap failed\n");
0095         return err;
0096     }
0097 
0098     mmio_base = pcim_iomap_table(pdev)[0];
0099 
0100     err = ufshcd_alloc_host(&pdev->dev, &hba);
0101     if (err) {
0102         dev_err(&pdev->dev, "Allocation failed\n");
0103         return err;
0104     }
0105 
0106     hba->vops = &tc_dwc_g210_pci_hba_vops;
0107 
0108     err = ufshcd_init(hba, mmio_base, pdev->irq);
0109     if (err) {
0110         dev_err(&pdev->dev, "Initialization failed\n");
0111         return err;
0112     }
0113 
0114     pm_runtime_put_noidle(&pdev->dev);
0115     pm_runtime_allow(&pdev->dev);
0116 
0117     return 0;
0118 }
0119 
0120 static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
0121     SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume)
0122     SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL)
0123     .prepare     = ufshcd_suspend_prepare,
0124     .complete    = ufshcd_resume_complete,
0125 };
0126 
0127 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
0128     { PCI_VENDOR_ID_SYNOPSYS, 0xB101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
0129     { PCI_VENDOR_ID_SYNOPSYS, 0xB102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
0130     { } /* terminate list */
0131 };
0132 
0133 MODULE_DEVICE_TABLE(pci, tc_dwc_g210_pci_tbl);
0134 
0135 static struct pci_driver tc_dwc_g210_pci_driver = {
0136     .name = "tc-dwc-g210-pci",
0137     .id_table = tc_dwc_g210_pci_tbl,
0138     .probe = tc_dwc_g210_pci_probe,
0139     .remove = tc_dwc_g210_pci_remove,
0140     .shutdown = tc_dwc_g210_pci_shutdown,
0141     .driver = {
0142         .pm = &tc_dwc_g210_pci_pm_ops
0143     },
0144 };
0145 
0146 module_pci_driver(tc_dwc_g210_pci_driver);
0147 
0148 MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
0149 MODULE_DESCRIPTION("Synopsys Test Chip G210 PCI glue driver");
0150 MODULE_LICENSE("Dual BSD/GPL");