mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-08 05:43:53 +00:00

Enforce full include path for includes. Deprecate old paths. The following folders inside include/lib have been left unchanged: - include/lib/cpus/${ARCH} - include/lib/el3_runtime/${ARCH} The reason for this change is that having a global namespace for includes isn't a good idea. It defeats one of the advantages of having folders and it introduces problems that are sometimes subtle (because you may not know the header you are actually including if there are two of them). For example, this patch had to be created because two headers were called the same way:e0ea0928d5
("Fix gpio includes of mt8173 platform to avoid collision."). More recently, this patch has had similar problems:46f9b2c3a2
("drivers: add tzc380 support"). This problem was introduced in commit4ecca33988
("Move include and source files to logical locations"). At that time, there weren't too many headers so it wasn't a real issue. However, time has shown that this creates problems. Platforms that want to preserve the way they include headers may add the removed paths to PLAT_INCLUDES, but this is discouraged. Change-Id: I39dc53ed98f9e297a5966e723d1936d6ccf2fc8f Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
302 lines
7.6 KiB
C
302 lines
7.6 KiB
C
/*
|
|
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include <arch.h>
|
|
#include <arch_helpers.h>
|
|
#include <common/debug.h>
|
|
#include <drivers/delay_timer.h>
|
|
#include <drivers/mmc.h>
|
|
#include <lib/mmio.h>
|
|
|
|
#include <imx_usdhc.h>
|
|
|
|
static void imx_usdhc_initialize(void);
|
|
static int imx_usdhc_send_cmd(struct mmc_cmd *cmd);
|
|
static int imx_usdhc_set_ios(unsigned int clk, unsigned int width);
|
|
static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size);
|
|
static int imx_usdhc_read(int lba, uintptr_t buf, size_t size);
|
|
static int imx_usdhc_write(int lba, uintptr_t buf, size_t size);
|
|
|
|
static const struct mmc_ops imx_usdhc_ops = {
|
|
.init = imx_usdhc_initialize,
|
|
.send_cmd = imx_usdhc_send_cmd,
|
|
.set_ios = imx_usdhc_set_ios,
|
|
.prepare = imx_usdhc_prepare,
|
|
.read = imx_usdhc_read,
|
|
.write = imx_usdhc_write,
|
|
};
|
|
|
|
static imx_usdhc_params_t imx_usdhc_params;
|
|
|
|
#define IMX7_MMC_SRC_CLK_RATE (200 * 1000 * 1000)
|
|
static void imx_usdhc_set_clk(int clk)
|
|
{
|
|
int div = 1;
|
|
int pre_div = 1;
|
|
unsigned int sdhc_clk = IMX7_MMC_SRC_CLK_RATE;
|
|
uintptr_t reg_base = imx_usdhc_params.reg_base;
|
|
|
|
assert(clk > 0);
|
|
|
|
while (sdhc_clk / (16 * pre_div) > clk && pre_div < 256)
|
|
pre_div *= 2;
|
|
|
|
while (sdhc_clk / div > clk && div < 16)
|
|
div++;
|
|
|
|
pre_div >>= 1;
|
|
div -= 1;
|
|
clk = (pre_div << 8) | (div << 4);
|
|
|
|
mmio_clrbits32(reg_base + VENDSPEC, VENDSPEC_CARD_CLKEN);
|
|
mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_CLOCK_MASK, clk);
|
|
udelay(10000);
|
|
|
|
mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_PER_CLKEN | VENDSPEC_CARD_CLKEN);
|
|
}
|
|
|
|
static void imx_usdhc_initialize(void)
|
|
{
|
|
unsigned int timeout = 10000;
|
|
uintptr_t reg_base = imx_usdhc_params.reg_base;
|
|
|
|
assert((imx_usdhc_params.reg_base & MMC_BLOCK_MASK) == 0);
|
|
|
|
/* reset the controller */
|
|
mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTA);
|
|
|
|
/* wait for reset done */
|
|
while ((mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTA)) {
|
|
if (!timeout)
|
|
ERROR("IMX MMC reset timeout.\n");
|
|
timeout--;
|
|
}
|
|
|
|
mmio_write_32(reg_base + MMCBOOT, 0);
|
|
mmio_write_32(reg_base + MIXCTRL, 0);
|
|
mmio_write_32(reg_base + CLKTUNECTRLSTS, 0);
|
|
|
|
mmio_write_32(reg_base + VENDSPEC, VENDSPEC_INIT);
|
|
mmio_write_32(reg_base + DLLCTRL, 0);
|
|
mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_IPG_CLKEN | VENDSPEC_PER_CLKEN);
|
|
|
|
/* Set the initial boot clock rate */
|
|
imx_usdhc_set_clk(MMC_BOOT_CLK_RATE);
|
|
udelay(100);
|
|
|
|
/* Clear read/write ready status */
|
|
mmio_clrbits32(reg_base + INTSTATEN, INTSTATEN_BRR | INTSTATEN_BWR);
|
|
|
|
/* configure as little endian */
|
|
mmio_write_32(reg_base + PROTCTRL, PROTCTRL_LE);
|
|
|
|
/* Set timeout to the maximum value */
|
|
mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_TIMEOUT_MASK,
|
|
SYSCTRL_TIMEOUT(15));
|
|
|
|
/* set wartermark level as 16 for safe for MMC */
|
|
mmio_clrsetbits32(reg_base + WATERMARKLEV, WMKLV_MASK, 16 | (16 << 16));
|
|
}
|
|
|
|
#define FSL_CMD_RETRIES 1000
|
|
|
|
static int imx_usdhc_send_cmd(struct mmc_cmd *cmd)
|
|
{
|
|
uintptr_t reg_base = imx_usdhc_params.reg_base;
|
|
unsigned int xfertype = 0, mixctl = 0, multiple = 0, data = 0, err = 0;
|
|
unsigned int state, flags = INTSTATEN_CC | INTSTATEN_CTOE;
|
|
unsigned int cmd_retries = 0;
|
|
|
|
assert(cmd);
|
|
|
|
/* clear all irq status */
|
|
mmio_write_32(reg_base + INTSTAT, 0xffffffff);
|
|
|
|
/* Wait for the bus to be idle */
|
|
do {
|
|
state = mmio_read_32(reg_base + PSTATE);
|
|
} while (state & (PSTATE_CDIHB | PSTATE_CIHB));
|
|
|
|
while (mmio_read_32(reg_base + PSTATE) & PSTATE_DLA)
|
|
;
|
|
|
|
mmio_write_32(reg_base + INTSIGEN, 0);
|
|
udelay(1000);
|
|
|
|
switch (cmd->cmd_idx) {
|
|
case MMC_CMD(12):
|
|
xfertype |= XFERTYPE_CMDTYP_ABORT;
|
|
break;
|
|
case MMC_CMD(18):
|
|
multiple = 1;
|
|
/* fall thru for read op */
|
|
case MMC_CMD(17):
|
|
case MMC_CMD(8):
|
|
mixctl |= MIXCTRL_DTDSEL;
|
|
data = 1;
|
|
break;
|
|
case MMC_CMD(25):
|
|
multiple = 1;
|
|
/* fall thru for data op flag */
|
|
case MMC_CMD(24):
|
|
data = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (multiple) {
|
|
mixctl |= MIXCTRL_MSBSEL;
|
|
mixctl |= MIXCTRL_BCEN;
|
|
}
|
|
|
|
if (data) {
|
|
xfertype |= XFERTYPE_DPSEL;
|
|
mixctl |= MIXCTRL_DMAEN;
|
|
}
|
|
|
|
if (cmd->resp_type & MMC_RSP_48 && cmd->resp_type != MMC_RESPONSE_R2)
|
|
xfertype |= XFERTYPE_RSPTYP_48;
|
|
else if (cmd->resp_type & MMC_RSP_136)
|
|
xfertype |= XFERTYPE_RSPTYP_136;
|
|
else if (cmd->resp_type & MMC_RSP_BUSY)
|
|
xfertype |= XFERTYPE_RSPTYP_48_BUSY;
|
|
|
|
if (cmd->resp_type & MMC_RSP_CMD_IDX)
|
|
xfertype |= XFERTYPE_CICEN;
|
|
|
|
if (cmd->resp_type & MMC_RSP_CRC)
|
|
xfertype |= XFERTYPE_CCCEN;
|
|
|
|
xfertype |= XFERTYPE_CMD(cmd->cmd_idx);
|
|
|
|
/* Send the command */
|
|
mmio_write_32(reg_base + CMDARG, cmd->cmd_arg);
|
|
mmio_clrsetbits32(reg_base + MIXCTRL, MIXCTRL_DATMASK, mixctl);
|
|
mmio_write_32(reg_base + XFERTYPE, xfertype);
|
|
|
|
/* Wait for the command done */
|
|
do {
|
|
state = mmio_read_32(reg_base + INTSTAT);
|
|
if (cmd_retries)
|
|
udelay(1);
|
|
} while ((!(state & flags)) && ++cmd_retries < FSL_CMD_RETRIES);
|
|
|
|
if ((state & (INTSTATEN_CTOE | CMD_ERR)) || cmd_retries == FSL_CMD_RETRIES) {
|
|
if (cmd_retries == FSL_CMD_RETRIES)
|
|
err = -ETIMEDOUT;
|
|
else
|
|
err = -EIO;
|
|
ERROR("imx_usdhc mmc cmd %d state 0x%x errno=%d\n",
|
|
cmd->cmd_idx, state, err);
|
|
goto out;
|
|
}
|
|
|
|
/* Copy the response to the response buffer */
|
|
if (cmd->resp_type & MMC_RSP_136) {
|
|
unsigned int cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
|
|
|
|
cmdrsp3 = mmio_read_32(reg_base + CMDRSP3);
|
|
cmdrsp2 = mmio_read_32(reg_base + CMDRSP2);
|
|
cmdrsp1 = mmio_read_32(reg_base + CMDRSP1);
|
|
cmdrsp0 = mmio_read_32(reg_base + CMDRSP0);
|
|
cmd->resp_data[3] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
|
|
cmd->resp_data[2] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
|
|
cmd->resp_data[1] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
|
|
cmd->resp_data[0] = (cmdrsp0 << 8);
|
|
} else {
|
|
cmd->resp_data[0] = mmio_read_32(reg_base + CMDRSP0);
|
|
}
|
|
|
|
/* Wait until all of the blocks are transferred */
|
|
if (data) {
|
|
flags = DATA_COMPLETE;
|
|
do {
|
|
state = mmio_read_32(reg_base + INTSTAT);
|
|
|
|
if (state & (INTSTATEN_DTOE | DATA_ERR)) {
|
|
err = -EIO;
|
|
ERROR("imx_usdhc mmc data state 0x%x\n", state);
|
|
goto out;
|
|
}
|
|
} while ((state & flags) != flags);
|
|
}
|
|
|
|
out:
|
|
/* Reset CMD and DATA on error */
|
|
if (err) {
|
|
mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTC);
|
|
while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTC)
|
|
;
|
|
|
|
if (data) {
|
|
mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTD);
|
|
while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTD)
|
|
;
|
|
}
|
|
}
|
|
|
|
/* clear all irq status */
|
|
mmio_write_32(reg_base + INTSTAT, 0xffffffff);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int imx_usdhc_set_ios(unsigned int clk, unsigned int width)
|
|
{
|
|
uintptr_t reg_base = imx_usdhc_params.reg_base;
|
|
|
|
imx_usdhc_set_clk(clk);
|
|
|
|
if (width == MMC_BUS_WIDTH_4)
|
|
mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK,
|
|
PROTCTRL_WIDTH_4);
|
|
else if (width == MMC_BUS_WIDTH_8)
|
|
mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK,
|
|
PROTCTRL_WIDTH_8);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size)
|
|
{
|
|
uintptr_t reg_base = imx_usdhc_params.reg_base;
|
|
|
|
mmio_write_32(reg_base + DSADDR, buf);
|
|
mmio_write_32(reg_base + BLKATT,
|
|
(size / MMC_BLOCK_SIZE) << 16 | MMC_BLOCK_SIZE);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int imx_usdhc_read(int lba, uintptr_t buf, size_t size)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int imx_usdhc_write(int lba, uintptr_t buf, size_t size)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void imx_usdhc_init(imx_usdhc_params_t *params,
|
|
struct mmc_device_info *mmc_dev_info)
|
|
{
|
|
assert((params != 0) &&
|
|
((params->reg_base & MMC_BLOCK_MASK) == 0) &&
|
|
(params->clk_rate > 0) &&
|
|
((params->bus_width == MMC_BUS_WIDTH_1) ||
|
|
(params->bus_width == MMC_BUS_WIDTH_4) ||
|
|
(params->bus_width == MMC_BUS_WIDTH_8)));
|
|
|
|
memcpy(&imx_usdhc_params, params, sizeof(imx_usdhc_params_t));
|
|
mmc_init(&imx_usdhc_ops, params->clk_rate, params->bus_width,
|
|
params->flags, mmc_dev_info);
|
|
}
|