@@ -406,6 +406,17 @@ struct hisi_sas_err_record_v2 {
__le32 dma_rx_err_type;
};
+struct signal_attenuation_s {
+ u32 de_emphasis;
+ u32 preshoot;
+ u32 boost;
+};
+
+struct sig_atten_lu_s {
+ const struct signal_attenuation_s *att;
+ u32 sas_phy_ctrl;
+};
+
static const struct hisi_sas_hw_error one_bit_ecc_errors[] = {
{
.irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF),
@@ -1130,9 +1141,16 @@ static void phys_try_accept_stp_links_v2_hw(struct hisi_hba *hisi_hba)
}
}
+static const struct signal_attenuation_s x6000 = {9200, 0, 10476};
+static const struct sig_atten_lu_s sig_atten_lu[] = {
+ { &x6000, 0x3016a68 },
+};
+
static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
{
struct device *dev = hisi_hba->dev;
+ u32 sas_phy_ctrl = 0x30b9908;
+ u32 signal[3];
int i;
/* Global registers init */
@@ -1176,9 +1194,28 @@ static void init_reg_v2_hw(struct hisi_hba *hisi_hba)
hisi_sas_write32(hisi_hba, AXI_AHB_CLK_CFG, 1);
hisi_sas_write32(hisi_hba, HYPER_STREAM_ID_EN_CFG, 1);
+ /* Get sas_phy_ctrl value to deal with TX FFE issue. */
+ if (!device_property_read_u32_array(dev, "signal-attenuation",
+ signal, ARRAY_SIZE(signal))) {
+ for (i = 0; i < ARRAY_SIZE(sig_atten_lu); i++) {
+ const struct sig_atten_lu_s *lookup = &sig_atten_lu[i];
+ const struct signal_attenuation_s *att = lookup->att;
+
+ if ((signal[0] == att->de_emphasis) &&
+ (signal[1] == att->preshoot) &&
+ (signal[2] == att->boost)) {
+ sas_phy_ctrl = lookup->sas_phy_ctrl;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(sig_atten_lu))
+ dev_warn(dev, "unknown signal attenuation values, using default PHY ctrl config\n");
+ }
+
for (i = 0; i < hisi_hba->n_phy; i++) {
hisi_sas_phy_write32(hisi_hba, i, PROG_PHY_LINK_RATE, 0x855);
- hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, 0x30b9908);
+ hisi_sas_phy_write32(hisi_hba, i, SAS_PHY_CTRL, sas_phy_ctrl);
hisi_sas_phy_write32(hisi_hba, i, SL_TOUT_CFG, 0x7d7d7d7d);
hisi_sas_phy_write32(hisi_hba, i, SL_CONTROL, 0x0);
hisi_sas_phy_write32(hisi_hba, i, TXID_AUTO, 0x2);