Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/sdhci/sdhci.c
Context not available. | |||||
#include <dev/mmc/mmcreg.h> | #include <dev/mmc/mmcreg.h> | ||||
#include <dev/mmc/mmcbrvar.h> | #include <dev/mmc/mmcbrvar.h> | ||||
#include <cam/cam.h> | |||||
#include <cam/cam_ccb.h> | |||||
#include <cam/cam_debug.h> | |||||
#include <cam/cam_sim.h> | |||||
#include <cam/cam_xpt_sim.h> | |||||
#include "mmcbr_if.h" | #include "mmcbr_if.h" | ||||
#include "sdhci.h" | #include "sdhci.h" | ||||
#include "sdhci_if.h" | #include "sdhci_if.h" | ||||
SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver"); | SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver"); | ||||
static int sdhci_debug; | static int sdhci_debug = 10; | ||||
SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, "Debug level"); | SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, "Debug level"); | ||||
#define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off)) | #define RD1(slot, off) SDHCI_READ_1((slot)->bus, (slot), (off)) | ||||
Context not available. | |||||
int err; | int err; | ||||
SDHCI_LOCK_INIT(slot); | SDHCI_LOCK_INIT(slot); | ||||
slot->num = num; | slot->num = num; | ||||
slot->bus = dev; | slot->bus = dev; | ||||
Context not available. | |||||
TASK_INIT(&slot->card_task, 0, sdhci_card_task, slot); | TASK_INIT(&slot->card_task, 0, sdhci_card_task, slot); | ||||
callout_init(&slot->card_callout, 1); | callout_init(&slot->card_callout, 1); | ||||
callout_init_mtx(&slot->timeout_callout, &slot->mtx, 0); | callout_init_mtx(&slot->timeout_callout, &slot->mtx, 0); | ||||
return (0); | return (0); | ||||
} | } | ||||
Context not available. | |||||
return (slot->max_clk / SDHCI_200_MAX_DIVIDER); | return (slot->max_clk / SDHCI_200_MAX_DIVIDER); | ||||
} | } | ||||
/* | |||||
* When called from the old stack: | |||||
sdhci_ti0: This is a bridge device | |||||
mmc0: This is a request device | |||||
sdhci_ti0-slot0: <--- The locking slot is this | |||||
* | |||||
*/ | |||||
int | int | ||||
sdhci_generic_update_ios(device_t brdev, device_t reqdev) | sdhci_generic_update_ios(device_t brdev, device_t reqdev) | ||||
{ | { | ||||
struct sdhci_slot *slot = device_get_ivars(reqdev); | struct sdhci_slot *slot = device_get_ivars(reqdev); | ||||
struct mmc_ios *ios = &slot->host.ios; | struct mmc_ios *ios = &slot->host.ios; | ||||
device_printf(brdev, "This is a bridge device\n"); | |||||
device_printf(reqdev, "This is a request device\n"); | |||||
slot_printf(slot, " <--- The locking slot is this\n"); | |||||
SDHCI_LOCK(slot); | SDHCI_LOCK(slot); | ||||
/* Do full reset on bus power down to clear from any state. */ | /* Do full reset on bus power down to clear from any state. */ | ||||
if (ios->power_mode == power_off) { | if (ios->power_mode == power_off) { | ||||
Context not available. | |||||
if ((state & SDHCI_CARD_PRESENT) == 0 || | if ((state & SDHCI_CARD_PRESENT) == 0 || | ||||
slot->power == 0 || | slot->power == 0 || | ||||
slot->clock == 0) { | slot->clock == 0) { | ||||
slot_printf(slot, | |||||
"Cannot issue a command (card=%d power=%d clock=%d)", | |||||
state, slot->power, slot->clock); | |||||
cmd->error = MMC_ERR_FAILED; | cmd->error = MMC_ERR_FAILED; | ||||
sdhci_req_done(slot); | sdhci_req_done(slot); | ||||
return; | return; | ||||
Context not available. | |||||
if (cmd->data || (cmd->flags & MMC_RSP_BUSY)) | if (cmd->data || (cmd->flags & MMC_RSP_BUSY)) | ||||
mask |= SDHCI_DAT_INHIBIT; | mask |= SDHCI_DAT_INHIBIT; | ||||
/* We shouldn't wait for DAT for stop commands. */ | /* We shouldn't wait for DAT for stop commands. */ | ||||
if (cmd == slot->req->stop) | /* if (cmd == slot->req->stop) | ||||
mask &= ~SDHCI_DAT_INHIBIT; | mask &= ~SDHCI_DAT_INHIBIT; | ||||
*/ | |||||
/* | /* | ||||
* Wait for bus no more then 250 ms. Typically there will be no wait | * Wait for bus no more then 250 ms. Typically there will be no wait | ||||
* here at all, but when writing a crash dump we may be bypassing the | * here at all, but when writing a crash dump we may be bypassing the | ||||
Context not available. | |||||
WR4(slot, SDHCI_ARGUMENT, cmd->arg); | WR4(slot, SDHCI_ARGUMENT, cmd->arg); | ||||
/* Set data transfer mode. */ | /* Set data transfer mode. */ | ||||
sdhci_set_transfer_mode(slot, cmd->data); | sdhci_set_transfer_mode(slot, cmd->data); | ||||
slot_printf(slot, "Starting command!\n"); | |||||
/* Start command. */ | /* Start command. */ | ||||
WR2(slot, SDHCI_COMMAND_FLAGS, (cmd->opcode << 8) | (flags & 0xff)); | WR2(slot, SDHCI_COMMAND_FLAGS, (cmd->opcode << 8) | (flags & 0xff)); | ||||
/* Start timeout callout. */ | /* Start timeout callout. */ | ||||
Context not available. | |||||
{ | { | ||||
int i; | int i; | ||||
slot_printf(slot, "%s: called, err %d flags %d\n", | |||||
__func__, slot->curcmd->error, slot->curcmd->flags); | |||||
slot->cmd_done = 1; | slot->cmd_done = 1; | ||||
/* Interrupt aggregation: Restore command interrupt. | /* Interrupt aggregation: Restore command interrupt. | ||||
* Main restore point for the case when command interrupt | * Main restore point for the case when command interrupt | ||||
Context not available. | |||||
} else | } else | ||||
slot->curcmd->resp[0] = RD4(slot, SDHCI_RESPONSE); | slot->curcmd->resp[0] = RD4(slot, SDHCI_RESPONSE); | ||||
} | } | ||||
printf("Resp: %02x %02x %02x %02x\n", | |||||
slot->curcmd->resp[0], slot->curcmd->resp[1], | |||||
slot->curcmd->resp[2], slot->curcmd->resp[3]); | |||||
/* If data ready - finish. */ | /* If data ready - finish. */ | ||||
if (slot->data_done) | if (slot->data_done) | ||||
sdhci_start(slot); | sdhci_start(slot); | ||||
Context not available. | |||||
} | } | ||||
SDHCI_UNLOCK(slot); | SDHCI_UNLOCK(slot); | ||||
/* Tell CAM the request is finished */ | |||||
slot->ccb->ccb_h.status = CAM_REQ_CMP; | |||||
xpt_done(slot->ccb); | |||||
} | } | ||||
int | int | ||||
Context not available. | |||||
{ | { | ||||
struct sdhci_slot *slot = device_get_ivars(child); | struct sdhci_slot *slot = device_get_ivars(child); | ||||
slot_printf(slot, "sdhci_generic_write_ivar, var=%d\n", which); | |||||
switch (which) { | switch (which) { | ||||
default: | default: | ||||
return (EINVAL); | return (EINVAL); | ||||
Context not available. | |||||
return (0); | return (0); | ||||
} | } | ||||
/* CAM-related functions */ | |||||
#include <cam/cam.h> | |||||
#include <cam/cam_ccb.h> | |||||
#include <cam/cam_debug.h> | |||||
#include <cam/cam_sim.h> | |||||
#include <cam/cam_xpt_sim.h> | |||||
int | |||||
sdhci_update_ios_cam(struct sdhci_slot *slot) | |||||
{ | |||||
struct mmc_ios *ios = &slot->host.ios; | |||||
slot_printf(slot, " <--- The locking slot is this\n"); | |||||
SDHCI_LOCK(slot); | |||||
/* Do full reset on bus power down to clear from any state. */ | |||||
if (ios->power_mode == power_off) { | |||||
WR4(slot, SDHCI_SIGNAL_ENABLE, 0); | |||||
sdhci_init(slot); | |||||
} | |||||
/* Configure the bus. */ | |||||
sdhci_set_clock(slot, ios->clock); | |||||
sdhci_set_power(slot, (ios->power_mode == power_off)?0:ios->vdd); | |||||
if (ios->bus_width == bus_width_4) | |||||
slot->hostctrl |= SDHCI_CTRL_4BITBUS; | |||||
else | |||||
slot->hostctrl &= ~SDHCI_CTRL_4BITBUS; | |||||
if (ios->timing == bus_timing_hs) | |||||
slot->hostctrl |= SDHCI_CTRL_HISPD; | |||||
else | |||||
slot->hostctrl &= ~SDHCI_CTRL_HISPD; | |||||
WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl); | |||||
/* Some controllers like reset after bus changes. */ | |||||
if(slot->quirks & SDHCI_QUIRK_RESET_ON_IOS) | |||||
sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA); | |||||
SDHCI_UNLOCK(slot); | |||||
return (0); | |||||
} | |||||
int | |||||
sdhci_request_cam(struct sdhci_slot *slot, union ccb *ccb) | |||||
{ | |||||
struct ccb_mmcio *mmcio; | |||||
mmcio = &ccb->mmcio; | |||||
SDHCI_LOCK(slot); | |||||
if (slot->req != NULL) { | |||||
SDHCI_UNLOCK(slot); | |||||
return (EBUSY); | |||||
} | |||||
if (sdhci_debug > 1) { | |||||
slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", | |||||
mmcio->cmd.opcode, mmcio->cmd.arg, mmcio->cmd.flags, | |||||
(mmcio->cmd.data)?(u_int)mmcio->cmd.data->len:0, | |||||
(mmcio->cmd.data)?mmcio->cmd.data->flags:0); | |||||
} | |||||
// slot->req = req; | |||||
slot->ccb = ccb; | |||||
slot->flags = 0; | |||||
sdhci_start_command(slot, &mmcio->cmd); | |||||
SDHCI_UNLOCK(slot); | |||||
if (dumping) { | |||||
while (slot->req != NULL) { | |||||
sdhci_generic_intr(slot); | |||||
DELAY(10); | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
MODULE_VERSION(sdhci, 1); | MODULE_VERSION(sdhci, 1); | ||||
Context not available. |