From d399ee5dbf78848350c23e48a9249e307fdaf63b Mon Sep 17 00:00:00 2001 From: Braden Kell <bradenkell@google.com> Date: Wed, 1 May 2019 14:42:09 +0000 Subject: [PATCH] [zircon][sdio] Add function 0 abstractions to SDIO protocol ops Function 0 is shared between all drivers using a particular card. Currently drivers read and write to function 0 directly, but eventually function 0 will only be accessible through one of the methods added here. Bug: ZX-3879 Test: runtests -t sdmmc-test Change-Id: If1dfff0eba05a4b1d6ff255b4800ab4843b7ea78 --- .../system/banjo/ddk.protocol.sdio/sdio.banjo | 7 ++++ .../sdmmc/sdio-controller-device-test.cpp | 37 +++++++++++++++++++ .../block/sdmmc/sdio-controller-device.cpp | 37 +++++++++++++++++++ .../dev/block/sdmmc/sdio-controller-device.h | 4 ++ .../dev/block/sdmmc/sdio-function-device.cpp | 14 +++++++ .../dev/block/sdmmc/sdio-function-device.h | 4 ++ .../include/lib/mock-sdio/mock-sdio.h | 13 +++++++ 7 files changed, 116 insertions(+) diff --git a/zircon/system/banjo/ddk.protocol.sdio/sdio.banjo b/zircon/system/banjo/ddk.protocol.sdio/sdio.banjo index 900bcd8bb54..7c9ae4ca0ef 100644 --- a/zircon/system/banjo/ddk.protocol.sdio/sdio.banjo +++ b/zircon/system/banjo/ddk.protocol.sdio/sdio.banjo @@ -81,4 +81,11 @@ protocol Sdio { DoRwTxn(uint8 fn_idx, SdioRwTxn? txn) -> (zx.status s); DoRwByte(bool write, uint8 fn_idx, uint32 addr, uint8 write_byte) -> (zx.status s, uint8 read_byte); GetInBandIntr(uint8 fn_idx) -> (zx.status s, handle<interrupt> irq); + /// The following functions access the card common control registers (CCCR) on function 0. + /// Aborts an I/O operation occurring on the specified function. + IoAbort(uint8 fn_idx) -> (zx.status s); + /// Returns true if an interrupt is pending for function fn_idx, false otherwise. + IntrPending(uint8 fn_idx) -> (zx.status s, bool pending); + /// Reads or writes to a vendor CCCR register. addr must be in [0xF0, 0xFF]. + DoVendorControlRwByte(bool write, uint8 addr, uint8 write_byte) -> (zx.status s, uint8 read_byte); }; diff --git a/zircon/system/dev/block/sdmmc/sdio-controller-device-test.cpp b/zircon/system/dev/block/sdmmc/sdio-controller-device-test.cpp index 1b44a756b7d..6522e453c80 100644 --- a/zircon/system/dev/block/sdmmc/sdio-controller-device-test.cpp +++ b/zircon/system/dev/block/sdmmc/sdio-controller-device-test.cpp @@ -329,4 +329,41 @@ TEST(SdioControllerDeviceTest, DdkLifecycle) { EXPECT_EQ(ddk.total_children(), 4); } +TEST(SdioControllerDeviceTest, SdioIntrPending) { + MockSdmmcDevice mock_sdmmc({}); + SdioControllerDeviceTest dut(&mock_sdmmc, {}); + + dut.mock_SdioDoRwByte() + .ExpectCall({ZX_OK, 0b0011'0010}, false, 0, SDIO_CIA_CCCR_INTx_INTR_PEN_ADDR, 0) + .ExpectCall({ZX_OK, 0b0010'0010}, false, 0, SDIO_CIA_CCCR_INTx_INTR_PEN_ADDR, 0) + .ExpectCall({ZX_OK, 0b1000'0000}, false, 0, SDIO_CIA_CCCR_INTx_INTR_PEN_ADDR, 0) + .ExpectCall({ZX_OK, 0b0000'0000}, false, 0, SDIO_CIA_CCCR_INTx_INTR_PEN_ADDR, 0) + .ExpectCall({ZX_OK, 0b0000'1110}, false, 0, SDIO_CIA_CCCR_INTx_INTR_PEN_ADDR, 0) + .ExpectCall({ZX_OK, 0b0000'1110}, false, 0, SDIO_CIA_CCCR_INTx_INTR_PEN_ADDR, 0) + .ExpectCall({ZX_OK, 0b0000'1110}, false, 0, SDIO_CIA_CCCR_INTx_INTR_PEN_ADDR, 0); + + bool pending; + + EXPECT_OK(dut.SdioIntrPending(4, &pending)); + EXPECT_TRUE(pending); + + EXPECT_OK(dut.SdioIntrPending(4, &pending)); + EXPECT_FALSE(pending); + + EXPECT_OK(dut.SdioIntrPending(7, &pending)); + EXPECT_TRUE(pending); + + EXPECT_OK(dut.SdioIntrPending(7, &pending)); + EXPECT_FALSE(pending); + + EXPECT_OK(dut.SdioIntrPending(1, &pending)); + EXPECT_TRUE(pending); + + EXPECT_OK(dut.SdioIntrPending(2, &pending)); + EXPECT_TRUE(pending); + + EXPECT_OK(dut.SdioIntrPending(3, &pending)); + EXPECT_TRUE(pending); +} + } // namespace sdmmc diff --git a/zircon/system/dev/block/sdmmc/sdio-controller-device.cpp b/zircon/system/dev/block/sdmmc/sdio-controller-device.cpp index 0b3c9dd34b5..e669c695317 100644 --- a/zircon/system/dev/block/sdmmc/sdio-controller-device.cpp +++ b/zircon/system/dev/block/sdmmc/sdio-controller-device.cpp @@ -24,6 +24,8 @@ namespace { +constexpr uint8_t kCccrVendorAddressMin = 0xf0; + constexpr uint32_t kBcmManufacturerId = 0x02d0; uint32_t SdioReadTupleBody(const uint8_t* tuple_body, size_t start, size_t numbytes) { @@ -630,6 +632,41 @@ int SdioControllerDevice::SdioIrqThread() { return thrd_success; } +zx_status_t SdioControllerDevice::SdioIoAbort(uint8_t fn_idx) { + if (!SdioFnIdxValid(fn_idx) || fn_idx == 0) { + return ZX_ERR_INVALID_ARGS; + } + + return SdioDoRwByte(true, 0, SDIO_CIA_CCCR_ASx_ABORT_SEL_CR_ADDR, fn_idx, nullptr); +} + +zx_status_t SdioControllerDevice::SdioIntrPending(uint8_t fn_idx, bool* out_pending) { + if (!SdioFnIdxValid(fn_idx) || fn_idx == 0) { + return ZX_ERR_INVALID_ARGS; + } + + uint8_t intr_byte; + zx_status_t st = SdioDoRwByte(false, 0, SDIO_CIA_CCCR_INTx_INTR_PEN_ADDR, 0, &intr_byte); + if (st != ZX_OK) { + zxlogf(ERROR, "sdio_intr_pending: Failed reading intr pending reg. status: %d\n", st); + return st; + } + + *out_pending = intr_byte & (1 << fn_idx); + return ZX_OK; +} + +zx_status_t SdioControllerDevice::SdioDoVendorControlRwByte(bool write, uint8_t addr, + uint8_t write_byte, + uint8_t* out_read_byte) { + // The vendor area of the CCCR is 0xf0 - 0xff. + if (addr < kCccrVendorAddressMin) { + return ZX_ERR_OUT_OF_RANGE; + } + + return SdioDoRwByte(write, 0, addr, write_byte, out_read_byte); +} + zx_status_t SdioControllerDevice::SdioReset() { zx_status_t st = ZX_OK; uint8_t abort_byte; diff --git a/zircon/system/dev/block/sdmmc/sdio-controller-device.h b/zircon/system/dev/block/sdmmc/sdio-controller-device.h index 69839e2d570..94b42d05886 100644 --- a/zircon/system/dev/block/sdmmc/sdio-controller-device.h +++ b/zircon/system/dev/block/sdmmc/sdio-controller-device.h @@ -61,6 +61,10 @@ public: virtual zx_status_t SdioDoRwByte(bool write, uint8_t fn_idx, uint32_t addr, uint8_t write_byte, uint8_t* out_read_byte); zx_status_t SdioGetInBandIntr(uint8_t fn_idx, zx::interrupt* out_irq); + zx_status_t SdioIoAbort(uint8_t fn_idx); + zx_status_t SdioIntrPending(uint8_t fn_idx, bool* out_pending); + zx_status_t SdioDoVendorControlRwByte(bool write, uint8_t addr, uint8_t write_byte, + uint8_t* out_read_byte); void InBandInterruptCallback(); diff --git a/zircon/system/dev/block/sdmmc/sdio-function-device.cpp b/zircon/system/dev/block/sdmmc/sdio-function-device.cpp index 36c435232bf..4a487d39000 100644 --- a/zircon/system/dev/block/sdmmc/sdio-function-device.cpp +++ b/zircon/system/dev/block/sdmmc/sdio-function-device.cpp @@ -98,4 +98,18 @@ zx_status_t SdioFunctionDevice::SdioGetInBandIntr(uint8_t fn_idx, zx::interrupt* return sdio_parent_->SdioGetInBandIntr(fn_idx, out_irq); } +zx_status_t SdioFunctionDevice::SdioIoAbort(uint8_t fn_idx) { + return sdio_parent_->SdioIoAbort(fn_idx); +} + +zx_status_t SdioFunctionDevice::SdioIntrPending(uint8_t fn_idx, bool* out_pending) { + return sdio_parent_->SdioIntrPending(fn_idx, out_pending); +} + +zx_status_t SdioFunctionDevice::SdioDoVendorControlRwByte(bool write, uint8_t addr, + uint8_t write_byte, + uint8_t* out_read_byte) { + return sdio_parent_->SdioDoVendorControlRwByte(write, addr, write_byte, out_read_byte); +} + } // namespace sdmmc diff --git a/zircon/system/dev/block/sdmmc/sdio-function-device.h b/zircon/system/dev/block/sdmmc/sdio-function-device.h index e16776283a5..2541e52dde9 100644 --- a/zircon/system/dev/block/sdmmc/sdio-function-device.h +++ b/zircon/system/dev/block/sdmmc/sdio-function-device.h @@ -44,6 +44,10 @@ public: zx_status_t SdioDoRwByte(bool write, uint8_t fn_idx, uint32_t addr, uint8_t write_byte, uint8_t* out_read_byte); zx_status_t SdioGetInBandIntr(uint8_t fn_idx, zx::interrupt* out_irq); + zx_status_t SdioIoAbort(uint8_t fn_idx); + zx_status_t SdioIntrPending(uint8_t fn_idx, bool* out_pending); + zx_status_t SdioDoVendorControlRwByte(bool write, uint8_t addr, uint8_t write_byte, + uint8_t* out_read_byte); private: std::atomic<bool> dead_; diff --git a/zircon/system/dev/lib/mock-sdio/include/lib/mock-sdio/mock-sdio.h b/zircon/system/dev/lib/mock-sdio/include/lib/mock-sdio/mock-sdio.h index bbb2cca2c90..0ed643b63ca 100644 --- a/zircon/system/dev/lib/mock-sdio/include/lib/mock-sdio/mock-sdio.h +++ b/zircon/system/dev/lib/mock-sdio/include/lib/mock-sdio/mock-sdio.h @@ -168,6 +168,19 @@ public: return ZX_OK; } + zx_status_t SdioIoAbort(uint8_t fn_idx) { + return ZX_ERR_NOT_SUPPORTED; + } + + zx_status_t SdioIntrPending(uint8_t fn_idx, bool* out_pending) { + return ZX_ERR_NOT_SUPPORTED; + } + + zx_status_t SdioDoVendorControlRwByte(bool write, uint8_t addr, uint8_t write_byte, + uint8_t* out_read_byte) { + return ZX_ERR_NOT_SUPPORTED; + } + private: struct SdioRwExpectation { uint8_t fn_idx; -- GitLab