5ec64c5cdd
Store the bus cookie in the mmc_disk driver and pass it to the bus manager when executing commands. This avoids calling into the device manager at each read and write operation. The code to get the cookie from mmc_disk isn't so nice since it needs to access the grandparent device (the mmc bus root), it would be simpler if this cookie would be available directly from mmc bus devices. We can get card removal and card insertion interrupt at the same time due to insufficient hardware debouncing (the SDHCI spec says we shouldn't, but it happens on Ricoh controllers. Can't blame them, they don't advertise themselves as compliant with the spec). So, check the card status from the interrupt handler and ignore the incorrect interrupts. Fix unreliable card initialization: power must be turned on before starting up the SD clock. Remove a now unneeded delay that was added in an attempt to avoid initial instability. Change-Id: Ibd8d051da1a1d859f3924ee535f4a05d9b6398d4 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3639 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
113 lines
3.3 KiB
C
113 lines
3.3 KiB
C
/*
|
|
* 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
|
|
};
|
|
|
|
|
|
// 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_READ_SINGLE_BLOCK = 17,
|
|
SD_READ_MULTIPLE_BLOCKS = 18,
|
|
|
|
SD_WRITE_SINGLE_BLOCK = 24,
|
|
SD_WRITE_MULTIPLE_BLOCKS = 25,
|
|
|
|
// 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_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
|
|
static const char* kMmcRcaAttribute = "mmc/rca";
|
|
static const char* kMmcTypeAttribute = "mmc/type";
|
|
|
|
|
|
#endif /* _MMC_H */
|