blob: 5fa322fc5f7f9c68f59bdc3528f9cca80238b0cc [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/uart/mock.h>
#include <lib/uart/pl011.h>
#include <lib/uart/uart.h>
#include <cstdint>
#include <zxtest/zxtest.h>
namespace {
using SimpleTestDriver =
uart::KernelDriver<uart::pl011::Driver, uart::mock::IoProvider, uart::UnsynchronizedPolicy>;
constexpr zbi_dcfg_simple_t kTestConfig = {};
TEST(Pl011Tests, HelloWorld) {
SimpleTestDriver driver(kTestConfig);
driver.io()
.mock()
.ExpectRead(uint16_t{0b0000'0000'0110'0000}, 0x2C) // Read state from LCR
.ExpectWrite(uint16_t{0b0000'0000'0111'0000}, 0x2C) // Writeback with FIFO enabled
.ExpectWrite(uint16_t{0b0001'0000'0001}, 0x30) // Init
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // TxReady -> true
.ExpectWrite(uint16_t{'h'}, 0) // Write
.ExpectRead(uint16_t{0b0000'0000}, 0x18) // TxReady -> false
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // TxReady -> true
.ExpectWrite(uint16_t{'i'}, 0) // Write
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // TxReady -> true
.ExpectWrite(uint16_t{'\r'}, 0) // Write
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // TxReady -> true
.ExpectWrite(uint16_t{'\n'}, 0); // Write
driver.Init();
EXPECT_EQ(3, driver.Write("hi\n"));
}
TEST(Pl011Tests, Read) {
SimpleTestDriver driver(kTestConfig);
driver.io()
.mock()
.ExpectRead(uint16_t{0b0000'0000'0110'0000}, 0x2C) // Read state from LCR
.ExpectWrite(uint16_t{0b0000'0000'0111'0000}, 0x2C) // Writeback with FIFO enabled
.ExpectWrite(uint16_t{0b0001'0000'0001}, 0x30) // Init
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // TxReady -> true
.ExpectWrite(uint16_t{'?'}, 0) // Write
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // TxReady -> true
.ExpectWrite(uint16_t{'\r'}, 0) // Write
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // TxReady -> true
.ExpectWrite(uint16_t{'\n'}, 0) // Write
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // Read (rx_fifo_empty)
.ExpectRead(uint16_t{'q'}, 0) // Read (data)
.ExpectRead(uint16_t{0b1000'0000}, 0x18) // Read (rx_fifo_empty)
.ExpectRead(uint16_t{'\r'}, 0); // Read (data)
driver.Init();
EXPECT_EQ(2, driver.Write("?\n"));
EXPECT_EQ(uint8_t{'q'}, driver.Read());
EXPECT_EQ(uint8_t{'\r'}, driver.Read());
}
// Helper for initializing the driver.
void Init(SimpleTestDriver& driver) {
driver.io()
.mock()
.ExpectRead(uint16_t{0b0000'0000'0110'0000}, 0x2C) // Read state from LCR
.ExpectWrite(uint16_t{0b0000'0000'0111'0000}, 0x2C) // Writeback with FIFO enabled
.ExpectWrite(uint16_t{0b0001'0000'0001}, 0x30); // Init
driver.Init();
driver.io().mock().VerifyAndClear();
}
void InitWithInterrupt(SimpleTestDriver& driver) {
driver.io()
.mock()
.ExpectRead(uint16_t{0b0000'0000'0110'0000}, 0x2C) // Read state from LCR
.ExpectWrite(uint16_t{0b0000'0000'0111'0000}, 0x2C) // Writeback with FIFO enabled
.ExpectWrite(uint16_t{0b0001'0000'0001}, 0x30) // Init
.ExpectWrite<uint16_t>(0b0000'0011'1111'1111, 0x44) // Clear Interrupts.
.ExpectWrite<uint16_t>(0b0000, 0x34) // Rx and Tx Fifo to 1/8
.ExpectRead<uint16_t>(0b000, 0x38) // Read Interrupt Mask.
.ExpectWrite<uint16_t>(0b1010000, 0x38) // Write Interrupt Mask with Rx and Rx Timeout
.ExpectRead<uint16_t>(0b0001'0000'0001, 0x30) // Read Control Register State
.ExpectWrite<uint16_t>(0b0011'0000'0001, 0x30); // Enable RX.
driver.Init();
driver.InitInterrupt([]() {});
driver.io().mock().VerifyAndClear();
}
TEST(Pl011Tests, InitInterrupt) {
SimpleTestDriver driver(kTestConfig);
Init(driver);
// Enable Rx Interrupt.
driver.io()
.mock()
.ExpectWrite<uint16_t>(0b0000'0011'1111'1111, 0x44) // Clear Interrupts.
.ExpectWrite<uint16_t>(0b0000, 0x34) // Rx and Tx Fifo to 1/8
.ExpectRead<uint16_t>(0b000, 0x38) // Read Interrupt Mask.
.ExpectWrite<uint16_t>(0b1010000, 0x38) // Write Interrupt Mask with Rx and Rx Timeout
.ExpectRead<uint16_t>(0b0001'0000'0001, 0x30) // Read Control Register State
.ExpectWrite<uint16_t>(0b0011'0000'0001, 0x30); // Enable RX.
bool unmasked_irq = false;
driver.InitInterrupt([&unmasked_irq]() { unmasked_irq = true; });
EXPECT_TRUE(unmasked_irq);
}
TEST(Pl011Tests, RxIrqEmptyFifo) {
SimpleTestDriver driver(kTestConfig);
Init(driver);
// Now actual IRQ Handler expectations.
driver.io()
.mock()
.ExpectRead<uint16_t>(0b1'0000, 0x40) // Read Interrupt Masked Status Register
.ExpectRead<uint16_t>(0b1'0000, 0x18); // Check if fifo is empty.
// Empty Fifo bit is set, so it should just return.
int call_count = 0;
driver.Interrupt([](auto& sync, auto& waiter,
auto&& disable_tx_irq) { FAIL("Unexpected call on |tx| irq callback."); },
[&](auto& sync, auto&& reader, auto&& full) { call_count++; });
driver.io().mock().VerifyAndClear();
EXPECT_EQ(call_count, 0);
}
TEST(Pl011Tests, RxIrqWithNonEmptyFifoAndNonFullQueue) {
SimpleTestDriver driver(kTestConfig);
InitWithInterrupt(driver);
// Now actual IRQ Handler expectations.
driver.io()
.mock()
.ExpectRead<uint16_t>(0b1'0000, 0x40) // Read Interrupt Masked Status Register
.ExpectRead<uint16_t>(0, 0x18) // Check if fifo is empty.
.ExpectRead<uint16_t>(123, 0) // Read 123 from data register.
.ExpectRead<uint16_t>(0, 0x18) // Read flag register
.ExpectRead<uint16_t>(111, 0) // Read 111 from data register
.ExpectRead<uint16_t>(0b1'0000, 0x18); // Read from flag register, fifo is empty.
int call_count = 0;
driver.Interrupt([](auto& sync, auto& waiter,
auto&& disable_tx_irq) { FAIL("Unexpected call on |tx| irq callback."); },
[&](auto& sync, auto&& reader, auto&& full) {
char expected_c = call_count == 0 ? 123 : 111;
call_count++;
auto c = reader();
ASSERT_TRUE(c);
EXPECT_EQ(c, expected_c);
});
EXPECT_EQ(call_count, 2);
}
TEST(Pl011Tests, RxTimeoutIrqWithNonEmptyFifoAndNonFullQueue) {
SimpleTestDriver driver(kTestConfig);
InitWithInterrupt(driver);
// Now actual IRQ Handler expectations.
driver.io()
.mock()
.ExpectRead<uint16_t>(0b100'0000, 0x40) // Read Interrupt Masked Status Register
.ExpectRead<uint16_t>(0, 0x18) // Check if fifo is empty.
.ExpectRead<uint16_t>(123, 0) // Read 123 from data register.
.ExpectRead<uint16_t>(0, 0x18) // Read flag register
.ExpectRead<uint16_t>(111, 0) // Read 111 from data register
.ExpectRead<uint16_t>(0b1'0000, 0x18); // Read from flag register, fifo is empty.
int call_count = 0;
driver.Interrupt([](auto& sync, auto& waiter,
auto&& disable_tx_irq) { FAIL("Unexpected call on |tx| irq callback."); },
[&](auto& sync, auto&& reader, auto&& full) {
char expected_c = call_count == 0 ? 123 : 111;
call_count++;
auto c = reader();
ASSERT_TRUE(c);
EXPECT_EQ(c, expected_c);
});
EXPECT_EQ(call_count, 2);
}
TEST(Pl011Tests, RxIrqWithNonEmptyFifoAndFullQueue) {
SimpleTestDriver driver(kTestConfig);
InitWithInterrupt(driver);
// Now actual IRQ Handler expectations.
driver.io()
.mock()
.ExpectRead<uint16_t>(0b1'0000, 0x40) // Read Interrupt Masked Status Register
.ExpectRead<uint16_t>(0, 0x18) // Check if fifo is empty.
.ExpectRead<uint16_t>(0b1010000, 0x38) // IMSR Should have Rx and Rx timeout enabled.
.ExpectWrite<uint16_t>(
0, 0x38); // The SW queue is full, so we should disable the RX interrupts.
int call_count = 0;
driver.Interrupt([](auto& sync, auto& waiter,
auto&& disable_tx_irq) { FAIL("Unexpected call on |tx| irq callback."); },
[&](auto& sync, auto&& reader, auto&& full) {
full();
call_count++;
});
EXPECT_EQ(call_count, 1);
}
TEST(Pl011Tests, TxIrqOnly) {
SimpleTestDriver driver(kTestConfig);
InitWithInterrupt(driver);
driver.io()
.mock()
.ExpectRead<uint16_t>(0b00100000, 0x40) // Read Masked Interrupt Status Register.
.ExpectRead<uint16_t>(
0b01110000,
0x38) // Read Interrupt Mask Set Clear Register. Eanbled should Be Rx,Tx and Rx Timeout.
.ExpectWrite<uint16_t>(0b01010000, 0x38); // Mask the Tx Interrupt.
int call_count = 0;
driver.Interrupt(
[&](auto& sync, auto& waiter, auto&& disable_tx_irq) {
call_count++;
disable_tx_irq();
},
[](auto& sync, auto&& reader, auto&& full) {
FAIL("Unexpected call on |tx| irq callback.");
});
EXPECT_EQ(call_count, 1);
}
} // namespace