Ühel kenal päeval, R, 07.02.2014 kell 22:33, kirjutas David Lanzendörfer:
> This is based on the driver Allwinner ships in their Android kernel 
sources.
> 
> Initial porting to upstream kernels done by David Lanzendörfer, additional
> fixes and cleanups by Hans de Goede.
> 
> It uses dma in bus-master mode using a built-in designware idmac 
controller,
> which is identical to the one found in the mmc-dw hosts.
> The rest of the host is not identical to mmc-dw.
> 
> Signed-off-by: David Lanzendörfer 
<[email protected]>
> Signed-off-by: Hans de Goede 
<[email protected]>
> ---
>  drivers/mmc/host/Kconfig     |    7 
>  drivers/mmc/host/Makefile    |    2 
>  drivers/mmc/host/sunxi-mci.c |  871 
++++++++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sunxi-mci.h |  239 ++++++++++++
>  4 files changed, 1119 insertions(+)
>  create mode 100644 drivers/mmc/host/sunxi-mci.c
>  create mode 100644 drivers/mmc/host/sunxi-mci.h
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 1384f67..7caf266 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -689,3 +689,10 @@ config MMC_REALTEK_PCI
>      help
>        Say Y here to include driver code to support SD/MMC card interface
>        of Realtek PCI-E card reader
> +
> +config MMC_SUNXI
> +    tristate "Allwinner sunxi SD/MMC Host Controller support"
> +    depends on ARCH_SUNXI
> +    help
> +      This selects support for the SD/MMC Host Controller on
> +      Allwinner sunxi SoCs.
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index 3483b6b..6c9cbd3 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -54,6 +54,8 @@ obj-$(CONFIG_MMC_WMT)        += wmt-sdmmc.o
>  
>  obj-$(CONFIG_MMC_REALTEK_PCI)    += rtsx_pci_sdmmc.o
>  
> +obj-$(CONFIG_MMC_SUNXI)        += sunxi-mci.o
> +
>  obj-$(CONFIG_MMC_SDHCI_PLTFM)        += sdhci-pltfm.o
>  obj-$(CONFIG_MMC_SDHCI_CNS3XXX)        += sdhci-cns3xxx.o
>  obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)    += sdhci-esdhc-imx.o
> diff --git a/drivers/mmc/host/sunxi-mci.c b/drivers/mmc/host/sunxi-mci.c
> new file mode 100644
> index 0000000..8b47c99
> --- /dev/null
> +++ b/drivers/mmc/host/sunxi-mci.c
> @@ -0,0 +1,871 @@
> +/*

[...]

> +
> +static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *smc_host)
> +{
> +    struct mmc_command *cmd = smc_host->mrq->cmd;
> +    struct mmc_data *data = smc_host->mrq->data;
> +
> +    /* For some cmds timeout is normal with sd/mmc cards */
> +    if ((smc_host->int_sum & SDXC_IntErrBit) == SDXC_RespTimeout &&
> +            (cmd->opcode == 5 || cmd->opcode == 52))
Aren't these the ones defined in linux/mmc/sdio.h:
5  - SD_IO_SEND_OP_COND
52 - SD_IO_RW_DIRECT

