Date: Fri, 8 Nov 2019 20:12:57 +0000 (UTC) From: Kyle Evans <kevans@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r354560 - head/sys/arm/broadcom/bcm2835 Message-ID: <201911082012.xA8KCvP0039284@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kevans Date: Fri Nov 8 20:12:57 2019 New Revision: 354560 URL: https://svnweb.freebsd.org/changeset/base/354560 Log: bcm2835_sdhci: add some very basic support for rpi4 DMA is currently disabled while I work out why it's broken, but this is enough for upstream U-Boot + rpi-firmware + our rpi3-psci-monitor to boot with the right config. The RPi 4 is still not in a good "supported" state, as we have no USB/PCI-E/Ethernet drivers, but if air-gapped pies only able to operate over cereal is your thing, here's your guy. Submitted by: Robert Crowston (with modifications) Modified: head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c Modified: head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c ============================================================================== --- head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c Fri Nov 8 20:08:44 2019 (r354559) +++ head/sys/arm/broadcom/bcm2835/bcm2835_sdhci.c Fri Nov 8 20:12:57 2019 (r354560) @@ -58,9 +58,12 @@ __FBSDID("$FreeBSD$"); #include "bcm2835_dma.h" #include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h> -#include "bcm2835_vcbus.h" +#ifdef NOTYET +#include <arm/broadcom/bcm2835/bcm2835_clkman.h> +#endif #define BCM2835_DEFAULT_SDHCI_FREQ 50 +#define BCM2838_DEFAULT_SDHCI_FREQ 100 #define BCM_SDHCI_BUFFER_SIZE 512 #define NUM_DMA_SEGS 2 @@ -84,10 +87,40 @@ SYSCTL_INT(_hw_sdhci, OID_AUTO, bcm2835_sdhci_debug, C static int bcm2835_sdhci_hs = 1; static int bcm2835_sdhci_pio_mode = 0; +struct bcm_mmc_conf { + int clock_id; + int clock_src; + int default_freq; + int power_id; + int quirks; + bool use_dma; +}; + +struct bcm_mmc_conf bcm2835_sdhci_conf = { + .clock_id = BCM2835_MBOX_CLOCK_ID_EMMC, + .clock_src = -1, + .default_freq = BCM2835_DEFAULT_SDHCI_FREQ, + .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DONT_SET_HISPD_BIT | + SDHCI_QUIRK_MISSING_CAPS, + .use_dma = true +}; + +struct bcm_mmc_conf bcm2838_emmc2_conf = { + .clock_id = BCM2838_MBOX_CLOCK_ID_EMMC2, + .clock_src = -1, + .default_freq = BCM2838_DEFAULT_SDHCI_FREQ, + .quirks = 0, + /* XXX DMA is currently broken, but it shouldn't be. */ + .use_dma = false +}; + static struct ofw_compat_data compat_data[] = { - {"broadcom,bcm2835-sdhci", 1}, - {"brcm,bcm2835-sdhci", 1}, - {"brcm,bcm2835-mmc", 1}, + {"broadcom,bcm2835-sdhci", (uintptr_t)&bcm2835_sdhci_conf}, + {"brcm,bcm2835-sdhci", (uintptr_t)&bcm2835_sdhci_conf}, + {"brcm,bcm2835-mmc", (uintptr_t)&bcm2835_sdhci_conf}, + {"brcm,bcm2711-emmc2", (uintptr_t)&bcm2838_emmc2_conf}, + {"brcm,bcm2838-emmc2", (uintptr_t)&bcm2838_emmc2_conf}, {NULL, 0} }; @@ -115,6 +148,10 @@ struct bcm_sdhci_softc { uint32_t blksz_and_count; uint32_t cmd_and_mode; bool need_update_blk; +#ifdef NOTYET + device_t clkman; +#endif + struct bcm_mmc_conf * conf; }; static int bcm_sdhci_probe(device_t); @@ -168,8 +205,12 @@ bcm_sdhci_attach(device_t dev) sc->sc_dev = dev; sc->sc_req = NULL; - err = bcm2835_mbox_set_power_state(BCM2835_MBOX_POWER_ID_EMMC, - TRUE); + sc->conf = (struct bcm_mmc_conf *)ofw_bus_search_compatible(dev, + compat_data)->ocd_data; + if (sc->conf == 0) + return (ENXIO); + + err = bcm2835_mbox_set_power_state(BCM2835_MBOX_POWER_ID_EMMC, TRUE); if (err != 0) { if (bootverbose) device_printf(dev, "Unable to enable the power\n"); @@ -177,8 +218,7 @@ bcm_sdhci_attach(device_t dev) } default_freq = 0; - err = bcm2835_mbox_get_clock_rate(BCM2835_MBOX_CLOCK_ID_EMMC, - &default_freq); + err = bcm2835_mbox_get_clock_rate(sc->conf->clock_id, &default_freq); if (err == 0) { /* Convert to MHz */ default_freq /= 1000000; @@ -190,11 +230,28 @@ bcm_sdhci_attach(device_t dev) default_freq = cell / 1000000; } if (default_freq == 0) - default_freq = BCM2835_DEFAULT_SDHCI_FREQ; + default_freq = sc->conf->default_freq; if (bootverbose) device_printf(dev, "SDHCI frequency: %dMHz\n", default_freq); +#ifdef NOTYET + if (sc->conf->clock_src > 0) { + uint32_t f; + sc->clkman = devclass_get_device(devclass_find("bcm2835_clkman"), 0); + if (sc->clkman == NULL) { + device_printf(dev, "cannot find Clock Manager\n"); + return (ENXIO); + } + f = bcm2835_clkman_set_frequency(sc->clkman, sc->conf->clock_src, default_freq); + if (f == 0) + return (EINVAL); + + if (bootverbose) + device_printf(dev, "Clock source frequency: %dMHz\n", f); + } +#endif + rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -209,7 +266,7 @@ bcm_sdhci_attach(device_t dev) rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_ACTIVE); + RF_ACTIVE | RF_SHAREABLE); if (!sc->sc_irq_res) { device_printf(dev, "cannot allocate interrupt\n"); err = ENXIO; @@ -230,36 +287,39 @@ bcm_sdhci_attach(device_t dev) if (bcm2835_sdhci_hs) sc->sc_slot.caps |= SDHCI_CAN_DO_HISPD; sc->sc_slot.caps |= (default_freq << SDHCI_CLOCK_BASE_SHIFT); - sc->sc_slot.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK - | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL - | SDHCI_QUIRK_DONT_SET_HISPD_BIT - | SDHCI_QUIRK_MISSING_CAPS; + sc->sc_slot.quirks = sc->conf->quirks; sdhci_init_slot(dev, &sc->sc_slot, 0); - sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY); - if (sc->sc_dma_ch == BCM_DMA_CH_INVALID) - goto fail; + if (sc->conf->use_dma) { + sc->sc_dma_ch = bcm_dma_allocate(BCM_DMA_CH_ANY); + if (sc->sc_dma_ch == BCM_DMA_CH_INVALID) + goto fail; - bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc); + if (bcm_dma_setup_intr(sc->sc_dma_ch, bcm_sdhci_dma_intr, sc) != 0) { + device_printf(dev, "cannot setup dma interrupt handler\n"); + err = ENXIO; + goto fail; + } - /* Allocate bus_dma resources. */ - err = bus_dma_tag_create(bus_get_dma_tag(dev), - 1, 0, BUS_SPACE_MAXADDR_32BIT, - BUS_SPACE_MAXADDR, NULL, NULL, - BCM_SDHCI_BUFFER_SIZE, NUM_DMA_SEGS, BCM_SDHCI_BUFFER_SIZE, - BUS_DMA_ALLOCNOW, NULL, NULL, - &sc->sc_dma_tag); + /* Allocate bus_dma resources. */ + err = bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, BUS_SPACE_MAXADDR_32BIT, + BUS_SPACE_MAXADDR, NULL, NULL, + BCM_SDHCI_BUFFER_SIZE, NUM_DMA_SEGS, BCM_SDHCI_BUFFER_SIZE, + BUS_DMA_ALLOCNOW, NULL, NULL, + &sc->sc_dma_tag); - if (err) { - device_printf(dev, "failed allocate DMA tag"); - goto fail; - } + if (err) { + device_printf(dev, "failed allocate DMA tag"); + goto fail; + } - err = bus_dmamap_create(sc->sc_dma_tag, 0, &sc->sc_dma_map); - if (err) { - device_printf(dev, "bus_dmamap_create failed\n"); - goto fail; + err = bus_dmamap_create(sc->sc_dma_tag, 0, &sc->sc_dma_map); + if (err) { + device_printf(dev, "bus_dmamap_create failed\n"); + goto fail; + } } /* FIXME: Fix along with other BUS_SPACE_PHYSADDR instances */ @@ -454,26 +514,25 @@ bcm_sdhci_start_dma_seg(struct bcm_sdhci_softc *sc) { struct sdhci_slot *slot; vm_paddr_t pdst, psrc; - int err, idx, len, sync_op; + int err, idx, len, sync_op, width; slot = &sc->sc_slot; idx = sc->dmamap_seg_index++; len = sc->dmamap_seg_sizes[idx]; slot->offset += len; + width = (len & 0xf ? BCM_DMA_32BIT : BCM_DMA_128BIT); if (slot->curcmd->data->flags & MMC_DATA_READ) { bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC, BCM_DMA_SAME_ADDR, BCM_DMA_32BIT); bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_NONE, - BCM_DMA_INC_ADDR, - (len & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT); + BCM_DMA_INC_ADDR, width); psrc = sc->sc_sdhci_buffer_phys; pdst = sc->dmamap_seg_addrs[idx]; sync_op = BUS_DMASYNC_PREREAD; } else { bcm_dma_setup_src(sc->sc_dma_ch, BCM_DMA_DREQ_NONE, - BCM_DMA_INC_ADDR, - (len & 0xf) ? BCM_DMA_32BIT : BCM_DMA_128BIT); + BCM_DMA_INC_ADDR, width); bcm_dma_setup_dst(sc->sc_dma_ch, BCM_DMA_DREQ_EMMC, BCM_DMA_SAME_ADDR, BCM_DMA_32BIT); psrc = sc->dmamap_seg_addrs[idx]; @@ -664,8 +723,12 @@ bcm_sdhci_write_dma(device_t dev, struct sdhci_slot *s static int bcm_sdhci_will_handle_transfer(device_t dev, struct sdhci_slot *slot) { + struct bcm_sdhci_softc *sc = device_get_softc(slot->bus); size_t left; + if (!sc->conf->use_dma) + return (0); + /* * Do not use DMA for transfers less than block size or with a length * that is not a multiple of four. @@ -744,6 +807,9 @@ static driver_t bcm_sdhci_driver = { DRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, NULL, NULL); +#ifdef NOTYET +MODULE_DEPEND(sdhci_bcm, bcm2835_clkman, 1, 1, 1); +#endif SDHCI_DEPEND(sdhci_bcm); #ifndef MMCCAM MMC_DECLARE_BRIDGE(sdhci_bcm);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201911082012.xA8KCvP0039284>