Stefan thinks they don't add value. Command used: sed -i -e '/file is part of /d' $(git grep "file is part of " |egrep ":( */\*.*\*/\$|#|;#|-- | *\* )" | cut -d: -f1 |grep -v crossgcc |grep -v gcov | grep -v /elf.h |grep -v nvramtool) The exceptions are for: - crossgcc (patch file) - gcov (imported from gcc) - elf.h (imported from GNU's libc) - nvramtool (more complicated header) The removed lines are: - fmt.Fprintln(f, "/* This file is part of the coreboot project. */") -# This file is part of a set of unofficial pre-commit hooks available -/* This file is part of coreboot */ -# This file is part of msrtool. -/* This file is part of msrtool. */ - * This file is part of ncurses, designed to be appended after curses.h.in -/* This file is part of pgtblgen. */ - * This file is part of the coreboot project. - /* This file is part of the coreboot project. */ -# This file is part of the coreboot project. -# This file is part of the coreboot project. -## This file is part of the coreboot project. --- This file is part of the coreboot project. -/* This file is part of the coreboot project */ -/* This file is part of the coreboot project. */ -;## This file is part of the coreboot project. -# This file is part of the coreboot project. It originated in the - * This file is part of the coreinfo project. -## This file is part of the coreinfo project. - * This file is part of the depthcharge project. -/* This file is part of the depthcharge project. */ -/* This file is part of the ectool project. */ - * This file is part of the GNU C Library. - * This file is part of the libpayload project. -## This file is part of the libpayload project. -/* This file is part of the Linux kernel. */ -## This file is part of the superiotool project. -/* This file is part of the superiotool project */ -/* This file is part of uio_usbdebug */ Change-Id: I82d872b3b337388c93d5f5bf704e9ee9e53ab3a9 Signed-off-by: Patrick Georgi <pgeorgi@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41194 Reviewed-by: HAOUAS Elyes <ehaouas@noos.fr> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
343 lines
9.2 KiB
C
343 lines
9.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* MultiMediaCard (MMC), eMMC and Secure Digital (SD) common code which
|
|
* transitions the card from the standby state to the transfer state. The
|
|
* common code supports read operations, erase and write operations are in
|
|
* a separate modules. This code is controller independent.
|
|
*/
|
|
|
|
#include <commonlib/storage.h>
|
|
#include "sd_mmc.h"
|
|
#include "storage.h"
|
|
#include <string.h>
|
|
|
|
#define DECIMAL_CAPACITY_MULTIPLIER 1000ULL
|
|
#define HEX_CAPACITY_MULTIPLIER 1024ULL
|
|
|
|
struct capacity {
|
|
const char *const units;
|
|
uint64_t bytes;
|
|
};
|
|
|
|
static void display_capacity(struct storage_media *media, int partition_number)
|
|
{
|
|
uint64_t capacity;
|
|
uint64_t decimal_divisor;
|
|
const char *decimal_units;
|
|
uint64_t hex_divisor;
|
|
const char *hex_units;
|
|
int index;
|
|
const char *name;
|
|
const char *separator;
|
|
const struct capacity decimal_list[] = {
|
|
{"TB", DECIMAL_CAPACITY_MULTIPLIER * DECIMAL_CAPACITY_MULTIPLIER
|
|
* DECIMAL_CAPACITY_MULTIPLIER
|
|
* DECIMAL_CAPACITY_MULTIPLIER},
|
|
{"GB", DECIMAL_CAPACITY_MULTIPLIER * DECIMAL_CAPACITY_MULTIPLIER
|
|
* DECIMAL_CAPACITY_MULTIPLIER},
|
|
{"MB", DECIMAL_CAPACITY_MULTIPLIER
|
|
* DECIMAL_CAPACITY_MULTIPLIER},
|
|
{"KB", DECIMAL_CAPACITY_MULTIPLIER},
|
|
{"B", 1}
|
|
};
|
|
const struct capacity hex_list[] = {
|
|
{"TiB", HEX_CAPACITY_MULTIPLIER * HEX_CAPACITY_MULTIPLIER
|
|
* HEX_CAPACITY_MULTIPLIER * HEX_CAPACITY_MULTIPLIER},
|
|
{"GiB", HEX_CAPACITY_MULTIPLIER * HEX_CAPACITY_MULTIPLIER
|
|
* HEX_CAPACITY_MULTIPLIER},
|
|
{"MiB", HEX_CAPACITY_MULTIPLIER * HEX_CAPACITY_MULTIPLIER},
|
|
{"KiB", HEX_CAPACITY_MULTIPLIER},
|
|
{"B", 1}
|
|
};
|
|
|
|
/* Get the partition name */
|
|
capacity = media->capacity[partition_number];
|
|
name = storage_partition_name(media, partition_number);
|
|
separator = "";
|
|
if (CONFIG(COMMONLIB_STORAGE_MMC) && !IS_SD(media))
|
|
separator = ": ";
|
|
|
|
/* Determine the decimal divisor for the capacity */
|
|
for (index = 0; index < ARRAY_SIZE(decimal_list) - 1; index++) {
|
|
if (capacity >= decimal_list[index].bytes)
|
|
break;
|
|
}
|
|
decimal_divisor = decimal_list[index].bytes;
|
|
decimal_units = decimal_list[index].units;
|
|
|
|
/* Determine the hex divisor for the capacity */
|
|
for (index = 0; index < ARRAY_SIZE(hex_list) - 1; index++) {
|
|
if (capacity >= hex_list[index].bytes)
|
|
break;
|
|
}
|
|
hex_divisor = hex_list[index].bytes;
|
|
hex_units = hex_list[index].units;
|
|
|
|
/* Display the capacity */
|
|
sdhc_debug("%3lld.%03lld %sytes (%3lld.%03lld %sytes)%s%s\n",
|
|
capacity / decimal_divisor,
|
|
(capacity / (decimal_divisor / 1000)) % 1000,
|
|
decimal_units,
|
|
capacity / hex_divisor,
|
|
((capacity / (hex_divisor / 1024)) * 1000 / 1024) % 1000,
|
|
hex_units,
|
|
separator,
|
|
name);
|
|
}
|
|
|
|
void storage_display_setup(struct storage_media *media)
|
|
{
|
|
int partition_number;
|
|
|
|
/* Display the device info */
|
|
sd_mmc_debug("Man %06x Snr %u ",
|
|
media->cid[0] >> 24,
|
|
(((media->cid[2] & 0xffff) << 16) |
|
|
((media->cid[3] >> 16) & 0xffff)));
|
|
sd_mmc_debug("Product %c%c%c%c", media->cid[0] & 0xff,
|
|
(media->cid[1] >> 24), (media->cid[1] >> 16) & 0xff,
|
|
(media->cid[1] >> 8) & 0xff);
|
|
if (!IS_SD(media)) /* eMMC product string is longer */
|
|
sd_mmc_debug("%c%c", media->cid[1] & 0xff,
|
|
(media->cid[2] >> 24) & 0xff);
|
|
sd_mmc_debug(" Revision %d.%d\n", (media->cid[2] >> 20) & 0xf,
|
|
(media->cid[2] >> 16) & 0xf);
|
|
|
|
/* Display the erase block size */
|
|
sdhc_debug("Erase block size: 0x%08x\n", media->erase_blocks
|
|
* media->write_bl_len);
|
|
|
|
/* Display the partition capacities */
|
|
if (CONFIG(SDHC_DEBUG)) {
|
|
for (partition_number = 0; partition_number
|
|
< ARRAY_SIZE(media->capacity); partition_number++) {
|
|
if (!media->capacity[partition_number])
|
|
continue;
|
|
display_capacity(media, partition_number);
|
|
}
|
|
}
|
|
}
|
|
|
|
int storage_startup(struct storage_media *media)
|
|
{
|
|
int err;
|
|
uint64_t capacity;
|
|
uint64_t cmult, csize;
|
|
struct mmc_command cmd;
|
|
struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
|
|
|
|
/* Determine the storage capacity */
|
|
if (media->high_capacity) {
|
|
cmult = 8;
|
|
csize = sd_mmc_extract_uint32_bits(media->csd, 58, 22);
|
|
} else {
|
|
csize = sd_mmc_extract_uint32_bits(media->csd, 54, 12);
|
|
cmult = sd_mmc_extract_uint32_bits(media->csd, 78, 3);
|
|
}
|
|
capacity = (csize + 1) << (cmult + 2);
|
|
capacity *= media->read_bl_len;
|
|
media->capacity[0] = capacity;
|
|
|
|
/* Limit the block size to 512 bytes */
|
|
if (media->read_bl_len > 512)
|
|
media->read_bl_len = 512;
|
|
if (media->write_bl_len > 512)
|
|
media->write_bl_len = 512;
|
|
|
|
/* Get the erase size in blocks */
|
|
media->erase_blocks =
|
|
(sd_mmc_extract_uint32_bits(media->csd, 47, 3) + 1)
|
|
* (sd_mmc_extract_uint32_bits(media->csd, 42, 5) + 1);
|
|
|
|
/* Select the card, and put it into Transfer Mode */
|
|
cmd.cmdidx = MMC_CMD_SELECT_CARD;
|
|
cmd.resp_type = CARD_RSP_R1;
|
|
cmd.cmdarg = media->rca << 16;
|
|
cmd.flags = 0;
|
|
err = ctrlr->send_cmd(ctrlr, &cmd, NULL);
|
|
if (err)
|
|
return err;
|
|
|
|
/* Increase the bus frequency */
|
|
if (CONFIG(COMMONLIB_STORAGE_SD) && IS_SD(media))
|
|
err = sd_change_freq(media);
|
|
else if (CONFIG(COMMONLIB_STORAGE_MMC)) {
|
|
err = mmc_change_freq(media);
|
|
if (!err)
|
|
mmc_update_capacity(media);
|
|
}
|
|
if (err)
|
|
return err;
|
|
|
|
/* Restrict card's capabilities by what the controller can do */
|
|
media->caps &= ctrlr->caps;
|
|
|
|
/* Increase the bus width if possible */
|
|
if (CONFIG(COMMONLIB_STORAGE_SD) && IS_SD(media))
|
|
err = sd_set_bus_width(media);
|
|
else if (CONFIG(COMMONLIB_STORAGE_MMC))
|
|
err = mmc_set_bus_width(media);
|
|
if (err)
|
|
return err;
|
|
|
|
/* Display the card setup */
|
|
storage_display_setup(media);
|
|
return 0;
|
|
}
|
|
|
|
int storage_setup_media(struct storage_media *media, struct sd_mmc_ctrlr *ctrlr)
|
|
{
|
|
int err;
|
|
|
|
memset(media, 0, sizeof(*media));
|
|
media->ctrlr = ctrlr;
|
|
|
|
err = sd_mmc_enter_standby(media);
|
|
if (err)
|
|
return err;
|
|
return storage_startup(media);
|
|
}
|
|
|
|
static int storage_read(struct storage_media *media, void *dest, uint32_t start,
|
|
uint32_t block_count)
|
|
{
|
|
struct mmc_command cmd;
|
|
struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
|
|
|
|
cmd.resp_type = CARD_RSP_R1;
|
|
cmd.flags = 0;
|
|
|
|
if (block_count > 1)
|
|
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
|
|
else
|
|
cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
|
|
|
|
if (media->high_capacity)
|
|
cmd.cmdarg = start;
|
|
else
|
|
cmd.cmdarg = start * media->read_bl_len;
|
|
|
|
struct mmc_data data;
|
|
data.dest = dest;
|
|
data.blocks = block_count;
|
|
data.blocksize = media->read_bl_len;
|
|
data.flags = DATA_FLAG_READ;
|
|
|
|
if (ctrlr->send_cmd(ctrlr, &cmd, &data))
|
|
return 0;
|
|
|
|
if ((block_count > 1) && !(ctrlr->caps
|
|
& DRVR_CAP_AUTO_CMD12)) {
|
|
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
|
|
cmd.cmdarg = 0;
|
|
cmd.resp_type = CARD_RSP_R1b;
|
|
cmd.flags = CMD_FLAG_IGNORE_INHIBIT;
|
|
if (ctrlr->send_cmd(ctrlr, &cmd, NULL)) {
|
|
sd_mmc_error("Failed to send stop cmd\n");
|
|
return 0;
|
|
}
|
|
|
|
/* Waiting for the ready status */
|
|
sd_mmc_send_status(media, SD_MMC_IO_RETRIES);
|
|
}
|
|
|
|
return block_count;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// BlockDevice utilities and callbacks
|
|
|
|
int storage_block_setup(struct storage_media *media, uint64_t start,
|
|
uint64_t count, int is_read)
|
|
{
|
|
struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
|
|
int partition_number;
|
|
|
|
if (count == 0)
|
|
return 0;
|
|
|
|
uint32_t bl_len = is_read ? media->read_bl_len :
|
|
media->write_bl_len;
|
|
|
|
/* Validate the block range */
|
|
partition_number = media->partition_config & EXT_CSD_PART_ACCESS_MASK;
|
|
if (((start * bl_len) > media->capacity[partition_number])
|
|
|| (((start + count) * bl_len) >
|
|
media->capacity[partition_number])) {
|
|
sd_mmc_error("Block range exceeds device capacity\n");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* CMD16 only applies to single data rate mode, and block
|
|
* length for double data rate is always 512 bytes.
|
|
*/
|
|
if ((ctrlr->timing == BUS_TIMING_UHS_DDR50) ||
|
|
(ctrlr->timing == BUS_TIMING_MMC_DDR52) ||
|
|
(ctrlr->timing == BUS_TIMING_MMC_HS400) ||
|
|
(ctrlr->timing == BUS_TIMING_MMC_HS400ES))
|
|
return 1;
|
|
if (sd_mmc_set_blocklen(ctrlr, bl_len))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
uint64_t storage_block_read(struct storage_media *media, uint64_t start,
|
|
uint64_t count, void *buffer)
|
|
{
|
|
uint8_t *dest = (uint8_t *)buffer;
|
|
|
|
if (storage_block_setup(media, start, count, 1) == 0)
|
|
return 0;
|
|
|
|
uint64_t todo = count;
|
|
struct sd_mmc_ctrlr *ctrlr = media->ctrlr;
|
|
do {
|
|
uint32_t cur = (uint32_t)MIN(todo, ctrlr->b_max);
|
|
if (storage_read(media, dest, start, cur) != cur)
|
|
return 0;
|
|
todo -= cur;
|
|
sd_mmc_trace("%s: Got %d blocks, more %d (total %d) to go.\n",
|
|
__func__, (int)cur, (int)todo, (int)count);
|
|
start += cur;
|
|
dest += cur * media->read_bl_len;
|
|
} while (todo > 0);
|
|
return count;
|
|
}
|
|
|
|
int storage_set_partition(struct storage_media *media,
|
|
unsigned int partition_number)
|
|
{
|
|
int err;
|
|
|
|
/* Select the partition */
|
|
err = -1;
|
|
if (CONFIG(COMMONLIB_STORAGE_SD) && IS_SD(media))
|
|
err = sd_set_partition(media, partition_number);
|
|
else if (CONFIG(COMMONLIB_STORAGE_MMC))
|
|
err = mmc_set_partition(media, partition_number);
|
|
if (err)
|
|
sd_mmc_error("Invalid partition number!\n");
|
|
return err;
|
|
}
|
|
|
|
const char *storage_partition_name(struct storage_media *media,
|
|
unsigned int partition_number)
|
|
{
|
|
const char *name;
|
|
|
|
/* Get the partition name */
|
|
name = NULL;
|
|
if (CONFIG(COMMONLIB_STORAGE_SD) && IS_SD(media))
|
|
name = sd_partition_name(media, partition_number);
|
|
else if (CONFIG(COMMONLIB_STORAGE_MMC))
|
|
name = mmc_partition_name(media, partition_number);
|
|
return name;
|
|
}
|
|
|
|
unsigned int storage_get_current_partition(struct storage_media *media)
|
|
{
|
|
return media->partition_config & EXT_CSD_PART_ACCESS_MASK;
|
|
}
|