> +        return;
> +
> +    dev_err(mmc_dev(smc_host->mmc),
> +        "smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
> +        smc_host->mmc->index, cmd->opcode,
> +        data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
> +        smc_host->int_sum & SDXC_RespErr     ? " RE"     : "",
> +        smc_host->int_sum & SDXC_RespCRCErr  ? " RCE"    : "",
> +        smc_host->int_sum & SDXC_DataCRCErr  ? " DCE"    : "",
> +        smc_host->int_sum & SDXC_RespTimeout ? " RTO"    : "",
> +        smc_host->int_sum & SDXC_DataTimeout ? " DTO"    : "",
> +        smc_host->int_sum & SDXC_FIFORunErr  ? " FE"     : "",
> +        smc_host->int_sum & SDXC_HardWLocked ? " HL"     : "",
> +        smc_host->int_sum & SDXC_StartBitErr ? " SBE"    : "",
> +        smc_host->int_sum & SDXC_EndBitErr   ? " EBE"    : ""
> +        );
> +}
[...]
> +static void sunxi_mmc_set_clk_dly(struct sunxi_mmc_host *smc_host,
> +                  u32 oclk_dly, u32 sclk_dly)
> +{
> +    unsigned long iflags;
> +    struct clk_hw *hw = __clk_get_hw(smc_host->clk_mod);
> +
> +    spin_lock_irqsave(&smc_host->lock, iflags);
> +    clk_sunxi_mmc_phase_control(hw, sclk_dly, oclk_dly);
> +    spin_unlock_irqrestore(&smc_host->lock, iflags);
> +}
> +
> +struct sunxi_mmc_clk_dly mmc_clk_dly[MMC_CLK_MOD_NUM] = {
> +    { MMC_CLK_400K, 0, 7 },
> +    { MMC_CLK_25M, 0, 5 },
> +    { MMC_CLK_50M, 3, 5 },
> +    { MMC_CLK_50MDDR, 2, 4 },
> +    { MMC_CLK_50MDDR_8BIT, 2, 4 },
> +    { MMC_CLK_100M, 1, 4 },
> +    { MMC_CLK_200M, 1, 4 },

>From the looks of it, it should be static const, but apparently this was
raising a warning when David did it.. Hints anyone?

> +};
> +
> +static void sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *smc_host,
> +                   unsigned int rate)
> +{
> +    u32 newrate;
> +    u32 src_clk;
> +    u32 oclk_dly;
> +    u32 sclk_dly;
> +    u32 temp;
> +    struct sunxi_mmc_clk_dly *dly = NULL;
> +
> +    newrate = clk_round_rate(smc_host->clk_mod, rate);
> +    if (smc_host->clk_mod_rate == newrate) {
> +        dev_dbg(mmc_dev(smc_host->mmc), "clk already %d, rounded %d\n",
> +            rate, newrate);
> +        return;
> +    }
> +
> +    dev_dbg(mmc_dev(smc_host->mmc), "setting clk to %d, rounded %d\n",
> +        rate, newrate);
> +
> +    /* setting clock rate */
> +    clk_disable(smc_host->clk_mod);
> +    clk_set_rate(smc_host->clk_mod, newrate);
> +    clk_enable(smc_host->clk_mod);
> +    smc_host->clk_mod_rate = newrate = clk_get_rate(smc_host->clk_mod);
> +    dev_dbg(mmc_dev(smc_host->mmc), "clk is now %d\n", newrate);
> +
> +    sunxi_mmc_oclk_onoff(smc_host, 0);
> +    /* clear internal divider */
> +    temp = mci_readl(smc_host, REG_CLKCR);
> +    temp &= ~0xff;
> +    mci_writel(smc_host, REG_CLKCR, temp);
> +
> +    /* determine delays */
> +    if (rate <= 400000) {
> +        dly = &mmc_clk_dly[MMC_CLK_400K];
> +    } else if (rate <= 25000000) {
> +        dly = &mmc_clk_dly[MMC_CLK_25M];
> +    } else if (rate <= 50000000) {
> +        if (smc_host->ddr) {
> +            if (smc_host->bus_width == 8)
> +                dly = &mmc_clk_dly[MMC_CLK_50MDDR_8BIT];
> +            else
> +                dly = &mmc_clk_dly[MMC_CLK_50MDDR];
> +        } else {
> +            dly = &mmc_clk_dly[MMC_CLK_50M];
> +        }
> +    } else if (rate <= 104000000) {
> +        dly = &mmc_clk_dly[MMC_CLK_100M];
> +    } else if (rate <= 208000000) {
> +        dly = &mmc_clk_dly[MMC_CLK_200M];
> +    } else {
> +        dly = &mmc_clk_dly[MMC_CLK_50M];
> +    }
> +
> +    oclk_dly = dly->oclk_dly;
> +    sclk_dly = dly->sclk_dly;
> +
> +    src_clk = clk_get_rate(clk_get_parent(smc_host->clk_mod));
> +
> +    if (src_clk >= 300000000 && src_clk <= 400000000) {
> +        if (oclk_dly)
> +            oclk_dly--;
> +        if (sclk_dly)
> +            sclk_dly--;
> +    }
> +
> +    sunxi_mmc_set_clk_dly(smc_host, oclk_dly, sclk_dly);
> +    sunxi_mmc_oclk_onoff(smc_host, 1);
> +
> +    /* oclk_onoff sets various irq status bits, clear these */
> +    mci_writel(smc_host, REG_RINTR,
> +           mci_readl(smc_host, REG_RINTR) & ~SDXC_SDIOInt);
> +}
> +

