files
SDHCI_driver_for_Kolibrios/sdhci.asm
Doczom 1b6354b284 add read CSD register SD and SDIO card
add read CSD register SD and SDIO card
2022-12-31 22:40:18 +05:00

1229 lines
55 KiB
NASM
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;; 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