[11/22] scsi: hisi_sas: add v3 hw PHY init

Message ID 1495018197-120535-12-git-send-email-john.garry@huawei.com
State New
Headers show
Series
  • [01/22] scsi: hisi_sas: fix timeout check in hisi_sas_internal_task_abort()
Related show

Commit Message

John Garry May 17, 2017, 10:49 a.m.
From: Xiang Chen <chenxiang66@hisilicon.com>


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>

---
 drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 126 +++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

-- 
1.9.1

Patch hide | download patch | download mbox

diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index f2ea8c8..ea18582 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -19,6 +19,10 @@ 
 #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
@@ -68,9 +73,11 @@ 
 #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
@@ -91,11 +98,33 @@ 
 
 /* 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)
@@ -135,6 +164,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)
 {
@@ -151,6 +187,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;
@@ -265,6 +309,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);
@@ -272,6 +355,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;
@@ -286,7 +410,9 @@  static int hisi_sas_v3_init(struct hisi_hba *hisi_hba)
 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,
+	.sl_notify = sl_notify_v3_hw,
 	.complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr),
+	.phys_init = phys_init_v3_hw,
 };
 
 enum {