blob: ac4368ad511de66e7d2448870f4aa821d3b13330 [file] [log] [blame]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package gscdevboard
import (
"context"
"time"
"go.chromium.org/tast-tests/cros/common/firmware/ti50"
"go.chromium.org/tast-tests/cros/remote/bundles/cros/gscdevboard/utils"
"go.chromium.org/tast-tests/cros/remote/firmware/ti50/fixture"
"go.chromium.org/tast/core/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: GSCECReset,
Desc: "Test workaround for EC double reset",
Timeout: 30 * time.Second,
Contacts: []string{
"gsc-sheriff@google.com", // CrOS GSC Developers
"jbk@chromium.org", // Test Author
},
BugComponent: "b:715469", // ChromeOS > Platform > System > Hardware Security > HwSec GSC > Ti50
Attr: []string{"group:gsc",
"gsc_dt_ab", "gsc_dt_shield", "gsc_h1_shield", "gsc_ot_shield",
"gsc_image_ti50",
"gsc_nightly"},
Fixture: fixture.GSCOpenCCD,
Params: []testing.Param{{
Name: "gsc_reset_gpio",
Val: verifyEcResetOnGscReset,
}, {
Name: "gsc_reset_tpmv",
Val: verifyEcResetOnTpmvRebootCmd,
}, {
Name: "gsc_reset_console",
Val: verifyEcResetOnConsoleRebootCmd,
}},
})
}
func GSCECReset(ctx context.Context, s *testing.State) {
subTest := s.Param().(func(context.Context, *testing.State, utils.DevboardHelper, *ti50.CrOSImage, utils.FirmwareTestingHelper))
b := utils.NewDevboardHelper(s)
th := utils.FirmwareTestingHelper{FirmwareTestingHelperDelegate: s}
i := ti50.MustOpenCrOSImage(ctx, b, s)
defer i.Close(ctx)
b.Reset(ctx)
th.MustSucceed(i.WaitUntilBooted(ctx), "Ti50 revives after reboot")
subTest(ctx, s, b, i, th)
}
func verifyEcResetOnGscReset(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage, th utils.FirmwareTestingHelper) {
hasEcReset := b.GscProperties().HasEcRstFet()
s.Log("Verify EC reset on GSC_RST_L toggle")
// Hold GSC in reset before start GPIO monitoring
b.GpioSet(ctx, ti50.GpioTi50ResetL, false)
s.Log("Start gpio monitoring")
gpios := []ti50.GpioName{ti50.GpioTi50ResetL, ti50.GpioTi50EcRstL}
if hasEcReset {
gpios = append(gpios, ti50.GpioTi50EcRstFet)
}
gpioMonitor := b.GpioMonitorStart(ctx, gpios...)
s.Log("Booting ti50")
b.GpioSet(ctx, ti50.GpioTi50ResetL, true)
th.MustSucceed(i.WaitUntilBooted(ctx), "Ti50 revives after reboot")
// Give a little more time for gpio monitoring to catch EC_RST edges after GSC boots
testing.Sleep(ctx, time.Second) // GoBigSleepLint: No good way to poll for EC_RST
events := b.GpioMonitorFinish(ctx, gpioMonitor)
s.Log("Stop gpio monitoring: ", events)
resetReleased := events.FindFirst(ti50.GpioTi50ResetL, utils.GpioEdgeRising)
if resetReleased == nil {
// Must be fatal so we don't dereference nil below
s.Fatal("GSC did not come out of reset")
}
// Depending on if GSC has a secondary EC RESET FET pin, we need to find
// the real EC RESET edge after it or not
var ecResetAfter *utils.GpioEvent
if hasEcReset {
firstFetAfterRelease := events.FindFirstAfter(*resetReleased, ti50.GpioTi50EcRstFet)
if firstFetAfterRelease == nil {
// Must be fatal so we don't dereference nil below
s.Fatalf("%s did have an edge after release GSC from reset", ti50.GpioTi50EcRstFet)
}
ecResetAfter = firstFetAfterRelease
} else {
ecResetAfter = resetReleased
}
// Find the real EC RESET edge
realEcRelease := events.FindFirstAfter(*ecResetAfter, ti50.GpioTi50EcRstL)
if realEcRelease == nil || realEcRelease.Edge != utils.GpioEdgeRising {
// Must be fatal so we don't dereference nil below
s.Fatalf("%s edge right after FET release is not rising edge", ti50.GpioTi50EcRstL)
}
s.Logf("EC released from Reset %dms after GSC released", (realEcRelease.TimestampUS-resetReleased.TimestampUS)/1000)
}
func verifyEcResetOnTpmvRebootCmd(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage, th utils.FirmwareTestingHelper) {
s.Log("Verify EC reset on GSC reboot TPMV command")
tpm := b.ResetAndTpmStartup(ctx, i, ti50.FfClamshell)
s.Log("Start gpio monitoring")
gpioMonitor := b.GpioMonitorStart(ctx, ti50.GpioTi50EcRstL)
err := tpm.TpmvReboot(1000)
th.MustSucceed(err, "Error sending TPMV reboot")
th.MustSucceed(i.WaitUntilBooted(ctx), "Ti50 revives after reboot")
// Give a little more time for gpio monitoring to catch EC_RST edges after GSC boots
testing.Sleep(ctx, 3*time.Second) // GoBigSleepLint: No good way to poll for EC_RST
events := b.GpioMonitorFinish(ctx, gpioMonitor)
s.Log("Stop gpio monitoring: ", events)
ecReset := events.FindFirst(ti50.GpioTi50EcRstL, utils.GpioEdgeFalling)
if ecReset == nil {
// Must be fatal so we don't dereference nil below
s.Fatal("EC not put in reset with GSC reboot TPMV command")
}
ecResetReleased := events.FindFirstAfter(*ecReset, ti50.GpioTi50EcRstL)
if ecResetReleased == nil {
s.Error("EC not released from reset after GSC reboot TPMV command")
}
}
func verifyEcResetOnConsoleRebootCmd(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage, th utils.FirmwareTestingHelper) {
s.Log("Verify EC reset on GSC reboot console command")
s.Log("Start gpio monitoring")
gpioMonitor := b.GpioMonitorStart(ctx, ti50.GpioTi50EcRstL)
th.MustSucceed(i.SendConsoleRebootCmd(ctx), "Error calling `reboot` gsctool console command")
th.MustSucceed(i.WaitUntilBooted(ctx), "Ti50 revives after reboot")
// Give a little more time for gpio monitoring to catch EC_RST edges after GSC boots
testing.Sleep(ctx, time.Second) // GoBigSleepLint: No good way to poll for EC_RST
events := b.GpioMonitorFinish(ctx, gpioMonitor)
s.Log("Stop gpio monitoring: ", events)
ecReset := events.FindFirst(ti50.GpioTi50EcRstL, utils.GpioEdgeFalling)
if ecReset == nil {
// Must be fatal so we don't dereference nil below
s.Fatal("EC not put in reset with GSC reboot console command")
}
ecResetReleased := events.FindFirstAfter(*ecReset, ti50.GpioTi50EcRstL)
if ecResetReleased == nil {
s.Error("EC not released from reset after GSC reboot console command")
}
}