;; Copyright (C) 2022, Michael 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 ; Этот регистр используется для контроля операций передачи данных.Драйвер должен установить этот регистр ; перед выполнением команды с передачей данных(смотрет Data Pressent Select в Command регистре), или перед ; выполнением Resume команды. Драйвер должен сохранить этот регистр когда передача данных преостановлена ; (в результате выполнения команды приостановки) и восстановить его перед выполнением команды восстановления ; Чтобы избежать потерю данных, контроллер должен реализовать защиту от записи для этого регистра во время ; транзакции данных.Запись в этот регистр должна игнорироваться когда Command Inhibit (DAT) равен 1. ; 0 - DMA Enable ; Этот бит обеспечивает функциональность DMA как описано в разделе 1.4 .DMA может быть ; включено только в том случае, если оно поддерживается в регистре возможностей. ; Один из режимов работы DMA может быть выбран с помощью DMA Select в Host Control регистре. ; Если DMA не поддерживается этот бит всегда должен быть выставлен в 0. Если этот бит ; установлен в 1, то операция DMA должна начинаться когда драйвер хоста записывает в ; верхний байт Command регистра(0x0f). ; 1 - Block Counter Enable ; Этот бит используется для включения регистра подсчёта блоков, которые имеет значение ; только для передачи нескольких блоко. Когда этот бит нравен 0, регистр подсчёта блоков ; отключается, что полезно при выполнении бесконечной передачи(см таблицу 2-8) ; Если передача данных ADMA2 составляет более 65535 блоков, этот бит должен быть ; установлен в 0. В этом случае длина передачи данных определяется таблицей дискрипторов. ; 2 - Auto CMD12 Enable ; Для многократной передачи блоков требуется остановка транзакции через CMD12 ; При установке этого бита контроллер сам отправляет эту команду при завершении транзакции ; Драйвер хоста не должен устанавливать этот бит, если команды не требуют cmd12 для ; остановки передачи данных. ; 4 - Data Transfer Direction Select ; Этот бит определяет направлене передачи данных по DAT линии. 1-Передача данных с карты ; в хост контроллер, 0 для всех остальных случаев.(1-чтение, 0-запись) ; 5 - Multi/ Single Block Select ; Этот бит устанавливается при выдаче команд многоблочной передачи с использованием ; DAT линии.Для любых других команд этот бит должен быть установлен в 0. Если этот бит ; установлен в 0 нет необходимости устанавливать Block Count регистр. SDHC_CMD_TRN = 0x0c transfer_mode_register = 0x0c ;word (using 0-5 bits) ; Этот регистр нужно записывать только после того как проверили Command Inhibit(DAT) и (CMD), ;Запись в верхний байт этого регистра начинает генерацию команды. Драйвер несёт ответственность ;за запись этого регистра, поскольку контроллер не защищает запись, когда установлена Command Inhibit ;(CMD) ; 0-1 - Response Type Select ; 00 - No Response ; 01 - Response Length 136 ; 10 - Response Length 48 ; 11 - Response Length 48 check Busy after response ; 3 - Command CRC Check Enable ; 4 - Command index Check Enable ; 5 - Data Present Select ; 6-7 - Command Type ; 8-13 - Command index 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 ; Этот статус используется для не DMA записи транзакций. ; 10 - Buffer Write Enable ; Этот статус используется для не DMA чтения транзакций. ; 11 - Buffer Read Enable ; 12-15 - Reserved ; Этот бит показывает вставлена карта или нет в слот. В нормальных условиях контроллер генерит ; прерывание Card Inesrtion и Card Removed. Ресет всего не должен влиять на это. ; 16 - Card Inserted ; 17 - Card State Stable ; 18 - Card Detect Pin Level ; Этот бит отображает пин SDWP#. Переключатель защиты от записи поддерживается для карт памяти ; и комбинированных карт. ; 19 - Write Protect Switch Pin Level (1 - Write enable SDWP#=1, 0 - Write protected SDWP#=0) ; ; 20-23 - DAT[0:3] Line Signal Level ; Этот статус используется для проверки уровня CMD линии для восстановления после ошибки и отладки. ; 24 - CMD Line Signal Level ; 25-31 - Reserved SDHC_PRSNT_STATE = 0x24 ;word (12-15 , 26 Rsvd) .CMD_INHIB_CMD = 0x01 ; for test [eax + SDHC_PRSNT_STATE], SDHC_PRSNT_STATE.CMD_INHIB_CMD .CMD_INHIB_DAT = 0x02 .DAT_LINE_ACTIVE = 0x04 .WR_TX_ACTIVE = 0x100 .RD_TX_ACTIVE = 0x200 .BUF_WR_EN = 0x400 .BUF_RD_EN = 0x800 .CARD_INS = 0x10000 .CARD_STABLE = 0x20000 .CD_LEVEL = 0x40000 .WP_LEVEL = 0x80000 .DAT_LEVEL = 0xf00000 ; 4 bits .CMD_LEVEL = 0x1000000 ; 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 ; Если появилось прерывания вставки или вытаскивания карты, нужно проверить это через регистр 0x24 . ;для отключения генерации прерываний записать в нужный бит единицу(через or например). .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' include 'sdhc_cmd.inc' include 'sdhc_disk.inc' include 'sdhci_adma.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 timeout_reg rd 1 ; offset 0x2e in reg map type_card rd 1 ; 0 - no card 1 - SDIO 2 - MMC(eMMC) 4 - standart flash card 5+ - other card_mode rd 1 ; 1 - spi 2 - sd bus 3+ - other dma_mode rd 1 ; 0-no dma 1-sdma 2-adma1 3 adma2 card_reg_ocr rd 1 ; 32 bit card voltage card_reg_cid rd 4 ; 128 bit 120 bit card_reg_csd rd 4 ; 128 bit (регистр может быть 2 версий) card_reg_rca rw 1 ; rw 1 ; 16 bit card_reg_dsr rw 1 ; rw 1 ;16 bit (optional) card_reg_scr rd 2 ; 64 bits card_reg_ssr rd 16 ; 512bit program_id rd 1 ; tid thread for working with no memory cards flag_command_copmlate rd 1 ; flag interrapt command complate 00 - interrapt is geting flag_transfer_copmlate rd 1 ; flag interrapt transfer complate 00 -interrapt is geting int_status rd 1 ; copy SDHC_INT_STATUS rd 4 ; reserved status_control rd 1 ; flags status controller(0x01 - get irq AND int_status good) ; status for write\read disk, global flags 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], DRV_ENTRY push ebx esi edi ebp 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, 0 ;service_proc pop ebp edi esi ebx ret .not_found: DEBUGF 1,"SDHCI: Contriller not found\n" mov eax, 0 pop ebp edi esi ebx ret .stop_drv: ; deattach irq ; stop power devise ; free struct ; free reg_map ; free memory for DMA DEBUGF 1, "SDHCI: Stop working driver\n" xor eax, eax pop ebp edi esi ebx 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] ; 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 DEBUGF 1,"SDHCI: base address = %x \n", eax 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] DEBUGF 1,"SLOT_INTRPT: %x \n", [eax + SLOT_INTRPT] ;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] ; получить DMA режим : 0 - no dma 1 - sdma 2 - adma1 3 - adma2-32bit 4 - adma2-64bit(не нужно, так как ос 32 бита) mov ebx, [eax + SDHC_CAPABILITY] mov ecx, 3 bt ebx, 19 ; support adma2 jc @f dec ecx bt ebx, 20 ; support adma1 jc @f dec ecx bt ebx, 22 ; support sdma jc @f dec ecx @@: mov [esi + SDHCI_CONTROLLER.dma_mode], ecx DEBUGF 1,"SDHCI: DMA mode: %x \n", [esi + SDHCI_CONTROLLER.dma_mode] test ecx, ecx jz @f dec ecx @@: shl ecx, 3 ;and ecx, not 0x111 ;не нужно так как shl ecx,3 и так запишет эти биты в ноль or dword[eax + SDHC_CTRL1], ecx ; байт 0x28 установлен в начальное значение ; установить значения частот push eax mov eax, [esi + SDHCI_CONTROLLER.Capabilities] shr eax, 8 and eax, 11111111b ; 1111 1111 mov ebx, 25 xor edx, edx div ebx ; 25 мгц bsr ecx, eax xor edx, edx bsf edx, eax cmp ecx, edx jnz @f dec ecx @@: xor edi, edi bts edi, ecx mov dword[esi + SDHCI_CONTROLLER.divider25MHz], edi DEBUGF 1,'25MHz : %u\n', edi shr edi, 1 ; +- десять mov dword[esi + SDHCI_CONTROLLER.divider50MHz], edi DEBUGF 1,'50MHz : %u\n', edi imul eax, 63 ; примерно bsr ecx, eax xor edx, edx bsf edx, eax cmp ecx, edx jnz @f dec ecx @@: xor edi, edi bts edi, ecx mov dword[esi + SDHCI_CONTROLLER.divider400KHz], edi DEBUGF 1,'400KHz : %u\n', edi pop eax ; Настроить маску прерываний TODO: переделать, в соответствии с режимом DMA ;mov eax, [esi + SDHCI_CONTROLLER.base_reg_map] or dword[eax + SDHC_INT_MASK], 0x40 or 0x80 or word[eax + SDHC_SOG_MASK], 0x40 or 0x80 DEBUGF 1,'SDHCI: Set maximum int mask and mask signal\n' ; Установить значения в Host Control Register ; на этом вроде настройка завершина ;прочитать регистр 0х0-0х4f ;установить значения в host control 2 ;set 0x2e ;test mov dword[eax + SDHC_INT_STATUS], 0x00 ; set Wekeup_control or byte[Wekeup_control], 111b ; 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 ;invoke PciWrite16, [esi + SDHCI_CONTROLLER.bus], [esi + SDHCI_CONTROLLER.dev], dword 0x82, 0x0000 ; disable smi ;SD_PCI_MSI_CTRL- RW - 16bits - [SD_PCI_CFG: 82h] ;attach interrupt mov [esi + SDHCI_CONTROLLER.irq_line], eax ;save irq line invoke AttachIntHandler, eax, sdhc_irq, esi ;esi = pointre to controller ; Детектим карты mov eax, [esi + SDHCI_CONTROLLER.base_reg_map] test dword[eax + SDHC_PRSNT_STATE], 0x10000 ; check 16 bit in SDHC_PRSNT_STATE.CARD_INS jz @f call card_detect ; eax - REGISTER MAP esi - SDHCI_CONTROLLER @@: xor eax, eax ret .fail: DEBUGF 1,"SDHC_INIT: RUNTIME ERROR" mov eax, 1 ret endp ; eax - map reg ; ebx - divider Clock base proc set_SD_clock and dword[eax + SDHC_CTRL2], 0xffffffff - 0x04 ; stop clock and dword[eax + SDHC_CTRL2], 0xffff004f ; clear cmp ebx, 0x80 jbe @f push ebx shr ebx, 8 and ebx, 11b shl ebx, 6 or dword[eax + SDHC_CTRL2], ebx pop ebx @@: and ebx, 0xff shl ebx, 8 or ebx, 0x01 ; start internal clock or dword[eax + SDHC_CTRL2], ebx DEBUGF 1,'SDHCI: Set clock divider\n' @@: test dword[eax + SDHC_CTRL2], 0x02; check stable jz @b DEBUGF 1,'SDHCI: Clock stable \n' or dword[eax + SDHC_CTRL2], 0x04 ; set SD clock enable ret endp ; out: ebx = type card 0 - unknow card 1 - sdio 2 - sd card(ver1 ver2 ver2-hsp ), 4 - spi(MMC, eMMC) proc card_init ;DEBUGF 1,'SDHCI: Card init\n' mov dword[esi + SDHCI_CONTROLLER.card_reg_rca], 0 ; обнуляем адрес карты ;включаем прерывания 0х01 or dword[eax + SDHC_INT_MASK], 0xFFFF0001 or dword[eax + SDHC_SOG_MASK], 0xFFFF0001 DEBUGF 1,'SDHCI: INT_MASK = %x\n',[eax + SDHC_INT_MASK] ; Включить питание (3.3В - не всегда) максимально возможное для хоста ; дай бог чтоб не сгорело ничего mov ebx, [esi + SDHCI_CONTROLLER.Capabilities] shr ebx, 24 and ebx, 111b ;26bit - 1.8 25bit - 3.0 24bit - 3.3 bsf ecx, ebx ;ecx= 0 for 3.3, 1 for 3.0 , 2 for 1.8 jz .err mov edx, 111b sub edx, ecx ; see format data this register in specs shl edx, 1 or edx, 0x01 ; для активации наприяжения shl edx, 8 ; offset 0x29 or dword[eax + SDHC_CTRL1], edx DEBUGF 1,'SDHCI: SDHC_CTRL1= %x \n',[eax + SDHC_CTRL1] DEBUGF 1,'SDHCI: Питание включено, дай бог чтоб ничего не сгорело \n' ; включить генератор частот контроллера и установим базовые значения регистров ; генератор на 400 КГц mov ebx, [esi + SDHCI_CONTROLLER.divider400KHz] call set_SD_clock ; очищает SDHC_CTRL1 and dword[eax + SDHC_CTRL1], 11000b + 0x0f00 ;оставляем только dma режим и power control ;; !!! Начинается алгоритм инициализации карты !!! ; cmd0 - reset card GO_IDLE_SATTE ; ok ;выбираем режим работы(sd bus, spi) - но это не точно ; Это не тут, ниже ; cmd5 voltage window = 0 - check sdio DEBUGF 1,"SDHCI: CMD5 - check SDIO\n" xor ebx, ebx ; arg cmd, zero to get voltage mask and to check SDIO functions call IO_SEND_OP_COND; 0 - test voltage mask to check SDIO interface, ZF=1-sdio jz .sdio ; acmd41 voltage window = 0 DEBUGF 1,"SDHCI: ACMD41 - get OCR\n" call SD_SEND_OP_COND jnz .mmc ; if error command ; cmd8 - проверка напряжения начиная со второй спецификации DEBUGF 1,"SDHCI: CMD8 - check SDHC card\n" call SEND_IF_COUND mov ebx, 0 ; no set EFLAGS ;if card supported 2 spec, acmd41 + set hsp=1 jnz @f mov ebx, 1 shl 30 ; set HSP @@: call get_ocr_mask jz .err .set_acmd41: ; acmd41 - с нужной маской вольтажа call SD_SEND_OP_COND jnz .mmc test dword[eax + SDHC_RESP1_0], 0x80000000 ; check 31 bit jz .set_acmd41 ; for no sdio card : cmd2 - get_CID ALL_SEND_CID ; пока выбрасывает ошибку таймаута, а в виду отсутствия ; правильной проверки irq всё виснит ; for all init card : cmd3 - get RCA call SEND_RCA ;TODO: get CSD register call SEND_CSD ;TODO: get SCR register mov ebx, 2 ret .sdio: xor ebx, ebx call get_ocr_mask jz .err @@: ; SDIO initialization (cmd5)set voltage window call IO_SEND_OP_COND jnz .err test dword[eax + SDHC_RESP1_0], 0x80000000 ; check 31 bit jz @b call SEND_RCA ;TODO: get CSD register call SEND_CSD ;TODO: get SCR register mov ebx, 1 ret .mmc: ;определяем и настраиваем карту и контроллер ;cmd1 ;TODO: НАЙТИ АЛГОРИТМ ИНИЦИАЛИЗАЦИИ MMC КАРТ!!! mov ebx, 4 xor ebx, ebx ;DELETE ret .err: DEBUGF 1,'SDHCI: ERROR INIT CARD\n' xor ebx, ebx ret endp proc thread_card_detect ;get event with data invoke Kmalloc, 6*4 ; 6*Dword test eax, eax jz .no_malloc mov edi, eax push edi invoke GetEvent pop edi ;DEBUGF 1,'SDHCI: Get event code=%x [edi + 4]=%x, [edi + 8]=%x\n', [edi], [edi + 4], [edi + 8] push dword[edi + 4] ; reg map push dword[edi + 8] ;controller struct mov eax, edi invoke Kfree pop esi pop eax call card_detect .no_malloc: ; destryct thread mov eax, -1 int 0x40 endp proc card_detect ;DEBUGF 1,'SDHCI: eax=%x esi=%x\n', eax, esi DEBUGF 1,'SDHCI: Card inserted\n' call card_init ; TODO: get CSD and SRC registers + get SSR register mov [esi + SDHCI_CONTROLLER.type_card], ebx test ebx, ebx jz .unknowe dec ebx jz .SDIO ; Если это карта памяти(SD memory, eMMC, SPI), то добавляем диск, else set flag SDIO device ; сохраняем все настройки и состояния процедур .memory_card: call add_card_disk DEBUGF 1,'SDHCI: Card init - Memory card\n' ret .SDIO: ;mov [esi + SDHCI_CONTROLLER.type_card], 1 ; sdio card DEBUGF 1,'SDHCI: Card init - SDIO card\n' DEBUGF 1,'SDHCI: SDIO card not supported. Power and clock stoped\n' and dword[eax + SDHC_CTRL1], not 0x0100 ; stop power and dword[eax + SDHC_CTRL2], not 0x04 ; stop SD clock ret .unknowe: and dword[eax + SDHC_CTRL1], not 0x0100 ; stop power and dword[eax + SDHC_CTRL2], not 0x04 ; stop SD clock DEBUGF 1,'SDHCI: Card not init\n' ret endp proc card_destryct DEBUGF 1,'SDHCI: Card removed\n' ; удаляем диск из списка дисков если это диск test ebx, 110b jz .no_memory_card call del_card_disk .no_memory_card: ;TODO: очищаем все регистры связанные с этим слотом ;stop power and clock gen and dword[eax + SDHC_CTRL1], not 0x0100 ; stop power and dword[eax + SDHC_CTRL2], not 0x04 ; stop SD clock ret endp ; TODO: Доделать систему обработки сигналов ошибки и переработать работу ; с сигналами результата работы команд(сейчас это очень плохо сделано). ; добавить(уже там) 2 поля, для хранения данных об полученном прерывании. ; + статус работы с контроллером(для блокировок) proc sdhc_irq pusha mov esi, [esp + 4 + 32] ;stdcall ;DEBUGF 1,"SDHCI: get_irq \n" mov eax,[esi + SDHCI_CONTROLLER.base_reg_map] DEBUGF 1,"SDHCI: INTRPT: %x \n", [eax + SLOT_INTRPT] DEBUGF 1,"SLOT_INT_STATUS: %x \n",[eax + SDHC_INT_STATUS] cmp dword[eax + SDHC_INT_STATUS], 0 jz .fail test dword[eax + SDHC_INT_STATUS], 0x40 jz .no_card_inserted or dword[eax + SDHC_INT_STATUS], 0x40 ; create thread for init card push esi push eax mov ebx, 1 mov ecx, thread_card_detect mov edx, 0 ; stack - for kernel mode kernel alloc 8Kb RAM invoke CreateThread DEBUGF 1,"SDHCI: create thread tid=%x \n", eax test eax, eax pop ebx pop ecx jz .no_card_inserted ; send event for thread mov [.event_struct + 4], ebx ; reg map mov [.event_struct + 8], ecx ; sdhci_controller struct mov esi, .event_struct ;DEBUGF 1,"SDHCI: send event tid=%x code[1]=%x code[2]=%x \n", eax, [.event_struct + 4], [.event_struct + 8] push ecx push ebx invoke SendEvent ;DEBUGF 1,"SDHCI: Evend sended, eax=%x uid=%x \n", eax, ebx pop eax pop esi .no_card_inserted: test dword[eax + SDHC_INT_STATUS], 0x80 jz .no_card_removed or dword[eax + SDHC_INT_STATUS], 0x80 call card_destryct .no_card_removed: mov ecx, [eax + SDHC_INT_STATUS] mov dword[esi + SDHCI_CONTROLLER.int_status], ecx mov [eax + SDHC_INT_STATUS], ecx ; гасим прерывания popa xor eax, eax ret .fail: popa xor eax, eax inc eax ret .event_struct: ; 6*dword dd 0xff0000ff rd 5 endp ; get voltage mask for ACMD41 and CMD5 ; IN: ebx - base data for OCR esi,eax -standart fo this driver ; OUT: ebx - OCR ; ZF - error mask(ebx[23:0]=0) proc get_ocr_mask or ebx, [esi + SDHCI_CONTROLLER.card_reg_ocr] ; set mask sd card cmp byte[eax + 0x29], 1011b ;1.8 jnz @f and ebx, (1 shl 30) + 0x80 ; see OCR reg @@: cmp byte[eax + 0x29], 1101b ;3.0 jnz @f and ebx, (1 shl 30) + (1 shl 17) ; see OCR reg @@: cmp byte[eax + 0x29], 1111b ;1.8 jnz @f and ebx, (1 shl 30) + (1 shl 20) ; see OCR reg @@: test ebx, 0xffffff 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