SDHostController.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * Copyright (c) 2023, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Badge.h>
  8. #include <AK/Function.h>
  9. #include <AK/Result.h>
  10. #include <AK/Types.h>
  11. #include <Kernel/Devices/Storage/SD/Commands.h>
  12. #include <Kernel/Devices/Storage/SD/Registers.h>
  13. #include <Kernel/Devices/Storage/SD/SDMemoryCard.h>
  14. #include <Kernel/Locking/Mutex.h>
  15. namespace Kernel {
  16. class SDHostController : public StorageController {
  17. public:
  18. SDHostController();
  19. ErrorOr<void> initialize();
  20. virtual ~SDHostController() = default;
  21. virtual LockRefPtr<StorageDevice> device(u32 index) const override { return index == 0 ? m_card : nullptr; }
  22. virtual ErrorOr<void> reset() override;
  23. virtual ErrorOr<void> shutdown() override;
  24. virtual size_t devices_count() const override { return m_card ? 1 : 0; }
  25. virtual void complete_current_request(AsyncDeviceRequest::RequestResult) override;
  26. ErrorOr<void> read_block(Badge<SDMemoryCard>, u32 block_address, u32 block_count, UserOrKernelBuffer out);
  27. ErrorOr<void> write_block(Badge<SDMemoryCard>, u32 block_address, u32 block_count, UserOrKernelBuffer in);
  28. void try_enable_dma();
  29. protected:
  30. virtual SD::HostControlRegisterMap volatile* get_register_map_base_address() = 0;
  31. private:
  32. ErrorOr<NonnullLockRefPtr<SDMemoryCard>> try_initialize_inserted_card();
  33. bool is_card_inserted() const
  34. {
  35. constexpr u32 card_inserted = 1 << 16;
  36. return m_registers->present_state & card_inserted;
  37. }
  38. SD::HostVersion host_version() { return m_registers->slot_interrupt_status_and_version.specification_version_number; }
  39. ErrorOr<void> reset_host_controller();
  40. SD::Command last_sent_command()
  41. {
  42. SD::Command command {};
  43. command.raw = m_registers->transfer_mode_and_command;
  44. return command;
  45. }
  46. bool currently_active_command_uses_transfer_complete_interrupt();
  47. ErrorOr<u32> calculate_sd_clock_divisor(u32 sd_clock_frequency, u32 frequency);
  48. bool is_sd_clock_enabled();
  49. ErrorOr<void> sd_clock_supply(u32 frequency);
  50. void sd_clock_stop();
  51. ErrorOr<void> sd_clock_frequency_change(u32 frequency);
  52. ErrorOr<u32> retrieve_sd_clock_frequency();
  53. struct Response {
  54. u32 response[4];
  55. };
  56. ErrorOr<void> issue_command(SD::Command const&, u32 argument);
  57. ErrorOr<Response> wait_for_response();
  58. bool card_status_contains_errors(SD::Command const&, u32);
  59. bool retry_with_timeout(Function<bool()>, i64 delay_between_tries = 100);
  60. enum class DataTransferType {
  61. Read,
  62. Write
  63. };
  64. enum class OperatingMode {
  65. PIO,
  66. ADMA2_32,
  67. ADMA2_64
  68. };
  69. ErrorOr<void> transaction_control_with_data_transfer_using_the_dat_line_without_dma(SD::Command const&, u32 argument, u32 block_count, u32 block_size, UserOrKernelBuffer, DataTransferType data_transfer_type);
  70. ErrorOr<void> transfer_blocks_adma2(u32 block_address, u32 block_count, UserOrKernelBuffer, SD::DataTransferDirection);
  71. ErrorOr<SD::SDConfigurationRegister> retrieve_sd_configuration_register(u32 relative_card_address);
  72. u32 make_adma_descriptor_table(u32 block_count);
  73. volatile SD::HostControlRegisterMap* m_registers;
  74. LockRefPtr<SDMemoryCard> m_card { nullptr };
  75. u32 m_hardware_relative_controller_id { 0 };
  76. OperatingMode m_mode { OperatingMode::PIO };
  77. Mutex m_lock { "SDHostController"sv };
  78. // For ADMA2
  79. // One page of descriptor tables with 16 bit lengths can address writes of
  80. // Up to 4 MiB ADMA2_32
  81. // Up to 2 MiB ADMA2_64
  82. // To not over allocate we use a buffer of just 16 pages
  83. // FIXME: Investigate the average usage and adjust this
  84. constexpr static size_t dma_rw_buffer_size = 16 * PAGE_SIZE;
  85. constexpr static size_t dma_region_size = PAGE_SIZE + dma_rw_buffer_size;
  86. OwnPtr<Memory::Region> m_dma_region;
  87. };
  88. }