public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: "André Przywara" <andre.przywara@arm.com>
To: u-boot@lists.denx.de
Subject: [PATCH 5/6] mmc: actions: add MMC driver for Actions OWL S700
Date: Mon, 14 Dec 2020 15:43:36 +0000	[thread overview]
Message-ID: <e2875aca-2193-690d-a3fd-41bd3cb690ff@arm.com> (raw)
In-Reply-To: <CADs3TdKpTqtK=KZbT5c2L5-Sutv0_T1dpBBz-igx0oD+e_Jj1w@mail.gmail.com>

On 14/12/2020 15:02, Amit Tomar wrote:
> Hi,
> 
> You could pass a pointer to owl_mmc_priv here, which can hold both those
> 
>     values. See below for more more on this.
> 
> Did you mean for argument 3rd and 4th but then in that case how one
> could have differentiated
> between source and destination.
> 
> for instance 3rd and 4th arguments are different for read and write flag.

No, just the first two arguments (that's why I put the comment after
this line).

> 
> 
>     > +? ? ? ? ? ? ?unsigned int src, unsigned int dst,
>     > +? ? ? ? ? ? ?unsigned int len)
>     > +{
>     > +? ? ?unsigned int mode = drq;
>     > +? ? ?u8 frame_cnt = 0x1;
> 
>     Not needed, just use the 0x1 below directly.
> 
> 
> Ok.
> 
> 
>     > +
>     > +? ? ?/* Set Source and Destination adderess mode */
>     > +? ? ?mode |= (DMA_MODE_ST_DEV | DMA_MODE_SAM_CONST |
>     DMA_MODE_DT_DCU |
>     > +? ? ? ? ? ? ? ? ? ? ?DMA_MODE_DAM_INC);
>     > +
>     > +? ? ?writel(mode, dma_base + DMA_MODE);
>     > +? ? ?writel(src, dma_base + DMA_SOURCE);
>     > +? ? ?writel(dst, dma_base + DMA_DESTINATION);
>     > +? ? ?writel(len, dma_base + DMA_FRAME_LEN);
>     > +? ? ?writel(frame_cnt, dma_base + DMA_FRAME_CNT);
>     > +}
>     > +
>     > +static void owl_mmc_prepare_data(struct owl_mmc_priv *priv,
>     > +? ? ? ? ? ? ?struct mmc_data *data)
>     > +{
>     > +? ? ?unsigned int reg, total;
>     > +? ? ?uint32_t buf = 0;
>     > +
>     > +? ? ?reg = readl(priv->reg_base + OWL_REG_SD_EN);
>     > +? ? ?reg |= OWL_SD_EN_BSEL;
>     > +? ? ?writel(reg, priv->reg_base + OWL_REG_SD_EN);
>     > +
>     > +? ? ?writel(data->blocks, priv->reg_base + OWL_REG_SD_BLK_NUM);
>     > +? ? ?writel(data->blocksize, priv->reg_base + OWL_REG_SD_BLK_SIZE);
>     > +? ? ?total = data->blocksize * data->blocks;
>     > +
>     > +? ? ?if (data->blocksize < 512)
>     > +? ? ? ? ? ? ?writel(total, priv->reg_base + OWL_REG_SD_BUF_SIZE);
>     > +? ? ?else
>     > +? ? ? ? ? ? ?writel(512, priv->reg_base + OWL_REG_SD_BUF_SIZE);
>     > +
>     > +? ? ?/* DMA STOP */
>     > +? ? ?writel(0x0, (DMA0_CHANNEL_BASE(2) + DMA_START));
>     > +
>     > +? ? ?if (data) {
>     > +? ? ? ? ? ? ?if (data->flags == MMC_DATA_READ) {
> 
>     Shouldn't that be used with '&', since it's one flag among others?
> 
> 
> ,Actually, I wasn't sure about some driver uses == and other one &, even
> here in Mainline
> U-boot.

Well, flags somewhat suggests it's a bitmap, but indeed mmc.c just
assigns a value, and "1" and "2" would work in both ways.

>     > +? ? ? ? ? ? ? ? ? ? ?buf = (ulong) (data->dest);
>     > +? ? ? ? ? ? ? ? ? ? ?owl_dma_config((void *) DMA0_CHANNEL_BASE(2),
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?priv->dma_drq,
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(ulong) priv->reg_base +
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OWL_REG_SD_DAT,
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?buf, total);
>     > +? ? ? ? ? ? ? ? ? ? ?invalidate_dcache_range(buf, buf + total);
>     > +? ? ? ? ? ? ?} else if (data->flags == MMC_DATA_WRITE) {
>     > +? ? ? ? ? ? ? ? ? ? ?buf = (ulong) (data->src);
>     > +? ? ? ? ? ? ? ? ? ? ?owl_dma_config((void *) DMA0_CHANNEL_BASE(2),
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?priv->dma_drq,
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?buf,
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(ulong) priv->reg_base +
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OWL_REG_SD_DAT,
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?total);
>     > +? ? ? ? ? ? ? ? ? ? ?flush_dcache_range(buf, buf + total);
>     > +? ? ? ? ? ? ?}
>     > +? ? ? ? ? ? ?/* DMA START */
>     > +? ? ? ? ? ? ?writel(0x1, (DMA0_CHANNEL_BASE(2) + DMA_START));
>     > +? ? ?}
>     > +}
>     > +
>     > +static int owl_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
>     > +? ? ? ? ? ? ?struct mmc_data *data)
>     > +{
>     > +? ? ?struct owl_mmc_priv *priv = dev_get_priv(dev);
>     > +? ? ?unsigned int cmd_rsp_mask, mode, reg;
>     > +? ? ?int timeout = DATA_TRANSFER_TIMEOUT;
>     > +
>     > +? ? ?reg = readl(priv->reg_base + OWL_REG_SD_EN);
>     > +? ? ?reg |= OWL_SD_ENABLE;
>     > +? ? ?writel(reg, priv->reg_base + OWL_REG_SD_EN);
>     > +
>     > +? ? ?/* setup response */
>     > +? ? ?switch (cmd->resp_type) {
>     > +? ? ?case MMC_RSP_NONE:
>     > +? ? ? ? ? ? ?break;
>     > +? ? ?case MMC_RSP_R1:
>     > +? ? ? ? ? ? ?if (data) {
>     > +? ? ? ? ? ? ? ? ? ? ?if (data->flags == MMC_DATA_READ)
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ?mode = OWL_SD_CTL_TM(4);
>     > +? ? ? ? ? ? ? ? ? ? ?else
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ?mode = OWL_SD_CTL_TM(5);
>     > +? ? ? ? ? ? ?} else {
>     > +? ? ? ? ? ? ? ? ? ? ?mode = OWL_SD_CTL_TM(1);
>     > +? ? ? ? ? ? ?}
>     > +? ? ? ? ? ? ?cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER;
>     > +? ? ? ? ? ? ?break;
>     > +? ? ?case MMC_RSP_R1b:
>     > +? ? ? ? ? ? ?mode = OWL_SD_CTL_TM(3);
>     > +? ? ? ? ? ? ?cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER;
>     > +? ? ? ? ? ? ?break;
>     > +? ? ?case MMC_RSP_R2:
>     > +? ? ? ? ? ? ?mode = OWL_SD_CTL_TM(2);
>     > +? ? ? ? ? ? ?cmd_rsp_mask = OWL_SD_STATE_CLNR | OWL_SD_STATE_CRC7ER;
>     > +? ? ? ? ? ? ?break;
>     > +? ? ?case MMC_RSP_R3:
>     > +? ? ? ? ? ? ?cmd->cmdarg = 0x40ff8000;
>     > +? ? ? ? ? ? ?mode = OWL_SD_CTL_TM(1);
>     > +? ? ? ? ? ? ?cmd_rsp_mask = OWL_SD_STATE_CLNR;
>     > +? ? ? ? ? ? ?break;
>     > +? ? ?default:
>     > +? ? ? ? ? ? ?printf("error: no math command RSP flag %x\n",
>     cmd->cmdarg);
>     > +? ? ? ? ? ? ?return -1;
>     > +? ? ?}
>     > +
>     > +? ? ?mode |= (readl(priv->reg_base + OWL_REG_SD_CTL) & (0xff << 16));
>     > +
>     > +? ? ?/* setup command */
>     > +? ? ?writel(cmd->cmdidx, priv->reg_base + OWL_REG_SD_CMD);
>     > +? ? ?writel(cmd->cmdarg, priv->reg_base + OWL_REG_SD_ARG);
>     > +
>     > +? ? ?/* Set LBE to send clk at the end of last read block */
>     > +? ? ?if (data)
>     > +? ? ? ? ? ? ?mode |= (OWL_SD_CTL_TS | OWL_SD_CTL_LBE | 0xE4000000);
>     > +? ? ?else
>     > +? ? ? ? ? ? ?mode |= OWL_SD_CTL_TS;
>     > +
>     > +? ? ?if (data)
>     > +? ? ? ? ? ? ?owl_mmc_prepare_data(priv, data);
>     > +
>     > +? ? ?/* Start transfer */
>     > +? ? ?writel(mode, priv->reg_base + OWL_REG_SD_CTL);
>     > +
>     > +? ? ?while ((readl(priv->reg_base + OWL_REG_SD_CTL) & OWL_SD_CTL_TS)
>     > +? ? ? ? ? ? ? ? ? ? ?&& timeout--)
>     > +? ? ? ? ? ? ?udelay(20);
>     > +
>     > +? ? ?if (!timeout) {
>     > +? ? ? ? ? ? ?printf("error: transferred data timeout\n");
>     > +? ? ? ? ? ? ?return -ETIMEDOUT;
>     > +? ? ?}
>     > +
>     > +? ? ?if (cmd->resp_type & MMC_RSP_136) {
>     > +? ? ? ? ? ? ?cmd->response[3] = readl(priv->reg_base +
>     OWL_REG_SD_RSPBUF0);
>     > +? ? ? ? ? ? ?cmd->response[2] = readl(priv->reg_base +
>     OWL_REG_SD_RSPBUF1);
>     > +? ? ? ? ? ? ?cmd->response[1] = readl(priv->reg_base +
>     OWL_REG_SD_RSPBUF2);
>     > +? ? ? ? ? ? ?cmd->response[0] = readl(priv->reg_base +
>     OWL_REG_SD_RSPBUF3);
>     > +? ? ?} else {
>     > +? ? ? ? ? ? ?u32 rsp[2];
>     > +
>     > +? ? ? ? ? ? ?rsp[0] = readl(priv->reg_base + OWL_REG_SD_RSPBUF0);
>     > +? ? ? ? ? ? ?rsp[1] = readl(priv->reg_base + OWL_REG_SD_RSPBUF1);
>     > +? ? ? ? ? ? ?cmd->response[0] = rsp[1] << 24 | rsp[0] >> 8;
>     > +? ? ? ? ? ? ?cmd->response[1] = rsp[1] >> 8;
>     > +? ? ?}
>     > +
>     > +? ? ?if (data) {
>     > +? ? ? ? ? ? ?/* DMA STOP */
>     > +? ? ? ? ? ? ?writel(0x0, (DMA0_CHANNEL_BASE(2) + DMA_START));
>     > +? ? ? ? ? ? ?/* Transmission STOP */
>     > +? ? ? ? ? ? ?while (readl(priv->reg_base + OWL_REG_SD_CTL) &
>     OWL_SD_CTL_TS)
>     > +? ? ? ? ? ? ? ? ? ? ?clrbits_le32(priv->reg_base + OWL_REG_SD_CTL,
>     > +? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?OWL_SD_CTL_TS);
>     > +? ? ?}
>     > +
>     > +? ? ?return 0;
>     > +}
>     > +
>     > +static void owl_mmc_clk_set(struct owl_mmc_priv *priv, int rate)
>     > +{
>     > +? ? ?u32 reg;
>     > +
>     > +? ? ?reg = readl(priv->reg_base + OWL_REG_SD_CTL);
>     > +? ? ?reg &= ~OWL_SD_CTL_DELAY_MSK;
>     > +
>     > +? ? ?/* Set RDELAY and WDELAY based on the clock */
>     > +? ? ?if (rate <= 1000000) {
>     > +? ? ? ? ? ? ?writel(reg | OWL_SD_CTL_RDELAY(OWL_SD_DELAY_LOW_CLK) |
>     > +? ? ? ? ? ? ? ? ? ? ?OWL_SD_CTL_WDELAY(OWL_SD_DELAY_LOW_CLK),
>     > +? ? ? ? ? ? ? ? ? ? ?priv->reg_base + OWL_REG_SD_CTL);
>     > +? ? ?} else if ((rate > 1000000) && (rate <= 26000000)) {
>     > +? ? ? ? ? ? ?writel(reg | OWL_SD_CTL_RDELAY(OWL_SD_DELAY_MID_CLK) |
>     > +? ? ? ? ? ? ? ? ? ? ?OWL_SD_CTL_WDELAY(OWL_SD_DELAY_MID_CLK),
>     > +? ? ? ? ? ? ? ? ? ? ?priv->reg_base + OWL_REG_SD_CTL);
>     > +? ? ?} else if ((rate > 26000000) && (rate <= 52000000)) {
>     > +? ? ? ? ? ? ?writel(reg | OWL_SD_CTL_RDELAY(OWL_SD_RDELAY_HIGH) |
>     > +? ? ? ? ? ? ? ? ? ? ?OWL_SD_CTL_WDELAY(OWL_SD_WDELAY_HIGH),
>     > +? ? ? ? ? ? ? ? ? ? ?priv->reg_base + OWL_REG_SD_CTL);
>     > +? ? ?} else {
>     > +? ? ? ? ? ? ?printf("SD clock rate not supported\n");
>     > +? ? ?}
>     > +}
>     > +
>     > +static int owl_mmc_set_ios(struct udevice *dev)
>     > +{
>     > +? ? ?struct owl_mmc_priv *priv = dev_get_priv(dev);
>     > +? ? ?struct owl_mmc_plat *plat = dev_get_platdata(dev);
>     > +? ? ?struct mmc *mmc = &plat->mmc;
>     > +? ? ?u32 reg, ret;
>     > +
>     > +? ? ?if (mmc->clock != priv->clock) {
>     > +? ? ? ? ? ? ?priv->clock = mmc->clock;
>     > +? ? ? ? ? ? ?owl_mmc_clk_set(priv, mmc->clock);
>     > +? ? ?}
>     > +
>     > +? ? ?ret = clk_set_rate(&priv->clk, mmc->clock);
>     > +? ? ?if (IS_ERR_VALUE(ret))
>     > +? ? ? ? ? ? ?return ret;
>     > +
>     > +? ? ?ret = clk_enable(&priv->clk);
>     > +? ? ?if (ret)
>     > +? ? ? ? ? ? ?return ret;
>     > +
>     > +? ? ?/* Set the Bus width */
>     > +? ? ?reg = readl(priv->reg_base + OWL_REG_SD_EN);
>     > +? ? ?reg &= ~0x03;
>     > +? ? ?if (mmc->bus_width == 8)
>     > +? ? ? ? ? ? ?reg |= OWL_SD_EN_DATAWID(2);
>     > +? ? ?else if (mmc->bus_width == 4)
>     > +? ? ? ? ? ? ?reg |= OWL_SD_EN_DATAWID(1);
>     > +
>     > +? ? ?writel(reg, priv->reg_base + OWL_REG_SD_EN);
>     > +
>     > +? ? ?return 0;
>     > +}
>     > +
>     > +static const struct dm_mmc_ops owl_mmc_ops = {
>     > +? ? ?.send_cmd? ? ? ?= owl_mmc_send_cmd,
>     > +? ? ?.set_ios? ? ? ? = owl_mmc_set_ios,
>     > +};
>     > +
>     > +static int owl_mmc_probe(struct udevice *dev)
>     > +{
>     > +? ? ?struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
>     > +? ? ?struct owl_mmc_plat *plat = dev_get_platdata(dev);
>     > +? ? ?struct owl_mmc_priv *priv = dev_get_priv(dev);
>     > +? ? ?struct mmc_config *cfg = &plat->cfg;
>     > +? ? ?int bus_width, ret;
>     > +? ? ?fdt_addr_t addr;
>     > +
>     > +? ? ?cfg->name = dev->name;
>     > +? ? ?cfg->voltages = OWL_MMC_OCR;
>     > +? ? ?cfg->f_min = 400000;
>     > +? ? ?cfg->f_max = 52000000;
>     > +? ? ?cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
>     > +
>     > +? ? ?bus_width = dev_read_u32_default(dev, "bus-width", 1);
>     > +? ? ?switch (bus_width) {
>     > +? ? ?case 8:
>     > +? ? ? ? ? ? ?cfg->host_caps |= MMC_MODE_8BIT;
>     > +? ? ? ? ? ? ?/* Hosts capable of 8-bit transfers can also do 4
>     bits */
>     > +? ? ?case 4:
>     > +? ? ? ? ? ? ?cfg->host_caps |= MMC_MODE_4BIT;
>     > +? ? ? ? ? ? ?break;
>     > +? ? ?case 1:
>     > +? ? ? ? ? ? ?break;
>     > +? ? ?default:
>     > +? ? ? ? ? ? ?printf("Invalid bus-width value %u\n", bus_width);
>     > +? ? ?}
>     > +? ? ?cfg->host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz;
>     > +
>     > +? ? ?addr = dev_read_addr(dev);
>     > +? ? ?if (addr == FDT_ADDR_T_NONE)
>     > +? ? ? ? ? ? ?return -EINVAL;
>     > +
>     > +? ? ?priv->reg_base = (void *)addr;
>     > +? ? ?priv->dma_drq? = 0x2;
>     > +
>     > +? ? ?ret = clk_get_by_index(dev, 0, &priv->clk);
>     > +? ? ?if (ret) {
>     > +? ? ? ? ? ? ?debug("clk_get_by_index() failed: %d\n", ret);
>     > +? ? ? ? ? ? ?return ret;
>     > +? ? ?}
> 
>     You should read the DMA parameters from the DT here. What you currently
>     hard code (channel 2) only works for the first MMC.
>     It should be fairly straight-forward to follow the phandle and get the
>     base address of the DMA device, and to read the second argument to learn
>     the DRQ number. Then put this into priv and use it in dma_config().
> 
>     Yeah, I initially thought about it but I wasn't sure that This
>     device trigger value is exactly matching to
> 
> ?? DAM channel number, So I left the idea of having it.

You should be able to verify this in in the Linux code.

Cheers,
Andre

  reply	other threads:[~2020-12-14 15:43 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-13 10:08 [PATCH 0/6] Add MMC/SD support for S700 Amit Singh Tomar
2020-12-13 10:08 ` [PATCH 1/6] clk: actions: Introduce dummy get/set_rate callbacks Amit Singh Tomar
2020-12-13 10:08 ` [PATCH 2/6] clk: actions: Add SD/MMC clocks Amit Singh Tomar
2020-12-13 10:08 ` [PATCH 3/6] ARM: dts: sync Actions Semi S700 DT from Linux 5.10-rc7 Amit Singh Tomar
2020-12-13 10:08 ` [PATCH 4/6] ARM: dts: s700: add MMC/SD controller node Amit Singh Tomar
2020-12-13 10:08 ` [PATCH 5/6] mmc: actions: add MMC driver for Actions OWL S700 Amit Singh Tomar
2020-12-14  0:49   ` Jaehoon Chung
2020-12-14 14:42     ` Amit Tomar
2020-12-14 13:56   ` André Przywara
2020-12-14 15:02     ` Amit Tomar
2020-12-14 15:43       ` André Przywara [this message]
2020-12-13 10:08 ` [PATCH 6/6] configs: Enable mmc support Amit Singh Tomar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e2875aca-2193-690d-a3fd-41bd3cb690ff@arm.com \
    --to=andre.przywara@arm.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox