arm: pxa: mmc: add driver model support

Add driver model (DM) support.

Signed-off-by: Marcel Ziswiler <marcel@ziswiler.com>
This commit is contained in:
Marcel Ziswiler 2019-05-20 02:44:59 +02:00 committed by Tom Rini
parent 9b515a81be
commit 290e6bb958
2 changed files with 154 additions and 28 deletions

View file

@ -2,6 +2,9 @@
/* /*
* Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
* *
* Modified to add driver model (DM) support
* Copyright (C) 2019 Marcel Ziswiler <marcel@ziswiler.com>
*
* Loosely based on the old code and Linux's PXA MMC driver * Loosely based on the old code and Linux's PXA MMC driver
*/ */
@ -11,6 +14,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/io.h> #include <asm/io.h>
#include <dm.h>
#include <dm/platform_data/pxa_mmc_gen.h>
#include <malloc.h> #include <malloc.h>
#include <mmc.h> #include <mmc.h>
@ -96,7 +101,7 @@ static int pxa_mmc_stop_clock(struct mmc *mmc)
} }
static int pxa_mmc_start_cmd(struct mmc *mmc, struct mmc_cmd *cmd, static int pxa_mmc_start_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
uint32_t cmdat) uint32_t cmdat)
{ {
struct pxa_mmc_priv *priv = mmc->priv; struct pxa_mmc_priv *priv = mmc->priv;
struct pxa_mmc_regs *regs = priv->regs; struct pxa_mmc_regs *regs = priv->regs;
@ -143,7 +148,7 @@ static int pxa_mmc_cmd_done(struct mmc *mmc, struct mmc_cmd *cmd)
{ {
struct pxa_mmc_priv *priv = mmc->priv; struct pxa_mmc_priv *priv = mmc->priv;
struct pxa_mmc_regs *regs = priv->regs; struct pxa_mmc_regs *regs = priv->regs;
uint32_t a, b, c; u32 a, b, c;
int i; int i;
int stat; int stat;
@ -152,7 +157,7 @@ static int pxa_mmc_cmd_done(struct mmc *mmc, struct mmc_cmd *cmd)
/* /*
* Linux says: * Linux says:
* Did I mention this is Sick. We always need to * Did I mention this is Sick. We always need to
* discard the upper 8 bits of the first 16-bit word. * discard the upper 8 bits of the first 16-bit word.
*/ */
a = readl(&regs->res) & 0xffff; a = readl(&regs->res) & 0xffff;
@ -164,13 +169,13 @@ static int pxa_mmc_cmd_done(struct mmc *mmc, struct mmc_cmd *cmd)
} }
/* The command response didn't arrive */ /* The command response didn't arrive */
if (stat & MMC_STAT_TIME_OUT_RESPONSE) if (stat & MMC_STAT_TIME_OUT_RESPONSE) {
return -ETIMEDOUT; return -ETIMEDOUT;
else if (stat & MMC_STAT_RES_CRC_ERROR } else if (stat & MMC_STAT_RES_CRC_ERROR &&
&& cmd->resp_type & MMC_RSP_CRC) { cmd->resp_type & MMC_RSP_CRC) {
#ifdef PXAMMC_CRC_SKIP #ifdef PXAMMC_CRC_SKIP
if (cmd->resp_type & MMC_RSP_136 if (cmd->resp_type & MMC_RSP_136 &&
&& cmd->response[0] & (1 << 31)) cmd->response[0] & (1 << 31))
printf("Ignoring CRC, this may be dangerous!\n"); printf("Ignoring CRC, this may be dangerous!\n");
else else
#endif #endif
@ -185,8 +190,8 @@ static int pxa_mmc_do_read_xfer(struct mmc *mmc, struct mmc_data *data)
{ {
struct pxa_mmc_priv *priv = mmc->priv; struct pxa_mmc_priv *priv = mmc->priv;
struct pxa_mmc_regs *regs = priv->regs; struct pxa_mmc_regs *regs = priv->regs;
uint32_t len; u32 len;
uint32_t *buf = (uint32_t *)data->dest; u32 *buf = (uint32_t *)data->dest;
int size; int size;
int ret; int ret;
@ -202,7 +207,6 @@ static int pxa_mmc_do_read_xfer(struct mmc *mmc, struct mmc_data *data)
/* Read data into the buffer */ /* Read data into the buffer */
while (size--) while (size--)
*buf++ = readl(&regs->rxfifo); *buf++ = readl(&regs->rxfifo);
} }
if (readl(&regs->stat) & MMC_STAT_ERRORS) if (readl(&regs->stat) & MMC_STAT_ERRORS)
@ -221,8 +225,8 @@ static int pxa_mmc_do_write_xfer(struct mmc *mmc, struct mmc_data *data)
{ {
struct pxa_mmc_priv *priv = mmc->priv; struct pxa_mmc_priv *priv = mmc->priv;
struct pxa_mmc_regs *regs = priv->regs; struct pxa_mmc_regs *regs = priv->regs;
uint32_t len; u32 len;
uint32_t *buf = (uint32_t *)data->src; u32 *buf = (uint32_t *)data->src;
int size; int size;
int ret; int ret;
@ -259,12 +263,11 @@ static int pxa_mmc_do_write_xfer(struct mmc *mmc, struct mmc_data *data)
return 0; return 0;
} }
static int pxa_mmc_request(struct mmc *mmc, struct mmc_cmd *cmd, static int pxa_mmc_send_cmd_common(struct pxa_mmc_priv *priv, struct mmc *mmc,
struct mmc_data *data) struct mmc_cmd *cmd, struct mmc_data *data)
{ {
struct pxa_mmc_priv *priv = mmc->priv;
struct pxa_mmc_regs *regs = priv->regs; struct pxa_mmc_regs *regs = priv->regs;
uint32_t cmdat = 0; u32 cmdat = 0;
int ret; int ret;
/* Stop the controller */ /* Stop the controller */
@ -313,12 +316,11 @@ static int pxa_mmc_request(struct mmc *mmc, struct mmc_cmd *cmd,
return 0; return 0;
} }
static int pxa_mmc_set_ios(struct mmc *mmc) static int pxa_mmc_set_ios_common(struct pxa_mmc_priv *priv, struct mmc *mmc)
{ {
struct pxa_mmc_priv *priv = mmc->priv;
struct pxa_mmc_regs *regs = priv->regs; struct pxa_mmc_regs *regs = priv->regs;
uint32_t tmp; u32 tmp;
uint32_t pxa_mmc_clock; u32 pxa_mmc_clock;
if (!mmc->clock) { if (!mmc->clock) {
pxa_mmc_stop_clock(mmc); pxa_mmc_stop_clock(mmc);
@ -346,9 +348,8 @@ static int pxa_mmc_set_ios(struct mmc *mmc)
return 0; return 0;
} }
static int pxa_mmc_init(struct mmc *mmc) static int pxa_mmc_init_common(struct pxa_mmc_priv *priv, struct mmc *mmc)
{ {
struct pxa_mmc_priv *priv = mmc->priv;
struct pxa_mmc_regs *regs = priv->regs; struct pxa_mmc_regs *regs = priv->regs;
/* Make sure the clock are stopped */ /* Make sure the clock are stopped */
@ -362,10 +363,34 @@ static int pxa_mmc_init(struct mmc *mmc)
/* Mask all interrupts */ /* Mask all interrupts */
writel(~(MMC_I_MASK_TXFIFO_WR_REQ | MMC_I_MASK_RXFIFO_RD_REQ), writel(~(MMC_I_MASK_TXFIFO_WR_REQ | MMC_I_MASK_RXFIFO_RD_REQ),
&regs->i_mask); &regs->i_mask);
return 0; return 0;
} }
#if !CONFIG_IS_ENABLED(DM_MMC)
static int pxa_mmc_init(struct mmc *mmc)
{
struct pxa_mmc_priv *priv = mmc->priv;
return pxa_mmc_init_common(priv, mmc);
}
static int pxa_mmc_request(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct pxa_mmc_priv *priv = mmc->priv;
return pxa_mmc_send_cmd_common(priv, mmc, cmd, data);
}
static int pxa_mmc_set_ios(struct mmc *mmc)
{
struct pxa_mmc_priv *priv = mmc->priv;
return pxa_mmc_set_ios_common(priv, mmc);
}
static const struct mmc_ops pxa_mmc_ops = { static const struct mmc_ops pxa_mmc_ops = {
.send_cmd = pxa_mmc_request, .send_cmd = pxa_mmc_request,
.set_ios = pxa_mmc_set_ios, .set_ios = pxa_mmc_set_ios,
@ -386,7 +411,7 @@ int pxa_mmc_register(int card_index)
{ {
struct mmc *mmc; struct mmc *mmc;
struct pxa_mmc_priv *priv; struct pxa_mmc_priv *priv;
uint32_t reg; u32 reg;
int ret = -ENOMEM; int ret = -ENOMEM;
priv = malloc(sizeof(struct pxa_mmc_priv)); priv = malloc(sizeof(struct pxa_mmc_priv));
@ -405,7 +430,7 @@ int pxa_mmc_register(int card_index)
default: default:
ret = -EINVAL; ret = -EINVAL;
printf("PXA MMC: Invalid MMC controller ID (card_index = %d)\n", printf("PXA MMC: Invalid MMC controller ID (card_index = %d)\n",
card_index); card_index);
goto err1; goto err1;
} }
@ -420,7 +445,7 @@ int pxa_mmc_register(int card_index)
#endif #endif
mmc = mmc_create(&pxa_mmc_cfg, priv); mmc = mmc_create(&pxa_mmc_cfg, priv);
if (mmc == NULL) if (!mmc)
goto err1; goto err1;
return 0; return 0;
@ -430,3 +455,82 @@ err1:
err0: err0:
return ret; return ret;
} }
#else /* !CONFIG_IS_ENABLED(DM_MMC) */
static int pxa_mmc_probe(struct udevice *dev)
{
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct pxa_mmc_plat *plat = dev_get_platdata(dev);
struct mmc_config *cfg = &plat->cfg;
struct mmc *mmc = &plat->mmc;
struct pxa_mmc_priv *priv = dev_get_priv(dev);
u32 reg;
upriv->mmc = mmc;
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
cfg->f_max = PXAMMC_MAX_SPEED;
cfg->f_min = PXAMMC_MIN_SPEED;
cfg->host_caps = PXAMMC_HOST_CAPS;
cfg->name = dev->name;
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->priv = priv;
priv->regs = plat->base;
#ifndef CONFIG_CPU_MONAHANS /* PXA2xx */
reg = readl(CKEN);
reg |= CKEN12_MMC;
writel(reg, CKEN);
#else /* PXA3xx */
reg = readl(CKENA);
reg |= CKENA_12_MMC0 | CKENA_13_MMC1;
writel(reg, CKENA);
#endif
return pxa_mmc_init_common(priv, mmc);
}
static int pxa_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct pxa_mmc_plat *plat = dev_get_platdata(dev);
struct pxa_mmc_priv *priv = dev_get_priv(dev);
return pxa_mmc_send_cmd_common(priv, &plat->mmc, cmd, data);
}
static int pxa_mmc_set_ios(struct udevice *dev)
{
struct pxa_mmc_plat *plat = dev_get_platdata(dev);
struct pxa_mmc_priv *priv = dev_get_priv(dev);
return pxa_mmc_set_ios_common(priv, &plat->mmc);
}
static const struct dm_mmc_ops pxa_mmc_ops = {
.get_cd = NULL,
.send_cmd = pxa_mmc_send_cmd,
.set_ios = pxa_mmc_set_ios,
};
#if CONFIG_IS_ENABLED(BLK)
static int pxa_mmc_bind(struct udevice *dev)
{
struct pxa_mmc_plat *plat = dev_get_platdata(dev);
return mmc_bind(dev, &plat->mmc, &plat->cfg);
}
#endif
U_BOOT_DRIVER(pxa_mmc) = {
#if CONFIG_IS_ENABLED(BLK)
.bind = pxa_mmc_bind,
#endif
.id = UCLASS_MMC,
.name = "pxa_mmc",
.ops = &pxa_mmc_ops,
.priv_auto_alloc_size = sizeof(struct pxa_mmc_priv),
.probe = pxa_mmc_probe,
};
#endif /* !CONFIG_IS_ENABLED(DM_MMC) */

View file

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2019 Marcel Ziswiler <marcel.ziswiler@toradex.com>
*/
#ifndef __PXA_MMC_GEN_H
#define __PXA_MMC_GEN_H
#include <mmc.h>
/*
* struct pxa_mmc_platdata - information about a PXA MMC controller
*
* @base: MMC controller base register address
*/
struct pxa_mmc_plat {
struct mmc_config cfg;
struct mmc mmc;
struct pxa_mmc_regs *base;
};
#endif /* __PXA_MMC_GEN_H */