scsi: hisi_sas: add v3 hw PHY init
authorXiang Chen <chenxiang66@hisilicon.com>
Wed, 14 Jun 2017 15:33:22 +0000 (23:33 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 20 Jun 2017 01:31:26 +0000 (21:31 -0400)
Add code to configure PHYs for v3 hw.

Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

index 1a5eae6..5580250 100644 (file)
 #define ITCT_BASE_ADDR_HI              0x14
 #define IO_BROKEN_MSG_ADDR_LO          0x18
 #define IO_BROKEN_MSG_ADDR_HI          0x1c
+#define PHY_CONTEXT                    0x20
+#define PHY_STATE                      0x24
+#define PHY_PORT_NUM_MA                        0x28
+#define PHY_CONN_RATE                  0x30
 #define AXI_AHB_CLK_CFG                        0x3c
 #define AXI_USER1                      0x48
 #define AXI_USER2                      0x4c
@@ -42,6 +46,7 @@
 #define CFG_SET_ABORTED_IPTT_OFF       0
 #define CFG_SET_ABORTED_IPTT_MSK       (0xfff << CFG_SET_ABORTED_IPTT_OFF)
 #define CFG_1US_TIMER_TRSH             0xcc
+#define CHNL_INT_STATUS                        0x148
 #define INT_COAL_EN                    0x19c
 #define OQ_INT_COAL_TIME               0x1a0
 #define OQ_INT_COAL_CNT                        0x1a4
 #define ENT_INT_SRC_MSK1               0x1c4
 #define ENT_INT_SRC_MSK2               0x1c8
 #define ENT_INT_SRC_MSK3               0x1cc
+#define ENT_INT_SRC_MSK3_ENT95_MSK_OFF 31
 #define CHNL_PHYUPDOWN_INT_MSK         0x1d0
 #define CHNL_ENT_INT_MSK                       0x1d4
 #define HGC_COM_INT_MSK                                0x1d8
+#define ENT_INT_SRC_MSK3_ENT95_MSK_MSK (0x1 << ENT_INT_SRC_MSK3_ENT95_MSK_OFF)
 #define SAS_ECC_INTR                   0x1e8
 #define SAS_ECC_INTR_MSK               0x1ec
 #define HGC_ERR_STAT_EN                        0x238
 
 /* phy registers requiring init */
 #define PORT_BASE                      (0x2000)
+#define PHY_CFG                                (PORT_BASE + 0x0)
+#define HARD_PHY_LINKRATE              (PORT_BASE + 0x4)
+#define PHY_CFG_ENA_OFF                        0
+#define PHY_CFG_ENA_MSK                        (0x1 << PHY_CFG_ENA_OFF)
+#define PHY_CFG_DC_OPT_OFF             2
+#define PHY_CFG_DC_OPT_MSK             (0x1 << PHY_CFG_DC_OPT_OFF)
 #define PROG_PHY_LINK_RATE             (PORT_BASE + 0x8)
 #define PHY_CTRL                       (PORT_BASE + 0x14)
 #define PHY_CTRL_RESET_OFF             0
 #define PHY_CTRL_RESET_MSK             (0x1 << PHY_CTRL_RESET_OFF)
 #define SL_CFG                         (PORT_BASE + 0x84)
+#define SL_CONTROL                     (PORT_BASE + 0x94)
+#define SL_CONTROL_NOTIFY_EN_OFF       0
+#define SL_CONTROL_NOTIFY_EN_MSK       (0x1 << SL_CONTROL_NOTIFY_EN_OFF)
+#define SL_CTA_OFF             17
+#define SL_CTA_MSK             (0x1 << SL_CTA_OFF)
+#define TX_ID_DWORD0                   (PORT_BASE + 0x9c)
+#define TX_ID_DWORD1                   (PORT_BASE + 0xa0)
+#define TX_ID_DWORD2                   (PORT_BASE + 0xa4)
+#define TX_ID_DWORD3                   (PORT_BASE + 0xa8)
+#define TX_ID_DWORD4                   (PORT_BASE + 0xaC)
+#define TX_ID_DWORD5                   (PORT_BASE + 0xb0)
+#define TX_ID_DWORD6                   (PORT_BASE + 0xb4)
+#define TXID_AUTO                              (PORT_BASE + 0xb8)
+#define CT3_OFF                1
+#define CT3_MSK                (0x1 << CT3_OFF)
+#define RX_IDAF_DWORD0                 (PORT_BASE + 0xc4)
 #define RXOP_CHECK_CFG_H               (PORT_BASE + 0xfc)
 #define SAS_SSP_CON_TIMER_CFG          (PORT_BASE + 0x134)
 #define SAS_SMP_CON_TIMER_CFG          (PORT_BASE + 0x138)
@@ -136,6 +165,13 @@ struct hisi_sas_complete_v3_hdr {
 };
 
 #define HISI_SAS_COMMAND_ENTRIES_V3_HW 4096
+#define HISI_SAS_MSI_COUNT_V3_HW 32
+
+enum {
+       HISI_SAS_PHY_PHY_UPDOWN,
+       HISI_SAS_PHY_CHNL_INT,
+       HISI_SAS_PHY_INT_NR
+};
 
 static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val)
 {
@@ -152,6 +188,14 @@ static void hisi_sas_phy_write32(struct hisi_hba *hisi_hba, int phy_no,
        writel(val, regs);
 }
 
+static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
+                                     int phy_no, u32 off)
+{
+       void __iomem *regs = hisi_hba->regs + (0x400 * phy_no) + off;
+
+       return readl(regs);
+}
+
 static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
 {
        int i;
@@ -266,6 +310,45 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba)
                         upper_32_bits(hisi_hba->initial_fis_dma));
 }
 
