;; Copyright (C) 2022, Michail Frolov(aka Doczom) ;; SD host controller driver. ;; ;; !!!!ВНИМАНИЕ!!!! ;; Драйвер работает только по спецификации 2.0 и тестируется только на ;; контроллере данной версии. Для контроллеров более новой версии драйвер ;; будет работать как с контроллером по спецификации версии 2.0. Функции ;; контроллера из за этого могут ограничены. format PE native entry START use32 ;;; ;;; ; ; ; Driver for SD host controller ; ; ; ;;; ;;; ; это драйвер для работы с файлами на sd картах и возможно для ещё чего-то ; при инициализации драйвер находит контроллер проверяет его состояние ; назначает ему обработчик прерываний, активация которого сигнализирует вроде как ; подключение или отключение карты DEBUG = 1 __DEBUG__ = 1 __DEBUG_LEVEL__ = 1 ; 1 = verbose, 2 = errors only API_VERSION = 0 ;debug STRIDE = 4 ;size of row in devices table SRV_GETVERSION = 0 ; base SD registers ;0x00-0x0f - SD Command Generation ; если версия контроллера меньше 3 или host_version_4_enable=0, то это адрес SDMA ;Этот регистр содержит адрес системной памяти для передачи SDMA в 32битном режиме адресациию. ;Когда хост контроллер останавливает передачу SDMA, этот регистр должен указывать на адрес ;слудующую непрерывную позицию данных. ;Доступ к этому регистру возможен только в том случае, если транзакция не выполняется(т.е. после ;остановки транзакции).Чтение этого регистра во время SDMA передачи вернёт недопустимое значеие. ;Драйвер хоста должен инициализировать этот регистр перед запуском SDMA передачи. ;После остановки SDMA следующий системный адрес следующей непрерывной позиции может быть считан ;из этого регистра. ; ;Хост контроллер генерирует прерывание DMA, чтобы запросить драйвер хоста для обновления этого ;регистра. Драйвер хоста устанавливает слудующий системный адрес следующей позиции данных в этот ;регистр.Когда записывается самый верхний байт этого регистра(03h), хост контроллер перезапускает ;передачу SDMA. ; ;ADMA не использует этот регистр ; если версия больше и host_version_4_enable=1 то это 32bit block count(более подробно смотреть в ;разделе 1.15) в версии 4.0 используется только для счётчика блоков для auto CMD23, длшя установки ;аргумента CMD23 при выполнении auto CMD23. Хост контроллер будет уменьшать значение этого регистра ;при каждой передаче и при достижении нуля передача данных прекращается.Доступ к этому регистру стоит ;осуществлять только когда транзакция не выполняется. при чтении при транзакции контроллер ;может вернуть недопустимое значение ;===== ; Как я понимаю значение этого регистра: адрес на область физ памяти на некое кол-во байт ; его должен устанавливать драйвер перед каждой операцией sdma SDHC_SYS_ADDR = 0x00 ;32bit block Count(SDMA System Address) ;В этом регистре содержится 3 значения. ;0-11 Transfer Block Size ; Этот регистр определяет размер блока передачи данных для CMD17, CMD18, CMD24, CMD25, CMD35. ; можно задать значение от 1 до 2048 байт. не изменять и не читать во время транзакции ; In case of memory? it shall be set up to 512 bytes( Reffer to Implementation Note in Section 1.7.2) ;12-14 SDMA Buffer Boundary ; Размер выделяемой нами физической памяти для SDMA команд.(4кб 8 кб 16 кб и тд. до 512к) ; когда контроллер дошёл до конца выделенной нами памяти, вызывается прерывание DMA interrupt ; если сгенерилось событие Transfer Complete interrupt то DMA interrupt не генерится ; ADMA не использует этот регистр ; эти регистры должны поддерживаться если в регистре capabilities register ; SDMA support = 1 и если в регистре Transfer Mode register DMA Enable = 1 ;16-31 16 bit block count Register ; Версия хост контроллера 4.10 расширяет количество блоков до 32бит(см Раздел 1.15) ; выбор либо 16 либо 32 битного регистра подсчёта блоков определяется следующим образом: ; если Host version 4 enable = 0 или если для регистра 0х06 установленно ненулевое значение ; то выбирается регистр 0х06 ; если Host version 4 enable = 1 и регистр 0x06 установлен в ноль, то выбирает 32битный регистр ; использование 16/32 битного регистра подсчёта блоков включено, если Block Count Enable в регистре ; Trancfer Mode установлен в 1, и оно допустимо только для передачи нескольких блоков. ; Драйвер должен установить в этот регистр значение от 1 до максимального количества блоков. ; контроллер уменьшает это значение после каждой передачи блоков и останавливается, кодга количество ; достигает нуля. установка регистра в нольприводит к тому, что блоки не передаются. ; Доступ к регистру возможен только когда нет транзакции. если она есть запись игнорится а чтение ; возвращает неверное значение. SDHX_BLK_CS = 0x04 Block_size_register = 0x04 ;word _16bit_block_count_register = 0x06 ;word ; Аргумент SD команды, подробнее в специфиации физического уровня SDHC_CMD_ARG = 0x08 ; dword ARGUMENT0 = 0x08 ; word ARGUMENT1 = 0x0A ; word ; Transfer Mode Register ; SDHC_CMD_TRN = 0x0c transfer_mode_register = 0x0c ;word (using 0-5 bits) command_register = 0x0e ;word (using 0-13) ;0x10-0x1f - Response SDHC_RESP1_0 = 0x10 SDHC_RESP3_2 = 0x14 SDHC_RESP5_4 = 0x18 SDHC_RESP7_6 = 0x1C ;0x20-0x23 - Buffer Data Port как я понимаю это указатель на буфер ; Доступ к буферу контроллера можно получить через 32bit Data Port регистр(смю Раздел 1.7) SDHC_BUFFER = 0x20 ;0x24-0x2f - Host Control 1 and Others ; Present Satte Register (offset 0x24) ; Драйвер может получить состояние контроллера через этот 32 битный регистр. ; 0 - Command inhibit (CMD) ; 1 - Command inhibit (DAT) ; 2 - DAT Line Active ; 3-7 - Resevred ; 8 - Write Transfer Active ; 9 - Read Transfer Active ; 10 - Buffer Write Enable ; 11 - Buffer Read Enable ; 12-15 - Reserved ; Этот бит показывает вставлена карта или нет в слот. В нормальных условиях контроллер генерит ; прерывание Card Inesrtion и Card Removed. Ресет всего не должен влиять на это. ; 16 - Card Inserted ; 17 - Card State Stable ; 18 - Card Detect Pin Level ; 19 - Write Protect Switch Pin Level ; 20-23 - DAT[0:3] Line Signal Level ; 24 - CMD Line Signal Level ; 25-31 - Reserved SDHC_PRSNT_STATE = 0x24 ;word (12-15 , 26 Rsvd) ; Host control Register (offset 0x28) ; 0 - LED Control (0 - LED off; 1 - LED on) ; Этот бит используется для предупреждения полдьзователя о том чтобы он не извлекал карту во ; время доступа к SD карте. Если ПО собирается выдавать несколько команд SD, этот бит может быть ; установлен во время всех этих транзакций. Нет необходимости вносить изменения для каждой ; транзакции. ; 1 - Data Transfer Width (0 - 1 bit mode; 1 - 4 bit mode) ; Этот бит выбирает ширину данных хост контроллера. Драйвер должен настроить его так чтобы он ; соответствовал шарене данных SD карты. ; 2 - High Speed Enable ( 0 - Normal Speed mode; 1 - High Speed mode) ; Это необязательный бит. Перед установкой проверить регистр Capabilities. ; Если этот бит равен 0 - частота до 25 МГц, если 1 - до 50 МГц. ; 3-4 - DMA Select ; Выбор одного из поддерживаемых режимов DMA. Перед этим проверить регистр Capabilities. ; Использование выбранного DMA оперделяется DMA Enable в регистре Transfer Mode. ; 00 - SDMA ; 01 - Reserved ; 10 - 32-bit Address ADMA2 ; 11 - 64-bit Address ADMA2 ; 6 - Card Detect Test Level (1 - Card Inserted; 0 - Not Card) ; Этот бит включён когда Card Detect Signal Selection равен 1 и он указывает вставлена ; карта или нет. ; 7 - Card Detect Signal Selection (0 - SDCD# (for normal use); 1 - The Card Detect Test Level (for test purpose)) ; Этот бит выбирает источник обнаружения карт. ; Зануляем всё что связанно с прерываниями(маску прерываний и прочее). SDHC_CTRL1 = 0x28 ; Power Control Regstre (offset 29h) ; 0 - SD Bus Power for VDD1 ; Если хост контроллер детектит No Card состояние, то надо этот флаг очистить ; 1-3 - SD Bus Voltage Select for VDD1 ; Этот бит может быть установлен если в регистре capabilities параметр 1.8V VDD2 Support ; установлен в 1. ; 101 - 1.8V ; 110 - 3.0V ; 111 - 3.3V Power_control = 0x29 ; byte (using 0-3 bits) ; block_gap_control = 0x2a ;byte (using 0-3 bits) ; Драйвер должен поддерживать вольтаж на SD шине устанавливая SD Bus Power в Power Control, when wake ; up event via Card Interrupt is desired. ; Как это понимаю я, я должен активировать эти флаги для того чтобы ловить прерывания подкл/откл карты. ; и FN_WUS в регистре CIS установить для 00 бита данного регистра. ; 00 - Wakeup Event Enable On Card Intwrrupt. ; 01 - Wakeup Event Enable On SD Card Insertion ; 02 - Wakeup Event Enable On SD Card Removal Wekeup_control = 0x2b ;byte (using 0-2 bits) ; 0x2c - SDHC_CTRL2 ; При инициализации необходимо заполнить поле SDCLK/RCLK Frequency Select в соответствии с регистром ; Capabilities. Этот регистр управляет SDCLK в SD Mode и RCLK в UHS-II Mode. ; 0 - Internal Clock Enable ; Этот бит устанавливается в ноль когда драйвер не использует контроллер или контроллер ; ожидает прерывание пробуждения.Контроллер переходит в режим низкого потреблеиния, ; останавливает внутренние часы(internal clock), регистры доступны и на чтените и на запись. ; Часы начинают колебаться, когда бит установлен в 1, Когда тактовая частота стабилизируется ; контроллер устанавливает бит Internal Clock Stable в состояние 1. Этот бит не влияет на ; обноружение карт(но это не точно). ; 1 - Internal Clock Stable ; Начиная с версии 4.0 драйвер проверяет этот статус дважды, после установки внутренних ; часов(см выше) и после установки PLL Enable.(Refer to Figure 3-3) ; 1) Internal Clock Stable(Когда PLL Enable = 0 или если не поддерживается) ; Контроллер устанавливает этот регистр в 1, когда частота стабилизируется (см выше) ; (Doczom: как то всё запутанно, я так понял надо очередной цикл по проверке тут делать) ; 2) PLL Clock Stable (PLL Enable = 1) ; Контроллер поддерживающий PLL Enable, устанавливает это значение в 0, при изменении ; PLL Enable с 0 на 1 и устанавливает 1, когда PLL заблокирован(PLL использует встроенный ; часы в качестве эталонных часов, которые включаются в Internal Clock Enable). После ; того, как этот бит установлен в 1, драйвер может менять SD clock Enable. ; 2 - SD Clcok Enable ; Хост контроллер должен остановить SDCLK при записи этого бита в 0. Выбор частоты SDCLK ; может быть изменён кагда этот бит равен 0. Затем хост контроллер должен поддерживать ; ту же частоту до тех пор, пока SDCLK не будет остановлен(Остановка при SDCLK=0). Если ; Card insert в регистре Present State очищен, этот бит должен быть очищен. ;; 3 - PLL Enable ;; Этот регистр появился в версии 4.10 контроллера, использующего PLL. Это позволяет ;; инициализировать clock генератор в 2 этапа: a)стабилизация входных тактовых импульсов ;; PLL с Internal Clock Enable и b) стабилизация PLL с PLL Enable. ;; Контроллер может настроить минимальные задержки с помощью SD Clock Enable. ;; ;; 4 - Reaerved ; 8 - 15 - SDCLK/RCLK Frequency Select ; Этот регистр используется для выбора частоты SDCLK пина.Определение этого поля ; зависит от версии контроллера ; 1) 8 битный Разделитель Тактов ; этот режим поддерживается в версии 1 и 2. Частота не программируется напрямую, а ; содержит делитель для Base Clock Frequency For SD Clock в регистре Capabilities ; 0x08 - base clock / 256 ; 0x40 - base clock / 128 ; 0x20 - base clock / 64 ; 0x10 - base clock / 32 ; 0x08 - base clock / 16 ; 0x04 - base clock / 8 ; 0x02 - base clock / 4 ; 0x01 - base clock / 2 ; 0x00 - base clock (10MHz-63MHz) ; При указании частоты используется самый старший бит, согласно спецификации физического ; уровня максимальная частота SD Clock = 25 MHz в нормальной скорости и 50 MHz, при высокой ; скорости и никогда не должна превышать этот лимит. Всегда надо выбирать ближайшую к нужной ; равную или меньше например base Clock = 33MHz а целевая частота равна 25MHz, то выбираем ; значение делителя 0x01 = 16,5MHz, ближайщее меньшее или равное. Аналогисно для целевой ; частоты 400KHz значение делителя ставим в 0x40 оптимальное тактовое значенике 258kHz. ; 2) 10 битный Разделитель тактов ; Хост контроллер версии 3.0 или более новые, значение просто расширяется до 10 бит ; и делитель меняется ; 0x3ff - 1/2046 base clock ; n - 1/2n base clock ; 0x002 - 1/4 base clock ; 0x001 - 1/2 base clock ; 0x000 - Base Clock (10MHz - 155MHz) ; 3) Программируемый Разделитель Тактов ; Контроллер версии 3.0 и выше если Clock Multiplier в регистре Capabilities не нулевой ; и что-то. Множитель позволяет хост-системе более чётко выбирать частоту нет необходимости ; поддерживать генерацию всех частот, указанных в этом поле, поскольку программируемый ; генератор импульсов зависит от конкретного поставщика и зависит от реализации. Поэтому ; этот режим используется с регистром Preset Value. ; Поставщик контроллера предоставляет возможные настройки, а поставщики хост-систем ; соответствующее значения в регистры Preset Value. ; 0x3FF - Base clock * M/1024 ; N-1 - base clock * M/N ; 0x002 - base clock * M/3 ; 0x001 - base clock * M/2 ; 0x000 - base clock * M ; Это поле зависит от установленного значение в Preset Value Enable в регистре ; Host control 2. Если Preset Value Enable = 0, то этот регистр устанавливает драйвер, ; если = 1 , то это значение автоматически устанавливается установленное в одном из ; Preset value регистров. SDHC_CTRL2 = 0x2C clock_control = 0x2c ;word ;При инициализации контроллера, драйвер должен установить это значение согласно регистру capabilities ; timeout_control = 0x2e ;byte (using 0-3 bits) ; Импульс генерится при изменении битов этого регистра ;для подтверждения завершения сброса смотрим чтобы все биты были равны нулю(скорее всего цикл) ; 0x02 - software reset для DAT линии (только SD Mode) ; очищаются: ; Buffer Data Port register ; буфер очищается и инициализируется ; Present State register ; Buffer Read Enable ; Buffer Write Enable ; Read Transfer Active ; Write Transfer Active ; DAT Line Active ; Command Lnhibit(DAT) ; Block Gap Control register ; Continue Request ; Stop At Block Gap Request ; Normal Interrupt Status register ; Buffer Read Ready ; Buffer Write Ready ; DMA interrupt ; Block Gap Event ; Transfer Complete ; 0x01 - software reset for CMD линии ; Для версии 4.10 используется для инициализации командной системы UHS-II ; Этот сброс действует только на схемы выдачи команд(включая состояние ошибки ответа в ; Command Inhibit(CMD) control) и не влияет на схему передачи данных. ; Контроллер может продолжать передачу данных, даже если этот сброс выполняется во время ; обработки ошибки ответа субкоманды. ; очищаются: ; Present State register ; Command Inhibit (cmd) ;` Normal Interrupt Status register ; Command Complete ; Error Interrupt Status (from Version 4.10) ; Response error statuses related to Command Inhibit (CMD) ; 0x00 - software reset for All ; Этот сброс влияет на весь контроллерЮ за исключением схемы обнаружения карты. ; Биты регистров с типом: ROC RW RW1C RWAC очищаются в 0 ; Во время инициализации драйвер должен вызвать этот сброс (контроллер очистит capabilities регистр) ;Повторное выцзывание этого сброса может не повлиять на capabilities register. ;Если этот бит установлен в 1,драйвер вызвает команду сброса и заново инициализирует SD-карту software_reset = 0x2f ;byte (using 0-2 bits) .software_reset_for_all = 0x01 ;1-reset 0-work .saftware_reset_for_cmd_line = 0x02 ;1-reset 0-work .software_reset_for_dat_line = 0x04 ;1-reset 0-work ;0x30-0x3d - Interrupt Controls ; В спецификации до 3.0 есть только 0-8 биты, бит 15 есть во всех версиях SDHC_INT_STATUS = 0x30 normal_int_status = 0x30 ; word .command_complete = 0x01 .transfer_complete = 0x02 .block_gap_event = 0x04 .dma_interrupt = 0x08 .buffer_write_ready = 0x10 .buffer_read_ready = 0x20 .card_insertion = 0x40 .card_removal = 0x80 .card_interrupt = 0x0100 .INT_A = 0x0200 .INT_B = 0x0400 .INT_C = 0x0800 .re_tuning_event = 0x1000 .FX_event = 0x2000 ; 14 bit reserved .error_interrupt = 0x8000 ;есть во всех версиях спеки error_int_status = 0x32 ;word .command_timeout_error = 0x01 ; 1=time out 0=no_error (SD mode only) .command_crc_error = 0x02 ; 1=crc error generation 0=no error (sd mode only) .command_end_bit_error = 0x04 ; 1=end_bit_error_generation 0=no error (sd mode only) .command_index_error = 0x08 ; 1=error 0=no error (SD mode only) .data_timeout_error = 0x10 ; 1=time out 0= no error (sd mode only) .data_crc_error = 0x20 ; 1=error 0=no error (sd mode only) .data_end_bit_error = 0x40 ; 1=error 0=no error (sd mode only) .current_limit_error = 0x80 ; 1=Power_fail 0=no_error .auto_cmd_error = 0x0100 ; 1=error 0=no error (sd mode only) .adma_error = 0x0200 ; 1=error 0=no error ; появляется во 2 версии спеки .tuning_error = 0x0400 ; 1=error 0=no error (UHS-I only) .response_error = 0x0800 ; 1=error 0=no error (SD mode only) .vendor_specific_error_status = 0xf000 ; 1=error 0=no error SDHC_INT_MASK = 0x34 normal_int_status_enable = 0x34 ;word .command_complete_status_enable = 0x01 ; 1=enabled 0=masked .transfer_complete_status_enable = 0x02 ; 1=enabled 0=masked .block_gap_event_status_enable = 0x04 ; 1=enabled 0=masked .dma_interrupt_status_enable = 0x08 ; 1=enabled 0=masked .buffer_write_readly_status_enable = 0x10 ; 1=enabled 0=masked .buffer_read_readly_status_enable = 0x20 ; 1=enabled 0=masked .card_insertion_status_enable = 0x40 ; 1=enabled 0=masked .card_removal_status_enable = 0x80 ; 1=enabled 0=masked .card_interrupt_status_enable = 0x0100 ; 1=enabled 0=masked .INT_A_status_enable = 0x0200 ; 1=enabled 0=masked (embedded) .INT_B_status_enable = 0x0400 ; 1=enabled 0=masked (embedded) .INT_C_status_enable = 0x0800 ; 1=enabled 0=masked (embedded) .Re_tuning_event_status_enable = 0x1000 ; 1=enabled 0=masked (UHS-I only) .FX_event_status_enable = 0x2000 ; 1=enabled 0=masked ;reserved 14 bit .Fixed_to_0 = 0x8000 ;есть во всех версиях спеки error_int_status = 0x36 .command_timeout_error_status_enable = 0x01 ; 1=enabled 0=masked (SD mode only) .command_crc_error_status_enable = 0x02 ; 1=enabled 0=masked (SD mode only) .command_end_bit_error_status_enable = 0x04 ; 1=enabled 0=masked (SD mode only) .command_index_error_status_enable = 0x08 ; 1=enabled 0=masked (SD mode only) .data_timeout_error_status_enable = 0x10 ; 1=enabled 0=masked (SD mode only) .data_crc_error_status_enable = 0x20 ; 1=enabled 0=masked (SD mode only) .data_end_bit_error_enable = 0x40 ; 1=enabled 0=masked (SD mode only) .current_limit_error_status_enable = 0x80 ; 1=enabled 0=masked .auto_cmd_error_status_enable = 0x0100 ; 1=enabled 0=masked (SD mode only) .adma_error_status_enable = 0x0200 ; 1=enabled 0=masked .tuning_error_status_enable = 0x0400 ; 1=enabled 0=masked (UHS-I only) .response_error_status_enable = 0x0800 ; 1=enabled 0=masked (SD mode only) .vendor_specific_error_status_enable = 0xf000 ; 1=enabled 0=masked (НЕ ИСПОЛЬЗОВАТЬ!!!) SDHC_SOG_MASK = 0x38 normal_int_signal_enable = 0x38 .command_complete_signal_enable = 0x01 ; 1=enabled 0=masked .transfer_complete_signal_enable = 0x02 ; 1=enabled 0=masked .block_gap_event_signal_enable = 0x04 ; 1=enabled 0=masked .dma_interrupt_signal_enable = 0x08 ; 1=enabled 0=masked .buffer_write_ready_signal_enable = 0x10 ; 1=enabled 0=masked .buffer_read_ready_signal_enable = 0x20 ; 1=enabled 0=masked .card_insertion_signal_enable = 0x40 ; 1=enabled 0=masked .card_removal_signal_enable = 0x80 ; 1=enabled 0=masked .card_interrupt_signal_enable = 0x0100 ; 1=enabled 0=masked .INT_A_Signal_enable = 0x0200 ; 1=enabled 0=masked (embedded) .INT_B_Signal_enable = 0x0400 ; 1=enabled 0=masked (embedded) .INT_C_Signal_enable = 0x0800 ; 1=enabled 0=masked (embedded) .Re_tunning_event_signal_enable = 0x1000 ; 1=enabled 0=masked (UHS_I only) .FX_event_signal_enable = 0x2000 ; 1=enabled 0=masked ;reserved 14 bit .Fixed_to_0 = 0x8000 ; The Host Driver shall control ; error interrupts using the Error Interrupt Signal Enable register. error_int_signal_enable = 0x3a .command_timeout_error_signal_enable = 0x01 ; 1=enabled 0=masked (SD mode only) .command_crc_error_signal_enable = 0x02 ; 1=enabled 0=masked (sd mode only) .command_end_bit_error_signal_enable = 0x04 ; 1=enabled 0=masked (sd mode only) .command_index_error_signal_enable = 0x08 ; 1=enabled 0=masked (sd mode only) .data_timeout_error_signal_enable = 0x10 ; 1=enabled 0=masked (sd mode only) .data_crc_error_signal_enable = 0x20 ; 1=enabled 0=masked (sd mode only) .data_end_bit_sagnal_enable = 0x40 ; 1=enabled 0=masked (sd mode only) .current_limit_error_signal_enable = 0x80 ; 1=enabled 0=masked .auto_cmd_error_signal_enable = 0x0100 ; 1=enabled 0=masked (sd mode only) .adma_error_signal_enable = 0x0200 ; 1=enabled 0=masked .tuning_error_signal_enable = 0x0400 ; 1=enabled 0=masked (UHS-I only) .response_error_signal_enable = 0x0800 ; 1=enabled 0=masked (sd mode only) .vendor_specific_error_signal_enable = 0xf000 ; 1=enabled 0=masked (НЕ ИСПОЛЬЗОВАТЬ!!!) SDHC_ACMD12_ERR = 0x3C Auto_cmd_error_status = 0x3C ;word(using 0-7 bits) .auto_cmd12_not_excuted = 0x01 ; check 0 bit - 1=not_executed 0=executed .auto_cmd_timeout_error = 0x02 ; check 1 bit 1=time out 0=no_error .auto_cmd_crc_error = 0x04 ; check 2 bit 1=crc error generation 0=no_error .auto_cmd_end_bit_error = 0x08 ; check 3 bit 1=end_bit_error_generated 0=no_error .auto_cmd_index_error = 0x10 ; check 4 bit 1=error 0=no_error .auto_cmd_response_error = 0x20 ; check 5 bit 1=error 0=no_error ; 6 bit is reserved .command_not_issued_by_auto_cmd12_error = 0x80 ; check 7 bit 1=Not_issued 0=no_error ;0x3e-0x3f - Host Control 2 ;spec version 3 SDHC_HOST_CONTROL_2_REG = 0x3e ; word ;0x40-0x4f - Capabilities ;Этот регистр предоставляет драйверу инфу, специфичную для реализации данного контроллера. ; Смотреть после полного сброса. Для разных версий спеки разная конфигурация регистров с ;сохранением обратной совместимости SDHC_CAPABILITY = 0x40 ;qword ;этот регистр указывает на максимальную токовую способность для каждого вида напряжения, ;если контроллер поддерживает это напряжение(регистр 0x40). Если контроллер передаёт ;эти значения другим методом, то этот регистр должен быть выставлен в ноль. ; 0 - 7 - 3.3V VDD1 ; 8 - 15 - 3.0V VDD1 ; 16 - 23 - 1.8V VDD1 ; 24 - 31 - reserved ; 32 - 39 - 1.8V VDD2 ; 40 - 63 - resevred ; Данный регистр измеряет ток с шагом 4мА ; 0 - Получение информации другим способом ; 1 - 4 мА ; 2 - 8 мА ; 3 - 12 мА ; ... ; 255 - 1020 мА ; Драйвер контроллера поддерживающего SDXC карты должен проверить этот регистр для установления ;значения XPC в аргументе ACMD41. Если контроллер может позволить себе больше 150 мА то XPC = 1, ;иначе XPC = 0. Подробнее о XPC в спеке физического уровня 3.0x. SDHC_CURR_CAPABILITY = 0x48 ; qword (using 0-23 32-39) ;0x50-0x53 - Force Event ; spec version 2 SDHC_FORCE_EVT = 0x50 force_event_register = 0x50 ;word (using 0-7 bits) force_event_register_for_interrupt_status = 0x52 ; word ;0x54-0x5f - ADMA2 ; spec version 2 SDHC_ADMA_ERR = 0x54 ADMA_error_status = 0x54 ; byte (using 0-2 bits) SDHC_ADMA_SAD = 0x58 ADMA_system_addres_register = 0x58 ;qword ;0x60-0x6f - Preset Value ;spec version 3 ;0x70-0x77 - ADMA3 ;spec version 4 ;0x80-0xD7 - UNS-II ;0xe0-0xef - Pointers ;0xf0-0xff - common area SDHC_VER_SLOT = 0xfc ; block data SLOT_INTRPT = 0xfc ;Slot interapt status register 1 byte; 0xfd - reserved ;как я понял, это глобальный флаг который показывает, где произошло прерывание ; всего есть 8 слотов, каждому из которых соответструет 1 бит SPEC_VERSION = 0xfe ; in map register controller(15-8 - vendor version; 7-0 - spec version) VENDOR_VERSION = 0xff ; PCI reg pci_class_sdhc = 0x0805 ;basic_class=0x08 sub_class=05 PCI_BAR0 = 0x10 PCI_BAR1 = 0x14 PCI_BAR2 = 0x18 PCI_BAR3 = 0x1C PCI_BAR4 = 0x20 PCI_BAR5 = 0x14 PCI_IRQ_LINE = 0x3C PCI_slot_information = 0x40 ;0-2 first BAR 4-6 - number of Slots(counter BAR?) ; code section '.flat' code readable writable executable include 'drivers/proc32.inc' include 'drivers/struct.inc' include 'drivers/macros.inc' include 'drivers/peimport.inc' include 'drivers/fdo.inc' ; structures struct SDHCI_CONTROLLER fd rd 1 ; next controller bk rd 1 ; pref controller dev rd 1 ; bus rd 1 ; base_reg_map rd 1 ;pointer to registers controller base_sdhc_reg rd 1 ; offset for BAR count_bar_reg rd 1 ; count BAR for this register ver_spec rb 1 ; using 0 - 4 bits flag_pci_dma rb 1 ; 0 - no DMA, 1 - yes DMA irq_line rd 1 ;rb Capabilities rd 2 ; qword - save Capabilities max_slot_amper rd 2 divider400KHz rd 1 ; for SDCLK frequency Select divider25MHz rd 1 divider50MHz rd 1 ends struct SDHCI_SLOT reg_map rd 1; pointer to register map Capabilities rd 2 ; qword - save Capabilities divider400KHz rd 1 ; for SDCLK frequency Select divider25MHz rd 1 divider50MHz rd 1 max_slot_amper rd 2 ends; count_controller: dd 0 list_controllers: .fd: dd list_controllers ; pointer to first item list .bk: dd list_controllers ; pointer to last item list tmp_void: dd 0 proc START c, state:dword, cmdline:dword cmp [state],1 jne .stop_drv ;detect controller DEBUGF 1,"SDHCI: Loading driver\n" invoke GetPCIList mov [tmp_void], eax push eax .next_dev: pop eax mov eax, [eax+PCIDEV.fd] cmp eax, [tmp_void] push eax jz .end_find cmp word[eax + PCIDEV.class + 1], 0x0805 jnz .next_dev mov esi, eax invoke KernelAlloc, sizeof.SDHCI_CONTROLLER test eax, eax jz .not_memory mov ecx, [list_controllers.bk] mov [eax + SDHCI_CONTROLLER.bk], ecx mov [ecx + SDHCI_CONTROLLER.fd], eax mov [eax + SDHCI_CONTROLLER.fd], list_controllers ;push eax push eax call sdhci_init ; in: eax - structure esi - pointer to PCIDEV ;return 0 - good ; other - error code pop esi DEBUGF 1,"SDHCI_INIT: error code =%d bus: %d devfn: %d \n", eax, [esi + SDHCI_CONTROLLER.bus], [esi + SDHCI_CONTROLLER.dev] inc dword[count_controller] test eax, eax mov eax, esi;pop eax ; structure SDHCI_CONTROLLER jz .next_dev DEBUGF 1,"ERROR: Contriller not init\n" mov ecx, [eax + SDHCI_CONTROLLER.fd] mov edx, [eax + SDHCI_CONTROLLER.bk] mov [ecx + SDHCI_CONTROLLER.bk], edx mov [edx + SDHCI_CONTROLLER.fd], ecx dec dword[count_controller] invoke KernelFree, eax ; free structure when error code not zero jmp .next_dev .not_memory: DEBUGF 1,"ERROR: can't alloc memory for structure SDHC_CONTROLLER\n" jmp .next_dev .end_find: pop eax xor eax, eax cmp eax, [count_controller] jz .not_found DEBUGF 1,"SDHCI: Found %d controllers\n", [count_controller] invoke RegService, drv_name, service_proc ret .not_found: DEBUGF 1,"SDHCI: Contriller not found\n" mov eax, 0 ret .stop_drv: DEBUGF 1,"SDHCI: Stop working driver\n" mov eax, 0 ret ;DEBUGF 1,"Controller found: class:=%x bus:=%x devfn:=%x \n",[eax + PCIDEV.class],[bus],[dev] ;set offset SDMA System address ;mov al, byte[ver_spec] ;and al, 111b ;mov ebx, [base_reg_map] ; set ebx=SDHC_SYS_ADRR +[base_sdhc_reg] ;cmp al, 0x02 ; ver 3.0 - adding register host control 2 ;jbe @f ; ;test word[ebx + SDHC_HOST_CONTROL_2_REG], 0xC ; check 12 bit this register ;jz @f; ;add ebx, SDHC_ADMA_SAD ;@@: ;mov [SDMA_sys_addr],ebx ;DEBUGF 1,"set SDMA_sys_addr : %x \n",[SDMA_sys_addr] ;reset controller ; TODO: working with registers controller ; set function for working in DMA and no DMA mode ; SDMA - алгоритм DMA для этого контроллера. За одну команду SDMA ; может быть выполенна одна транзакция SD command. ; Support of SDMA can be checked by the SDMA Support in the Capabilities register. endp ;init controller, set base value, add interrupt function, set stucture for controller ; in: eax - pointer to structure controller; esi - pointer to PCIDEV structure ; out: eax - error code 0 - good; other - error init proc sdhci_init ;set base data in SDHCI_CONTROLLER structure movzx ebx, [esi + PCIDEV.devfn] mov [eax + SDHCI_CONTROLLER.dev], ebx movzx ebx, [esi + PCIDEV.bus] mov [eax + SDHCI_CONTROLLER.bus], ebx ;controller found and init mov bl, byte [esi + PCIDEV.class] ; get interface code mov [eax + SDHCI_CONTROLLER.flag_pci_dma], bl ; 0-not use dma 1-use dma 2 -Vendor unique SD hoet controller DEBUGF 1,"DMA using: %x \n",[eax + SDHCI_CONTROLLER.flag_pci_dma] mov esi, eax invoke PciRead32, [esi + SDHCI_CONTROLLER.bus], [esi + SDHCI_CONTROLLER.dev], dword 4 test eax, 0x4 ; Test Master bit jnz @f or eax, 0x4 ; Set Master bit movi ebx, 0x6 and ebx, eax cmp ebx, 0x6 ; Test Master and Memory bits jz @f or eax, 0x6 ; Set Master and Memory bits invoke PciWrite32, [esi + SDHCI_CONTROLLER.bus], [esi + SDHCI_CONTROLLER.dev], dword 4, eax invoke PciRead32, [esi + SDHCI_CONTROLLER.bus], [esi + SDHCI_CONTROLLER.dev], dword 4 @@: DEBUGF 1,"Status: %x \n", eax ;get slot information and get base register sd host controller invoke PciRead8, [esi + SDHCI_CONTROLLER.bus], dword[esi + SDHCI_CONTROLLER.dev], PCI_slot_information movzx edx, al and edx, 111b mov [esi + SDHCI_CONTROLLER.base_sdhc_reg], edx ;save offset base register sdhc ;mov ebx, edx ;save offset for get base addr reg sdhc shr eax, 4 and eax, 111b mov [esi + SDHCI_CONTROLLER.count_bar_reg], eax ;save count working basical addres register DEBUGF 1,"SDHCI: base BAR: %x count BAR: %x\n",[esi + SDHCI_CONTROLLER.base_sdhc_reg], [esi + SDHCI_CONTROLLER.count_bar_reg] ;get base addr reg sdhc and open mmio on 256 byte(standart size for sdhc) add edx, PCI_BAR0 ; get base pci_bar controller invoke PciRead32, dword [esi + SDHCI_CONTROLLER.bus], dword [esi + SDHCI_CONTROLLER.dev], edx and al, not 0Fh ;? not 0xff invoke MapIoMem, eax, 0x100, PG_SW+PG_NOCACHE ;? test eax, eax jz .fail mov [esi + SDHCI_CONTROLLER.base_reg_map], eax mov cl, [eax + SPEC_VERSION] ; get specification version mov [esi + SDHCI_CONTROLLER.ver_spec], cl DEBUGF 1,"Version specification: %x \n",[esi + SDHCI_CONTROLLER.ver_spec] ;reset controller (all) mov eax, [esi + SDHCI_CONTROLLER.base_reg_map] inc byte[eax + software_reset] @@: test byte[eax + software_reset], 0xFF jnz @b ;TODO: add settings controller ; Сохранить регистр Capabiliti и max Current Capabilities mov ebx, [eax + SDHC_CAPABILITY] mov [esi + SDHCI_CONTROLLER.Capabilities], ebx mov ebx, [eax + SDHC_CAPABILITY + 4] mov [esi + SDHCI_CONTROLLER.Capabilities + 4], ebx DEBUGF 1,"SDHCI:Capabilities %x %x\n",[esi + SDHCI_CONTROLLER.Capabilities + 4],[esi + SDHCI_CONTROLLER.Capabilities] mov ebx, [eax + SDHC_CURR_CAPABILITY] mov [esi + SDHCI_CONTROLLER.max_slot_amper], ebx mov ebx, [eax + SDHC_CURR_CAPABILITY + 4] mov [esi + SDHCI_CONTROLLER.max_slot_amper + 4], ebx DEBUGF 1,"SDHCI:Max current capabilities %x %x\n",[esi + SDHCI_CONTROLLER.max_slot_amper + 4],[esi + SDHCI_CONTROLLER.max_slot_amper] ; установить значения частот ;push eax ;mov ebx, [esi + SDHCI_CPNTROLLER.Capabilities] ;shr ebx, 8 ;and ebx, 111111b ; 11 1111 ;mov eax, ebx ;div dword 25 ; 25 мгц ;bsr eax ;xor edx, edx ;inc edx ;shl edx, eax ;mov dword[esi + SDHCI_CONTROLLER.divider25MHz], edx ;shr edx, 1 ;mov dword[esi + SDHCI_CONTROLLER.divider50MHz], edx ;mov eax, ebx ;imul eax, 1000 ;div 400 ;div 1000 ;pop eax ; Настроить маску прерываний ; Установить значения в Host Control Register ; Детектим карты test byte[eax + SDHC_PRSNT_STATE + 2],0x01 ; check 16 bit in SDHC_PRSNT_STATE jz @f DEBUGF 1,'Card inserted\n' call card_init ; eax - REGISTER MAP esi - SDHCI_CONTROLLER @@: jnz @f DEBUGF 1,'Card removed\n' @@: ; включить генератор частот контроллера ; на этом вроде настройка завершина ;прочитать регистр 0х0-0х4f ;установить значения в host control 2 ;set 0x2e ;attach interrupt ; set Wekeup_control ;or byte[Wekeup_control], 111b ; set irq mask mov eax, [esi + SDHCI_CONTROLLER.base_reg_map] or dword[eax + SDHC_INT_MASK], -1 or word[eax + SDHC_SOG_MASK], -1 DEBUGF 1,'Set test int mask: insert and remove card \n' ; save and attach IRQ invoke PciRead8, dword [esi + SDHCI_CONTROLLER.bus], dword [esi + SDHCI_CONTROLLER.dev], PCI_IRQ_LINE ;al=irq DEBUGF 1,'Attaching to IRQ %x\n',al movzx eax, al mov [esi + SDHCI_CONTROLLER.irq_line], eax ;save irq line invoke AttachIntHandler, eax, sdhc_irq, esi ;esi = pointre to controller ; set irq mask mov eax, [esi + SDHCI_CONTROLLER.base_reg_map] or dword[eax + SDHC_INT_MASK], -1 xor eax, eax ret .fail: DEBUGF 1,"SDHC_INIT: RUNTIME ERROR" mov eax, 1 ret endp proc card_init ret endp proc sdhc_irq cli mov esi, [esp + 4] ;stdcall DEBUGF 1,"SDHCI: get_irq \n" mov eax,[esi + SDHCI_CONTROLLER.base_reg_map] DEBUGF 1,"SLOT_INTRPT: %x \n", [eax + SLOT_INTRPT] DEBUGF 1,"SLOT_INT_STATUS: %x \n",[eax + SDHC_INT_STATUS] test dword[eax + SDHC_INT_STATUS], 0x40 jz @f or dword[eax + SDHC_INT_STATUS], 0x40 DEBUGF 1,"SDHCI: Card insered \n" call card_init @@: test dword[eax + SDHC_INT_STATUS], 0x80 jz @f or dword[eax + SDHC_INT_STATUS], 0x80 DEBUGF 1,"SDHCI: Card removed \n" @@: DEBUGF 1,"SLOT_SOG_MASK: %x \n",[eax + SDHC_SOG_MASK] sti ret endp ; This function for working drivers and programs worked ; with SDIO interface. proc service_proc stdcall, ioctl:dword ret endp drv_name: db 'SDHCI',0 ;base_reg_map: dd 0;pointer on base registers comntroller ;SDMA_sys_addr: dq 0; [base_sdhc_reg]+offset(0x00 or 0x58-0x5f) 32 or 64 bit ;pt_call_command: dd 0; noDMA or DMA function align 4 data fixups end data include_debug_strings