haiku/headers/private/drivers/mmc.h

118 lines
3.4 KiB
C
Raw Normal View History

/*
* Copyright 2019-2020, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Adrien Destugues, pulkomandy@pulkomandy.tk
*/
#ifndef _MMC_H
#define _MMC_H
#include <device_manager.h>
#define MMC_BUS_MODULE_NAME "bus_managers/mmc/driver_v1"
struct IOOperation;
enum {
CARD_TYPE_MMC,
CARD_TYPE_SD,
CARD_TYPE_SDHC,
CARD_TYPE_UHS1,
CARD_TYPE_UHS2,
CARD_TYPE_SDIO
};
sd/mmc: read, naive method First implementation of reading sectors from an SD card. This is not the best performance for many reasons: - No DMA - Reads only one sector at a time - Cannot read more than 512 bytes per syscall Also there are major limitations: - Cannot read less than 512 bytes. The hardware of course works in full sectors. The mmc_disk driver should go through the io scheduler to make sure requests have a reasonable size and offset, and nothing tries to read just a few bytes in the middle of a sector. - SD cards only (no SDHC, no MMC) Architecture problems: I think too much of the implementation is done in sdhci_pci and should be moved to the upper layers. However it is difficult to say without having implemented DMA (which indeed will be at the low level of the sdhci controller). It doesn't help that the order of operations is a bit different depending on wether there is DMA or not. In DMA mode you first prepare the buffer, then run the command. In non-DMA mode you first send the command, then read the data into the buffer. We need an API at the mmc_bus level that doesn't care about that low-level detail. There are other things that the MMC bus should be doing however, such as switching to different clock speeds depending on which card is activated and how fast it can go. At least the following should be done: - The read method for mmc_bus and sdhci_pci should use a scatter-gather structure as a parameter instead of a single buffer - See if can be integrated into ExecuteCommand at sdhci level (it's essentially a command with an additional data phase) Change-Id: I688b6c694561074535c9c0c2545f06dc04b06e7d Reviewed-on: https://review.haiku-os.org/c/haiku/+/3466 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
2020-10-14 16:10:01 +03:00
// Commands for SD cards defined in SD Specifications Part 1:
// Physical Layer Simplified Specification Version 8.00
// They are in the common .h file for the mmc stack because the SDHCI driver
// currently needs to map them to the corresponding expected response types.
enum SD_COMMANDS {
// Basic commands, class 0
SD_GO_IDLE_STATE = 0,
SD_ALL_SEND_CID = 2,
SD_SEND_RELATIVE_ADDR = 3,
SD_SELECT_DESELECT_CARD = 7,
SD_SEND_IF_COND = 8,
SD_SEND_CSD = 9,
SD_STOP_TRANSMISSION = 12,
// Block oriented read and write commands, class 2
sd/mmc: read, naive method First implementation of reading sectors from an SD card. This is not the best performance for many reasons: - No DMA - Reads only one sector at a time - Cannot read more than 512 bytes per syscall Also there are major limitations: - Cannot read less than 512 bytes. The hardware of course works in full sectors. The mmc_disk driver should go through the io scheduler to make sure requests have a reasonable size and offset, and nothing tries to read just a few bytes in the middle of a sector. - SD cards only (no SDHC, no MMC) Architecture problems: I think too much of the implementation is done in sdhci_pci and should be moved to the upper layers. However it is difficult to say without having implemented DMA (which indeed will be at the low level of the sdhci controller). It doesn't help that the order of operations is a bit different depending on wether there is DMA or not. In DMA mode you first prepare the buffer, then run the command. In non-DMA mode you first send the command, then read the data into the buffer. We need an API at the mmc_bus level that doesn't care about that low-level detail. There are other things that the MMC bus should be doing however, such as switching to different clock speeds depending on which card is activated and how fast it can go. At least the following should be done: - The read method for mmc_bus and sdhci_pci should use a scatter-gather structure as a parameter instead of a single buffer - See if can be integrated into ExecuteCommand at sdhci level (it's essentially a command with an additional data phase) Change-Id: I688b6c694561074535c9c0c2545f06dc04b06e7d Reviewed-on: https://review.haiku-os.org/c/haiku/+/3466 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
2020-10-14 16:10:01 +03:00
SD_READ_SINGLE_BLOCK = 17,
SD_READ_MULTIPLE_BLOCKS = 18,
SD_WRITE_SINGLE_BLOCK = 24,
SD_WRITE_MULTIPLE_BLOCKS = 25,
// Erase commands, class 5
SD_ERASE_WR_BLK_START = 32,
SD_ERASE_WR_BLK_END = 33,
SD_ERASE = 38,
sd/mmc: read, naive method First implementation of reading sectors from an SD card. This is not the best performance for many reasons: - No DMA - Reads only one sector at a time - Cannot read more than 512 bytes per syscall Also there are major limitations: - Cannot read less than 512 bytes. The hardware of course works in full sectors. The mmc_disk driver should go through the io scheduler to make sure requests have a reasonable size and offset, and nothing tries to read just a few bytes in the middle of a sector. - SD cards only (no SDHC, no MMC) Architecture problems: I think too much of the implementation is done in sdhci_pci and should be moved to the upper layers. However it is difficult to say without having implemented DMA (which indeed will be at the low level of the sdhci controller). It doesn't help that the order of operations is a bit different depending on wether there is DMA or not. In DMA mode you first prepare the buffer, then run the command. In non-DMA mode you first send the command, then read the data into the buffer. We need an API at the mmc_bus level that doesn't care about that low-level detail. There are other things that the MMC bus should be doing however, such as switching to different clock speeds depending on which card is activated and how fast it can go. At least the following should be done: - The read method for mmc_bus and sdhci_pci should use a scatter-gather structure as a parameter instead of a single buffer - See if can be integrated into ExecuteCommand at sdhci level (it's essentially a command with an additional data phase) Change-Id: I688b6c694561074535c9c0c2545f06dc04b06e7d Reviewed-on: https://review.haiku-os.org/c/haiku/+/3466 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
2020-10-14 16:10:01 +03:00
// Application specific commands, class 8
SD_APP_CMD = 55,
// I/O mode commands, class 9
SD_IO_ABORT = 52,
};
enum SDHCI_APPLICATION_COMMANDS {
SD_SET_BUS_WIDTH = 6,
sd/mmc: read, naive method First implementation of reading sectors from an SD card. This is not the best performance for many reasons: - No DMA - Reads only one sector at a time - Cannot read more than 512 bytes per syscall Also there are major limitations: - Cannot read less than 512 bytes. The hardware of course works in full sectors. The mmc_disk driver should go through the io scheduler to make sure requests have a reasonable size and offset, and nothing tries to read just a few bytes in the middle of a sector. - SD cards only (no SDHC, no MMC) Architecture problems: I think too much of the implementation is done in sdhci_pci and should be moved to the upper layers. However it is difficult to say without having implemented DMA (which indeed will be at the low level of the sdhci controller). It doesn't help that the order of operations is a bit different depending on wether there is DMA or not. In DMA mode you first prepare the buffer, then run the command. In non-DMA mode you first send the command, then read the data into the buffer. We need an API at the mmc_bus level that doesn't care about that low-level detail. There are other things that the MMC bus should be doing however, such as switching to different clock speeds depending on which card is activated and how fast it can go. At least the following should be done: - The read method for mmc_bus and sdhci_pci should use a scatter-gather structure as a parameter instead of a single buffer - See if can be integrated into ExecuteCommand at sdhci level (it's essentially a command with an additional data phase) Change-Id: I688b6c694561074535c9c0c2545f06dc04b06e7d Reviewed-on: https://review.haiku-os.org/c/haiku/+/3466 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
2020-10-14 16:10:01 +03:00
SD_SEND_OP_COND = 41,
};
// Interface between mmc_bus and underlying implementation (sdhci_pci or any
// other thing that can execute mmc commands)
typedef struct mmc_bus_interface {
driver_module_info info;
status_t (*set_clock)(void* controller, uint32_t kilohertz);
// Configure the bus clock. The bus is initialized with a slow clock
// that allows device enumeration in all cases, but after enumeration
// the mmc_bus knows how fast each card can go, and configures the bus
// accordingly.
status_t (*execute_command)(void* controller, uint8_t command,
uint32_t argument, uint32_t* result);
// Execute a command with no I/O phase
status_t (*do_io)(void* controller, uint8_t command,
IOOperation* operation, bool offsetAsSectors);
// Execute a command that involves a data transfer.
void (*set_scan_semaphore)(void* controller, sem_id sem);
// Pass the semaphore used for device rescan to the bus controller
void (*set_bus_width)(void* controller, int width);
// Set the data bus width to 1, 4 or 8 bit mode.
} mmc_bus_interface;
// Interface between mmc device driver (mmc_disk, sdio drivers, ...) and mmc_bus
// This interface is rather generic as it allows implementation of drivers for
// different type of cards, which will use different commands. The bus
// provides a generic interface for all of them, and is not specific to any
// type of card.
typedef struct mmc_device_interface {
driver_module_info info;
status_t (*execute_command)(device_node* node, void* cookie, uint16_t rca,
uint8_t command, uint32_t argument, uint32_t* result);
// Execute a command with no I/O phase
status_t (*do_io)(device_node* controller, void* cookie, uint16_t rca,
uint8_t command, IOOperation* operation, bool offsetAsSectors);
// Execute a command that involves a data transfer.
void (*set_bus_width)(device_node* controller, void* cookie, int width);
// Set the data bus width to 1, 4 or 8 bit mode.
} mmc_device_interface;
// Device attribute paths for the MMC device
const char* const kMmcRcaAttribute = "mmc/rca";
const char* const kMmcTypeAttribute = "mmc/type";
#endif /* _MMC_H */