blob: bdaecaefa0930130ade292a26a6b15cd7f01687a [file] [log] [blame]
// Copyright 2024 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"
)
const (
// minEcResetPulse is how long EC reset must be asserted.
minEcResetPulse = 10 * time.Millisecond
// battDisconnectMinimum is how long AC must be removed before battery
// disconnect is asserted
battDisconnectMinimum = 5 * time.Second
deepSleepDelay = ti50.WaitForSleepTimeout
)
const (
// tabletEcResetHoldDelay is how long EC reset keys must be held to trigger EC reset
tabletEcResetHoldDelay = 10 * time.Second
// tabletGscResetHoldDelay is how long GSC reset keys must be held to trigger GSC reset
tabletGscResetHoldDelay = 20 * time.Second
)
const (
// clamshellGscResetHoldDelay is how long GSC reset keys must be held to trigger GSC reset
clamshellGscResetHoldDelay = 10 * time.Second
)
type ti50ValidRBOXParam struct {
formFactor ti50.GpioStrap
mainFunction func(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage)
}
func init() {
testing.AddTest(&testing.Test{
Func: Ti50RBOX,
Desc: "Verify keyboard combination for rbox on all form factors",
Timeout: 5 * time.Minute,
Contacts: []string{
"gsc-sheriff@google.com", // CrOS GSC Developers
"jettrink@google.com",
},
BugComponent: "b:715469", // ChromeOS > Platform > System > Hardware Security > HwSec GSC > Ti50
Attr: []string{
"group:gsc",
"gsc_dt_ab", "gsc_dt_shield", "gsc_ot_shield",
"gsc_image_ti50",
"gsc_nightly"},
Fixture: fixture.GSCOpenCCD,
Vars: []string{"bypass_sleep_check"},
Params: []testing.Param{{
Name: "clamshell",
Val: ti50ValidRBOXParam{
formFactor: ti50.FfClamshell,
mainFunction: ti50RBOXClamshell,
},
}, {
Name: "tablet",
Val: ti50ValidRBOXParam{
formFactor: ti50.FfTablet,
mainFunction: ti50RBOXTablet,
},
}, {
Name: "box",
Val: ti50ValidRBOXParam{
formFactor: ti50.FfBox,
mainFunction: ti50RBOXBox,
},
}},
})
}
func Ti50RBOX(ctx context.Context, s *testing.State) {
params := s.Param().(ti50ValidRBOXParam)
b := utils.NewDevboardHelper(s)
th := utils.FirmwareTestingHelper{FirmwareTestingHelperDelegate: s}
i := ti50.MustOpenCrOSImage(ctx, b, s)
defer i.Close(ctx)
s.Logf("Restarting ti50 with %s straps and SuzyQ connected", string(params.formFactor))
b.ResetWithStraps(ctx, params.formFactor, ti50.CcdSuzyQ)
th.MustSucceed(i.WaitUntilBooted(ctx), "Ti50 revives after reboot")
params.mainFunction(ctx, s, b, i)
}
func ti50RBOXBox(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage) {
s.Log("Verifying Recovery Button is passed through when power button not pressed")
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ti50.GpioTi50RecoveryIn, true)
if b.GpioGet(ctx, ti50.GpioTi50RecoveryOut) != true {
s.Errorf("GSC should forward high from %s to %s", ti50.GpioTi50RecoveryIn, ti50.GpioTi50RecoveryOut)
}
b.GpioSet(ctx, ti50.GpioTi50RecoveryIn, false)
if b.GpioGet(ctx, ti50.GpioTi50RecoveryOut) != false {
s.Errorf("GSC should forward low from %s to %s", ti50.GpioTi50RecoveryIn, ti50.GpioTi50RecoveryOut)
}
s.Log("Verifying Recovery Button is held high when power button pressed")
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
b.GpioSet(ctx, ti50.GpioTi50RecoveryIn, true)
if b.GpioGet(ctx, ti50.GpioTi50RecoveryOut) != true {
s.Error("GSC should keep Recovery Button high if power button pressed")
}
b.GpioSet(ctx, ti50.GpioTi50RecoveryIn, false)
if b.GpioGet(ctx, ti50.GpioTi50RecoveryOut) != true {
s.Error("GSC should not forward Recovery Button press with Power button pressed")
}
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50PowerBtnL, ti50.GpioTi50RecoveryIn, nil)
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50RecoveryIn, ti50.GpioTi50PowerBtnL, nil)
verifyMinECPulseWidth(ctx, s, b)
verifyRMAKeySequence(ctx, s, b, i, ti50.GpioTi50RecoveryIn)
// Finish test if bypass_sleep_check var is present (even if value is "false")
if _, noSleepCheck := s.Var("bypass_sleep_check"); noSleepCheck {
s.Log("Bypassing all rbox sleep tests")
return
}
s.Log("Disconnecting CCD to allow deep sleep")
b.GpioApplyStrap(ctx, ti50.CcdDisconnected)
s.Log("Waiting for deep sleep")
if err := i.WaitUntilDeepSleep(ctx, deepSleepDelay); err != nil {
s.Fatal("GSC dut not enter deep sleep as precondition for next test: ", err)
}
s.Log("GSC in deep sleep")
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50RecoveryIn, ti50.GpioTi50PowerBtnL, nil)
s.Log("Waiting for deep sleep")
if err := i.WaitUntilDeepSleep(ctx, deepSleepDelay); err != nil {
s.Fatal("GSC dut not enter deep sleep as precondition for next test: ", err)
}
s.Log("GSC in deep sleep")
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50PowerBtnL, ti50.GpioTi50RecoveryIn, nil)
}
func ti50RBOXClamshell(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage) {
th := utils.FirmwareTestingHelper{FirmwareTestingHelperDelegate: s}
s.Log("Verifying KSO is passed through when power button not pressed")
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ti50.GpioTi50EcKso2Inv, true)
if b.GpioGet(ctx, ti50.GpioTi50Kso2) != false {
s.Error("GSC should forward asserted GpioTi50EcKso2Inv")
}
b.GpioSet(ctx, ti50.GpioTi50EcKso2Inv, false)
if b.GpioGet(ctx, ti50.GpioTi50Kso2) != true {
s.Error("GSC should forward de-asserted GpioTi50EcKso2Inv")
}
s.Log("Verifying KSO is always asserted when power button pressed")
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
if b.GpioGet(ctx, ti50.GpioTi50Kso2) != false {
s.Error("GSC should be asserting KSO low when power button is pressed")
}
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50PowerBtnL, ti50.GpioTi50KsiRefresh, nil)
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50KsiRefresh, ti50.GpioTi50PowerBtnL, nil)
verifyMinECPulseWidth(ctx, s, b)
s.Log("Pushing GSC reset keys")
// Ensure that all GSC reset key combo keys are not being pushed yet
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ti50.GpioTi50KsiRefresh, true)
b.GpioSet(ctx, ti50.GpioTi50KsiBack, true)
// Push all GSC reset keys
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
b.GpioSet(ctx, ti50.GpioTi50KsiRefresh, false)
b.GpioSet(ctx, ti50.GpioTi50KsiBack, false)
s.Log("Waiting for GSC to reset")
beforeReset := time.Now()
if err := i.WaitUntilRoBoot(ctx, clamshellGscResetHoldDelay+time.Second*5); err != nil {
s.Error("GSC did not reset with reset key combo after 10 seconds")
} else {
timeForReset := time.Now().Sub(beforeReset)
// Allow 1% measurement error.
if timeForReset.Milliseconds() < int64(float64(clamshellGscResetHoldDelay.Milliseconds())*0.99) {
s.Error("GSC reset before 10s minimum hold time: ", timeForReset)
} else {
s.Log("GSC reset after ", timeForReset)
}
}
// Release all GSC reset keys
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ti50.GpioTi50KsiRefresh, true)
b.GpioSet(ctx, ti50.GpioTi50KsiBack, true)
verifyRMAKeySequence(ctx, s, b, i, ti50.GpioTi50KsiRefresh)
verifyBatteryDisconnectCancelled(ctx, s, b, ti50.GpioTi50KsiRefresh)
verifyBatteryDisconnect(ctx, s, b, ti50.GpioTi50KsiRefresh)
// Finish test if bypass_sleep_check var is present (even if value is "false")
if _, noSleepCheck := s.Var("bypass_sleep_check"); noSleepCheck {
s.Log("Bypassing all rbox sleep tests")
return
}
s.Log("Disconnecting CCD to allow deep sleep")
b.GpioApplyStrap(ctx, ti50.CcdDisconnected)
s.Log("Waiting for deep sleep")
if err := i.WaitUntilDeepSleep(ctx, deepSleepDelay); err != nil {
s.Fatal("GSC dut not enter deep sleep as precondition for next test: ", err)
}
s.Log("GSC in deep sleep")
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50KsiRefresh, ti50.GpioTi50PowerBtnL, nil)
s.Log("Waiting for deep sleep")
if err := i.WaitUntilDeepSleep(ctx, deepSleepDelay); err != nil {
s.Fatal("GSC dut not enter deep sleep as precondition for next test: ", err)
}
s.Log("GSC in deep sleep")
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50PowerBtnL, ti50.GpioTi50KsiRefresh, nil)
s.Log("Reconnecting SuzyQ to prevent deep sleep")
b.GpioApplyStrap(ctx, ti50.CcdSuzyQ)
th.MustSucceed(i.WaitUntilBooted(ctx), "Ti50 is awake")
}
func ti50RBOXTablet(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage) {
th := utils.FirmwareTestingHelper{FirmwareTestingHelperDelegate: s}
s.Log("Verifying VolDown and VolUp are passed through when power button not pressed")
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
verifyPassthrough(ctx, s, b, ti50.GpioTi50VolDownIn, ti50.GpioTi50VolDownOut)
verifyPassthrough(ctx, s, b, ti50.GpioTi50VolUpIn, ti50.GpioTi50VolUpOut)
s.Log("Verifying VolDown and VolUp are passed through when power button pressed")
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
verifyPassthrough(ctx, s, b, ti50.GpioTi50VolDownIn, ti50.GpioTi50VolDownOut)
verifyPassthrough(ctx, s, b, ti50.GpioTi50VolUpIn, ti50.GpioTi50VolUpOut)
// Ensure keys for combo are not pushed
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ti50.GpioTi50VolDownIn, true)
b.GpioSet(ctx, ti50.GpioTi50VolUpIn, true)
delay := tabletEcResetHoldDelay
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50PowerBtnL, ti50.GpioTi50VolUpIn, &delay)
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50VolUpIn, ti50.GpioTi50PowerBtnL, &delay)
verifyMinECPulseWidth(ctx, s, b)
// Ensure EC reset works when Volume Down is also pressed. This is the
// recovery key combo and needs to reset the EC as well.
s.Log("Verify EC reset still happens when VolDown is also pressed")
b.GpioSet(ctx, ti50.GpioTi50VolDownIn, false)
verifyEcResetWithKeysInOrder(ctx, s, b, ti50.GpioTi50PowerBtnL, ti50.GpioTi50VolUpIn, &delay)
b.GpioSet(ctx, ti50.GpioTi50VolDownIn, true)
s.Log("Pushing GSC reset keys")
// Ensure that all GSC reset key combo keys are not being pushed
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ti50.GpioTi50VolUpIn, true)
// Volume Down is required not to be pushed during the 20 seconds
b.GpioSet(ctx, ti50.GpioTi50VolDownIn, true)
// Push all GSC reset keys
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
b.GpioSet(ctx, ti50.GpioTi50VolUpIn, false)
s.Log("Waiting for GSC to reset")
beforeReset := time.Now()
if err := i.WaitUntilRoBoot(ctx, tabletGscResetHoldDelay+time.Second*5); err != nil {
s.Error("GSC did not reset with reset key combo after 25 seconds")
} else {
timeForReset := time.Now().Sub(beforeReset)
// Allow 1% measurement error.
if timeForReset.Milliseconds() < int64(float64(tabletGscResetHoldDelay.Milliseconds())*0.99) {
s.Error("GSC reset before 20s minimum hold time: ", timeForReset)
} else {
s.Log("GSC reset after ", timeForReset)
}
}
// Release all GSC reset keys
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ti50.GpioTi50VolUpIn, true)
s.Log("Start verifying GSC reset does not trigger with Volume Down pressed")
// Push all GSC reset keys but with extra Volume Down, which should prevent GSC reset
th.MustSucceed(i.WaitUntilBooted(ctx), "GSC booted")
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
b.GpioSet(ctx, ti50.GpioTi50VolUpIn, false)
b.GpioSet(ctx, ti50.GpioTi50VolDownIn, false)
s.Log("Waiting for GSC to reset")
beforeReset = time.Now()
if err := i.WaitUntilRoBoot(ctx, tabletGscResetHoldDelay+time.Second*5); err != nil {
s.Log("GSC did not reset (which is correct) after 25 seconds with Volume Up also pushed")
} else {
timeForReset := time.Now().Sub(beforeReset)
s.Error("GSC reset incorrectly after ", timeForReset)
}
// Release all GSC reset keys
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ti50.GpioTi50VolUpIn, true)
b.GpioSet(ctx, ti50.GpioTi50VolDownIn, true)
verifyRMAKeySequence(ctx, s, b, i, ti50.GpioTi50VolUpIn)
verifyBatteryDisconnectCancelled(ctx, s, b, ti50.GpioTi50VolUpIn)
verifyBatteryDisconnect(ctx, s, b, ti50.GpioTi50VolUpIn)
}
// verifyEcResetWithKeysInOrder verifies that pushing the first gpio then the
// second for the minimum + 500ms causes EC_RST_L to assert
func verifyEcResetWithKeysInOrder(ctx context.Context, s *testing.State, b utils.DevboardHelper, first, second ti50.GpioName, minHold *time.Duration) {
s.Logf("Verifying EC_RST_L asserted when pushing %s then %s", first, second)
// Ensure that both keys start not pressed
b.GpioSet(ctx, first, true)
b.GpioSet(ctx, second, true)
s.Log("Start gpio monitoring")
gpioMonitor := b.GpioMonitorStart(ctx, ti50.GpioTi50EcRstL)
if gpioMonitor.InitialValues[ti50.GpioTi50EcRstL] != true {
s.Error("EC_RST_L not de-asserted before pressing EC Refresh combo")
}
s.Log("Pushing ", first)
b.GpioSet(ctx, first, false)
hold := time.Millisecond * 500
if minHold != nil {
hold += *minHold
}
s.Logf("Pressing %s for %s", second, hold)
b.GpioSet(ctx, second, false)
testing.Sleep(ctx, hold) // GoBigSleepLint: Simulating press push
b.GpioSet(ctx, second, true)
s.Log("Releasing ", first)
b.GpioSet(ctx, first, true)
events := b.GpioMonitorFinish(ctx, gpioMonitor)
s.Log("Stop gpio monitoring: ", events)
assertReset := events.FindFirst(ti50.GpioTi50EcRstL, utils.GpioEdgeFalling)
if assertReset == nil {
s.Errorf("EC_RST_L did not assert with key combo %s then %s", first, second)
return
}
deassertReset := events.FindFirstAfter(*assertReset, ti50.GpioTi50EcRstL)
if deassertReset == nil {
s.Errorf("EC_RST_L did not de-assert after key combo released %s then %s", first, second)
return
}
assertTime := deassertReset.TimestampUS - assertReset.TimestampUS
// Allow 1% measurement error.
if assertTime < uint64(float64(minEcResetPulse.Microseconds())*0.99) {
s.Errorf("EC_RST_L did stay asserted long enough: %dus", assertTime)
return
}
s.Logf("EC_RST_L asserted for %dus", assertTime)
if minHold != nil {
resetDelayMs := assertReset.TimestampUS / 1000
// Allow 2% measurement error (b/311438894).
if resetDelayMs < uint64(float64(minHold.Milliseconds())*0.98) {
s.Errorf("EC_RST_L asserted before minimum hold time: %dms", resetDelayMs)
return
}
s.Logf("EC_RST_L delayed by %dms", resetDelayMs)
}
}
// verifyBatteryDisconnect verifies the battery disconnect sequence
func verifyBatteryDisconnect(ctx context.Context, s *testing.State, b utils.DevboardHelper, ecResetPin ti50.GpioName) {
s.Log("Start gpio monitoring for battery disconnect ")
// Start with AC connected
b.GpioSet(ctx, ti50.GpioTi50ACPresent, true)
gpioMonitor := b.GpioMonitorStart(ctx, ti50.GpioTi50BattDisableL, ti50.GpioTi50ACPresent)
if gpioMonitor.InitialValues[ti50.GpioTi50BattDisableL] != true {
s.Errorf("%s not de-asserted before battery disconnect combo", ti50.GpioTi50BattDisableL)
}
// Press EC Reset key combo
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
b.GpioSet(ctx, ecResetPin, false)
// Remove power
b.GpioSet(ctx, ti50.GpioTi50ACPresent, false)
s.Log("Hold battery disconnect key combo for a few seconds")
// GoBigSleepLint: Hold key combo for 5+ seconds
testing.Sleep(ctx, battDisconnectMinimum+time.Second)
// Release EC Reset key combo
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ecResetPin, true)
events := b.GpioMonitorFinish(ctx, gpioMonitor)
s.Log("Stop gpio monitoring: ", events)
assertBattDisable := events.FindFirst(ti50.GpioTi50BattDisableL, utils.GpioEdgeFalling)
if assertBattDisable == nil {
s.Errorf("%s did not assert with key combo", ti50.GpioTi50BattDisableL)
} else {
acRemovedEdge := events.FindFirst(ti50.GpioTi50ACPresent, utils.GpioEdgeFalling)
if acRemovedEdge == nil {
s.Fatal("Could not find AC_PRESENT falling edge")
}
delayTime := assertBattDisable.TimestampUS - acRemovedEdge.TimestampUS
// Allow 1% measurement error.
if delayTime < uint64(float64(battDisconnectMinimum.Microseconds())*0.99) {
s.Errorf("Asserted %s too soon after removing AC power: %dus", ti50.GpioTi50BattDisableL, delayTime)
} else if delayTime > uint64(float64(battDisconnectMinimum.Microseconds())*1.01) {
s.Errorf("Asserted %s too later after removing AC power: %dus", ti50.GpioTi50BattDisableL, delayTime)
} else {
s.Logf("%s asserted after %dus", ti50.GpioTi50BattDisableL, delayTime)
}
}
}
// verifyBatteryDisconnectCancelled verifies the battery disconnect sequence
// is cancelled if the AC power is re connected within 5 seconds
func verifyBatteryDisconnectCancelled(ctx context.Context, s *testing.State, b utils.DevboardHelper, ecResetPin ti50.GpioName) {
s.Log("Start gpio monitoring for battery disconnect")
// Start with AC connected
b.GpioSet(ctx, ti50.GpioTi50ACPresent, true)
gpioMonitor := b.GpioMonitorStart(ctx, ti50.GpioTi50BattDisableL, ti50.GpioTi50ACPresent)
if gpioMonitor.InitialValues[ti50.GpioTi50BattDisableL] != true {
s.Errorf("%s not de-asserted before battery disconnect combo", ti50.GpioTi50BattDisableL)
}
// Press EC Reset key combo
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
b.GpioSet(ctx, ecResetPin, false)
// Remove power
b.GpioSet(ctx, ti50.GpioTi50ACPresent, false)
s.Log("Hold battery disconnect key combo for a few seconds")
// GoBigSleepLint: Hold key combo for half of the required time
testing.Sleep(ctx, battDisconnectMinimum/2)
// Send a pulse on AC Present. This should cancel battery disconnect
b.GpioSet(ctx, ti50.GpioTi50ACPresent, true)
b.GpioSet(ctx, ti50.GpioTi50ACPresent, false)
s.Log("Hold battery disconnect key combo for a few seconds")
// GoBigSleepLint: Hold key combo for half of the required time
testing.Sleep(ctx, battDisconnectMinimum/2+time.Second)
// Release EC Reset key combo
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
b.GpioSet(ctx, ecResetPin, true)
events := b.GpioMonitorFinish(ctx, gpioMonitor)
s.Log("Stop gpio monitoring: ", events)
assertBattDisable := events.FindFirst(ti50.GpioTi50BattDisableL, utils.GpioEdgeFalling)
if assertBattDisable != nil {
acRemovedEdge := events.FindFirst(ti50.GpioTi50ACPresent, utils.GpioEdgeFalling)
if acRemovedEdge == nil {
s.Fatal("Could not find AC_PRESENT falling edge")
}
delayTime := assertBattDisable.TimestampUS - acRemovedEdge.TimestampUS
s.Errorf("Battery disconnect after %dus when it should have been canceled", delayTime)
}
}
// verifyPassthrough verifies that the specified from gpio is matches on the to gpio for both
// level high and low
func verifyPassthrough(ctx context.Context, s *testing.State, b utils.DevboardHelper, from, to ti50.GpioName) {
b.GpioSet(ctx, from, true)
if b.GpioGet(ctx, to) != true {
s.Errorf("GSC should forward high from %s to %s", from, to)
}
b.GpioSet(ctx, from, false)
if b.GpioGet(ctx, to) != false {
s.Errorf("GSC should forward low from %s to %s", from, to)
}
}
// verifyMinECPulseWidth verifies that the EC_RESET_L pulse width is extended
// to 10ms when an external source asserts it for less than 10ms.
func verifyMinECPulseWidth(ctx context.Context, s *testing.State, b utils.DevboardHelper) {
// Send a short 1ms pulse on EC reset pin, and collect the value of EC reset
// during the entire bit bang operation
result := b.GpioBitbang(ctx, "1kHz", "101111111111111", true, ti50.GpioTi50EcRstL)
numAssertedEcReset := 0
for _, level := range result.All {
if !level[ti50.GpioTi50EcRstL] {
numAssertedEcReset++
}
}
// Allow some variance in the automated tests to ensure it is not flaky, but
// it might not be needed.
if numAssertedEcReset < 9 {
s.Errorf("EC_RESET_L not held long enough, only %dms", numAssertedEcReset)
} else if numAssertedEcReset > 11 {
s.Errorf("EC_RESET_L held too long, was %dms", numAssertedEcReset)
} else {
s.Logf("EC_RESET_L held for %dms", numAssertedEcReset)
}
}
func verifyRMAKeySequence(ctx context.Context, s *testing.State, b utils.DevboardHelper, i *ti50.CrOSImage, gpio ti50.GpioName) {
th := utils.FirmwareTestingHelper{FirmwareTestingHelperDelegate: s}
params := s.Param().(ti50ValidRBOXParam)
assertVal := false
tapDelay := 100 * time.Millisecond
// Verify that AP RO result is one of the V2 errors before performing
// the RMA key sequence. This only applies to Ti50 not Cr50.
tpm := b.ResetAndTpmStartup(ctx, i, params.formFactor)
mode, err := tpm.TpmvGetApRoVerificationStatus()
th.MustSucceed(err, "Get AP RO verification status via TPMV command")
if !mode.IsV2Code() {
s.Error("AP RO verification status not V2 code: ", mode)
}
// Turn AP off while performing RMA key combo (AP would be shut off with the
// first refresh/recovery key tap anyway due to EC reset).
s.Log("Send RMA request key combo")
b.GpioSet(ctx, ti50.GpioTi50PltRstL, false)
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, false)
b.GpioSet(ctx, gpio, assertVal)
// GoBigSleepLint: Simulating button press
testing.Sleep(ctx, tapDelay)
b.GpioSet(ctx, gpio, !assertVal)
// GoBigSleepLint: Simulating reasonable time between button press
testing.Sleep(ctx, time.Millisecond*500)
b.GpioSet(ctx, gpio, assertVal)
// GoBigSleepLint: Simulating button press
testing.Sleep(ctx, tapDelay)
b.GpioSet(ctx, gpio, !assertVal)
// GoBigSleepLint: Simulating reasonable time between button press
testing.Sleep(ctx, time.Millisecond*500)
b.GpioSet(ctx, gpio, assertVal)
// GoBigSleepLint: Simulating button press
testing.Sleep(ctx, tapDelay)
b.GpioSet(ctx, gpio, !assertVal)
b.GpioSet(ctx, ti50.GpioTi50PowerBtnL, true)
// Turn AP back on
b.GpioSet(ctx, ti50.GpioTi50PltRstL, true)
b.WaitForTpm(ctx, tpm)
// Turn AP back off. This should not reset the RMA request since we are not
// going to read the RMA request via TPMV command.
b.GpioSet(ctx, ti50.GpioTi50PltRstL, false)
// GoBigSleepLint: Simulating AP being off for reasonable amount of time
testing.Sleep(ctx, time.Millisecond*200)
// Turn AP back on. Should still have RMA request pending
b.GpioSet(ctx, ti50.GpioTi50PltRstL, true)
b.WaitForTpm(ctx, tpm)
// Ensure that AP RO verification status is a V1 code. This indicates that
// RMA was requested.
mode, err = tpm.TpmvGetApRoVerificationStatus()
th.MustSucceed(err, "Get AP RO verification status via TPMV command")
if mode.IsV2Code() {
s.Error("AP RO verification status should be V1 code: ", mode)
}
// Ensure that AP RO verification status is still a V1 code. The status should
// not reset until AP is reset.
mode, err = tpm.TpmvGetApRoVerificationStatus()
th.MustSucceed(err, "Get AP RO verification status via TPMV command")
if mode.IsV2Code() {
s.Error("AP RO verification status should be V1 code: ", mode)
}
// Turn AP back off. This should reset the RMA request since we read the
// RMA request.
b.GpioSet(ctx, ti50.GpioTi50PltRstL, false)
// GoBigSleepLint: Simulating AP being off for reasonable amount of time
testing.Sleep(ctx, time.Millisecond*200)
// Turn AP back on. Should still have RMA request pending
b.GpioSet(ctx, ti50.GpioTi50PltRstL, true)
b.WaitForTpm(ctx, tpm)
// Ensure that AP RO verification status has returned to V2 code meaning there
// is not RMA request pending.
mode, err = tpm.TpmvGetApRoVerificationStatus()
th.MustSucceed(err, "Get AP RO verification status via TPMV command")
if !mode.IsV2Code() {
s.Error("AP RO verification status should be V2 code: ", mode)
}
// Turn AP back off for further testing to allow deep sleeping
b.GpioSet(ctx, ti50.GpioTi50PltRstL, false)
}