mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Enable high-speed on the card before increasing frequency on the controller
Increasing operating frequency without telling card to switch to high-speed mode first upsets some cards and generates CRC errors. While here, deselect / reselect cards after CMD6 and SCR fetch, as in original code. Approved by: imp (mentor) Differential Revision: https://reviews.freebsd.org/D15568
This commit is contained in:
parent
10c66ed32e
commit
d670d9518f
1 changed files with 62 additions and 8 deletions
|
|
@ -171,7 +171,7 @@ static void sdda_start_init_task(void *context, int pending);
|
|||
static void sdda_process_mmc_partitions(struct cam_periph *periph, union ccb *start_ccb);
|
||||
static uint32_t sdda_get_host_caps(struct cam_periph *periph, union ccb *ccb);
|
||||
static void sdda_init_switch_part(struct cam_periph *periph, union ccb *start_ccb, u_int part);
|
||||
|
||||
static int mmc_select_card(struct cam_periph *periph, union ccb *ccb, uint32_t rca);
|
||||
static inline uint32_t mmc_get_sector_size(struct cam_periph *periph) {return MMC_SECTOR_SIZE;}
|
||||
|
||||
/* TODO: actually issue GET_TRAN_SETTINGS to get R/O status */
|
||||
|
|
@ -900,6 +900,38 @@ mmc_switch_fill_mmcio(union ccb *ccb,
|
|||
/*timeout*/ timeout);
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_select_card(struct cam_periph *periph, union ccb *ccb, uint32_t rca)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC;
|
||||
cam_fill_mmcio(&ccb->mmcio,
|
||||
/*retries*/ 0,
|
||||
/*cbfcnp*/ NULL,
|
||||
/*flags*/ CAM_DIR_IN,
|
||||
/*mmc_opcode*/ MMC_SELECT_CARD,
|
||||
/*mmc_arg*/ rca << 16,
|
||||
/*mmc_flags*/ flags,
|
||||
/*mmc_data*/ NULL,
|
||||
/*timeout*/ 0);
|
||||
|
||||
cam_periph_runccb(ccb, sddaerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL);
|
||||
|
||||
if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) {
|
||||
if (ccb->mmcio.cmd.error != 0) {
|
||||
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_PERIPH,
|
||||
("%s: MMC_SELECT command failed", __func__));
|
||||
return EIO;
|
||||
}
|
||||
return 0; /* Normal return */
|
||||
} else {
|
||||
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_PERIPH,
|
||||
("%s: CAM request failed\n", __func__));
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_switch(struct cam_periph *periph, union ccb *ccb,
|
||||
uint8_t set, uint8_t index, uint8_t value, u_int timeout)
|
||||
|
|
@ -953,18 +985,24 @@ mmc_sd_switch(struct cam_periph *periph, union ccb *ccb,
|
|||
uint8_t *res) {
|
||||
|
||||
struct mmc_data mmc_d;
|
||||
uint32_t arg;
|
||||
|
||||
memset(res, 0, 64);
|
||||
mmc_d.len = 64;
|
||||
mmc_d.data = res;
|
||||
mmc_d.flags = MMC_DATA_READ;
|
||||
|
||||
arg = mode << 31; /* 0 - check, 1 - set */
|
||||
arg |= 0x00FFFFFF;
|
||||
arg &= ~(0xF << (grp * 4));
|
||||
arg |= value << (grp * 4);
|
||||
|
||||
cam_fill_mmcio(&ccb->mmcio,
|
||||
/*retries*/ 0,
|
||||
/*cbfcnp*/ NULL,
|
||||
/*flags*/ CAM_DIR_IN,
|
||||
/*mmc_opcode*/ SD_SWITCH_FUNC,
|
||||
/*mmc_arg*/ mode << 31,
|
||||
/*mmc_arg*/ arg,
|
||||
/*mmc_flags*/ MMC_RSP_R1 | MMC_CMD_ADTC,
|
||||
/*mmc_data*/ &mmc_d,
|
||||
/*timeout*/ 0);
|
||||
|
|
@ -1273,6 +1311,19 @@ sdda_start_init(void *context, union ccb *start_ccb)
|
|||
CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Card supports HS\n"));
|
||||
softc->card_f_max = SD_HS_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* We deselect then reselect the card here. Some cards
|
||||
* become unselected and timeout with the above two
|
||||
* commands, although the state tables / diagrams in the
|
||||
* standard suggest they go back to the transfer state.
|
||||
* Other cards don't become deselected, and if we
|
||||
* attempt to blindly re-select them, we get timeout
|
||||
* errors from some controllers. So we deselect then
|
||||
* reselect to handle all situations.
|
||||
*/
|
||||
mmc_select_card(periph, start_ccb, 0);
|
||||
mmc_select_card(periph, start_ccb, get_rca(periph));
|
||||
} else {
|
||||
CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Not trying the switch\n"));
|
||||
goto finish_hs_tests;
|
||||
|
|
@ -1293,6 +1344,15 @@ finish_hs_tests:
|
|||
f_max = min(host_f_max, softc->card_f_max);
|
||||
CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Set SD freq to %d MHz (min out of host f=%d MHz and card f=%d MHz)\n", f_max / 1000000, host_f_max / 1000000, softc->card_f_max / 1000000));
|
||||
|
||||
/* Enable high-speed timing on the card */
|
||||
if (f_max > 25000000) {
|
||||
err = mmc_set_timing(periph, start_ccb, bus_timing_hs);
|
||||
if (err != MMC_ERR_NONE) {
|
||||
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("Cannot switch card to high-speed mode"));
|
||||
f_max = 25000000;
|
||||
}
|
||||
}
|
||||
/* Set frequency on the controller */
|
||||
start_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
|
||||
start_ccb->ccb_h.flags = CAM_DIR_NONE;
|
||||
start_ccb->ccb_h.retry_count = 0;
|
||||
|
|
@ -1327,12 +1387,6 @@ finish_hs_tests:
|
|||
bus_width_str(max_card_bus_width)));
|
||||
sdda_set_bus_width(periph, start_ccb, desired_bus_width);
|
||||
|
||||
if (f_max > 25000000) {
|
||||
err = mmc_set_timing(periph, start_ccb, bus_timing_hs);
|
||||
if (err != MMC_ERR_NONE)
|
||||
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("Cannot switch card to high-speed mode"));
|
||||
}
|
||||
|
||||
softc->state = SDDA_STATE_NORMAL;
|
||||
|
||||
/* MMC partitions support */
|
||||
|
|
|
|||
Loading…
Reference in a new issue