7878#define CFG_MEM_RAM_SHUTDOWN 0x00000070
7979#define BLOCK_MEM_RDY 0x00000074
8080
81+ /* Max retry for link down */
82+ #define MAX_LINK_DOWN_RETRY 3
83+
8184struct xgene_ahci_context {
8285 struct ahci_host_priv * hpriv ;
8386 struct device * dev ;
@@ -145,6 +148,14 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
145148 return rc ;
146149}
147150
151+ static bool xgene_ahci_is_memram_inited (struct xgene_ahci_context * ctx )
152+ {
153+ void __iomem * diagcsr = ctx -> csr_diag ;
154+
155+ return (readl (diagcsr + CFG_MEM_RAM_SHUTDOWN ) == 0 &&
156+ readl (diagcsr + BLOCK_MEM_RDY ) == 0xFFFFFFFF );
157+ }
158+
148159/**
149160 * xgene_ahci_read_id - Read ID data from the specified device
150161 * @dev: device
@@ -229,8 +240,11 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
229240 * and Gen1 (1.5Gbps). Otherwise during long IO stress test, the PHY will
230241 * report disparity error and etc. In addition, during COMRESET, there can
231242 * be error reported in the register PORT_SCR_ERR. For SERR_DISPARITY and
232- * SERR_10B_8B_ERR, the PHY receiver line must be reseted. The following
233- * algorithm is followed to proper configure the hardware PHY during COMRESET:
243+ * SERR_10B_8B_ERR, the PHY receiver line must be reseted. Also during long
244+ * reboot cycle regression, sometimes the PHY reports link down even if the
245+ * device is present because of speed negotiation failure. so need to retry
246+ * the COMRESET to get the link up. The following algorithm is followed to
247+ * proper configure the hardware PHY during COMRESET:
234248 *
235249 * Alg Part 1:
236250 * 1. Start the PHY at Gen3 speed (default setting)
@@ -246,9 +260,15 @@ static void xgene_ahci_set_phy_cfg(struct xgene_ahci_context *ctx, int channel)
246260 * Alg Part 2:
247261 * 1. On link up, if there are any SERR_DISPARITY and SERR_10B_8B_ERR error
248262 * reported in the register PORT_SCR_ERR, then reset the PHY receiver line
249- * 2. Go to Alg Part 3
263+ * 2. Go to Alg Part 4
250264 *
251265 * Alg Part 3:
266+ * 1. Check the PORT_SCR_STAT to see whether device presence detected but PHY
267+ * communication establishment failed and maximum link down attempts are
268+ * less than Max attempts 3 then goto Alg Part 1.
269+ * 2. Go to Alg Part 4.
270+ *
271+ * Alg Part 4:
252272 * 1. Clear any pending from register PORT_SCR_ERR.
253273 *
254274 * NOTE: For the initial version, we will NOT support Gen1/Gen2. In addition
@@ -267,19 +287,27 @@ static int xgene_ahci_do_hardreset(struct ata_link *link,
267287 u8 * d2h_fis = pp -> rx_fis + RX_FIS_D2H_REG ;
268288 void __iomem * port_mmio = ahci_port_base (ap );
269289 struct ata_taskfile tf ;
290+ int link_down_retry = 0 ;
270291 int rc ;
271- u32 val ;
272-
273- /* clear D2H reception area to properly wait for D2H FIS */
274- ata_tf_init (link -> device , & tf );
275- tf .command = ATA_BUSY ;
276- ata_tf_to_fis (& tf , 0 , 0 , d2h_fis );
277- rc = sata_link_hardreset (link , timing , deadline , online ,
292+ u32 val , sstatus ;
293+
294+ do {
295+ /* clear D2H reception area to properly wait for D2H FIS */
296+ ata_tf_init (link -> device , & tf );
297+ tf .command = ATA_BUSY ;
298+ ata_tf_to_fis (& tf , 0 , 0 , d2h_fis );
299+ rc = sata_link_hardreset (link , timing , deadline , online ,
278300 ahci_check_ready );
301+ if (* online ) {
302+ val = readl (port_mmio + PORT_SCR_ERR );
303+ if (val & (SERR_DISPARITY | SERR_10B_8B_ERR ))
304+ dev_warn (ctx -> dev , "link has error\n" );
305+ break ;
306+ }
279307
280- val = readl ( port_mmio + PORT_SCR_ERR );
281- if ( val & ( SERR_DISPARITY | SERR_10B_8B_ERR ))
282- dev_warn ( ctx -> dev , "link has error\n" );
308+ sata_scr_read ( link , SCR_STATUS , & sstatus );
309+ } while ( link_down_retry ++ < MAX_LINK_DOWN_RETRY &&
310+ ( sstatus & 0xff ) == 0x1 );
283311
284312 /* clear all errors if any pending */
285313 val = readl (port_mmio + PORT_SCR_ERR );
@@ -467,6 +495,11 @@ static int xgene_ahci_probe(struct platform_device *pdev)
467495 return - ENODEV ;
468496 }
469497
498+ if (xgene_ahci_is_memram_inited (ctx )) {
499+ dev_info (dev , "skip clock and PHY initialization\n" );
500+ goto skip_clk_phy ;
501+ }
502+
470503 /* Due to errata, HW requires full toggle transition */
471504 rc = ahci_platform_enable_clks (hpriv );
472505 if (rc )
@@ -479,7 +512,7 @@ static int xgene_ahci_probe(struct platform_device *pdev)
479512
480513 /* Configure the host controller */
481514 xgene_ahci_hw_init (hpriv );
482-
515+ skip_clk_phy :
483516 hpriv -> flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ ;
484517
485518 rc = ahci_platform_init_host (pdev , hpriv , & xgene_ahci_port_info );
0 commit comments