Changeset View
Standalone View
sys/dev/mmc/mmc.c
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
* herein shall be construed as an obligation by the SD Group, the SD-3C LLC | * herein shall be construed as an obligation by the SD Group, the SD-3C LLC | ||||
* or the SD Card Association to disclose or distribute any technical | * or the SD Card Association to disclose or distribute any technical | ||||
* information, know-how or other confidential information to any third party. | * information, know-how or other confidential information to any third party. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include "opt_platform.h" | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/time.h> | #include <sys/time.h> | ||||
#ifdef FDT | |||||
#include <dev/ofw/ofw_bus.h> | |||||
#include <dev/ofw/ofw_bus_subr.h> | |||||
#endif | |||||
#include <dev/mmc/mmcreg.h> | #include <dev/mmc/mmcreg.h> | ||||
#include <dev/mmc/mmcbrvar.h> | #include <dev/mmc/mmcbrvar.h> | ||||
#include <dev/mmc/mmcvar.h> | #include <dev/mmc/mmcvar.h> | ||||
#include "mmcbr_if.h" | #include "mmcbr_if.h" | ||||
#include "mmcbus_if.h" | #include "mmcbus_if.h" | ||||
#ifdef FDT | |||||
#include <dev/gpio/gpiobusvar.h> | |||||
#include <sys/gpio.h> | |||||
#endif | |||||
struct mmc_softc { | struct mmc_softc { | ||||
device_t dev; | device_t dev; | ||||
struct mtx sc_mtx; | struct mtx sc_mtx; | ||||
struct intr_config_hook config_intrhook; | struct intr_config_hook config_intrhook; | ||||
device_t owner; | device_t owner; | ||||
uint32_t last_rca; | uint32_t last_rca; | ||||
int squelched; /* suppress reporting of (expected) errors */ | int squelched; /* suppress reporting of (expected) errors */ | ||||
int log_count; | int log_count; | ||||
struct timeval log_time; | struct timeval log_time; | ||||
#ifdef FDT | |||||
gpio_pin_t cd_gpio; | |||||
bool cd_value; | |||||
#endif | |||||
}; | }; | ||||
#define LOG_PPS 5 /* Log no more than 5 errors per second. */ | #define LOG_PPS 5 /* Log no more than 5 errors per second. */ | ||||
/* | /* | ||||
* Per-card data | * Per-card data | ||||
*/ | */ | ||||
struct mmc_ivars { | struct mmc_ivars { | ||||
▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | mmc_probe(device_t dev) | ||||
device_set_desc(dev, "MMC/SD bus"); | device_set_desc(dev, "MMC/SD bus"); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
mmc_attach(device_t dev) | mmc_attach(device_t dev) | ||||
{ | { | ||||
struct mmc_softc *sc; | struct mmc_softc *sc; | ||||
#ifdef FDT | |||||
phandle_t node; | |||||
#endif | |||||
sc = device_get_softc(dev); | sc = device_get_softc(dev); | ||||
sc->dev = dev; | sc->dev = dev; | ||||
MMC_LOCK_INIT(sc); | MMC_LOCK_INIT(sc); | ||||
#ifdef FDT | |||||
/* Map the cd-gpios if it exists */ | |||||
if ((node = ofw_bus_get_node(device_get_parent(dev))) == -1) | |||||
andrew: This will break on arm64 when booting with ACPI. There is no ofw node in this case, but `FDT`… | |||||
manuAuthorUnsubmitted Not Done Inline ActionsMhm, ok, is there a way we can know we booted with ACPI ? manu: Mhm, ok, is there a way we can know we booted with ACPI ? | |||||
andrewUnsubmitted Not Done Inline ActionsYou can subclass the mmc driver for FDT. It would check if ofw_bus_get_node returns a valid node in the probe function & run these in the attach function before calling into the existing mmc_attach. You will need to change mmc_probe to return a BUS_PROBE_ so this new driver will attach. andrew: You can subclass the mmc driver for FDT. It would check if `ofw_bus_get_node` returns a valid… | |||||
return (ENXIO); | |||||
ofw_gpiobus_parse_gpios(device_get_parent(dev), "cd-gpios", &sc->cd_gpio); | |||||
loosUnsubmitted Not Done Inline ActionsThe use of ofw_gpiobus_parse_gpios() is incorrect. The *-gpios property can specify any number of pins, ofw_gpiobus_parse_gpios() will return the number of read pins and will allocate the correct amount of memory for the pins structure (with all the pins). You are supposed to free that memory after use. Here is an usage example: + /* Get GPIO power pins, if any. */ loos: The use of ofw_gpiobus_parse_gpios() is incorrect.
The *-gpios property can specify any number… | |||||
mmelUnsubmitted Not Done Inline Actionsor you can simply use gpio_pin_get_by_ofw_property(() ... mmel: or you can simply use gpio_pin_get_by_ofw_property(() ... | |||||
manuAuthorUnsubmitted Not Done Inline ActionsCorrected in my tree, thanks manu: Corrected in my tree, thanks | |||||
if (sc->cd_gpio) { | |||||
gpio_pin_setflags(sc->cd_gpio, GPIO_PIN_INPUT); | |||||
if (OF_hasprop(node, "cd-inverted") == 1) | |||||
sc->cd_value = false; | |||||
else | |||||
sc->cd_value = true; | |||||
} | |||||
#endif | |||||
/* We'll probe and attach our children later, but before / mount */ | /* We'll probe and attach our children later, but before / mount */ | ||||
sc->config_intrhook.ich_func = mmc_delayed_attach; | sc->config_intrhook.ich_func = mmc_delayed_attach; | ||||
sc->config_intrhook.ich_arg = sc; | sc->config_intrhook.ich_arg = sc; | ||||
if (config_intrhook_establish(&sc->config_intrhook) != 0) | if (config_intrhook_establish(&sc->config_intrhook) != 0) | ||||
device_printf(dev, "config_intrhook_establish failed\n"); | device_printf(dev, "config_intrhook_establish failed\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,525 Lines • ▼ Show 20 Lines | mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) | ||||
*/ | */ | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
static void | static void | ||||
mmc_delayed_attach(void *xsc) | mmc_delayed_attach(void *xsc) | ||||
{ | { | ||||
struct mmc_softc *sc = xsc; | struct mmc_softc *sc = xsc; | ||||
#ifdef FDT | |||||
bool cd_status; | |||||
if (sc->cd_gpio) { | |||||
gpio_pin_is_active(sc->cd_gpio, &cd_status); | |||||
if (cd_status != sc->cd_value) { | |||||
config_intrhook_disestablish(&sc->config_intrhook); | |||||
return; | |||||
} | |||||
} | |||||
#endif | |||||
mmc_scan(sc); | mmc_scan(sc); | ||||
config_intrhook_disestablish(&sc->config_intrhook); | config_intrhook_disestablish(&sc->config_intrhook); | ||||
} | } | ||||
static int | static int | ||||
mmc_child_location_str(device_t dev, device_t child, char *buf, | mmc_child_location_str(device_t dev, device_t child, char *buf, | ||||
size_t buflen) | size_t buflen) | ||||
{ | { | ||||
Show All 34 Lines |
This will break on arm64 when booting with ACPI. There is no ofw node in this case, but FDT may be defined.