[...]

> diff --git a/drivers/mmc/host/sunxi-mci.h b/drivers/mmc/host/sunxi-mci.h
> new file mode 100644
> index 0000000..4f3c2d9
> --- /dev/null
> +++ b/drivers/mmc/host/sunxi-mci.h
> @@ -0,0 +1,239 @@
> +/*
> + * Driver for sunxi SD/MMC host controllers
> + * (C) Copyright 2014-2015 Reuuimlla Technology Co., Ltd.
> + * (C) Copyright 2014-2015 Aaron Maoye 
<leafy.myeh-jFKXxz0WcGyYHARAtoI1EgC/[email protected]>
> + * (C) Copyright 2014-2015 O2S GmbH <www.o2s.ch>
> + * (C) Copyright 2014-2015 David Lanzendörfer 
<[email protected]>
> + * (C) Copyright 2014-2015 Hans de Goede 
<[email protected]>

Had to take a look at the calendar...

> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + */
> +
> +#ifndef __SUNXI_MCI_H__
> +#define __SUNXI_MCI_H__
> +

[...]

> +
> +struct sunxi_idma_des {
> +    u32    config;
> +#define SDXC_IDMAC_DES0_DIC    BIT(1)  /* disable interrupt on 
completion */
> +#define SDXC_IDMAC_DES0_LD    BIT(2)  /* last descriptor */
> +#define SDXC_IDMAC_DES0_FD    BIT(3)  /* first descriptor */
> +#define SDXC_IDMAC_DES0_CH    BIT(4)  /* chain mode */
> +#define SDXC_IDMAC_DES0_ER    BIT(5)  /* end of ring */
> +#define SDXC_IDMAC_DES0_CES    BIT(30) /* card error summary */
> +#define SDXC_IDMAC_DES0_OWN    BIT(31) /* 1-idma owns it, 0-host owns it 
*/

This #define placement inside the struct looks really weird.

> +
> +    /*
> +     * If the idma-des-size-bits of property is ie 13, bufsize bits are:
> +     *  Bits  0-12: buf1 size
> +     *  Bits 13-25: buf2 size
> +     *  Bits 26-31: not used
> +     * Since we only ever set buf1 size, we can simply store it directly.
> +     */
> +    u32    buf_size;
> +    u32    buf_addr_ptr1;
> +    u32    buf_addr_ptr2;
> +};
> +
[...]
> +
> +#define MMC_CLK_400K            0
> +#define MMC_CLK_25M             1
> +#define MMC_CLK_50M             2
> +#define MMC_CLK_50MDDR          3
> +#define MMC_CLK_50MDDR_8BIT     4
> +#define MMC_CLK_100M            5
> +#define MMC_CLK_200M            6
> +#define MMC_CLK_MOD_NUM         7
> +
> +struct sunxi_mmc_clk_dly {
> +    u32 mode;
> +    u32 oclk_dly;
> +    u32 sclk_dly;

Do these members have to be u32? They all seem to be smaller than 10.


-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to