diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig index 984499e0107b8d..e8f2da5c9141ef 100644 --- a/arch/arm/configs/bcm2709_defconfig +++ b/arch/arm/configs/bcm2709_defconfig @@ -1283,10 +1283,11 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BCM2835_MMC=y CONFIG_MMC_BCM2835_DMA=y -CONFIG_MMC_BCM2835_SDHOST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SPI=m +CONFIG_MMC_HSQ=y +CONFIG_MMC_BCM2835=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_MULTICOLOR=m CONFIG_LEDS_PCA9532=m diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig index f21442c5328ebd..29c19c0a351914 100644 --- a/arch/arm/configs/bcm2711_defconfig +++ b/arch/arm/configs/bcm2711_defconfig @@ -1311,11 +1311,12 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BCM2835_MMC=y CONFIG_MMC_BCM2835_DMA=y -CONFIG_MMC_BCM2835_SDHOST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_IPROC=y CONFIG_MMC_SPI=m +CONFIG_MMC_HSQ=y +CONFIG_MMC_BCM2835=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_MULTICOLOR=m CONFIG_LEDS_PCA9532=m diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig index d7a15995b00c28..1c060ec754e5f0 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -1275,10 +1275,11 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BCM2835_MMC=y CONFIG_MMC_BCM2835_DMA=y -CONFIG_MMC_BCM2835_SDHOST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SPI=m +CONFIG_MMC_HSQ=y +CONFIG_MMC_BCM2835=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_MULTICOLOR=m CONFIG_LEDS_PCA9532=m diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index ec68f0595d82a4..9a8e3d167fd36e 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -1366,12 +1366,13 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BCM2835_MMC=y CONFIG_MMC_BCM2835_DMA=y -CONFIG_MMC_BCM2835_SDHOST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_OF_DWCMSHC=m CONFIG_MMC_SDHCI_IPROC=y CONFIG_MMC_SPI=m +CONFIG_MMC_HSQ=y +CONFIG_MMC_BCM2835=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_MULTICOLOR=m CONFIG_LEDS_PCA9532=m diff --git a/arch/arm64/configs/bcm2712_defconfig b/arch/arm64/configs/bcm2712_defconfig index 7579f2032e0f50..2567adec4d9420 100644 --- a/arch/arm64/configs/bcm2712_defconfig +++ b/arch/arm64/configs/bcm2712_defconfig @@ -1368,12 +1368,13 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BCM2835_MMC=y CONFIG_MMC_BCM2835_DMA=y -CONFIG_MMC_BCM2835_SDHOST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_OF_DWCMSHC=m CONFIG_MMC_SDHCI_IPROC=y CONFIG_MMC_SPI=m +CONFIG_MMC_HSQ=y +CONFIG_MMC_BCM2835=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_MULTICOLOR=m CONFIG_LEDS_PCA9532=m diff --git a/arch/arm64/configs/bcmrpi3_defconfig b/arch/arm64/configs/bcmrpi3_defconfig index 019d42e79fdcb2..6e4e66baae1a58 100644 --- a/arch/arm64/configs/bcmrpi3_defconfig +++ b/arch/arm64/configs/bcmrpi3_defconfig @@ -1257,11 +1257,12 @@ CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BCM2835_MMC=y CONFIG_MMC_BCM2835_DMA=y -CONFIG_MMC_BCM2835_SDHOST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_IPROC=m CONFIG_MMC_SPI=m +CONFIG_MMC_HSQ=y +CONFIG_MMC_BCM2835=y CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS_MULTICOLOR=m CONFIG_LEDS_PCA9532=m diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index 746a60fac0f0a2..bc4a33c35f1768 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -48,6 +48,8 @@ #include #include +#include + #define SDCMD 0x00 /* Command to SD card - 16 R/W */ #define SDARG 0x04 /* Argument to SD card - 32 R/W */ #define SDTOUT 0x08 /* Start value for timeout counter - 32 R/W */ @@ -186,6 +188,14 @@ struct bcm2835_host { struct page *drain_page; u32 drain_offset; bool use_dma; + + /* Downstream additions */ + struct rpi_firmware *fw; + u32 pio_limit; /* Maximum block count for PIO (0 = always DMA) */ + u32 user_overclock_50; /* User's preferred overclock frequency */ + u32 overclock_50; /* Freq to use when 50MHz is requested (MHz) */ + u32 overclock; /* Current frequency if overclocked, else zero */ + bool reset_clock:1; /* Reset the clock for the next request */ }; static void bcm2835_dumpcmd(struct bcm2835_host *host, struct mmc_command *cmd, @@ -240,8 +250,11 @@ static void bcm2835_dumpregs(struct bcm2835_host *host) static void bcm2835_reset_internal(struct bcm2835_host *host) { + u32 cdiv = host->cdiv; u32 temp; + if (!cdiv) + cdiv = readl(host->ioaddr + SDCDIV); writel(SDVDD_POWER_OFF, host->ioaddr + SDVDD); writel(0, host->ioaddr + SDCMD); writel(0, host->ioaddr + SDARG); @@ -262,9 +275,8 @@ static void bcm2835_reset_internal(struct bcm2835_host *host) msleep(20); writel(SDVDD_POWER_ON, host->ioaddr + SDVDD); msleep(20); - host->clock = 0; writel(host->hcfg, host->ioaddr + SDHCFG); - writel(host->cdiv, host->ioaddr + SDCDIV); + writel(cdiv, host->ioaddr + SDCDIV); } static void bcm2835_reset(struct mmc_host *mmc) @@ -595,6 +607,25 @@ static void bcm2835_finish_request(struct bcm2835_host *host) mrq = host->mrq; + /* Drop the overclock after any data corruption, or after any + * error while overclocked. Ignore errors for status commands, + * as they are likely when a card is ejected. + */ + if (host->overclock) { + if ((mrq->cmd && mrq->cmd->error && + (mrq->cmd->opcode != MMC_SEND_STATUS)) || + (mrq->data && mrq->data->error) || + (mrq->stop && mrq->stop->error) || + (mrq->sbc && mrq->sbc->error)) { + host->overclock_50--; + dev_warn(&host->pdev->dev, + "reducing overclock due to errors\n"); + host->reset_clock = 1; + mrq->cmd->error = -ETIMEDOUT; + mrq->cmd->retries = 1; + } + } + host->mrq = NULL; host->cmd = NULL; host->data = NULL; @@ -1091,8 +1122,13 @@ static void bcm2835_dma_complete_work(struct work_struct *work) static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock) { struct mmc_host *mmc = mmc_from_priv(host); + const unsigned int input_clock = clock; + const unsigned int MHZ = 1000000; int div; + if (host->overclock_50 && (clock == 50*MHZ)) + clock = host->overclock_50 * MHZ + (MHZ - 1); + /* The SDCDIV register has 11 bits, and holds (div - 2). But * in data mode the max is 50MHz wihout a minimum, and only * the bottom 3 bits are used. Since the switch over is @@ -1114,38 +1150,78 @@ static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock) * clock divisor at all times. */ - if (clock < 100000) { - /* Can't stop the clock, but make it as slow as possible - * to show willing - */ - host->cdiv = SDCDIV_MAX_CDIV; - writel(host->cdiv, host->ioaddr + SDCDIV); - return; - } + if (host->fw) { + u32 msg[3] = { clock, 0, 0 }; - div = host->max_clk / clock; - if (div < 2) - div = 2; - if ((host->max_clk / div) > clock) - div++; - div -= 2; + rpi_firmware_property(host->fw, + RPI_FIRMWARE_SET_SDHOST_CLOCK, + &msg, sizeof(msg)); - if (div > SDCDIV_MAX_CDIV) - div = SDCDIV_MAX_CDIV; + clock = max(msg[1], msg[2]); + host->cdiv = 0; + } else { + if (clock < 100000) { + /* Can't stop the clock, but make it as slow as possible + * to show willing + */ + host->cdiv = SDCDIV_MAX_CDIV; + writel(host->cdiv, host->ioaddr + SDCDIV); + return; + } - clock = host->max_clk / (div + 2); - mmc->actual_clock = clock; + div = host->max_clk / clock; + if (div < 2) + div = 2; + if ((host->max_clk / div) > clock) + div++; + div -= 2; + + if (div > SDCDIV_MAX_CDIV) + div = SDCDIV_MAX_CDIV; + + clock = host->max_clk / (div + 2); + + host->cdiv = div; + writel(host->cdiv, host->ioaddr + SDCDIV); + } /* Calibrate some delays */ host->ns_per_fifo_word = (1000000000 / clock) * ((mmc->caps & MMC_CAP_4_BIT_DATA) ? 8 : 32); - host->cdiv = div; - writel(host->cdiv, host->ioaddr + SDCDIV); + if (input_clock == 50 * MHZ) { + if (clock > input_clock) { + /* Save the closest value, to make it easier + * to reduce in the event of error + */ + host->overclock_50 = (clock/MHZ); + + if (clock != host->overclock) { + pr_info("%s: overclocking to %dHz\n", + mmc_hostname(mmc), clock); + host->overclock = clock; + } + } else if (host->overclock) { + host->overclock = 0; + if (clock == 50 * MHZ) + pr_warn("%s: cancelling overclock\n", + mmc_hostname(mmc)); + } + } else if (input_clock == 0) { + /* Reset the preferred overclock when the clock is stopped. + * This always happens during initialisation. + */ + host->overclock_50 = host->user_overclock_50; + host->overclock = 0; + } /* Set the timeout to 500ms */ - writel(mmc->actual_clock / 2, host->ioaddr + SDTOUT); + writel(clock / 2, host->ioaddr + SDTOUT); + + mmc->actual_clock = clock; + host->clock = input_clock; + host->reset_clock = 0; } static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) @@ -1175,6 +1251,9 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } + if (host->reset_clock) + bcm2835_set_clock(host, host->clock); + mutex_lock(&host->mutex); WARN_ON(host->mrq); @@ -1198,7 +1277,7 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } - if (host->use_dma && mrq->data && (mrq->data->blocks > PIO_THRESHOLD)) + if (host->use_dma && mrq->data && (mrq->data->blocks > host->pio_limit)) bcm2835_prepare_dma(host, mrq->data); host->use_sbc = !!mrq->sbc && host->mrq->data && @@ -1333,8 +1412,8 @@ static int bcm2835_add_host(struct bcm2835_host *host) } pio_limit_string[0] = '\0'; - if (host->use_dma && (PIO_THRESHOLD > 0)) - sprintf(pio_limit_string, " (>%d)", PIO_THRESHOLD); + if (host->use_dma && (host->pio_limit > 0)) + sprintf(pio_limit_string, " (>%d)", host->pio_limit); dev_info(dev, "loaded - DMA %s%s\n", host->use_dma ? "enabled" : "disabled", pio_limit_string); @@ -1344,10 +1423,13 @@ static int bcm2835_add_host(struct bcm2835_host *host) static int bcm2835_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct clk *clk; + struct device_node *node = dev->of_node; struct bcm2835_host *host; + struct rpi_firmware *fw; struct resource *iomem; + bool allow_dma = true; struct mmc_host *mmc; + struct clk *clk; int ret; dev_dbg(dev, "%s\n", __func__); @@ -1367,6 +1449,23 @@ static int bcm2835_probe(struct platform_device *pdev) } host->phys_addr = iomem->start; + host->pio_limit = PIO_THRESHOLD; + + if (node) { + /* Read any custom properties */ + of_property_read_u32(node, + "brcm,overclock-50", + &host->user_overclock_50); + of_property_read_u32(node, + "brcm,pio-limit", + &host->pio_limit); + allow_dma = + !of_property_read_bool(node, "brcm,force-pio"); + + /* Formally recognise the other way of disabling DMA */ + if (host->pio_limit == 0x7fffffff) + allow_dma = false; + } host->dma_chan = NULL; host->dma_desc = NULL; @@ -1389,6 +1488,24 @@ static int bcm2835_probe(struct platform_device *pdev) goto err; } + fw = rpi_firmware_get( + of_parse_phandle(dev->of_node, "firmware", 0)); + if (fw) { + u32 msg[3]; + + msg[0] = 0; + msg[1] = ~0; + msg[2] = ~0; + + rpi_firmware_property(fw, RPI_FIRMWARE_SET_SDHOST_CLOCK, + &msg, sizeof(msg)); + + if (msg[1] != ~0) + host->fw = fw; + else + rpi_firmware_put(fw); + } + host->max_clk = clk_get_rate(clk); host->irq = platform_get_irq(pdev, 0);