From 613f4171f3065a2c425c79dbd86bd28afc31a7a4 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 15 Dec 2016 15:37:18 +0100 Subject: [PATCH] sd_card: i.MX6 support The i.MX6 driver shares most of its code with the i.MX53 driver. Ref #2206 --- .../spec/imx53/trustzone/platform_support.cc | 2 +- .../spec/imx53/drivers/board_base_support.h | 6 +- .../include/spec/imx6/drivers/board_base.h | 5 + repos/os/lib/mk/spec/imx53/sd_card_bench.mk | 7 +- repos/os/lib/mk/spec/imx53/sd_card_drv.mk | 9 +- repos/os/lib/mk/spec/imx6/sd_card_bench.mk | 5 + repos/os/lib/mk/spec/imx6/sd_card_drv.mk | 6 + .../sd_card/spec/{imx53 => imx}/adma2.cc | 0 .../sd_card/spec/{imx53 => imx}/adma2.h | 0 .../sd_card/spec/{imx53 => imx}/driver.h | 24 +- .../sd_card/spec/{imx53 => imx}/main.cc | 0 .../spec/{imx53/esdhcv2.cc => imx/sdhc.cc} | 216 +++++++-------- repos/os/src/drivers/sd_card/spec/imx/sdhc.h | 261 ++++++++++++++++++ .../src/drivers/sd_card/spec/imx53/esdhcv2.h | 243 ---------------- .../os/src/drivers/sd_card/spec/imx53/sdhc.cc | 120 ++++++++ .../os/src/drivers/sd_card/spec/imx6/sdhc.cc | 116 ++++++++ 16 files changed, 631 insertions(+), 389 deletions(-) create mode 100644 repos/os/lib/mk/spec/imx6/sd_card_bench.mk create mode 100644 repos/os/lib/mk/spec/imx6/sd_card_drv.mk rename repos/os/src/drivers/sd_card/spec/{imx53 => imx}/adma2.cc (100%) rename repos/os/src/drivers/sd_card/spec/{imx53 => imx}/adma2.h (100%) rename repos/os/src/drivers/sd_card/spec/{imx53 => imx}/driver.h (82%) rename repos/os/src/drivers/sd_card/spec/{imx53 => imx}/main.cc (100%) rename repos/os/src/drivers/sd_card/spec/{imx53/esdhcv2.cc => imx/sdhc.cc} (65%) create mode 100644 repos/os/src/drivers/sd_card/spec/imx/sdhc.h delete mode 100644 repos/os/src/drivers/sd_card/spec/imx53/esdhcv2.h create mode 100644 repos/os/src/drivers/sd_card/spec/imx53/sdhc.cc create mode 100644 repos/os/src/drivers/sd_card/spec/imx6/sdhc.cc diff --git a/repos/base-hw/src/core/spec/imx53/trustzone/platform_support.cc b/repos/base-hw/src/core/spec/imx53/trustzone/platform_support.cc index efecf0ef5..b77b58fc2 100644 --- a/repos/base-hw/src/core/spec/imx53/trustzone/platform_support.cc +++ b/repos/base-hw/src/core/spec/imx53/trustzone/platform_support.cc @@ -33,7 +33,7 @@ bool secure_irq(unsigned const i) if (i == Board::EPIT_2_IRQ) return true; if (i == Board::I2C_2_IRQ) return SECURE_I2C; if (i == Board::I2C_3_IRQ) return SECURE_I2C; - if (i == Board::ESDHCV2_1_IRQ) return SECURE_ESDHC; + if (i == Board::SDHC_IRQ) return SECURE_ESDHC; if (i >= Board::GPIO1_IRQL && i <= Board::GPIO4_IRQH) return SECURE_GPIO; if (i >= Board::GPIO5_IRQL && i <= Board::GPIO7_IRQH) return SECURE_GPIO; return false; diff --git a/repos/base/include/spec/imx53/drivers/board_base_support.h b/repos/base/include/spec/imx53/drivers/board_base_support.h index a52d174fd..3e41405d7 100644 --- a/repos/base/include/spec/imx53/drivers/board_base_support.h +++ b/repos/base/include/spec/imx53/drivers/board_base_support.h @@ -26,9 +26,9 @@ struct Imx53::Board_base MMIO_BASE = 0x0, MMIO_SIZE = 0x70000000, - ESDHCV2_1_IRQ = 1, - ESDHCV2_1_MMIO_BASE = 0x50004000, - ESDHCV2_1_MMIO_SIZE = 0x00004000, + SDHC_IRQ = 1, + SDHC_MMIO_BASE = 0x50004000, + SDHC_MMIO_SIZE = 0x00004000, UART_1_IRQ = 31, UART_1_MMIO_BASE = 0x53fbc000, diff --git a/repos/base/include/spec/imx6/drivers/board_base.h b/repos/base/include/spec/imx6/drivers/board_base.h index acd6af83b..3fa58265f 100644 --- a/repos/base/include/spec/imx6/drivers/board_base.h +++ b/repos/base/include/spec/imx6/drivers/board_base.h @@ -40,6 +40,11 @@ struct Genode::Board_base UART_1_MMIO_BASE = 0x02020000, UART_1_MMIO_SIZE = 0x00004000, + /* SD host controller */ + SDHC_IRQ = 54, + SDHC_MMIO_BASE = 0x02190000, + SDHC_MMIO_SIZE = 0x00004000, + /* timer */ EPIT_2_IRQ = 89, EPIT_2_MMIO_BASE = 0x020d4000, diff --git a/repos/os/lib/mk/spec/imx53/sd_card_bench.mk b/repos/os/lib/mk/spec/imx53/sd_card_bench.mk index 5cedf62a3..e3981845b 100644 --- a/repos/os/lib/mk/spec/imx53/sd_card_bench.mk +++ b/repos/os/lib/mk/spec/imx53/sd_card_bench.mk @@ -1,4 +1,5 @@ -INC_DIR += $(REP_DIR)/src/drivers/sd_card/spec/imx53 -SRC_CC += spec/imx53/adma2.cc -SRC_CC += spec/imx53/esdhcv2.cc +INC_DIR += $(REP_DIR)/src/drivers/sd_card/spec/imx +SRC_CC += spec/imx/adma2.cc +SRC_CC += spec/imx/sdhc.cc +SRC_CC += spec/imx53/sdhc.cc include $(REP_DIR)/lib/mk/sd_card_bench.inc diff --git a/repos/os/lib/mk/spec/imx53/sd_card_drv.mk b/repos/os/lib/mk/spec/imx53/sd_card_drv.mk index e42f8b2ff..84122ff48 100644 --- a/repos/os/lib/mk/spec/imx53/sd_card_drv.mk +++ b/repos/os/lib/mk/spec/imx53/sd_card_drv.mk @@ -1,5 +1,6 @@ -INC_DIR += $(REP_DIR)/src/drivers/sd_card/spec/imx53 -SRC_CC += spec/imx53/adma2.cc -SRC_CC += spec/imx53/esdhcv2.cc -SRC_CC += spec/imx53/main.cc +INC_DIR += $(REP_DIR)/src/drivers/sd_card/spec/imx +SRC_CC += spec/imx/adma2.cc +SRC_CC += spec/imx/sdhc.cc +SRC_CC += spec/imx/main.cc +SRC_CC += spec/imx53/sdhc.cc include $(REP_DIR)/lib/mk/sd_card.inc diff --git a/repos/os/lib/mk/spec/imx6/sd_card_bench.mk b/repos/os/lib/mk/spec/imx6/sd_card_bench.mk new file mode 100644 index 000000000..c6a50e2db --- /dev/null +++ b/repos/os/lib/mk/spec/imx6/sd_card_bench.mk @@ -0,0 +1,5 @@ +INC_DIR += $(REP_DIR)/src/drivers/sd_card/spec/imx +SRC_CC += spec/imx/adma2.cc +SRC_CC += spec/imx/sdhc.cc +SRC_CC += spec/imx6/sdhc.cc +include $(REP_DIR)/lib/mk/sd_card_bench.inc diff --git a/repos/os/lib/mk/spec/imx6/sd_card_drv.mk b/repos/os/lib/mk/spec/imx6/sd_card_drv.mk new file mode 100644 index 000000000..7ad4a1629 --- /dev/null +++ b/repos/os/lib/mk/spec/imx6/sd_card_drv.mk @@ -0,0 +1,6 @@ +INC_DIR += $(REP_DIR)/src/drivers/sd_card/spec/imx +SRC_CC += spec/imx/adma2.cc +SRC_CC += spec/imx/sdhc.cc +SRC_CC += spec/imx/main.cc +SRC_CC += spec/imx6/sdhc.cc +include $(REP_DIR)/lib/mk/sd_card.inc diff --git a/repos/os/src/drivers/sd_card/spec/imx53/adma2.cc b/repos/os/src/drivers/sd_card/spec/imx/adma2.cc similarity index 100% rename from repos/os/src/drivers/sd_card/spec/imx53/adma2.cc rename to repos/os/src/drivers/sd_card/spec/imx/adma2.cc diff --git a/repos/os/src/drivers/sd_card/spec/imx53/adma2.h b/repos/os/src/drivers/sd_card/spec/imx/adma2.h similarity index 100% rename from repos/os/src/drivers/sd_card/spec/imx53/adma2.h rename to repos/os/src/drivers/sd_card/spec/imx/adma2.h diff --git a/repos/os/src/drivers/sd_card/spec/imx53/driver.h b/repos/os/src/drivers/sd_card/spec/imx/driver.h similarity index 82% rename from repos/os/src/drivers/sd_card/spec/imx53/driver.h rename to repos/os/src/drivers/sd_card/spec/imx/driver.h index caef1d649..ae4e7dace 100644 --- a/repos/os/src/drivers/sd_card/spec/imx53/driver.h +++ b/repos/os/src/drivers/sd_card/spec/imx/driver.h @@ -1,19 +1,20 @@ /* - * \brief Imx53-specific implementation of the Block::Driver interface + * \brief Implementation of the Block::Driver interface * \author Martin Stein * \date 2015-02-04 */ /* - * Copyright (C) 2012-2015 Genode Labs GmbH + * Copyright (C) 2012-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ -#ifndef _DRIVERS__SD_CARD__SPEC__IMX53__DRIVER_H_ -#define _DRIVERS__SD_CARD__SPEC__IMX53__DRIVER_H_ +#ifndef _DRIVER_H_ +#define _DRIVER_H_ +/* Genode includes */ #include #include #include @@ -23,7 +24,7 @@ #include /* local includes */ -#include +#include namespace Block { using namespace Genode; @@ -43,8 +44,8 @@ class Block::Sdhci_driver : public Block::Driver void usleep(unsigned us) { Timer::Connection::usleep(us); } } _delayer; - Attached_io_mem_dataspace _esdhcv2_1_mmio; - Esdhcv2_controller _controller; + Attached_io_mem_dataspace _sdhc_mmio; + Sdhc _controller; bool const _use_dma; @@ -52,10 +53,9 @@ class Block::Sdhci_driver : public Block::Driver Sdhci_driver(Entrypoint &, bool use_dma) : - _esdhcv2_1_mmio(Genode::Board_base::ESDHCV2_1_MMIO_BASE, - Genode::Board_base::ESDHCV2_1_MMIO_SIZE), - _controller((addr_t)_esdhcv2_1_mmio.local_addr(), - Genode::Board_base::ESDHCV2_1_IRQ, _delayer, use_dma), + _sdhc_mmio(Board_base::SDHC_MMIO_BASE, Board_base::SDHC_MMIO_SIZE), + _controller((addr_t)_sdhc_mmio.local_addr(), + Board_base::SDHC_IRQ, _delayer, use_dma), _use_dma(use_dma) { Sd_card::Card_info const card_info = _controller.card_info(); @@ -133,4 +133,4 @@ class Block::Sdhci_driver : public Block::Driver return Genode::env()->ram_session()->free(c); } }; -#endif /* _DRIVERS__SD_CARD__SPEC__IMX53__DRIVER_H_ */ +#endif /* _DRIVER_H_ */ diff --git a/repos/os/src/drivers/sd_card/spec/imx53/main.cc b/repos/os/src/drivers/sd_card/spec/imx/main.cc similarity index 100% rename from repos/os/src/drivers/sd_card/spec/imx53/main.cc rename to repos/os/src/drivers/sd_card/spec/imx/main.cc diff --git a/repos/os/src/drivers/sd_card/spec/imx53/esdhcv2.cc b/repos/os/src/drivers/sd_card/spec/imx/sdhc.cc similarity index 65% rename from repos/os/src/drivers/sd_card/spec/imx53/esdhcv2.cc rename to repos/os/src/drivers/sd_card/spec/imx/sdhc.cc index b11f04234..cc22c44cb 100644 --- a/repos/os/src/drivers/sd_card/spec/imx53/esdhcv2.cc +++ b/repos/os/src/drivers/sd_card/spec/imx/sdhc.cc @@ -1,24 +1,24 @@ /* - * \brief Freescale Enhanced Secured Digital Host Controller Version 2 + * \brief Secured Digital Host Controller * \author Martin Stein * \date 2015-02-05 */ /* - * Copyright (C) 2015 Genode Labs GmbH + * Copyright (C) 2015-2016 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ /* local includes */ -#include +#include using namespace Sd_card; using namespace Genode; -int Esdhcv2_controller::_wait_for_card_ready_mbw() +int Sdhc::_wait_for_card_ready_mbw() { /* * Poll card status @@ -69,7 +69,7 @@ int Esdhcv2_controller::_wait_for_card_ready_mbw() } -int Esdhcv2_controller::_stop_transmission_mbw() +int Sdhc::_stop_transmission() { /* write argument register */ write(0); @@ -81,9 +81,7 @@ int Esdhcv2_controller::_stop_transmission_mbw() Xfertyp::Cccen::set(xfertyp, 1); Xfertyp::Cicen::set(xfertyp, 1); Xfertyp::Rsptyp::set(xfertyp, Xfertyp::Rsptyp::_48BIT_BUSY); - Xfertyp::Msbsel::set(xfertyp, 1); - Xfertyp::Bcen::set(xfertyp, 1); - Xfertyp::Dmaen::set(xfertyp, 1); + _stop_transmission_finish_xfertyp(xfertyp); write(xfertyp); /* wait for command completion */ @@ -92,10 +90,10 @@ int Esdhcv2_controller::_stop_transmission_mbw() } -int Esdhcv2_controller::_wait_for_cmd_complete_mb(bool const r) +int Sdhc::_wait_for_cmd_complete_mb(bool const r) { /* - * The ESDHC signals on multi-block transfers seem to be broken. + * The host signals on multi-block transfers seem to be broken. * Synchronizing to "Transfer Complete" before returning from transfers * and to "Command Inhibit" before sending further commands - as it is * done with other controllers - isn't sufficient. Instead, both "Transfer @@ -120,29 +118,11 @@ int Esdhcv2_controller::_wait_for_cmd_complete_mb(bool const r) } /* acknowledge completion signals */ write(irq_goal); - if (!r) { - - /* - * The "Auto Command 12" feature of the ESDHC seems to be - * broken for multi-block writes as it causes command- - * timeout errors sometimes. Thus, we stop such transfers - * manually. - */ - if (_stop_transmission_mbw()) { return -1; } - - /* - * The manual termination of multi-block writes seems to leave - * the card in a busy state sometimes. This causes - * errors on subsequent commands. Thus, we have to synchronize - * manually with the card-internal state. - */ - if (_wait_for_card_ready_mbw()) { return -1; } - } - return 0; + return _wait_for_cmd_complete_mb_finish(r); } -int Esdhcv2_controller::_wait_for_cmd_complete() +int Sdhc::_wait_for_cmd_complete() { /* wait for "Command Completion" signal and acknowledge it */ _wait_for_irq(); @@ -155,54 +135,50 @@ int Esdhcv2_controller::_wait_for_cmd_complete() } -bool Esdhcv2_controller::_issue_command(Command_base const & command) +bool Sdhc::_issue_command(Command_base const & command) { - /* detect if command is a multi-block transfer and whether it reads */ - bool const r = command.transfer == TRANSFER_READ; - bool const mb = + /* get command characteristics */ + bool const transfer = command.transfer != TRANSFER_NONE; + bool const reading = command.transfer == TRANSFER_READ; + bool const multiblock = command.index == Read_multiple_block::INDEX || command.index == Write_multiple_block::INDEX; - /* assemble command register value */ - Xfertyp::access_t cmd = 0; - Xfertyp::Cmdinx::set(cmd, command.index); - if (command.transfer != TRANSFER_NONE) { - Xfertyp::Dpsel::set(cmd); - Xfertyp::Bcen::set(cmd); - Xfertyp::Msbsel::set(cmd); - if (mb) { - /* - * The "Auto Command 12" feature of the ESDHC seems to be - * broken for multi-block writes as it causes command- - * timeout errors sometimes. - */ - if (r) { Xfertyp::Ac12en::set(cmd); } - if (_use_dma) { Xfertyp::Dmaen::set(cmd); } - } - Xfertyp::Dtdsel::set(cmd, - r ? Xfertyp::Dtdsel::READ : Xfertyp::Dtdsel::WRITE); - } - typedef Xfertyp::Rsptyp Rsptyp; - Xfertyp::access_t rt = 0; - switch (command.rsp_type) { - case RESPONSE_NONE: rt = Rsptyp::_0BIT; break; - case RESPONSE_136_BIT: rt = Rsptyp::_136BIT; break; - case RESPONSE_48_BIT: rt = Rsptyp::_48BIT; break; - case RESPONSE_48_BIT_WITH_BUSY: rt = Rsptyp::_48BIT_BUSY; break; - } - Xfertyp::Rsptyp::set(cmd, rt); + /* set command index */ + Xfertyp::access_t xfertyp = 0; + Xfertyp::Cmdinx::set(xfertyp, command.index); - /* send command as soon as the host allows it */ - if (_wait_for_cmd_allowed()) { return false; } + /* select response type */ + typedef Xfertyp::Rsptyp Rsptyp; + Xfertyp::access_t rsptyp = 0; + switch (command.rsp_type) { + case RESPONSE_NONE: rsptyp = Rsptyp::_0BIT; break; + case RESPONSE_136_BIT: rsptyp = Rsptyp::_136BIT; break; + case RESPONSE_48_BIT: rsptyp = Rsptyp::_48BIT; break; + case RESPONSE_48_BIT_WITH_BUSY: rsptyp = Rsptyp::_48BIT_BUSY; break; + } + Xfertyp::Rsptyp::set(xfertyp, rsptyp); + + /* generic transfer settings */ + if (command.transfer != TRANSFER_NONE) { + Xfertyp::Dpsel::set(xfertyp); + if (multiblock) { + Xfertyp::Cicen::set(xfertyp, 1); + Xfertyp::Cccen::set(xfertyp, 1); + } + } + /* version-dependent transfer settings and issue command */ + _issue_cmd_finish_xfertyp(xfertyp, transfer, multiblock, reading); write(command.arg); - write(cmd); + write(xfertyp); /* wait for completion */ - return mb ? !_wait_for_cmd_complete_mb(r) : !_wait_for_cmd_complete(); + return multiblock ? !_wait_for_cmd_complete_mb(reading) : + !_wait_for_cmd_complete(); } -Cid Esdhcv2_controller::_read_cid() +Cid Sdhc::_read_cid() { Cid cid; cid.raw_0 = read(); @@ -213,7 +189,7 @@ Cid Esdhcv2_controller::_read_cid() } -Csd Esdhcv2_controller::_read_csd() +Csd Sdhc::_read_csd() { Csd csd; csd.csd0 = read(); @@ -224,36 +200,35 @@ Csd Esdhcv2_controller::_read_csd() } -unsigned Esdhcv2_controller::_read_rca() +unsigned Sdhc::_read_rca() { Cmdrsp0::access_t const rsp0 = read(); return Send_relative_addr::Response::Rca::get(rsp0); } -bool Esdhcv2_controller::read_blocks(size_t, size_t, char *) +bool Sdhc::read_blocks(size_t, size_t, char *) { error("block transfer without DMA not supported by now"); return false; } -bool Esdhcv2_controller::write_blocks(size_t, size_t, char const *) +bool Sdhc::write_blocks(size_t, size_t, char const *) { error("block transfer without DMA not supported by now"); return false; } -bool Esdhcv2_controller::read_blocks_dma(size_t blk_nr, size_t blk_cnt, - addr_t buf_phys) +bool Sdhc::read_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys) { if (_prepare_dma_mb(blk_cnt, buf_phys)) { return false; } return issue_command(Read_multiple_block(blk_nr)); } -bool Esdhcv2_controller::write_blocks_dma(size_t blk_nr, size_t blk_cnt, +bool Sdhc::write_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys) { if (_prepare_dma_mb(blk_cnt, buf_phys)) { return false; } @@ -261,15 +236,17 @@ bool Esdhcv2_controller::write_blocks_dma(size_t blk_nr, size_t blk_cnt, } -Esdhcv2_controller::Esdhcv2_controller(addr_t const base, unsigned const irq, - Delayer & delayer, bool const use_dma) +Sdhc::Sdhc(addr_t const base, + unsigned const irq, + Delayer &delayer, + bool const use_dma) : - Esdhcv2(base), _irq(irq), _delayer(delayer), _card_info(_init()), + Mmio(base), _irq(irq), _delayer(delayer), _card_info(_init()), _use_dma(use_dma) { } -int Esdhcv2_controller::_prepare_dma_mb(size_t blk_cnt, addr_t buf_phys) +int Sdhc::_prepare_dma_mb(size_t blk_cnt, addr_t buf_phys) { /* write ADMA2 table to DMA */ size_t const req_size = blk_cnt * BLOCK_SIZE; @@ -283,14 +260,18 @@ int Esdhcv2_controller::_prepare_dma_mb(size_t blk_cnt, addr_t buf_phys) } -int Esdhcv2_controller::_wait_for_cmd_allowed() +int Sdhc::_wait_for_cmd_allowed() { /* - * At least after multi-block writes with the fix for the broken "Auto - * Command 12", waiting only for "Command Inhibit" isn't sufficient as - * "Data Line Active" and "Data Inhibit" may also be active. + * At least after multi-block writes on i.MX53 with the fix for the broken + * "Auto Command 12", waiting only for "Command Inhibit" isn't sufficient + * as "Data Line Active" and "Data Inhibit" may also be active. */ - if (!wait_for(Prsstat_lhw::cmd_allowed(), _delayer)) { + if (!wait_for(0, _delayer) || + !wait_for(1, _delayer) || + !wait_for(0, _delayer) || + !wait_for(0, _delayer)) + { error("wait till issuing a new command is allowed timed out"); return -1; } @@ -298,7 +279,7 @@ int Esdhcv2_controller::_wait_for_cmd_allowed() } -void Esdhcv2_controller::_wait_for_irq() +void Sdhc::_wait_for_irq() { /* acknowledge IRQ first, to activate IRQ propagation initially */ _irq.ack_irq(); @@ -306,7 +287,7 @@ void Esdhcv2_controller::_wait_for_irq() } -Card_info Esdhcv2_controller::_init() +Card_info Sdhc::_init() { /* install IRQ signal */ _irq.sigh(_irq_rec.manage(&_irq_ctx)); @@ -315,24 +296,22 @@ Card_info Esdhcv2_controller::_init() if (_reset(_delayer)) { _detect_err("Host reset failed"); } _disable_irqs(); - /* check host version */ - Hostver::access_t const hostver = read(); - if (Hostver::Vvn::get(hostver) != 18) { - _detect_err("Unexpected Vendor Version Number"); } - if (Hostver::Svn::get(hostver) != 1) { - _detect_err("Unexpected Specification Version Number"); } + if (!_supported_host_version(read())) { + error("host version not supported"); + throw Detection_failed(); + } /* * We should check host capabilities at this point if we want to - * support other versions of the ESDHC. For the i.MX53 ESDHCv2 we - * know that the capabilities fit our requirements. + * support other versions of the SDHC. For the already supported + * versions we know that the capabilities fit our requirements. */ /* configure IRQs, bus width, and clock for initialization */ _enable_irqs(); _bus_width(BUS_WIDTH_1); _delayer.usleep(10000); - _clock(CLOCK_DIV_512, _delayer); + _clock(CLOCK_INITIAL); /* * Initialize card @@ -405,7 +384,7 @@ Card_info Esdhcv2_controller::_init() * checks (maybe read SSR/SCR, read switch, try frequencies) are * necessary for that. */ - _clock(CLOCK_DIV_8, _delayer); + _clock(CLOCK_OPERATIONAL); /* * Configure card and host to use 4 data signals @@ -427,10 +406,7 @@ Card_info Esdhcv2_controller::_init() /* configure host buffer */ Wml::access_t wml = read(); - Wml::Rd_wml::set(wml, WATERMARK_WORDS); - Wml::Rd_brst_len::set(wml, BURST_WORDS); - Wml::Wr_wml::set(wml, WATERMARK_WORDS); - Wml::Wr_brst_len::set(wml, BURST_WORDS); + _watermark_level(wml); write(wml); /* configure ADMA */ @@ -444,30 +420,18 @@ Card_info Esdhcv2_controller::_init() } -void Esdhcv2_controller::_detect_err(char const * const err) +void Sdhc::_detect_err(char const * const err) { error(err); throw Detection_failed(); } -int Esdhcv2_controller::_reset(Delayer & delayer) +int Sdhc::_reset(Delayer &delayer) { /* start reset */ write(1); - - /* - * The SDHC specification says that a software reset shouldn't - * have an effect on the the card detection circuit. The ESDHC - * clears Sysctl::Ipgen, Sysctl::Hcken, and Sysctl::Peren - * nonetheless which disables clocks that card detection relies - * on. - */ - Sysctl::access_t sysctl = read(); - Sysctl::Ipgen::set(sysctl, 1); - Sysctl::Hcken::set(sysctl, 1); - Sysctl::Peren::set(sysctl, 1); - write(sysctl); + _reset_amendments(); /* wait for reset completion */ if (!wait_for(0, delayer)) { @@ -478,14 +442,14 @@ int Esdhcv2_controller::_reset(Delayer & delayer) } -void Esdhcv2_controller::_disable_irqs() +void Sdhc::_disable_irqs() { write(0); write(0); } -void Esdhcv2_controller::_enable_irqs() +void Sdhc::_enable_irqs() { Irq::access_t irq = 0; Irq::Cc::set(irq, 1); @@ -505,7 +469,7 @@ void Esdhcv2_controller::_enable_irqs() } -void Esdhcv2_controller::_bus_width(Bus_width bus_width) +void Sdhc::_bus_width(Bus_width bus_width) { switch (bus_width) { case BUS_WIDTH_1: write(Proctl::Dtw::_1BIT); break; @@ -514,8 +478,9 @@ void Esdhcv2_controller::_bus_width(Bus_width bus_width) } -void Esdhcv2_controller::_disable_clock() +void Sdhc::_disable_clock() { + _disable_clock_preparation(); Sysctl::access_t sysctl = read(); Sysctl::Ipgen::set(sysctl, 0); Sysctl::Hcken::set(sysctl, 0); @@ -526,13 +491,17 @@ void Esdhcv2_controller::_disable_clock() } -void Esdhcv2_controller::_enable_clock(Clock_divider divider, Delayer &delayer) +void Sdhc::_enable_clock(Clock_divider divider) { Sysctl::access_t sysctl = read(); Sysctl::Ipgen::set(sysctl, 1); Sysctl::Hcken::set(sysctl, 1); Sysctl::Peren::set(sysctl, 1); switch (divider) { + case CLOCK_DIV_4: + Sysctl::Dvs::set(sysctl, Sysctl::Dvs::DIV4); + Sysctl::Sdclkfs::set(sysctl, Sysctl::Sdclkfs::DIV1); + break; case CLOCK_DIV_8: Sysctl::Dvs::set(sysctl, Sysctl::Dvs::DIV4); Sysctl::Sdclkfs::set(sysctl, Sysctl::Sdclkfs::DIV2); @@ -543,13 +512,14 @@ void Esdhcv2_controller::_enable_clock(Clock_divider divider, Delayer &delayer) break; } write(sysctl); - delayer.usleep(1000); + _enable_clock_finish(); + _delayer.usleep(1000); } -void Esdhcv2_controller::_clock(enum Clock_divider divider, Delayer &delayer) +void Sdhc::_clock(Clock clock) { + wait_for(1, _delayer); _disable_clock(); - write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27); - _enable_clock(divider, delayer); + _clock_finish(clock); } diff --git a/repos/os/src/drivers/sd_card/spec/imx/sdhc.h b/repos/os/src/drivers/sd_card/spec/imx/sdhc.h new file mode 100644 index 000000000..8943475d8 --- /dev/null +++ b/repos/os/src/drivers/sd_card/spec/imx/sdhc.h @@ -0,0 +1,261 @@ +/* + * \brief Secured Digital Host Controller + * \author Martin Stein + * \date 2015-02-05 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _SDHC_H_ +#define _SDHC_H_ + +/* Genode includes */ +#include +#include +#include + +/* local includes */ +#include +#include + +namespace Genode { class Sdhc; } + + +class Genode::Sdhc : public Sd_card::Host_controller, public Mmio +{ + private: + + struct Blkattr : Register<0x4, 32> + { + struct Blksize : Bitfield<0, 13> { }; + struct Blkcnt : Bitfield<16, 16> { }; + }; + template + struct Cmdrsp_tpl : Register + { + struct Rsp136_8_24 : Register::template Bitfield<0, 24> { }; + struct Rsp136_0_8 : Register::template Bitfield<24, 8> { }; + }; + struct Cmdarg : Register<0x8, 32> { }; + struct Cmdrsp0 : Cmdrsp_tpl<0x10> { }; + struct Cmdrsp1 : Cmdrsp_tpl<0x14> { }; + struct Cmdrsp2 : Cmdrsp_tpl<0x18> { }; + struct Cmdrsp3 : Cmdrsp_tpl<0x1c> { }; + struct Rsp136_0 : Bitset_2 { }; + struct Rsp136_1 : Bitset_2 { }; + struct Rsp136_2 : Bitset_2 { }; + struct Rsp136_3 : Bitset_2 { }; + + template + struct Xfertyp_base : Register + { + struct Dmaen : Register::template Bitfield<0, 1> { }; + struct Bcen : Register::template Bitfield<1, 1> { }; + struct Ac12en : Register::template Bitfield<2, 1> { }; + struct Dtdsel : Register::template Bitfield<4, 1> + { + enum { WRITE = 0, READ = 1, }; + }; + struct Msbsel : Register::template Bitfield<5, 1> { }; + }; + struct Mixctrl : Xfertyp_base<0x48> + { + struct Ddren : Bitfield<3, 1> { }; + struct Nibblepos : Bitfield<6, 1> { }; + struct Ac23en : Bitfield<7, 1> { }; + struct Always_ones : Bitfield<31, 1> { }; + }; + struct Xfertyp : Xfertyp_base<0xc> + { + struct Rsptyp : Bitfield<16, 2> + { + enum { + _0BIT = 0, + _136BIT = 1, + _48BIT = 2, + _48BIT_BUSY = 3, + }; + }; + struct Cccen : Bitfield<19, 1> { }; + struct Cicen : Bitfield<20, 1> { }; + struct Dpsel : Bitfield<21, 1> { }; + struct Cmdtyp : Bitfield<22, 2> + { + enum { ABORT_CMD12 = 3 }; + }; + struct Cmdinx : Bitfield<24, 6> { }; + }; + struct Prsstat : Register<0x24, 32> + { + struct Cihb : Bitfield<0, 1> { }; + struct Cdihb : Bitfield<1, 1> { }; + struct Dla : Bitfield<2, 1> { }; + struct Sdstb : Bitfield<3, 1> { }; + }; + struct Proctl : Register<0x28, 32> + { + struct Dtw : Bitfield<1, 2> + { + enum { _1BIT = 0, _4BIT = 1 }; + }; + struct Dmas : Bitfield<8, 2> { enum { ADMA2 = 2 }; }; + }; + struct Sysctl : Register<0x2c, 32> + { + struct Ipgen : Bitfield<0, 1> { }; + struct Hcken : Bitfield<1, 1> { }; + struct Peren : Bitfield<2, 1> { }; + struct Dvs : Bitfield<4, 4> + { + enum { DIV1 = 0x0, DIV4 = 0x3, DIV16 = 0xf, }; + }; + struct Sdclkfs : Bitfield<8, 8> + { + enum { DIV1 = 0x00, DIV2 = 0x01, DIV32 = 0x10, }; + }; + struct Dtocv : Bitfield<16, 4> + { + enum { + SDCLK_TIMES_2_POW_28 = 0xf, + SDCLK_TIMES_2_POW_27 = 0xe, + SDCLK_TIMES_2_POW_13 = 0x0, + }; + }; + struct Ipp_rst_n : Bitfield<23, 1> { }; + struct Rsta : Bitfield<24, 1> { }; + struct Rstc : Bitfield<25, 1> { }; + struct Rstd : Bitfield<26, 1> { }; + }; + + template + struct Irq_tpl : Register + { + struct Cc : Register::template Bitfield<0, 1> { }; + struct Tc : Register::template Bitfield<1, 1> { }; + struct Dint : Register::template Bitfield<3, 1> { }; + struct Ctoe : Register::template Bitfield<16, 1> { }; + struct Cce : Register::template Bitfield<17, 1> { }; + struct Cebe : Register::template Bitfield<18, 1> { }; + struct Cie : Register::template Bitfield<19, 1> { }; + struct Dtoe : Register::template Bitfield<20, 1> { }; + struct Dce : Register::template Bitfield<21, 1> { }; + struct Debe : Register::template Bitfield<22, 1> { }; + struct Ac12e : Register::template Bitfield<24, 1> { }; + struct Dmae : Register::template Bitfield<28, 1> { }; + }; + struct Irq : Irq_tpl<0> { }; + struct Irqstat : Irq_tpl<0x30> { }; + struct Irqstaten : Irq_tpl<0x34> { }; + struct Irqsigen : Irq_tpl<0x38> { }; + struct Maxcurrent : Register<0x48, 32> { }; + struct Adsaddr : Register<0x58, 32> { }; + struct Hostver : Register<0xfc, 32> + { + struct Svn : Bitfield<0, 8> { }; + struct Vvn : Bitfield<8, 8> { }; + }; + struct Wml : Register<0x44, 32> + { + struct Rd_wml : Bitfield<0, 8> { }; + struct Rd_brst_len : Bitfield<8, 5> { }; + struct Wr_wml : Bitfield<16, 8> { }; + struct Wr_brst_len : Bitfield<24, 5> { }; + }; + struct Vendspec : Register<0xc0, 32> + { + struct Frc_sdclk_on : Bitfield<8, 1> { }; + }; + + enum { BLOCK_SIZE = 512 }; + + enum Bus_width { BUS_WIDTH_1, BUS_WIDTH_4 }; + + enum Clock { CLOCK_INITIAL, CLOCK_OPERATIONAL }; + + enum Clock_divider { CLOCK_DIV_4, CLOCK_DIV_8, CLOCK_DIV_512 }; + + Irq_connection _irq; + Signal_receiver _irq_rec; + Signal_context _irq_ctx; + Delayer & _delayer; + Sd_card::Card_info _card_info; + bool const _use_dma; + Adma2::Table _adma2_table; + + static bool _supported_host_version(Hostver::access_t hostver); + static void _watermark_level(Wml::access_t &wml); + + void _detect_err(char const * const err); + void _disable_irqs(); + void _enable_irqs(); + void _bus_width(Bus_width bus_width); + void _disable_clock(); + void _disable_clock_preparation(); + void _enable_clock(Clock_divider divider); + void _enable_clock_finish(); + void _clock(Clock clock); + void _clock_finish(Clock clock); + void _wait_for_irq(); + int _reset(Delayer & delayer); + void _reset_amendments(); + int _wait_for_cmd_allowed(); + int _wait_for_cmd_complete(); + int _wait_for_card_ready_mbw(); + int _stop_transmission(); + void _stop_transmission_finish_xfertyp(Xfertyp::access_t &xfertyp); + int _wait_for_cmd_complete_mb(bool const r); + int _wait_for_cmd_complete_mb_finish(bool const reading); + int _prepare_dma_mb(size_t blk_cnt, addr_t buf_phys); + bool _issue_cmd_finish_xfertyp(Xfertyp::access_t &xfertyp, + bool const transfer, + bool const multiblock, + bool const reading); + + Sd_card::Card_info _init(); + + + /**************************************** + ** Sd_card::Host_controller interface ** + ****************************************/ + + Sd_card::Cid _read_cid(); + Sd_card::Csd _read_csd(); + unsigned _read_rca(); + bool _issue_command(Sd_card::Command_base const & command); + + public: + + /** + * Constructor + * + * \param base local base address of MMIO registers + * \param irq host-interrupt ID + * \param delayer delayer timing of MMIO accesses + * \param use_dma wether to use DMA or direct IO for transfers + */ + Sdhc(addr_t const base, + unsigned const irq, + Delayer &delayer, + bool const use_dma); + + ~Sdhc() { _irq_rec.dissolve(&_irq_ctx); } + + + /**************************************** + ** Sd_card::Host_controller interface ** + ****************************************/ + + bool read_blocks(size_t, size_t, char *); + bool write_blocks(size_t, size_t, char const *); + bool read_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys); + bool write_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys); + + Sd_card::Card_info card_info() const { return _card_info; } +}; + +#endif /* _SDHC_H_ */ diff --git a/repos/os/src/drivers/sd_card/spec/imx53/esdhcv2.h b/repos/os/src/drivers/sd_card/spec/imx53/esdhcv2.h deleted file mode 100644 index a87bb4abd..000000000 --- a/repos/os/src/drivers/sd_card/spec/imx53/esdhcv2.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * \brief Freescale Enhanced Secured Digital Host Controller Version 2 - * \author Martin Stein - * \date 2015-02-05 - */ - -/* - * Copyright (C) 2015 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU General Public License version 2. - */ - -#ifndef _ESDHCV2_H_ -#define _ESDHCV2_H_ - -/* Genode includes */ -#include -#include -#include - -/* local includes */ -#include -#include - -namespace Genode -{ - struct Esdhcv2; - class Esdhcv2_controller; -} - -/** - * MMIO structure of a Freescale ESDHCv2 - */ -struct Genode::Esdhcv2 : Mmio -{ - struct Blkattr : Register<0x4, 32> - { - struct Blksize : Bitfield<0, 13> { }; - struct Blkcnt : Bitfield<16, 16> { }; - }; - template - struct Cmdrsp_tpl : Register - { - struct Rsp136_8_24 : Register::template Bitfield<0, 24> { }; - struct Rsp136_0_8 : Register::template Bitfield<24, 8> { }; - }; - struct Cmdarg : Register<0x8, 32> { }; - struct Cmdrsp0 : Cmdrsp_tpl<0x10> { }; - struct Cmdrsp1 : Cmdrsp_tpl<0x14> { }; - struct Cmdrsp2 : Cmdrsp_tpl<0x18> { }; - struct Cmdrsp3 : Cmdrsp_tpl<0x1c> { }; - struct Rsp136_0 : Bitset_2 { }; - struct Rsp136_1 : Bitset_2 { }; - struct Rsp136_2 : Bitset_2 { }; - struct Rsp136_3 : Bitset_2 { }; - struct Xfertyp : Register<0xc, 32> - { - struct Dmaen : Bitfield<0, 1> { }; - struct Bcen : Bitfield<1, 1> { }; - struct Ac12en : Bitfield<2, 1> { }; - struct Dtdsel : Bitfield<4, 1> - { - enum { WRITE = 0, READ = 1, }; - }; - struct Msbsel : Bitfield<5, 1> { }; - struct Rsptyp : Bitfield<16, 2> - { - enum { - _0BIT = 0, - _136BIT = 1, - _48BIT = 2, - _48BIT_BUSY = 3, - }; - }; - struct Cccen : Bitfield<19, 1> { }; - struct Cicen : Bitfield<20, 1> { }; - struct Dpsel : Bitfield<21, 1> { }; - struct Cmdtyp : Bitfield<22, 2> - { - enum { ABORT_CMD12 = 3 }; - }; - struct Cmdinx : Bitfield<24, 6> { }; - }; - struct Prsstat : Register<0x24, 32> { }; - struct Prsstat_lhw : Register<0x24, 16> - { - struct Sdstb : Bitfield<3, 1> { }; - - static constexpr access_t cmd_allowed() { return Sdstb::reg_mask(); } - }; - struct Proctl : Register<0x28, 32> - { - struct Dtw : Bitfield<1, 2> - { - enum { _1BIT = 0, _4BIT = 1 }; - }; - struct Dmas : Bitfield<8, 2> { enum { ADMA2 = 2 }; }; - }; - struct Sysctl : Register<0x2c, 32> - { - struct Ipgen : Bitfield<0, 1> { }; - struct Hcken : Bitfield<1, 1> { }; - struct Peren : Bitfield<2, 1> { }; - struct Dvs : Bitfield<4, 4> - { - enum { DIV1 = 0x0, DIV4 = 0x3, DIV16 = 0xf, }; - }; - struct Sdclkfs : Bitfield<8, 8> - { - enum { DIV1 = 0x00, DIV2 = 0x01, DIV32 = 0x10, }; - }; - struct Dtocv : Bitfield<16, 4> - { - enum { SDCLK_TIMES_2_POW_27 = 0xe }; - }; - struct Rsta : Bitfield<24, 1> { }; - struct Rstc : Bitfield<25, 1> { }; - struct Rstd : Bitfield<26, 1> { }; - }; - - template - struct Irq_tpl : Register - { - struct Cc : Register::template Bitfield<0, 1> { }; - struct Tc : Register::template Bitfield<1, 1> { }; - struct Dint : Register::template Bitfield<3, 1> { }; - struct Ctoe : Register::template Bitfield<16, 1> { }; - struct Cce : Register::template Bitfield<17, 1> { }; - struct Cebe : Register::template Bitfield<18, 1> { }; - struct Cie : Register::template Bitfield<19, 1> { }; - struct Dtoe : Register::template Bitfield<20, 1> { }; - struct Dce : Register::template Bitfield<21, 1> { }; - struct Debe : Register::template Bitfield<22, 1> { }; - struct Ac12e : Register::template Bitfield<24, 1> { }; - struct Dmae : Register::template Bitfield<28, 1> { }; - }; - struct Irq : Irq_tpl<0> { }; - struct Irqstat : Irq_tpl<0x30> { }; - struct Irqstaten : Irq_tpl<0x34> { }; - struct Irqsigen : Irq_tpl<0x38> { }; - struct Maxcurrent : Register<0x48, 32> { }; - struct Adsaddr : Register<0x58, 32> { }; - struct Hostver : Register<0xfc, 32> - { - struct Svn : Bitfield<0, 8> { }; - struct Vvn : Bitfield<8, 8> { }; - }; - struct Wml : Register<0x44, 32> - { - struct Rd_wml : Bitfield<0, 8> { }; - struct Rd_brst_len : Bitfield<8, 5> { }; - struct Wr_wml : Bitfield<16, 8> { }; - struct Wr_brst_len : Bitfield<24, 5> { }; - }; - - Esdhcv2(addr_t const mmio_base) : Mmio(mmio_base) { } -}; - -/** - * Implementation of the SD host-controller interface for the ESDHCv2 - */ -struct Genode::Esdhcv2_controller -: - private Esdhcv2, public Sd_card::Host_controller -{ - private: - - enum { - BLOCK_SIZE = 512, - WATERMARK_WORDS = 16, - BURST_WORDS = 8, - }; - - enum Bus_width { BUS_WIDTH_1, BUS_WIDTH_4 }; - - enum Clock_divider { CLOCK_DIV_8, CLOCK_DIV_512 }; - - Irq_connection _irq; - Signal_receiver _irq_rec; - Signal_context _irq_ctx; - Delayer & _delayer; - Sd_card::Card_info _card_info; - bool const _use_dma; - Adma2::Table _adma2_table; - - void _detect_err(char const * const err); - void _disable_irqs(); - void _enable_irqs(); - void _bus_width(Bus_width bus_width); - void _disable_clock(); - void _enable_clock(Clock_divider divider, Delayer &delayer); - void _clock(enum Clock_divider divider, Delayer &delayer); - void _wait_for_irq(); - int _reset(Delayer & delayer); - int _wait_for_cmd_allowed(); - int _wait_for_cmd_complete(); - int _wait_for_card_ready_mbw(); - int _stop_transmission_mbw(); - int _wait_for_cmd_complete_mb(bool const r); - int _prepare_dma_mb(size_t blk_cnt, addr_t buf_phys); - - Sd_card::Card_info _init(); - - - /**************************************** - ** Sd_card::Host_controller interface ** - ****************************************/ - - Sd_card::Cid _read_cid(); - Sd_card::Csd _read_csd(); - unsigned _read_rca(); - bool _issue_command(Sd_card::Command_base const & command); - - public: - - /** - * Constructor - * - * \param base local base address of MMIO registers - * \param irq host-interrupt ID - * \param delayer delayer timing of MMIO accesses - * \param use_dma wether to use DMA or direct IO for transfers - */ - Esdhcv2_controller(addr_t const base, unsigned const irq, - Delayer & delayer, bool const use_dma); - - ~Esdhcv2_controller() { _irq_rec.dissolve(&_irq_ctx); } - - - /**************************************** - ** Sd_card::Host_controller interface ** - ****************************************/ - - bool read_blocks(size_t, size_t, char *); - bool write_blocks(size_t, size_t, char const *); - bool read_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys); - bool write_blocks_dma(size_t blk_nr, size_t blk_cnt, addr_t buf_phys); - - Sd_card::Card_info card_info() const { return _card_info; } -}; - -#endif /* _ESDHCV2_H_ */ diff --git a/repos/os/src/drivers/sd_card/spec/imx53/sdhc.cc b/repos/os/src/drivers/sd_card/spec/imx53/sdhc.cc new file mode 100644 index 000000000..8cf843d29 --- /dev/null +++ b/repos/os/src/drivers/sd_card/spec/imx53/sdhc.cc @@ -0,0 +1,120 @@ +/* + * \brief Secured Digital Host Controller + * \author Martin Stein + * \date 2016-12-13 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* local includes */ +#include + +using namespace Sd_card; +using namespace Genode; + + +void Sdhc::_stop_transmission_finish_xfertyp(Xfertyp::access_t &xfertyp) +{ + Xfertyp::Msbsel::set(xfertyp, 1); + Xfertyp::Bcen::set(xfertyp, 1); + Xfertyp::Dmaen::set(xfertyp, 1); +} + + +int Sdhc::_wait_for_cmd_complete_mb_finish(bool const reading) +{ + if (reading) { return 0; } + + /* + * The "Auto Command 12" feature of the ESDHC seems to be + * broken for multi-block writes as it causes command- + * timeout errors sometimes. Thus, we stop such transfers + * manually. + */ + if (_stop_transmission()) { return -1; } + + /* + * The manual termination of multi-block writes seems to leave + * the card in a busy state sometimes. This causes + * errors on subsequent commands. Thus, we have to synchronize + * manually with the card-internal state. + */ + return _wait_for_card_ready_mbw() ? -1 : 0; +} + + +bool Sdhc::_issue_cmd_finish_xfertyp(Xfertyp::access_t &xfertyp, + bool const transfer, + bool const multiblock, + bool const reading) +{ + if (transfer) { + Xfertyp::Bcen::set(xfertyp, 1); + Xfertyp::Msbsel::set(xfertyp, 1); + if (multiblock) { + /* + * The "Auto Command 12" feature of the ESDHC seems to be + * broken for multi-block writes as it causes command- + * timeout errors sometimes. + */ + if (reading) { + Xfertyp::Ac12en::set(xfertyp, 1); } + + if (_use_dma) { + Xfertyp::Dmaen::set(xfertyp, 1); } + } + Xfertyp::Dtdsel::set(xfertyp, + reading ? Xfertyp::Dtdsel::READ : Xfertyp::Dtdsel::WRITE); + } + return _wait_for_cmd_allowed() ? false : true; +} + + +bool Sdhc::_supported_host_version(Hostver::access_t hostver) +{ + return Hostver::Vvn::get(hostver) == 18 && + Hostver::Svn::get(hostver) == 1; +} + + +void Sdhc::_watermark_level(Wml::access_t &wml) +{ + Wml::Wr_wml::set(wml, 16); + Wml::Wr_brst_len::set(wml, 8); +} + + +void Sdhc::_reset_amendments() +{ + /* + * The SDHC specification says that a software reset shouldn't + * have an effect on the the card detection circuit. The ESDHC + * clears Sysctl::Ipgen, Sysctl::Hcken, and Sysctl::Peren + * nonetheless which disables clocks that card detection relies + * on. + */ + Sysctl::access_t sysctl = read(); + Sysctl::Ipgen::set(sysctl, 1); + Sysctl::Hcken::set(sysctl, 1); + Sysctl::Peren::set(sysctl, 1); + write(sysctl); +} + + +void Sdhc::_clock_finish(Clock clock) +{ + write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27); + switch (clock) { + case CLOCK_INITIAL: _enable_clock(CLOCK_DIV_512); break; + case CLOCK_OPERATIONAL: _enable_clock(CLOCK_DIV_8); break; } + write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_27); +} + + +void Sdhc::_disable_clock_preparation() { } +void Sdhc::_enable_clock_finish() { } diff --git a/repos/os/src/drivers/sd_card/spec/imx6/sdhc.cc b/repos/os/src/drivers/sd_card/spec/imx6/sdhc.cc new file mode 100644 index 000000000..5574443fa --- /dev/null +++ b/repos/os/src/drivers/sd_card/spec/imx6/sdhc.cc @@ -0,0 +1,116 @@ +/* + * \brief Secured Digital Host Controller + * \author Martin Stein + * \date 2016-12-13 + */ + +/* + * Copyright (C) 2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* local includes */ +#include + +using namespace Sd_card; +using namespace Genode; + + +void Sdhc::_stop_transmission_finish_xfertyp(Xfertyp::access_t &xfertyp) +{ + Mixctrl::access_t mixctrl = read(); + Mixctrl::Dmaen::set(mixctrl, 1); + Mixctrl::Bcen::set(mixctrl, 1); + Mixctrl::Ac12en::set(mixctrl, 0); + Mixctrl::Ddren::set(mixctrl, 0); + Mixctrl::Dtdsel::set(mixctrl, Mixctrl::Dtdsel::READ); + Mixctrl::Msbsel::set(mixctrl, 1); + Mixctrl::Nibblepos::set(mixctrl, 0); + Mixctrl::Ac23en::set(mixctrl, 0); + write(mixctrl); +} + + +int Sdhc::_wait_for_cmd_complete_mb_finish(bool const reading) +{ + /* we can't use the "Auto Command 12" feature as it does not work */ + return _stop_transmission() ? -1 : 0; +} + + +bool Sdhc::_issue_cmd_finish_xfertyp(Xfertyp::access_t &, + bool const transfer, + bool const multiblock, + bool const reading) +{ + Mixctrl::access_t mixctrl = read(); + Mixctrl::Dmaen ::set(mixctrl, transfer && multiblock && _use_dma); + Mixctrl::Bcen ::set(mixctrl, transfer); + Mixctrl::Ac12en ::set(mixctrl, 0); + Mixctrl::Msbsel ::set(mixctrl, transfer); + Mixctrl::Ddren ::set(mixctrl, 0); + Mixctrl::Nibblepos::set(mixctrl, 0); + Mixctrl::Ac23en ::set(mixctrl, 0); + Mixctrl::Dtdsel ::set(mixctrl, reading ? Mixctrl::Dtdsel::READ : + Mixctrl::Dtdsel::WRITE); + + if (_wait_for_cmd_allowed()) { + return false; } + + write(mixctrl); + return true; +} + + +bool Sdhc::_supported_host_version(Hostver::access_t hostver) +{ + return Hostver::Vvn::get(hostver) == 0 && + Hostver::Svn::get(hostver) == 3; +} + + +void Sdhc::_watermark_level(Wml::access_t &wml) +{ + Wml::Wr_wml::set(wml, 64); + Wml::Wr_brst_len::set(wml, 16); +} + + +void Sdhc::_reset_amendments() +{ + /* the USDHC doesn't reset the Mixer Control register automatically */ + Mixctrl::access_t mixctrl = read(); + Mixctrl::Dmaen::set(mixctrl, 0); + Mixctrl::Bcen::set(mixctrl, 0); + Mixctrl::Ac12en::set(mixctrl, 0); + Mixctrl::Ddren::set(mixctrl, 0); + Mixctrl::Dtdsel::set(mixctrl, 0); + Mixctrl::Msbsel::set(mixctrl, 0); + Mixctrl::Nibblepos::set(mixctrl, 0); + Mixctrl::Ac23en::set(mixctrl, 0); + Mixctrl::Always_ones::set(mixctrl, 1); + write(mixctrl); +} + + +void Sdhc::_clock_finish(Clock clock) +{ + switch (clock) { + case CLOCK_INITIAL: + write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_13); + _enable_clock(CLOCK_DIV_512); + break; + case CLOCK_OPERATIONAL: + write(Sysctl::Dtocv::SDCLK_TIMES_2_POW_28); + write(0); + _enable_clock(CLOCK_DIV_4); + break; + } +} + + +void Sdhc::_disable_clock_preparation() { write(0); } + +void Sdhc::_enable_clock_finish() { write(0); }