| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #pragma once |
| |
| #include <zircon/compiler.h> |
| #include <zircon/listnode.h> |
| |
| #include <ddk/protocol/block.h> |
| |
| __BEGIN_CDECLS; |
| |
| typedef enum sdmmc_voltage { |
| SDMMC_VOLTAGE_330, |
| SDMMC_VOLTAGE_180, |
| SDMMC_VOLTAGE_MAX, |
| } sdmmc_voltage_t; |
| |
| typedef enum sdmmc_bus_width { |
| SDMMC_BUS_WIDTH_1, |
| SDMMC_BUS_WIDTH_4, |
| SDMMC_BUS_WIDTH_8, |
| SDMMC_BUS_WIDTH_MAX, |
| } sdmmc_bus_width_t; |
| |
| typedef enum sdmmc_timing { |
| SDMMC_TIMING_LEGACY, |
| SDMMC_TIMING_HS, |
| SDMMC_TIMING_HSDDR, |
| SDMMC_TIMING_HS200, |
| SDMMC_TIMING_HS400, |
| SDMMC_TIMING_MAX, |
| } sdmmc_timing_t; |
| |
| // block io transactions. one per client request |
| typedef struct sdmmc_txn { |
| block_op_t bop; |
| list_node_t node; |
| } sdmmc_txn_t; |
| |
| typedef struct sdmmc_req sdmmc_req_t; |
| |
| // number of pages per request - 2M per request |
| // matches DMA_DESC_COUNT in dev/block/sdhci |
| #define SDMMC_PAGES_COUNT (PAGE_SIZE / sizeof(zx_paddr_t)) |
| |
| // sdmmc requests. one per command |
| struct sdmmc_req { |
| uint32_t cmd; |
| uint32_t arg; |
| |
| // (optional) related txn |
| sdmmc_txn_t* txn; |
| |
| // data command parameters |
| |
| uint16_t blockcount; |
| uint16_t blocksize; |
| |
| bool use_dma; |
| void* virt; |
| zx_paddr_t phys; |
| |
| // response data |
| uint32_t response[4]; |
| |
| // status |
| zx_status_t status; |
| }; |
| |
| typedef struct sdmmc_host_info { |
| // Controller capabilities |
| uint64_t caps; |
| #define SDMMC_HOST_CAP_BUS_WIDTH_8 (1 << 0) |
| #define SDMMC_HOST_CAP_ADMA2 (1 << 1) |
| #define SDMMC_HOST_CAP_64BIT (1 << 2) |
| #define SDMMC_HOST_CAP_VOLTAGE_330 (1 << 3) |
| // Maximum data request size |
| uint64_t max_transfer_size; |
| } sdmmc_host_info_t; |
| |
| typedef struct sdmmc_protocol_ops { |
| // get host info |
| zx_status_t (*host_info)(void* ctx, sdmmc_host_info_t* info); |
| // set signal voltage |
| zx_status_t (*set_signal_voltage)(void* ctx, sdmmc_voltage_t voltage); |
| // set bus width |
| zx_status_t (*set_bus_width)(void* ctx, sdmmc_bus_width_t bus_width); |
| // set bus frequency |
| zx_status_t (*set_bus_freq)(void* ctx, uint32_t bus_freq); |
| // set mmc timing |
| zx_status_t (*set_timing)(void* ctx, sdmmc_timing_t timing); |
| // issue a hw reset |
| void (*hw_reset)(void* ctx); |
| // perform tuning |
| zx_status_t (*perform_tuning)(void* ctx); |
| // issue a request |
| zx_status_t (*request)(void* ctx, sdmmc_req_t* req); |
| } sdmmc_protocol_ops_t; |
| |
| typedef struct sdmmc_protocol { |
| sdmmc_protocol_ops_t* ops; |
| void* ctx; |
| } sdmmc_protocol_t; |
| |
| static inline zx_status_t sdmmc_host_info(sdmmc_protocol_t* sdmmc, sdmmc_host_info_t* info) { |
| return sdmmc->ops->host_info(sdmmc->ctx, info); |
| } |
| |
| static inline zx_status_t sdmmc_set_signal_voltage(sdmmc_protocol_t* sdmmc, |
| sdmmc_voltage_t voltage) { |
| return sdmmc->ops->set_signal_voltage(sdmmc->ctx, voltage); |
| } |
| |
| static inline zx_status_t sdmmc_set_bus_width(sdmmc_protocol_t* sdmmc, |
| sdmmc_bus_width_t bus_width) { |
| return sdmmc->ops->set_bus_width(sdmmc->ctx, bus_width); |
| } |
| |
| static inline zx_status_t sdmmc_set_bus_freq(sdmmc_protocol_t* sdmmc, uint32_t bus_freq) { |
| return sdmmc->ops->set_bus_freq(sdmmc->ctx, bus_freq); |
| } |
| |
| static inline zx_status_t sdmmc_set_timing(sdmmc_protocol_t* sdmmc, sdmmc_timing_t timing) { |
| return sdmmc->ops->set_timing(sdmmc->ctx, timing); |
| } |
| |
| static inline void sdmmc_hw_reset(sdmmc_protocol_t* sdmmc) { |
| sdmmc->ops->hw_reset(sdmmc->ctx); |
| } |
| |
| static inline zx_status_t sdmmc_perform_tuning(sdmmc_protocol_t* sdmmc) { |
| return sdmmc->ops->perform_tuning(sdmmc->ctx); |
| } |
| |
| static inline zx_status_t sdmmc_request(sdmmc_protocol_t* sdmmc, sdmmc_req_t* req) { |
| return sdmmc->ops->request(sdmmc->ctx, req); |
| } |
| |
| __END_CDECLS; |