1818#include <linux/stat.h>
1919#include <linux/clk.h>
2020#include <linux/cpu.h>
21+ #include <linux/cpu_pm.h>
2122#include <linux/coresight.h>
2223#include <linux/coresight-pmu.h>
2324#include <linux/pm_wakeup.h>
2627#include <linux/uaccess.h>
2728#include <linux/perf_event.h>
2829#include <linux/pm_runtime.h>
30+ #include <linux/property.h>
2931#include <asm/sections.h>
3032#include <asm/local.h>
3133#include <asm/virt.h>
@@ -37,6 +39,15 @@ static int boot_enable;
3739module_param (boot_enable , int , 0444 );
3840MODULE_PARM_DESC (boot_enable , "Enable tracing on boot" );
3941
42+ #define PARAM_PM_SAVE_FIRMWARE 0 /* save self-hosted state as per firmware */
43+ #define PARAM_PM_SAVE_NEVER 1 /* never save any state */
44+ #define PARAM_PM_SAVE_SELF_HOSTED 2 /* save self-hosted state only */
45+
46+ static int pm_save_enable = PARAM_PM_SAVE_FIRMWARE ;
47+ module_param (pm_save_enable , int , 0444 );
48+ MODULE_PARM_DESC (pm_save_enable ,
49+ "Save/restore state on power down: 1 = never, 2 = self-hosted" );
50+
4051/* The number of ETMv4 currently registered */
4152static int etm4_count ;
4253static struct etmv4_drvdata * etmdrvdata [NR_CPUS ];
@@ -54,6 +65,14 @@ static void etm4_os_unlock(struct etmv4_drvdata *drvdata)
5465 isb ();
5566}
5667
68+ static void etm4_os_lock (struct etmv4_drvdata * drvdata )
69+ {
70+ /* Writing 0x1 to TRCOSLAR locks the trace registers */
71+ writel_relaxed (0x1 , drvdata -> base + TRCOSLAR );
72+ drvdata -> os_unlock = false;
73+ isb ();
74+ }
75+
5776static bool etm4_arch_supported (u8 arch )
5877{
5978 /* Mask out the minor version number */
@@ -1085,6 +1104,288 @@ static void etm4_init_trace_id(struct etmv4_drvdata *drvdata)
10851104 drvdata -> trcid = coresight_get_trace_id (drvdata -> cpu );
10861105}
10871106
1107+ #ifdef CONFIG_CPU_PM
1108+ static int etm4_cpu_save (struct etmv4_drvdata * drvdata )
1109+ {
1110+ int i , ret = 0 ;
1111+ struct etmv4_save_state * state ;
1112+ struct device * etm_dev = & drvdata -> csdev -> dev ;
1113+
1114+ /*
1115+ * As recommended by 3.4.1 ("The procedure when powering down the PE")
1116+ * of ARM IHI 0064D
1117+ */
1118+ dsb (sy );
1119+ isb ();
1120+
1121+ CS_UNLOCK (drvdata -> base );
1122+
1123+ /* Lock the OS lock to disable trace and external debugger access */
1124+ etm4_os_lock (drvdata );
1125+
1126+ /* wait for TRCSTATR.PMSTABLE to go up */
1127+ if (coresight_timeout (drvdata -> base , TRCSTATR ,
1128+ TRCSTATR_PMSTABLE_BIT , 1 )) {
1129+ dev_err (etm_dev ,
1130+ "timeout while waiting for PM Stable Status\n" );
1131+ etm4_os_unlock (drvdata );
1132+ ret = - EBUSY ;
1133+ goto out ;
1134+ }
1135+
1136+ state = drvdata -> save_state ;
1137+
1138+ state -> trcprgctlr = readl (drvdata -> base + TRCPRGCTLR );
1139+ state -> trcprocselr = readl (drvdata -> base + TRCPROCSELR );
1140+ state -> trcconfigr = readl (drvdata -> base + TRCCONFIGR );
1141+ state -> trcauxctlr = readl (drvdata -> base + TRCAUXCTLR );
1142+ state -> trceventctl0r = readl (drvdata -> base + TRCEVENTCTL0R );
1143+ state -> trceventctl1r = readl (drvdata -> base + TRCEVENTCTL1R );
1144+ state -> trcstallctlr = readl (drvdata -> base + TRCSTALLCTLR );
1145+ state -> trctsctlr = readl (drvdata -> base + TRCTSCTLR );
1146+ state -> trcsyncpr = readl (drvdata -> base + TRCSYNCPR );
1147+ state -> trcccctlr = readl (drvdata -> base + TRCCCCTLR );
1148+ state -> trcbbctlr = readl (drvdata -> base + TRCBBCTLR );
1149+ state -> trctraceidr = readl (drvdata -> base + TRCTRACEIDR );
1150+ state -> trcqctlr = readl (drvdata -> base + TRCQCTLR );
1151+
1152+ state -> trcvictlr = readl (drvdata -> base + TRCVICTLR );
1153+ state -> trcviiectlr = readl (drvdata -> base + TRCVIIECTLR );
1154+ state -> trcvissctlr = readl (drvdata -> base + TRCVISSCTLR );
1155+ state -> trcvipcssctlr = readl (drvdata -> base + TRCVIPCSSCTLR );
1156+ state -> trcvdctlr = readl (drvdata -> base + TRCVDCTLR );
1157+ state -> trcvdsacctlr = readl (drvdata -> base + TRCVDSACCTLR );
1158+ state -> trcvdarcctlr = readl (drvdata -> base + TRCVDARCCTLR );
1159+
1160+ for (i = 0 ; i < drvdata -> nrseqstate ; i ++ )
1161+ state -> trcseqevr [i ] = readl (drvdata -> base + TRCSEQEVRn (i ));
1162+
1163+ state -> trcseqrstevr = readl (drvdata -> base + TRCSEQRSTEVR );
1164+ state -> trcseqstr = readl (drvdata -> base + TRCSEQSTR );
1165+ state -> trcextinselr = readl (drvdata -> base + TRCEXTINSELR );
1166+
1167+ for (i = 0 ; i < drvdata -> nr_cntr ; i ++ ) {
1168+ state -> trccntrldvr [i ] = readl (drvdata -> base + TRCCNTRLDVRn (i ));
1169+ state -> trccntctlr [i ] = readl (drvdata -> base + TRCCNTCTLRn (i ));
1170+ state -> trccntvr [i ] = readl (drvdata -> base + TRCCNTVRn (i ));
1171+ }
1172+
1173+ for (i = 0 ; i < drvdata -> nr_resource * 2 ; i ++ )
1174+ state -> trcrsctlr [i ] = readl (drvdata -> base + TRCRSCTLRn (i ));
1175+
1176+ for (i = 0 ; i < drvdata -> nr_ss_cmp ; i ++ ) {
1177+ state -> trcssccr [i ] = readl (drvdata -> base + TRCSSCCRn (i ));
1178+ state -> trcsscsr [i ] = readl (drvdata -> base + TRCSSCSRn (i ));
1179+ state -> trcsspcicr [i ] = readl (drvdata -> base + TRCSSPCICRn (i ));
1180+ }
1181+
1182+ for (i = 0 ; i < drvdata -> nr_addr_cmp * 2 ; i ++ ) {
1183+ state -> trcacvr [i ] = readl (drvdata -> base + TRCACVRn (i ));
1184+ state -> trcacatr [i ] = readl (drvdata -> base + TRCACATRn (i ));
1185+ }
1186+
1187+ /*
1188+ * Data trace stream is architecturally prohibited for A profile cores
1189+ * so we don't save (or later restore) trcdvcvr and trcdvcmr - As per
1190+ * section 1.3.4 ("Possible functional configurations of an ETMv4 trace
1191+ * unit") of ARM IHI 0064D.
1192+ */
1193+
1194+ for (i = 0 ; i < drvdata -> numcidc ; i ++ )
1195+ state -> trccidcvr [i ] = readl (drvdata -> base + TRCCIDCVRn (i ));
1196+
1197+ for (i = 0 ; i < drvdata -> numvmidc ; i ++ )
1198+ state -> trcvmidcvr [i ] = readl (drvdata -> base + TRCVMIDCVRn (i ));
1199+
1200+ state -> trccidcctlr0 = readl (drvdata -> base + TRCCIDCCTLR0 );
1201+ state -> trccidcctlr1 = readl (drvdata -> base + TRCCIDCCTLR1 );
1202+
1203+ state -> trcvmidcctlr0 = readl (drvdata -> base + TRCVMIDCCTLR0 );
1204+ state -> trcvmidcctlr0 = readl (drvdata -> base + TRCVMIDCCTLR1 );
1205+
1206+ state -> trcclaimset = readl (drvdata -> base + TRCCLAIMCLR );
1207+
1208+ state -> trcpdcr = readl (drvdata -> base + TRCPDCR );
1209+
1210+ /* wait for TRCSTATR.IDLE to go up */
1211+ if (coresight_timeout (drvdata -> base , TRCSTATR , TRCSTATR_IDLE_BIT , 1 )) {
1212+ dev_err (etm_dev ,
1213+ "timeout while waiting for Idle Trace Status\n" );
1214+ etm4_os_unlock (drvdata );
1215+ ret = - EBUSY ;
1216+ goto out ;
1217+ }
1218+
1219+ drvdata -> state_needs_restore = true;
1220+
1221+ /*
1222+ * Power can be removed from the trace unit now. We do this to
1223+ * potentially save power on systems that respect the TRCPDCR_PU
1224+ * despite requesting software to save/restore state.
1225+ */
1226+ writel_relaxed ((state -> trcpdcr & ~TRCPDCR_PU ),
1227+ drvdata -> base + TRCPDCR );
1228+
1229+ out :
1230+ CS_LOCK (drvdata -> base );
1231+ return ret ;
1232+ }
1233+
1234+ static void etm4_cpu_restore (struct etmv4_drvdata * drvdata )
1235+ {
1236+ int i ;
1237+ struct etmv4_save_state * state = drvdata -> save_state ;
1238+
1239+ CS_UNLOCK (drvdata -> base );
1240+
1241+ writel_relaxed (state -> trcclaimset , drvdata -> base + TRCCLAIMSET );
1242+
1243+ writel_relaxed (state -> trcprgctlr , drvdata -> base + TRCPRGCTLR );
1244+ writel_relaxed (state -> trcprocselr , drvdata -> base + TRCPROCSELR );
1245+ writel_relaxed (state -> trcconfigr , drvdata -> base + TRCCONFIGR );
1246+ writel_relaxed (state -> trcauxctlr , drvdata -> base + TRCAUXCTLR );
1247+ writel_relaxed (state -> trceventctl0r , drvdata -> base + TRCEVENTCTL0R );
1248+ writel_relaxed (state -> trceventctl1r , drvdata -> base + TRCEVENTCTL1R );
1249+ writel_relaxed (state -> trcstallctlr , drvdata -> base + TRCSTALLCTLR );
1250+ writel_relaxed (state -> trctsctlr , drvdata -> base + TRCTSCTLR );
1251+ writel_relaxed (state -> trcsyncpr , drvdata -> base + TRCSYNCPR );
1252+ writel_relaxed (state -> trcccctlr , drvdata -> base + TRCCCCTLR );
1253+ writel_relaxed (state -> trcbbctlr , drvdata -> base + TRCBBCTLR );
1254+ writel_relaxed (state -> trctraceidr , drvdata -> base + TRCTRACEIDR );
1255+ writel_relaxed (state -> trcqctlr , drvdata -> base + TRCQCTLR );
1256+
1257+ writel_relaxed (state -> trcvictlr , drvdata -> base + TRCVICTLR );
1258+ writel_relaxed (state -> trcviiectlr , drvdata -> base + TRCVIIECTLR );
1259+ writel_relaxed (state -> trcvissctlr , drvdata -> base + TRCVISSCTLR );
1260+ writel_relaxed (state -> trcvipcssctlr , drvdata -> base + TRCVIPCSSCTLR );
1261+ writel_relaxed (state -> trcvdctlr , drvdata -> base + TRCVDCTLR );
1262+ writel_relaxed (state -> trcvdsacctlr , drvdata -> base + TRCVDSACCTLR );
1263+ writel_relaxed (state -> trcvdarcctlr , drvdata -> base + TRCVDARCCTLR );
1264+
1265+ for (i = 0 ; i < drvdata -> nrseqstate ; i ++ )
1266+ writel_relaxed (state -> trcseqevr [i ],
1267+ drvdata -> base + TRCSEQEVRn (i ));
1268+
1269+ writel_relaxed (state -> trcseqrstevr , drvdata -> base + TRCSEQRSTEVR );
1270+ writel_relaxed (state -> trcseqstr , drvdata -> base + TRCSEQSTR );
1271+ writel_relaxed (state -> trcextinselr , drvdata -> base + TRCEXTINSELR );
1272+
1273+ for (i = 0 ; i < drvdata -> nr_cntr ; i ++ ) {
1274+ writel_relaxed (state -> trccntrldvr [i ],
1275+ drvdata -> base + TRCCNTRLDVRn (i ));
1276+ writel_relaxed (state -> trccntctlr [i ],
1277+ drvdata -> base + TRCCNTCTLRn (i ));
1278+ writel_relaxed (state -> trccntvr [i ],
1279+ drvdata -> base + TRCCNTVRn (i ));
1280+ }
1281+
1282+ for (i = 0 ; i < drvdata -> nr_resource * 2 ; i ++ )
1283+ writel_relaxed (state -> trcrsctlr [i ],
1284+ drvdata -> base + TRCRSCTLRn (i ));
1285+
1286+ for (i = 0 ; i < drvdata -> nr_ss_cmp ; i ++ ) {
1287+ writel_relaxed (state -> trcssccr [i ],
1288+ drvdata -> base + TRCSSCCRn (i ));
1289+ writel_relaxed (state -> trcsscsr [i ],
1290+ drvdata -> base + TRCSSCSRn (i ));
1291+ writel_relaxed (state -> trcsspcicr [i ],
1292+ drvdata -> base + TRCSSPCICRn (i ));
1293+ }
1294+
1295+ for (i = 0 ; i < drvdata -> nr_addr_cmp * 2 ; i ++ ) {
1296+ writel_relaxed (state -> trcacvr [i ],
1297+ drvdata -> base + TRCACVRn (i ));
1298+ writel_relaxed (state -> trcacatr [i ],
1299+ drvdata -> base + TRCACATRn (i ));
1300+ }
1301+
1302+ for (i = 0 ; i < drvdata -> numcidc ; i ++ )
1303+ writel_relaxed (state -> trccidcvr [i ],
1304+ drvdata -> base + TRCCIDCVRn (i ));
1305+
1306+ for (i = 0 ; i < drvdata -> numvmidc ; i ++ )
1307+ writel_relaxed (state -> trcvmidcvr [i ],
1308+ drvdata -> base + TRCVMIDCVRn (i ));
1309+
1310+ writel_relaxed (state -> trccidcctlr0 , drvdata -> base + TRCCIDCCTLR0 );
1311+ writel_relaxed (state -> trccidcctlr1 , drvdata -> base + TRCCIDCCTLR1 );
1312+
1313+ writel_relaxed (state -> trcvmidcctlr0 , drvdata -> base + TRCVMIDCCTLR0 );
1314+ writel_relaxed (state -> trcvmidcctlr0 , drvdata -> base + TRCVMIDCCTLR1 );
1315+
1316+ writel_relaxed (state -> trcclaimset , drvdata -> base + TRCCLAIMSET );
1317+
1318+ writel_relaxed (state -> trcpdcr , drvdata -> base + TRCPDCR );
1319+
1320+ drvdata -> state_needs_restore = false;
1321+
1322+ /*
1323+ * As recommended by section 4.3.7 ("Synchronization when using the
1324+ * memory-mapped interface") of ARM IHI 0064D
1325+ */
1326+ dsb (sy );
1327+ isb ();
1328+
1329+ /* Unlock the OS lock to re-enable trace and external debug access */
1330+ etm4_os_unlock (drvdata );
1331+ CS_LOCK (drvdata -> base );
1332+ }
1333+
1334+ static int etm4_cpu_pm_notify (struct notifier_block * nb , unsigned long cmd ,
1335+ void * v )
1336+ {
1337+ struct etmv4_drvdata * drvdata ;
1338+ unsigned int cpu = smp_processor_id ();
1339+
1340+ if (!etmdrvdata [cpu ])
1341+ return NOTIFY_OK ;
1342+
1343+ drvdata = etmdrvdata [cpu ];
1344+
1345+ if (!drvdata -> save_state )
1346+ return NOTIFY_OK ;
1347+
1348+ if (WARN_ON_ONCE (drvdata -> cpu != cpu ))
1349+ return NOTIFY_BAD ;
1350+
1351+ switch (cmd ) {
1352+ case CPU_PM_ENTER :
1353+ /* save the state if self-hosted coresight is in use */
1354+ if (local_read (& drvdata -> mode ))
1355+ if (etm4_cpu_save (drvdata ))
1356+ return NOTIFY_BAD ;
1357+ break ;
1358+ case CPU_PM_EXIT :
1359+ /* fallthrough */
1360+ case CPU_PM_ENTER_FAILED :
1361+ if (drvdata -> state_needs_restore )
1362+ etm4_cpu_restore (drvdata );
1363+ break ;
1364+ default :
1365+ return NOTIFY_DONE ;
1366+ }
1367+
1368+ return NOTIFY_OK ;
1369+ }
1370+
1371+ static struct notifier_block etm4_cpu_pm_nb = {
1372+ .notifier_call = etm4_cpu_pm_notify ,
1373+ };
1374+
1375+ static int etm4_cpu_pm_register (void )
1376+ {
1377+ return cpu_pm_register_notifier (& etm4_cpu_pm_nb );
1378+ }
1379+
1380+ static void etm4_cpu_pm_unregister (void )
1381+ {
1382+ cpu_pm_unregister_notifier (& etm4_cpu_pm_nb );
1383+ }
1384+ #else
1385+ static int etm4_cpu_pm_register (void ) { return 0 ; }
1386+ static void etm4_cpu_pm_unregister (void ) { }
1387+ #endif
1388+
10881389static int etm4_probe (struct amba_device * adev , const struct amba_id * id )
10891390{
10901391 int ret ;
@@ -1101,6 +1402,17 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
11011402
11021403 dev_set_drvdata (dev , drvdata );
11031404
1405+ if (pm_save_enable == PARAM_PM_SAVE_FIRMWARE )
1406+ pm_save_enable = coresight_loses_context_with_cpu (dev ) ?
1407+ PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER ;
1408+
1409+ if (pm_save_enable != PARAM_PM_SAVE_NEVER ) {
1410+ drvdata -> save_state = devm_kmalloc (dev ,
1411+ sizeof (struct etmv4_save_state ), GFP_KERNEL );
1412+ if (!drvdata -> save_state )
1413+ return - ENOMEM ;
1414+ }
1415+
11041416 /* Validity for the resource is already checked by the AMBA core */
11051417 base = devm_ioremap_resource (dev , res );
11061418 if (IS_ERR (base ))
@@ -1135,6 +1447,10 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
11351447 if (ret < 0 )
11361448 goto err_arch_supported ;
11371449 hp_online = ret ;
1450+
1451+ ret = etm4_cpu_pm_register ();
1452+ if (ret )
1453+ goto err_arch_supported ;
11381454 }
11391455
11401456 cpus_read_unlock ();
@@ -1185,6 +1501,8 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
11851501
11861502err_arch_supported :
11871503 if (-- etm4_count == 0 ) {
1504+ etm4_cpu_pm_unregister ();
1505+
11881506 cpuhp_remove_state_nocalls (CPUHP_AP_ARM_CORESIGHT_STARTING );
11891507 if (hp_online )
11901508 cpuhp_remove_state_nocalls (hp_online );
0 commit comments