/** * Fusée SD/MMC driver for the Switch * ~ktemkin */ #ifndef __FUSEE_SDMMC_H__ #define __FUSEE_SDMMC_H__ #include #include #include "utils.h" #include "gpio.h" /* Opaque pointer to the Tegra SDMMC registers */ struct tegra_sdmmc; /** * Bus widths supported by the SD/MMC cards. */ enum sdmmc_bus_width { MMC_BUS_WIDTH_1BIT = 0, MMC_BUS_WIDTH_4BIT = 1, MMC_BUS_WIDTH_8BIT = 2, SD_BUS_WIDTH_1BIT = 0, SD_BUS_WIDTH_4BIT = 2 }; /** * Describes the voltages that the host will use to drive the SD card. * CAUTION: getting these wrong can damage (especially embedded) cards! */ enum sdmmc_bus_voltage { MMC_VOLTAGE_3V3 = 0b111, MMC_VOLTAGE_1V8 = 0b101, }; /** * Represents the different types of devices an MMC object * can represent. */ enum sdmmc_card_type { MMC_CARD_EMMC, MMC_CARD_MMC, MMC_CARD_SD, MMC_CARD_CART, }; /** * Specification versions for SD/MMC cards. */ enum sdmmc_spec_version { /* MMC card versions */ MMC_VERSION_4 = 0, /* SD card versions */ SD_VERSION_1_0 = 0, SD_VERSION_1_1 = 1, SD_VERSION_2_0 = 2, }; /** * SDMMC controllers */ enum sdmmc_controller { SWITCH_MICROSD = 0, SWITCH_EMMC = 3 }; /** * Write permission modes for SD cards. */ enum sdmmc_write_permission { SDMMC_WRITE_DISABLED, SDMMC_WRITE_ENABLED, /* use this with the utmost caution so you don't wind up with a brick */ SDMMC_WRITE_ENABLED_INCLUDING_EMMC, }; /** * Methods by which we can touch registers accessed via. * CMD_SWITCH_MODE. */ enum sdmmc_switch_access_mode { /* Normal commands */ MMC_SWITCH_MODE_CMD_SET = 0, MMC_SWITCH_MODE_SET_BITS = 1, MMC_SWITCH_MODE_CLEAR_BITS = 2, MMC_SWITCH_MODE_WRITE_BYTE = 3, /* EXTCSD access */ MMC_SWITCH_EXTCSD_NORMAL = 1, }; /** * Offsets into the SWITCH_MODE argument. */ enum sdmmc_switch_argument_offsets { MMC_SWITCH_VALUE_SHIFT = 8, MMC_SWITCH_FIELD_SHIFT = 16, MMC_SWITCH_ACCESS_MODE_SHIFT = 24, }; /** * Bus speeds possible for an SDMMC controller. */ enum sdmmc_bus_speed { /* SD card speeds */ SDMMC_SPEED_SDR12 = 0, SDMMC_SPEED_SDR25 = 1, SDMMC_SPEED_SDR50 = 2, SDMMC_SPEED_SDR104 = 3, SDMMC_SPEED_DDR50 = 4, /* Other speed: non-spec-compliant value used for e.g. HS400 */ SDMMC_SPEED_OTHER = 5, /* eMMC card speeds */ /* note: to avoid an enum clash, we add ten to these */ SDMMC_SPEED_HS26 = 10 , SDMMC_SPEED_HS52 = 11 , SDMMC_SPEED_HS200 = 12 , SDMMC_SPEED_HS400 = 13 , /* special speeds */ SDMMC_SPEED_INIT = -1, }; /** * Primary data structure describing a Fusée MMC driver. */ struct mmc { enum sdmmc_controller controller; /* Controller properties */ const char *name; bool use_dma; bool allow_voltage_switching; unsigned int timeout; enum tegra_named_gpio card_detect_gpio; enum sdmmc_write_permission write_enable; /* Per-controller operations. */ int (*set_up_clock_and_io)(struct mmc *mmc); void (*configure_clock)(struct mmc *mmc, int source, int car_divisor, int sdmmc_divisor); int (*enable_supplies)(struct mmc *mmc); int (*switch_to_low_voltage)(struct mmc *mmc); bool (*card_present)(struct mmc *mmc); /* Per-card-type operations */ int (*card_init)(struct mmc *mmc); int (*establish_relative_address)(struct mmc *mmc); int (*switch_mode)(struct mmc *mmc, int a, int b, int c, uint32_t timeout, void *response); int (*switch_bus_width)(struct mmc *mmc, enum sdmmc_bus_width width); int (*optimize_speed)(struct mmc *mmc); int (*card_switch_bus_speed)(struct mmc *mmc, enum sdmmc_bus_speed speed); /* Card properties */ enum sdmmc_card_type card_type; uint32_t mmc_card_type; uint8_t cid[15]; uint32_t relative_address; uint8_t partitioned; enum sdmmc_spec_version spec_version; enum sdmmc_bus_width max_bus_width; enum sdmmc_bus_voltage operating_voltage; enum sdmmc_bus_speed operating_speed; uint8_t partition_support; uint8_t partition_config; uint8_t partition_attribute; uint32_t partition_switch_time; uint8_t read_block_order; uint8_t write_block_order; uint8_t tuning_block_order; bool uses_block_addressing; /* Current operation status flags */ uint32_t active_data_buffer; /* Pointers to hardware structures */ volatile struct tegra_sdmmc *regs; }; /** * Primary data structure describing a Fusée MMC driver. */ struct mmc; /** * Parititions supported by the Switch eMMC. */ enum sdmmc_partition { SDMMC_PARTITION_USER = 0, SDMMC_PARTITION_BOOT0 = 1, SDMMC_PARTITION_BOOT1 = 2, }; /** * Sets the current SDMMC debugging loglevel. * * @param loglevel Current log level. A higher value prints more logs. * @return The loglevel prior to when this was applied, for easy restoration. */ int sdmmc_set_loglevel(int loglevel); /** * Set up a new SDMMC driver. * * @param mmc The SDMMC structure to be initiailized with the device state. * @param controler The controller description to be used; usually SWITCH_EMMC * or SWITCH_MICROSD. * @param allow_voltage_switching True if we should allow voltage switching, * which may not make sense if we're about to chainload to another component, * a la fusee stage1. */ int sdmmc_init(struct mmc *mmc, enum sdmmc_controller controller, bool allow_voltage_switching); /** * Selects the active MMC partition. Can be used to select * boot partitions for access. Affects all operations going forward. * * @param mmc The MMC controller whose card is to be used. * @param partition The partition number to be selected. * * @return 0 on success, or an error code on failure. */ int sdmmc_select_partition(struct mmc *mmc, enum sdmmc_partition partition); /** * Reads a sector or sectors from a given SD card. * * @param mmc The MMC device to work with. * @param buffer The output buffer to target. * @param sector The sector number to read. * @param count The number of sectors to read. */ int sdmmc_read(struct mmc *mmc, void *buffer, uint32_t sector, unsigned int count); /** * Releases the SDMMC write lockout, enabling access to the card. * Note that by default, setting this to WRITE_ENABLED will not allow access to eMMC. * Check the source for a third constant that can be used to enable eMMC writes. * * @param perms The permissions to apply-- typically WRITE_DISABLED or WRITE_ENABLED. */ void sdmmc_set_write_enable(struct mmc *mmc, enum sdmmc_write_permission perms); /** * Writes a sector or sectors to a given SD/MMC card. * * @param mmc The MMC device to work with. * @param buffer The input buffer to write. * @param block The sector number to write from. * @param count The number of sectors to write. * * @return 0 on success, or an error code on failure. */ int sdmmc_write(struct mmc *mmc, const void *buffer, uint32_t block, unsigned int count); /** * Checks to see whether an SD card is present. * * @mmc mmc The controller with which to check for card presence. * @return true iff a card is present */ bool sdmmc_card_present(struct mmc *mmc); #endif