2222#include <linux/platform_device.h>
2323#include <linux/regmap.h>
2424#include <linux/reset.h>
25+ #include <linux/workqueue.h>
26+ #include <trace/events/pci_controller.h>
2527
2628#include "../../pci.h"
2729#include "pcie-designware.h"
7375#define PCIE_CLIENT_CDM_RASDES_TBA_L1_1 BIT(4)
7476#define PCIE_CLIENT_CDM_RASDES_TBA_L1_2 BIT(5)
7577
78+ /* Debug FIFO information */
79+ #define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
80+ #define PCIE_CLIENT_DBG_EN 0xffff0007
81+ #define PCIE_CLIENT_DBG_DIS 0xffff0000
82+ #define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
83+ #define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
84+ #define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
85+ #define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
86+ #define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
87+ #define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
88+ #define PCIE_DBG_FIFO_RATE_MASK GENMASK(22, 20)
89+ #define PCIE_DBG_FIFO_L1SUB_MASK GENMASK(10, 8)
90+ #define PCIE_DBG_LTSSM_HISTORY_CNT 64
91+
7692/* Hot Reset Control Register */
7793#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
7894#define PCIE_LTSSM_APP_DLY2_EN BIT(1)
@@ -98,6 +114,7 @@ struct rockchip_pcie {
98114 struct irq_domain * irq_domain ;
99115 const struct rockchip_pcie_of_data * data ;
100116 bool supports_clkreq ;
117+ struct delayed_work trace_work ;
101118};
102119
103120struct rockchip_pcie_of_data {
@@ -208,6 +225,96 @@ static enum dw_pcie_ltssm rockchip_pcie_get_ltssm(struct dw_pcie *pci)
208225 return rockchip_pcie_get_ltssm_reg (rockchip ) & PCIE_LTSSM_STATUS_MASK ;
209226}
210227
228+ #ifdef CONFIG_TRACING
229+ static void rockchip_pcie_ltssm_trace_work (struct work_struct * work )
230+ {
231+ struct rockchip_pcie * rockchip = container_of (work ,
232+ struct rockchip_pcie ,
233+ trace_work .work );
234+ struct dw_pcie * pci = & rockchip -> pci ;
235+ enum dw_pcie_ltssm state ;
236+ u32 i , l1ss , prev_val = DW_PCIE_LTSSM_UNKNOWN , rate , val ;
237+
238+ if (!trace_pcie_ltssm_state_transition_enabled ())
239+ goto skip_trace ;
240+
241+ for (i = 0 ; i < PCIE_DBG_LTSSM_HISTORY_CNT ; i ++ ) {
242+ val = rockchip_pcie_readl_apb (rockchip ,
243+ PCIE_CLIENT_DBG_FIFO_STATUS );
244+ rate = FIELD_GET (PCIE_DBG_FIFO_RATE_MASK , val );
245+ l1ss = FIELD_GET (PCIE_DBG_FIFO_L1SUB_MASK , val );
246+ val = FIELD_GET (PCIE_LTSSM_STATUS_MASK , val );
247+
248+ /*
249+ * Hardware Mechanism: The ring FIFO employs two tracking
250+ * counters:
251+ * - 'last-read-point': maintains the user's last read position
252+ * - 'last-valid-point': tracks the HW's last state update
253+ *
254+ * Software Handling: When two consecutive LTSSM states are
255+ * identical, it indicates invalid subsequent data in the FIFO.
256+ * In this case, we skip the remaining entries. The dual counter
257+ * design ensures that on the next state transition, reading can
258+ * resume from the last user position.
259+ */
260+ if ((i > 0 && val == prev_val ) || val > DW_PCIE_LTSSM_RCVRY_EQ3 )
261+ break ;
262+
263+ state = prev_val = val ;
264+ if (val == DW_PCIE_LTSSM_L1_IDLE ) {
265+ if (l1ss == 2 )
266+ state = DW_PCIE_LTSSM_L1_2 ;
267+ else if (l1ss == 1 )
268+ state = DW_PCIE_LTSSM_L1_1 ;
269+ }
270+
271+ trace_pcie_ltssm_state_transition (dev_name (pci -> dev ),
272+ dw_pcie_ltssm_status_string (state ),
273+ ((rate + 1 ) > pci -> max_link_speed ) ?
274+ PCI_SPEED_UNKNOWN : PCIE_SPEED_2_5GT + rate );
275+ }
276+
277+ skip_trace :
278+ schedule_delayed_work (& rockchip -> trace_work , msecs_to_jiffies (5000 ));
279+ }
280+
281+ static void rockchip_pcie_ltssm_trace (struct rockchip_pcie * rockchip ,
282+ bool enable )
283+ {
284+ if (enable ) {
285+ rockchip_pcie_writel_apb (rockchip ,
286+ PCIE_CLIENT_DBG_TRANSITION_DATA ,
287+ PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 );
288+ rockchip_pcie_writel_apb (rockchip ,
289+ PCIE_CLIENT_DBG_TRANSITION_DATA ,
290+ PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 );
291+ rockchip_pcie_writel_apb (rockchip ,
292+ PCIE_CLIENT_DBG_TRANSITION_DATA ,
293+ PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 );
294+ rockchip_pcie_writel_apb (rockchip ,
295+ PCIE_CLIENT_DBG_TRANSITION_DATA ,
296+ PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 );
297+ rockchip_pcie_writel_apb (rockchip ,
298+ PCIE_CLIENT_DBG_EN ,
299+ PCIE_CLIENT_DBG_FIFO_MODE_CON );
300+
301+ INIT_DELAYED_WORK (& rockchip -> trace_work ,
302+ rockchip_pcie_ltssm_trace_work );
303+ schedule_delayed_work (& rockchip -> trace_work , 0 );
304+ } else {
305+ rockchip_pcie_writel_apb (rockchip ,
306+ PCIE_CLIENT_DBG_DIS ,
307+ PCIE_CLIENT_DBG_FIFO_MODE_CON );
308+ cancel_delayed_work_sync (& rockchip -> trace_work );
309+ }
310+ }
311+ #else
312+ static void rockchip_pcie_ltssm_trace (struct rockchip_pcie * rockchip ,
313+ bool enable )
314+ {
315+ }
316+ #endif
317+
211318static void rockchip_pcie_enable_ltssm (struct rockchip_pcie * rockchip )
212319{
213320 rockchip_pcie_writel_apb (rockchip , PCIE_CLIENT_ENABLE_LTSSM ,
@@ -291,6 +398,9 @@ static int rockchip_pcie_start_link(struct dw_pcie *pci)
291398 * 100us as we don't know how long should the device need to reset.
292399 */
293400 msleep (PCIE_T_PVPERL_MS );
401+
402+ rockchip_pcie_ltssm_trace (rockchip , true);
403+
294404 gpiod_set_value_cansleep (rockchip -> rst_gpio , 1 );
295405
296406 return 0 ;
@@ -301,6 +411,7 @@ static void rockchip_pcie_stop_link(struct dw_pcie *pci)
301411 struct rockchip_pcie * rockchip = to_rockchip_pcie (pci );
302412
303413 rockchip_pcie_disable_ltssm (rockchip );
414+ rockchip_pcie_ltssm_trace (rockchip , false);
304415}
305416
306417static int rockchip_pcie_host_init (struct dw_pcie_rp * pp )
0 commit comments