blob: e174c56fe7893b6502905afb566d8613671368f9 [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/errors"
"go.chromium.org/tast/core/testing"
)
var gpioTimeout = 1 * time.Second
var gpioInterval = 100 * time.Millisecond
var powerButtonInput = ti50.GpioCr50RBOXPwrbLIn
var key0Input = ti50.GpioCr50RBOXKey0In
var key1Input = ti50.GpioCr50RBOXKey1In
// Power Button (All SKUs):
// The power button output follows the power button input. They're both active low.
// Nothing blocks the power button output.
var powerButton = rboxConfig{
input: powerButtonInput,
inputAssertedVal: false,
output: ti50.GpioCr50RBOXPwrbLOut,
outputAssertedVal: false,
blocked: false,
}
// Key0 (Clamshell SKUs):
// The Key0 output follows the Key0 input. They're both active low.
// Key0 output is blocked when the power button is pressed.
var key0Clamshell = rboxConfig{
input: key0Input,
inputAssertedVal: false,
output: ti50.GpioCr50RBOXKey0Out,
outputAssertedVal: false,
blocked: true,
blockedBy: powerButton.input,
}
// Key0 (Detachable SKUs):
// The Key0 output follows the Key0 input. They're both active low.
// Key0 output is not blocked.
var key0Detachable = rboxConfig{
input: key0Input,
inputAssertedVal: false,
output: ti50.GpioCr50RBOXKey0Out,
outputAssertedVal: false,
blocked: false,
}
// Key1 (Clamshell SKUs):
// The Key1 input is inverted. It's active low.
// The Key1 output normal.
// Key1 output is blocked when the power button is pressed
var key1Clamshell = rboxConfig{
input: key1Input,
inputAssertedVal: false,
output: ti50.GpioCr50RBOXKey1Out,
outputAssertedVal: true,
blocked: true,
blockedBy: powerButton.input,
}
// Key1 (Detachable SKUs):
// The Key0 output follows the Key0 input. They're both active low.
// Key1 input is not inverted.
// Key1 output is not blocked.
var key1Detachable = rboxConfig{
input: key1Input,
inputAssertedVal: false,
output: ti50.GpioCr50RBOXKey1Out,
outputAssertedVal: false,
blocked: false,
}
func init() {
testing.AddTest(&testing.Test{
Func: Cr50RBOXBufferOutput,
Desc: "Verify RBOX handles buffering the rbox inputs",
Timeout: 5 * time.Minute,
Contacts: []string{
"gsc-sheriff@google.com", // CrOS GSC Developers
"mruthven@chromium.org", // Test Author
},
BugComponent: "b:715469", // ChromeOS > Platform > System > Hardware Security > HwSec GSC > Ti50
Attr: []string{"group:gsc", "gsc_h1_shield", "gsc_image_ti50", "gsc_nightly"},
Fixture: fixture.GSCOpenCCD,
Params: []testing.Param{{
Name: "power_button",
Val: powerButtonInput,
}, {
Name: "key0",
Val: key0Input,
}, {
Name: "key1",
Val: key1Input,
}},
})
}
type rboxConfig struct {
name string
input ti50.GpioName
inputAssertedVal bool
output ti50.GpioName
outputAssertedVal bool
blocked bool
blockedBy ti50.GpioName
}
func getRboxConfig(gpio ti50.GpioName, sku ti50.ChipSKU) (rboxConfig, error) {
switch gpio {
case powerButton.input:
return powerButton, nil
case key0Input:
if sku == ti50.SKUH1Detachable {
return key0Detachable, nil
}
if sku == ti50.SKUH1Clamshell {
return key0Clamshell, nil
}
return rboxConfig{}, errors.Errorf("Did not find key0 rbox config for %s", sku)
case key1Input:
if sku == ti50.SKUH1Detachable {
return key1Detachable, nil
}
if sku == ti50.SKUH1Clamshell {
return key1Clamshell, nil
}
return rboxConfig{}, errors.Errorf("Did not find key1 rbox config for %s", sku)
default:
return rboxConfig{}, errors.Errorf("Did not find %s rbox config for %s", gpio, sku)
}
}
// Cr50RBOXBufferOutput verifies GSC RBOX buffers the outputs of the power
// button, key0, and key1 signals correctly.
func Cr50RBOXBufferOutput(ctx context.Context, s *testing.State) {
b := utils.NewDevboardHelper(s)
th := utils.FirmwareTestingHelper{FirmwareTestingHelperDelegate: s}
i := ti50.MustOpenCrOSImage(ctx, b, s)
defer i.Close(ctx)
testSignal := s.Param().(ti50.GpioName)
s.Log("(Re)starting GSC")
b.ResetAndTpmStartup(ctx, i, ti50.CcdSuzyQ, ti50.FfClamshell)
chipSKU, err := i.ChipSKU(ctx)
s.Logf("Running %s test for %s", testSignal, chipSKU)
th.MustSucceed(err, "did not find chip SKU")
config, err := getRboxConfig(testSignal, chipSKU)
th.MustSucceed(err, "did not find RBOX config")
s.Log("config:", config)
blockedBy, err := getRboxConfig(config.blockedBy, chipSKU)
if config.blocked {
th.MustSucceed(err, "did not find RBOX block config")
s.Log("blockedBy:", blockedBy)
}
s.Log("Deasserting Signals")
// Make sure the signal that blocks buffering is deasserted.
if config.blocked {
b.GpioSet(ctx, blockedBy.input, !blockedBy.inputAssertedVal)
}
gpioMonitor := b.GpioMonitorStart(ctx, config.output)
// Set the initial RBOX state to deasserted.
b.GpioSet(ctx, config.input, !config.inputAssertedVal)
// Wait to see if the gpio value changes. It may not.
s.Log("gpio events:", b.GpioMonitorWait(ctx, gpioMonitor, gpioTimeout, gpioInterval))
inVal := b.GpioGet(ctx, config.input)
outVal := b.GpioGet(ctx, config.output)
s.Logf("input signal - %s - %t", config.input, inVal)
s.Logf("output signal - %s - %t", config.output, outVal)
if inVal == config.inputAssertedVal {
s.Fatalf("Failed to setup %s", config.input)
}
if outVal == config.outputAssertedVal {
s.Fatalf("Failed to setup rbox output. %s not deasserted when %s was deasserted", config.output, config.input)
}
// Read from the gpio monitor to clear existing events.
b.GpioMonitorRead(ctx, gpioMonitor)
// Verify the RBOX output is asserted after the input is asserted.
s.Log("Asserting", config.input)
b.GpioSet(ctx, config.input, config.inputAssertedVal)
// Wait until the output is asserted
events := b.GpioMonitorWait(ctx, gpioMonitor, gpioTimeout, gpioInterval)
if len(events.Sorted) == 0 {
s.Errorf("Failed to detect %s change when %s was asserted", config.output, config.input)
}
s.Log("gpio events:", events.Sorted)
inVal = b.GpioGet(ctx, config.input)
outVal = b.GpioGet(ctx, config.output)
s.Logf("input signal - %s - %t", config.input, inVal)
s.Logf("output signal - %s - %t", config.output, outVal)
if inVal != config.inputAssertedVal {
s.Fatalf("Failed to assert %s", config.input)
}
if outVal != config.outputAssertedVal {
s.Errorf("RBOX output %s not asserted when %s was asserted", config.output, config.input)
} else {
s.Logf("%s was asserted", config.output)
}
// Read from the gpio monitor to clear existing events.
b.GpioMonitorRead(ctx, gpioMonitor)
// Verify the RBOX output can be deasserted again.
s.Log("Deasserting", config.input)
b.GpioSet(ctx, config.input, !config.inputAssertedVal)
// Wait until the output is asserted
events = b.GpioMonitorWait(ctx, gpioMonitor, gpioTimeout, gpioInterval)
if len(events.Sorted) == 0 {
s.Errorf("Failed to detect %s change", config.output)
}
s.Log("gpio events:", events.Sorted)
inVal = b.GpioGet(ctx, config.input)
outVal = b.GpioGet(ctx, config.output)
s.Logf("input signal - %s - %t", config.input, inVal)
s.Logf("output signal - %s - %t", config.output, outVal)
if inVal == config.inputAssertedVal {
s.Fatalf("Failed to deassert %s", config.input)
}
if outVal == config.outputAssertedVal {
s.Errorf("RBOX output %s not deasserted when %s was deasserted", config.output, config.input)
} else {
s.Logf("%s was deasserted", config.output)
s.Logf("%s output followed the %s input", config.output, config.input)
}
if !config.blocked {
return
}
// Read from the gpio monitor to clear existing events.
b.GpioMonitorRead(ctx, gpioMonitor)
// Verify the RBOX output is blocked.
s.Logf("Verifying %s output is blocked by %s", config.output, blockedBy.input)
b.GpioSet(ctx, blockedBy.input, blockedBy.inputAssertedVal)
b.GpioSet(ctx, config.input, config.inputAssertedVal)
// Wait to see if the signal gets asserted.
events = b.GpioMonitorWait(ctx, gpioMonitor, gpioTimeout, gpioInterval)
if len(events.Sorted) != 0 {
s.Errorf("detected %s change when %s was asserted: %v", config.output, blockedBy.input, events.Sorted)
}
s.Log("gpio events:", events.Sorted)
blockVal := b.GpioGet(ctx, blockedBy.input)
inVal = b.GpioGet(ctx, config.input)
outVal = b.GpioGet(ctx, config.output)
s.Logf("blocking signal - %s - %t", blockedBy.input, blockVal)
s.Logf("input signal - %s - %t", config.input, inVal)
s.Logf("blocked output - %s - %t", config.output, outVal)
if blockVal != blockedBy.inputAssertedVal {
s.Fatalf("Failed to assert %s", blockedBy.input)
}
if inVal != config.inputAssertedVal {
s.Fatalf("Failed to assert %s", config.input)
}
if outVal == config.outputAssertedVal {
s.Errorf("%s did not block %s. %s was asserted", blockedBy.input, config.output, config.output)
}
// Read from the gpio monitor to clear existing events.
b.GpioMonitorRead(ctx, gpioMonitor)
s.Log("Deasserting", blockedBy.input)
s.Logf("Verify %s becomes unblocked", config.output)
b.GpioSet(ctx, blockedBy.input, !blockedBy.inputAssertedVal)
// Wait to see if the signal gets deasserted.
events = b.GpioMonitorWait(ctx, gpioMonitor, gpioTimeout, gpioInterval)
if len(events.Sorted) == 0 {
s.Errorf("deaserring %s did not unblock %s: %v", blockedBy.input, config.output, events.Sorted)
}
s.Log("gpio events:", events.Sorted)
blockVal = b.GpioGet(ctx, blockedBy.input)
inVal = b.GpioGet(ctx, config.input)
outVal = b.GpioGet(ctx, config.output)
s.Logf("blocking signal - %s - %t", blockedBy.input, blockVal)
s.Logf("input signal - %s - %t", config.input, inVal)
s.Logf("blocked output - %s - %t", config.output, outVal)
if blockVal == blockedBy.inputAssertedVal {
s.Fatalf("Failed to deassert %s", blockedBy.input)
}
if inVal != config.inputAssertedVal {
s.Fatalf("The input signal %s was deasserted after deaserting %s", config.input, blockedBy.input)
}
if outVal != config.outputAssertedVal {
s.Errorf("%s was not asserted after deasserting %s", config.output, blockedBy.input)
} else {
s.Logf("%s blocked the %s output", blockedBy.input, config.output)
}
}