+static void config_phy_opt_mode_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+       cfg &= ~PHY_CFG_DC_OPT_MSK;
+       cfg |= 1 << PHY_CFG_DC_OPT_OFF;
+       hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void config_id_frame_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       struct sas_identify_frame identify_frame;
+       u32 *identify_buffer;
+
+       memset(&identify_frame, 0, sizeof(identify_frame));
+       identify_frame.dev_type = SAS_END_DEVICE;
+       identify_frame.frame_type = 0;
+       identify_frame._un1 = 1;
+       identify_frame.initiator_bits = SAS_PROTOCOL_ALL;
+       identify_frame.target_bits = SAS_PROTOCOL_NONE;
+       memcpy(&identify_frame._un4_11[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+       memcpy(&identify_frame.sas_addr[0], hisi_hba->sas_addr, SAS_ADDR_SIZE);
+       identify_frame.phy_id = phy_no;
+       identify_buffer = (u32 *)(&identify_frame);
+
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD0,
+                       __swab32(identify_buffer[0]));
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD1,
+                       __swab32(identify_buffer[1]));
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD2,
+                       __swab32(identify_buffer[2]));
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD3,
+                       __swab32(identify_buffer[3]));
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD4,
+                       __swab32(identify_buffer[4]));
+       hisi_sas_phy_write32(hisi_hba, phy_no, TX_ID_DWORD5,
+                       __swab32(identify_buffer[5]));
+}
+
 static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
 {
        init_reg_v3_hw(hisi_hba);
@@ -273,6 +356,47 @@ static int hw_init_v3_hw(struct hisi_hba *hisi_hba)
        return 0;
 }
 
+static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG);
+
+       cfg |= PHY_CFG_ENA_MSK;
+       hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg);
+}
+
+static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       config_id_frame_v3_hw(hisi_hba, phy_no);
+       config_phy_opt_mode_v3_hw(hisi_hba, phy_no);
+       enable_phy_v3_hw(hisi_hba, phy_no);
+}
+
+static void start_phys_v3_hw(struct hisi_hba *hisi_hba)
+{
+       int i;
+
+       for (i = 0; i < hisi_hba->n_phy; i++)
+               start_phy_v3_hw(hisi_hba, i);
+}
+
+static void phys_init_v3_hw(struct hisi_hba *hisi_hba)
+{
+       start_phys_v3_hw(hisi_hba);
+}
+
+static void sl_notify_v3_hw(struct hisi_hba *hisi_hba, int phy_no)
+{
+       u32 sl_control;
+
+       sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+       sl_control |= SL_CONTROL_NOTIFY_EN_MSK;
+       hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+       msleep(1);
+       sl_control = hisi_sas_phy_read32(hisi_hba, phy_no, SL_CONTROL);
+       sl_control &= ~SL_CONTROL_NOTIFY_EN_MSK;
+       hisi_sas_phy_write32(hisi_hba, phy_no, SL_CONTROL, sl_control);
+}
+
 static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
 {
        int rc;
@@ -288,6 +412,8 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = {
        .hw_init = hisi_sas_v3_init,
        .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW,
        .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
+       .sl_notify = sl_notify_v3_hw,
+       .phys_init = phys_init_v3_hw,
 };
 
 static struct Scsi_Host *
@@ -451,7 +577,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-
 enum {
        /* instances of the controller */
        hip08,