Skip to content
Snippets Groups Projects
omap_hsmmc.c 48 KiB
Newer Older
/*
 * (C) Copyright 2008
 * Texas Instruments, <www.ti.com>
 * Sukumar Ghorai <s-ghorai@ti.com>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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's version 2 of
 * the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <config.h>
#include <common.h>
#include <mmc.h>
#include <part.h>
#include <i2c.h>
#if defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)
#include <palmas.h>
#include <asm/io.h>
#include <asm/arch/mmc_host_def.h>
#ifdef CONFIG_OMAP54XX
#include <asm/arch/mux_dra7xx.h>
#include <asm/arch/dra7xx_iodelay.h>
#endif
#if !defined(CONFIG_SOC_KEYSTONE)
#include <asm/gpio.h>
#include <asm/arch/sys_proto.h>
#ifdef CONFIG_MMC_OMAP36XX_PINS
#include <asm/arch/mux.h>
#endif
#include <power/regulator.h>
/* simplify defines to OMAP_HSMMC_USE_GPIO */
#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
	(defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_GPIO_SUPPORT))
#define OMAP_HSMMC_USE_GPIO
#else
#undef OMAP_HSMMC_USE_GPIO
#endif

/* common definitions for all OMAPs */
#define SYSCTL_SRC	(1 << 25)
#define SYSCTL_SRD	(1 << 26)

#ifdef CONFIG_IODELAY_RECALIBRATION
struct omap_hsmmc_pinctrl_state {
	struct pad_conf_entry *padconf;
	int npads;
	struct iodelay_cfg_entry *iodelay;
	int niodelays;
};
#endif

struct omap_hsmmc_data {
	struct hsmmc *base_addr;
#if !CONFIG_IS_ENABLED(DM_MMC)
#ifdef OMAP_HSMMC_USE_GPIO
#if CONFIG_IS_ENABLED(DM_MMC)
	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
	struct gpio_desc wp_gpio;	/* Write Protect GPIO */
	bool cd_inverted;
#else
#endif
#if CONFIG_IS_ENABLED(DM_MMC)
	u8 controller_flags;
#ifndef CONFIG_OMAP34XX
	struct omap_hsmmc_adma_desc *adma_desc_table;
	uint desc_slot;
#endif
	struct udevice *pbias_supply;
	uint signal_voltage;
#ifdef CONFIG_IODELAY_RECALIBRATION
	struct omap_hsmmc_pinctrl_state *default_pinctrl_state;
	struct omap_hsmmc_pinctrl_state *hs_pinctrl_state;
	struct omap_hsmmc_pinctrl_state *hs200_1_8v_pinctrl_state;
	struct omap_hsmmc_pinctrl_state *ddr_1_8v_pinctrl_state;
	struct omap_hsmmc_pinctrl_state *sdr12_pinctrl_state;
	struct omap_hsmmc_pinctrl_state *sdr25_pinctrl_state;
	struct omap_hsmmc_pinctrl_state *ddr50_pinctrl_state;
	struct omap_hsmmc_pinctrl_state *sdr50_pinctrl_state;
	struct omap_hsmmc_pinctrl_state *sdr104_pinctrl_state;
#endif
};

struct omap_mmc_of_data {
	u8 controller_flags;
};

#ifndef CONFIG_OMAP34XX
struct omap_hsmmc_adma_desc {
	u8 attr;
	u8 reserved;
	u16 len;
	u32 addr;
#define ADMA_MAX_LEN	63488

/* Decriptor table defines */
#define ADMA_DESC_ATTR_VALID		BIT(0)
#define ADMA_DESC_ATTR_END		BIT(1)
#define ADMA_DESC_ATTR_INT		BIT(2)
#define ADMA_DESC_ATTR_ACT1		BIT(4)
#define ADMA_DESC_ATTR_ACT2		BIT(5)

#define ADMA_DESC_TRANSFER_DATA		ADMA_DESC_ATTR_ACT2
#define ADMA_DESC_LINK_DESC	(ADMA_DESC_ATTR_ACT1 | ADMA_DESC_ATTR_ACT2)
#endif

/* If we fail after 1 second wait, something is really bad */
#define MAX_RETRY_MS	1000
/* DMA transfers can take a long time if a lot a data is transferred.
 * The timeout must take in account the amount of data. Let's assume
 * that the time will never exceed 333 ms per MB (in other word we assume
 * that the bandwidth is always above 3MB/s).
 */
#define DMA_TIMEOUT_PER_MB	333
#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT		BIT(0)
#define OMAP_HSMMC_NO_1_8_V			BIT(1)
#define OMAP_HSMMC_USE_ADMA			BIT(2)
#define OMAP_HSMMC_REQUIRE_IODELAY		BIT(3)
Sricharan's avatar
Sricharan committed
static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
			unsigned int siz);
static void omap_hsmmc_start_clock(struct hsmmc *mmc_base);
static void omap_hsmmc_stop_clock(struct hsmmc *mmc_base);
static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit);
static inline struct omap_hsmmc_data *omap_hsmmc_get_data(struct mmc *mmc)
{
#if CONFIG_IS_ENABLED(DM_MMC)
	return dev_get_priv(mmc->dev);
#else
	return (struct omap_hsmmc_data *)mmc->priv;
#endif
}
static inline struct mmc_config *omap_hsmmc_get_cfg(struct mmc *mmc)
{
#if CONFIG_IS_ENABLED(DM_MMC)
	struct omap_hsmmc_plat *plat = dev_get_platdata(mmc->dev);
	return &plat->cfg;
#else
	return &((struct omap_hsmmc_data *)mmc->priv)->cfg;
#endif
#if defined(OMAP_HSMMC_USE_GPIO) && !CONFIG_IS_ENABLED(DM_MMC)
static int omap_mmc_setup_gpio_in(int gpio, const char *label)
{
#ifndef CONFIG_DM_GPIO
	if (!gpio_is_valid(gpio))
#endif
	ret = gpio_request(gpio, label);
	if (ret)
		return ret;
	ret = gpio_direction_input(gpio);
	if (ret)
		return ret;
Loading
Loading full blame...