Changeset View
Changeset View
Standalone View
Standalone View
sys/arm/ti/ti_sdhci.c
Context not available. | |||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||
#include <sys/lock.h> | |||||
#include <sys/mutex.h> | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
Context not available. | |||||
#include <dev/mmc/mmcreg.h> | #include <dev/mmc/mmcreg.h> | ||||
#include <dev/mmc/mmcbrvar.h> | #include <dev/mmc/mmcbrvar.h> | ||||
/* CAM includes */ | |||||
#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 <dev/sdhci/sdhci.h> | #include <dev/sdhci/sdhci.h> | ||||
#include "sdhci_if.h" | #include "sdhci_if.h" | ||||
Context not available. | |||||
uint32_t sdhci_clkdiv; | uint32_t sdhci_clkdiv; | ||||
boolean_t disable_highspeed; | boolean_t disable_highspeed; | ||||
boolean_t force_card_present; | boolean_t force_card_present; | ||||
struct mtx sc_mtx; | |||||
struct cam_devq *devq; | |||||
struct cam_sim *sim; | |||||
struct cam_path *path; | |||||
}; | }; | ||||
/* | /* | ||||
Context not available. | |||||
#define MMCHS_SD_CAPA_VS30 (1 << 25) | #define MMCHS_SD_CAPA_VS30 (1 << 25) | ||||
#define MMCHS_SD_CAPA_VS33 (1 << 24) | #define MMCHS_SD_CAPA_VS33 (1 << 24) | ||||
/* Forward declarations, CAM-relataed */ | |||||
static void ti_sdhci_cam_poll(struct cam_sim *); | |||||
static void ti_sdhci_cam_action(struct cam_sim *, union ccb *); | |||||
static int ti_sdhci_cam_settran_settings(struct ti_sdhci_softc *sc, union ccb *); | |||||
static inline uint32_t | static inline uint32_t | ||||
ti_mmchs_read_4(struct ti_sdhci_softc *sc, bus_size_t off) | ti_mmchs_read_4(struct ti_sdhci_softc *sc, bus_size_t off) | ||||
{ | { | ||||
Context not available. | |||||
bus_generic_probe(dev); | bus_generic_probe(dev); | ||||
bus_generic_attach(dev); | bus_generic_attach(dev); | ||||
sdhci_start_slot(&sc->slot); | // sdhci_start_slot(&sc->slot); | ||||
/* CAM-specific init */ | |||||
mtx_init(&sc->sc_mtx, "tisdhcimtx", NULL, MTX_DEF); | |||||
if ((sc->devq = cam_simq_alloc(1)) == NULL) { | |||||
err = ENOMEM; | |||||
goto fail; | |||||
} | |||||
sc->sim = cam_sim_alloc(ti_sdhci_cam_action, ti_sdhci_cam_poll, | |||||
"ti_sdhci", sc, device_get_unit(dev), | |||||
&sc->sc_mtx, 1, 1, sc->devq); | |||||
if (sc->sim == NULL) { | |||||
cam_simq_free(sc->devq); | |||||
device_printf(dev, "cannot allocate CAM SIM\n"); | |||||
err = EINVAL; | |||||
goto fail; | |||||
} | |||||
mtx_lock(&sc->sc_mtx); | |||||
if (xpt_bus_register(sc->sim, dev, 0) != 0) { | |||||
device_printf(dev, | |||||
"cannot register SCSI pass-through bus\n"); | |||||
cam_sim_free(sc->sim, FALSE); | |||||
cam_simq_free(sc->devq); | |||||
mtx_unlock(&sc->sc_mtx); | |||||
err = EINVAL; | |||||
goto fail; | |||||
} | |||||
mtx_unlock(&sc->sc_mtx); | |||||
/* End CAM-specific init */ | |||||
return (0); | return (0); | ||||
Context not available. | |||||
if (sc->mem_res) | if (sc->mem_res) | ||||
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); | bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); | ||||
if (sc->sim != NULL) { | |||||
mtx_lock(&sc->sc_mtx); | |||||
xpt_bus_deregister(cam_sim_path(sc->sim)); | |||||
cam_sim_free(sc->sim, FALSE); | |||||
mtx_unlock(&sc->sc_mtx); | |||||
} | |||||
if (sc->devq != NULL) | |||||
cam_simq_free(sc->devq); | |||||
return (err); | return (err); | ||||
} | } | ||||
Context not available. | |||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
static void | |||||
ti_sdhci_handle_mmcio(struct cam_sim *sim, union ccb *ccb) | |||||
{ | |||||
struct ti_sdhci_softc *sc; | |||||
sc = cam_sim_softc(sim); | |||||
sdhci_request_cam(&sc->slot, ccb); | |||||
} | |||||
static void | |||||
ti_sdhci_cam_action(struct cam_sim *sim, union ccb *ccb) | |||||
{ | |||||
struct ti_sdhci_softc *sc; | |||||
sc = cam_sim_softc(sim); | |||||
if (sc == NULL) { | |||||
ccb->ccb_h.status = CAM_SEL_TIMEOUT; | |||||
xpt_done(ccb); | |||||
return; | |||||
} | |||||
mtx_assert(&sc->sc_mtx, MA_OWNED); | |||||
device_printf(sc->dev, "action: func_code %0x\n", ccb->ccb_h.func_code); | |||||
switch (ccb->ccb_h.func_code) { | |||||
case XPT_PATH_INQ: | |||||
{ | |||||
struct ccb_pathinq *cpi; | |||||
cpi = &ccb->cpi; | |||||
cpi->version_num = 1; | |||||
cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_16; | |||||
cpi->target_sprt = 0; | |||||
cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN; | |||||
cpi->hba_eng_cnt = 0; | |||||
cpi->max_target = 0; | |||||
cpi->max_lun = 0; | |||||
cpi->initiator_id = 1; | |||||
strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); | |||||
strncpy(cpi->hba_vid, "Deglitch Networks", HBA_IDLEN); | |||||
strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); | |||||
cpi->unit_number = cam_sim_unit(sim); | |||||
cpi->bus_id = cam_sim_bus(sim); | |||||
cpi->base_transfer_speed = 100; /* XXX WTF? */ | |||||
cpi->protocol = PROTO_MMCSD; | |||||
cpi->protocol_version = SCSI_REV_0; | |||||
cpi->transport = XPORT_MMCSD; | |||||
cpi->transport_version = 0; | |||||
cpi->ccb_h.status = CAM_REQ_CMP; | |||||
break; | |||||
} | |||||
case XPT_GET_TRAN_SETTINGS: | |||||
{ | |||||
struct ccb_trans_settings *cts = &ccb->cts; | |||||
device_printf(sc->dev, "Got XPT_GET_TRAN_SETTINGS\n"); | |||||
cts->protocol = PROTO_MMCSD; | |||||
cts->protocol_version = 0; | |||||
cts->transport = XPORT_MMCSD; | |||||
cts->transport_version = 0; | |||||
cts->xport_specific.valid = 0; | |||||
cts->proto_specific.mmc.host_ocr = sc->slot.host.host_ocr; | |||||
ccb->ccb_h.status = CAM_REQ_CMP; | |||||
break; | |||||
} | |||||
case XPT_SET_TRAN_SETTINGS: | |||||
device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS, should update IOS...\n"); | |||||
ti_sdhci_cam_settran_settings(sc, ccb); | |||||
ccb->ccb_h.status = CAM_REQ_CMP; | |||||
break; | |||||
case XPT_RESET_BUS: | |||||
device_printf(sc->dev, "Got XPT_RESET_BUS, ACK it...\n"); | |||||
ccb->ccb_h.status = CAM_REQ_CMP; | |||||
break; | |||||
case XPT_MMC_IO: | |||||
/* | |||||
* Here is the HW-dependent part of | |||||
* sending the command to the underlying h/w | |||||
* At some point in the future an interrupt comes. | |||||
* Then the request will be marked as completed. | |||||
*/ | |||||
device_printf(sc->dev, "Got XPT_MMC_IO\n"); | |||||
ccb->ccb_h.status = CAM_REQ_INPROG; | |||||
ti_sdhci_handle_mmcio(sim, ccb); | |||||
return; | |||||
/* NOTREACHED */ | |||||
break; | |||||
default: | |||||
ccb->ccb_h.status = CAM_REQ_INVALID; | |||||
break; | |||||
} | |||||
xpt_done(ccb); | |||||
return; | |||||
} | |||||
static void | |||||
ti_sdhci_cam_poll(struct cam_sim *sim) | |||||
{ | |||||
return; | |||||
} | |||||
static int | |||||
ti_sdhci_cam_settran_settings(struct ti_sdhci_softc *sc, union ccb *ccb) | |||||
{ | |||||
struct sdhci_slot *slot; | |||||
struct mmc_ios *ios; | |||||
struct mmc_ios *new_ios; | |||||
uint32_t val32; | |||||
struct ccb_trans_settings_mmc *cts; | |||||
slot = &sc->slot; | |||||
ios = &slot->host.ios; | |||||
cts = &ccb->cts.proto_specific.mmc; | |||||
new_ios = &cts->ios; | |||||
/* Update only requested fields */ | |||||
if (cts->ios_valid & MMC_CLK) | |||||
ios->clock = new_ios->clock; | |||||
if (cts->ios_valid & MMC_VDD) { | |||||
ios->vdd = new_ios->vdd; | |||||
device_printf(sc->dev, "VDD => %d\n", ios->vdd); | |||||
} | |||||
if (cts->ios_valid & MMC_CS) | |||||
ios->chip_select = new_ios->chip_select; | |||||
if (cts->ios_valid & MMC_BW) | |||||
ios->bus_width = new_ios->bus_width; | |||||
if (cts->ios_valid & MMC_PM) | |||||
ios->power_mode = new_ios->power_mode; | |||||
if (cts->ios_valid & MMC_BT) | |||||
ios->timing = new_ios->timing; | |||||
if (cts->ios_valid & MMC_BM) | |||||
ios->bus_mode = new_ios->bus_mode; | |||||
/* | |||||
* There is an 8-bit-bus bit in the MMCHS control register which, when | |||||
* set, overrides the 1 vs 4 bit setting in the standard SDHCI | |||||
* registers. Set that bit first according to whether an 8-bit bus is | |||||
* requested, then let the standard driver handle everything else. | |||||
*/ | |||||
val32 = ti_mmchs_read_4(sc, MMCHS_CON); | |||||
if (ios->bus_width == bus_width_8) | |||||
ti_mmchs_write_4(sc, MMCHS_CON, val32 | MMCHS_CON_DW8); | |||||
else | |||||
ti_mmchs_write_4(sc, MMCHS_CON, val32 & ~MMCHS_CON_DW8); | |||||
return (sdhci_update_ios_cam(slot)); | |||||
} | |||||
static device_method_t ti_sdhci_methods[] = { | static device_method_t ti_sdhci_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, ti_sdhci_probe), | DEVMETHOD(device_probe, ti_sdhci_probe), | ||||
Context not available. |