提交 9450ab2b 编写于 作者: T Tom Rini

Merge branch 'master' of git://git.denx.de/u-boot-spi

- Various MTD fixes from Boris
- Zap various unused / legacy paths.
- pxa3xx NAND update from Miquel
Signed-off-by: NTom Rini <trini@konsulko.com>
......@@ -1932,14 +1932,6 @@ The following options need to be configured:
SPI configuration items (port pins to use, etc). For
an example, see include/configs/sacsng.h.
CONFIG_HARD_SPI
Enables a hardware SPI driver for general-purpose reads
and writes. As with CONFIG_SOFT_SPI, the board configuration
must define a list of chip-select function pointers.
Currently supported on some MPC8xxx processors. For an
example, see include/configs/mpc8349emds.h.
CONFIG_SYS_SPI_MXC_WAIT
Timeout for waiting until spi transfer completed.
default: (CONFIG_SYS_HZ/100) /* 10 ms */
......
......@@ -18,13 +18,6 @@
#define HWCONFIG_BUFFER_SIZE 256
#endif
/* CONFIG_HARD_SPI triggers SPI bus initialization in PowerPC */
#if defined(CONFIG_MPC8XXX_SPI) || defined(CONFIG_FSL_ESPI)
# ifndef CONFIG_HARD_SPI
# define CONFIG_HARD_SPI
# endif
#endif
#define CONFIG_LMB
#define CONFIG_SYS_BOOT_RAMDISK_HIGH
......
......@@ -273,7 +273,7 @@ void spi_cs_deactivate(struct spi_slave *slave)
iopd->dat |= SPI_CS_MASK;
}
#endif /* CONFIG_HARD_SPI */
#endif
#if defined(CONFIG_OF_BOARD_SETUP)
int ft_board_setup(void *blob, bd_t *bd)
......
......@@ -208,4 +208,4 @@ void spi_cs_deactivate(struct spi_slave *slave)
/* deactivate the spi_cs */
setbits_be32(&iopd->dat, IDSCPLD_SPI_CS_MASK);
}
#endif /* CONFIG_HARD_SPI */
#endif
......@@ -66,11 +66,6 @@ __weak int eeprom_write_enable(unsigned dev_addr, int state)
void eeprom_init(int bus)
{
/* SPI EEPROM */
#if defined(CONFIG_MPC8XX_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
spi_init_f();
#endif
/* I2C EEPROM */
#if defined(CONFIG_SYS_I2C)
if (bus >= 0)
......@@ -129,14 +124,6 @@ static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen,
{
int ret = 0;
/* SPI */
#if defined(CONFIG_MPC8XX_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
if (read)
spi_read(addr, alen, buffer, len);
else
spi_write(addr, alen, buffer, len);
#else /* I2C */
#if defined(CONFIG_DM_I2C) && defined(CONFIG_SYS_I2C_EEPROM_BUS)
struct udevice *dev;
......@@ -162,7 +149,6 @@ static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen,
ret = i2c_read(addr[0], offset, alen - 1, buffer, len);
else
ret = i2c_write(addr[0], offset, alen - 1, buffer, len);
#endif
#endif /* CONFIG_DM_I2C && CONFIG_SYS_I2C_EEPROM_BUS */
if (ret)
ret = CMD_RET_FAILURE;
......
......@@ -101,7 +101,6 @@ static int ubi_check(char *name)
return 1;
}
static int verify_mkvol_req(const struct ubi_device *ubi,
const struct ubi_mkvol_req *req)
{
......@@ -415,7 +414,7 @@ static int ubi_dev_scan(struct mtd_info *info, const char *vid_header_offset)
return 0;
}
int ubi_detach(void)
static int ubi_detach(void)
{
#ifdef CONFIG_CMD_UBIFS
/*
......@@ -473,7 +472,6 @@ static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (argc < 2)
return CMD_RET_USAGE;
if (strcmp(argv[1], "detach") == 0) {
if (argc < 2)
return CMD_RET_USAGE;
......@@ -481,7 +479,6 @@ static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return ubi_detach();
}
if (strcmp(argv[1], "part") == 0) {
const char *vid_header_offset = NULL;
......
......@@ -24,7 +24,6 @@
#include <os.h>
#include <post.h>
#include <relocate.h>
#include <spi.h>
#ifdef CONFIG_SPL
#include <spl.h>
#endif
......@@ -262,16 +261,6 @@ __weak int init_func_vid(void)
}
#endif
#if defined(CONFIG_HARD_SPI)
static int init_func_spi(void)
{
puts("SPI: ");
spi_init();
puts("ready\n");
return 0;
}
#endif
static int setup_mon_len(void)
{
#if defined(__ARM__) || defined(__MICROBLAZE__)
......@@ -912,9 +901,6 @@ static const init_fnc_t init_sequence_f[] = {
#endif
#if defined(CONFIG_VID) && !defined(CONFIG_SPL)
init_func_vid,
#endif
#if defined(CONFIG_HARD_SPI)
init_func_spi,
#endif
announce_dram_init,
dram_init, /* configure available RAM banks */
......
......@@ -36,7 +36,6 @@
#include <onenand_uboot.h>
#include <scsi.h>
#include <serial.h>
#include <spi.h>
#include <stdio_dev.h>
#include <timer.h>
#include <trace.h>
......@@ -379,20 +378,6 @@ static int initr_flash(void)
}
#endif
#if defined(CONFIG_PPC) && !defined(CONFIG_DM_SPI)
static int initr_spi(void)
{
/* MPC8xx does this here */
#ifdef CONFIG_MPC8XX_SPI
#if !defined(CONFIG_ENV_IS_IN_EEPROM)
spi_init_f();
#endif
spi_init_r();
#endif
return 0;
}
#endif
#ifdef CONFIG_CMD_NAND
/* go init the NAND */
static int initr_nand(void)
......@@ -744,9 +729,6 @@ static init_fnc_t init_sequence_r[] = {
/* initialize higher level parts of CPU like time base and timers */
cpu_init_r,
#endif
#if defined(CONFIG_PPC) && !defined(CONFIG_DM_SPI)
initr_spi,
#endif
#ifdef CONFIG_CMD_NAND
initr_nand,
#endif
......
......@@ -163,11 +163,6 @@ At this point you should be able to build U-Boot for your board with the
empty SPI driver. You still have empty methods in your driver, but we will
write these one by one.
If you have spi_init() functions or the like that are called from your
board then the build will fail. Remove these calls and make a note of the
init that needs to be done.
7. Set up your platform data structure
This will hold the information your driver to operate, like its hardware
......
......@@ -13,6 +13,29 @@
#define MTD_NAME_MAX_LEN 20
void board_mtdparts_default(const char **mtdids, const char **mtdparts);
static const char *get_mtdids(void)
{
__maybe_unused const char *mtdparts = NULL;
const char *mtdids = env_get("mtdids");
if (mtdids)
return mtdids;
#if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
board_mtdparts_default(&mtdids, &mtdparts);
#elif defined(MTDIDS_DEFAULT)
mtdids = MTDIDS_DEFAULT;
#elif defined(CONFIG_MTDIDS_DEFAULT)
mtdids = CONFIG_MTDIDS_DEFAULT;
#endif
if (mtdids)
env_set("mtdids", mtdids);
return mtdids;
}
/**
* mtd_search_alternate_name - Search an alternate name for @mtdname thanks to
......@@ -34,7 +57,7 @@ int mtd_search_alternate_name(const char *mtdname, char *altname,
const char *mtdids, *equal, *comma, *dev_id, *mtd_id;
int dev_id_len, mtd_id_len;
mtdids = env_get("mtdids");
mtdids = get_mtdids();
if (!mtdids)
return -EINVAL;
......@@ -92,30 +115,6 @@ static void mtd_probe_uclass_mtd_devs(void) { }
#endif
#if defined(CONFIG_MTD_PARTITIONS)
extern void board_mtdparts_default(const char **mtdids,
const char **mtdparts);
static const char *get_mtdids(void)
{
__maybe_unused const char *mtdparts = NULL;
const char *mtdids = env_get("mtdids");
if (mtdids)
return mtdids;
#if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
board_mtdparts_default(&mtdids, &mtdparts);
#elif defined(MTDIDS_DEFAULT)
mtdids = MTDIDS_DEFAULT;
#elif defined(CONFIG_MTDIDS_DEFAULT)
mtdids = CONFIG_MTDIDS_DEFAULT;
#endif
if (mtdids)
env_set("mtdids", mtdids);
return mtdids;
}
#define MTDPARTS_MAXLEN 512
......@@ -150,20 +149,74 @@ static const char *get_mtdparts(void)
return mtdparts;
}
static int mtd_del_parts(struct mtd_info *mtd, bool quiet)
{
int ret;
if (!mtd_has_partitions(mtd))
return 0;
/* do not delete partitions if they are in use. */
if (mtd_partitions_used(mtd)) {
if (!quiet)
printf("\"%s\" partitions still in use, can't delete them\n",
mtd->name);
return -EACCES;
}
ret = del_mtd_partitions(mtd);
if (ret)
return ret;
return 1;
}
static bool mtd_del_all_parts_failed;
static void mtd_del_all_parts(void)
{
struct mtd_info *mtd;
int ret = 0;
mtd_del_all_parts_failed = false;
/*
* It is not safe to remove entries from the mtd_for_each_device loop
* as it uses idr indexes and the partitions removal is done in bulk
* (all partitions of one device at the same time), so break and
* iterate from start each time a new partition is found and deleted.
*/
do {
mtd_for_each_device(mtd) {
ret = mtd_del_parts(mtd, false);
if (ret > 0)
break;
else if (ret < 0)
mtd_del_all_parts_failed = true;
}
} while (ret > 0);
}
int mtd_probe_devices(void)
{
static char *old_mtdparts;
static char *old_mtdids;
const char *mtdparts = get_mtdparts();
const char *mtdids = get_mtdids();
bool remaining_partitions = true;
const char *mtdparts_next = mtdparts;
struct mtd_info *mtd;
mtd_probe_uclass_mtd_devs();
/* Check if mtdparts/mtdids changed since last call, otherwise: exit */
/*
* Check if mtdparts/mtdids changed, if the MTD dev list was updated
* or if our previous attempt to delete existing partititions failed.
* In any of these cases we want to update the partitions, otherwise,
* everything is up-to-date and we can return 0 directly.
*/
if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) ||
(mtdparts && old_mtdparts && mtdids && old_mtdids &&
!mtd_dev_list_updated() && !mtd_del_all_parts_failed &&
!strcmp(mtdparts, old_mtdparts) &&
!strcmp(mtdids, old_mtdids)))
return 0;
......@@ -174,55 +227,55 @@ int mtd_probe_devices(void)
old_mtdparts = strdup(mtdparts);
old_mtdids = strdup(mtdids);
/* If at least one partition is still in use, do not delete anything */
mtd_for_each_device(mtd) {
if (mtd->usecount) {
printf("Partition \"%s\" already in use, aborting\n",
mtd->name);
return -EACCES;
}
}
/*
* Remove all old parts. Note that partition removal can fail in case
* one of the partition is still being used by an MTD user, so this
* does not guarantee that all old partitions are gone.
*/
mtd_del_all_parts();
/*
* Everything looks clear, remove all partitions. It is not safe to
* remove entries from the mtd_for_each_device loop as it uses idr
* indexes and the partitions removal is done in bulk (all partitions of
* one device at the same time), so break and iterate from start each
* time a new partition is found and deleted.
* Call mtd_dev_list_updated() to clear updates generated by our own
* parts removal loop.
*/
while (remaining_partitions) {
remaining_partitions = false;
mtd_for_each_device(mtd) {
if (!mtd_is_partition(mtd) && mtd_has_partitions(mtd)) {
del_mtd_partitions(mtd);
remaining_partitions = true;
break;
}
}
}
mtd_dev_list_updated();
/* If either mtdparts or mtdids is empty, then exit */
if (!mtdparts || !mtdids)
return 0;
/* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
if (strstr(mtdparts, "mtdparts="))
if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1))
mtdparts += 9;
/* For each MTD device in mtdparts */
while (mtdparts[0] != '\0') {
for (; mtdparts[0] != '\0'; mtdparts = mtdparts_next) {
char mtd_name[MTD_NAME_MAX_LEN], *colon;
struct mtd_partition *parts;
int mtd_name_len, nparts;
int ret;
unsigned int mtd_name_len;
int nparts, ret;
mtdparts_next = strchr(mtdparts, ';');
if (!mtdparts_next)
mtdparts_next = mtdparts + strlen(mtdparts);
else
mtdparts_next++;
colon = strchr(mtdparts, ':');
if (colon > mtdparts_next)
colon = NULL;
if (!colon) {
printf("Wrong mtdparts: %s\n", mtdparts);
return -EINVAL;
}
mtd_name_len = colon - mtdparts;
mtd_name_len = (unsigned int)(colon - mtdparts);
if (mtd_name_len + 1 > sizeof(mtd_name)) {
printf("MTD name too long: %s\n", mtdparts);
return -EINVAL;
}
strncpy(mtd_name, mtdparts, mtd_name_len);
mtd_name[mtd_name_len] = '\0';
/* Move the pointer forward (including the ':') */
......@@ -249,14 +302,22 @@ int mtd_probe_devices(void)
if (ret || IS_ERR_OR_NULL(mtd)) {
printf("Could not find a valid device for %s\n",
mtd_name);
mtdparts = strchr(mtdparts, ';');
if (mtdparts)
mtdparts++;
mtdparts = mtdparts_next;
continue;
}
}
/*
* Call mtd_del_parts() again, even if it's already been called
* in mtd_del_all_parts(). We need to know if old partitions are
* still around (because they are still being used by someone),
* and if they are, we shouldn't create new partitions, so just
* skip this MTD device and try the next one.
*/
ret = mtd_del_parts(mtd, true);
if (ret < 0)
continue;
/*
* Parse the MTD device partitions. It will update the mtdparts
* pointer, create an array of parts (that must be freed), and
......@@ -281,6 +342,12 @@ int mtd_probe_devices(void)
put_mtd_device(mtd);
}
/*
* Call mtd_dev_list_updated() to clear updates generated by our own
* parts registration loop.
*/
mtd_dev_list_updated();
return 0;
}
#else
......
......@@ -87,14 +87,17 @@ struct idr_layer {
struct idr {
struct idr_layer id[MAX_IDR_ID];
bool updated;
};
#define DEFINE_IDR(name) struct idr name;
void idr_remove(struct idr *idp, int id)
{
if (idp->id[id].used)
if (idp->id[id].used) {
idp->id[id].used = 0;
idp->updated = true;
}
return;
}
......@@ -134,6 +137,7 @@ int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask)
if (idl->used == 0) {
idl->used = 1;
idl->ptr = ptr;
idp->updated = true;
return i;
}
i++;
......@@ -155,6 +159,16 @@ struct mtd_info *__mtd_next_device(int i)
}
EXPORT_SYMBOL_GPL(__mtd_next_device);
bool mtd_dev_list_updated(void)
{
if (mtd_idr.updated) {
mtd_idr.updated = false;
return true;
}
return false;
}
#ifndef __UBOOT__
static LIST_HEAD(mtd_notifiers);
......@@ -514,6 +528,13 @@ int del_mtd_device(struct mtd_info *mtd)
struct mtd_notifier *not;
#endif
ret = del_mtd_partitions(mtd);
if (ret) {
debug("Failed to delete MTD partitions attached to %s (err %d)\n",
mtd->name, ret);
return ret;
}
mutex_lock(&mtd_table_mutex);
if (idr_find(&mtd_idr, mtd->index) != mtd) {
......
......@@ -63,6 +63,18 @@ char *kstrdup(const char *s, gfp_t gfp)
#define MTD_SIZE_REMAINING (~0LLU)
#define MTD_OFFSET_NOT_SPECIFIED (~0LLU)
bool mtd_partitions_used(struct mtd_info *master)
{
struct mtd_info *slave;
list_for_each_entry(slave, &master->partitions, node) {
if (slave->usecount)
return true;
}
return false;
}
/**
* mtd_parse_partition - Parse @mtdparts partition definition, fill @partition
* with it and update the @mtdparts string pointer.
......
......@@ -195,6 +195,7 @@ struct pxa3xx_nand_info {
int cs;
int use_ecc; /* use HW ECC ? */
int force_raw; /* prevent use_ecc to be set */
int ecc_bch; /* using BCH ECC? */
int use_spare; /* use spare ? */
int need_wait;
......@@ -326,14 +327,14 @@ static struct nand_ecclayout ecc_layout_2KB_bch4bit = {
static struct nand_ecclayout ecc_layout_2KB_bch8bit = {
.eccbytes = 64,
.eccpos = {
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127},
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95},
.oobfree = { {1, 4}, {6, 26} }
};
......@@ -579,7 +580,7 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
{
if (info->ecc_bch) {
if (info->ecc_bch && !info->force_raw) {
u32 ts;
/*
......@@ -612,12 +613,22 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
static void handle_data_pio(struct pxa3xx_nand_info *info)
{
int data_len = info->step_chunk_size;
/*
* In raw mode, include the spare area and the ECC bytes that are not
* consumed by the controller in the data section. Do not reorganize
* here, do it in the ->read_page_raw() handler instead.
*/
if (info->force_raw)
data_len += info->step_spare_size + info->ecc_size;
switch (info->state) {
case STATE_PIO_WRITING:
if (info->step_chunk_size)
writesl(info->mmio_base + NDDB,
info->data_buff + info->data_buff_pos,
DIV_ROUND_UP(info->step_chunk_size, 4));
DIV_ROUND_UP(data_len, 4));
if (info->step_spare_size)
writesl(info->mmio_base + NDDB,
......@@ -628,7 +639,10 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
if (info->step_chunk_size)
drain_fifo(info,
info->data_buff + info->data_buff_pos,
DIV_ROUND_UP(info->step_chunk_size, 4));
DIV_ROUND_UP(data_len, 4));
if (info->force_raw)
break;
if (info->step_spare_size)
drain_fifo(info,
......@@ -642,7 +656,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
}
/* Update buffer pointers for multi-page read/write */
info->data_buff_pos += info->step_chunk_size;
info->data_buff_pos += data_len;
info->oob_buff_pos += info->step_spare_size;
}
......@@ -796,7 +810,8 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
case NAND_CMD_READ0:
case NAND_CMD_READOOB:
case NAND_CMD_PAGEPROG:
info->use_ecc = 1;
if (!info->force_raw)
info->use_ecc = 1;
break;
case NAND_CMD_PARAM:
info->use_spare = 0;
......@@ -866,7 +881,13 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
* which is either naked-read or last-read according to the
* state.
*/
if (mtd->writesize == info->chunk_size) {
if (info->force_raw) {
info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) |
NDCB0_LEN_OVRD |
NDCB0_EXT_CMD_TYPE(ext_cmd_type);
info->ndcb3 = info->step_chunk_size +
info->step_spare_size + info->ecc_size;
} else if (mtd->writesize == info->chunk_size) {
info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
} else if (mtd->writesize > info->chunk_size) {
info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
......@@ -1216,6 +1237,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
{
struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
struct pxa3xx_nand_info *info = host->info_data;
int bf;
chip->read_buf(mtd, buf, mtd->writesize);
chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
......@@ -1223,12 +1245,30 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
if (info->retcode == ERR_CORERR && info->use_ecc) {
mtd->ecc_stats.corrected += info->ecc_err_cnt;
} else if (info->retcode == ERR_UNCORERR) {
} else if (info->retcode == ERR_UNCORERR && info->ecc_bch) {
/*
* for blank page (all 0xff), HW will calculate its ECC as
* 0, which is different from the ECC information within
* OOB, ignore such uncorrectable errors
* Empty pages will trigger uncorrectable errors. Re-read the
* entire page in raw mode and check for bits not being "1".
* If there are more than the supported strength, then it means
* this is an actual uncorrectable error.
*/
chip->ecc.read_page_raw(mtd, chip, buf, oob_required, page);
bf = nand_check_erased_ecc_chunk(buf, mtd->writesize,
chip->oob_poi, mtd->oobsize,
NULL, 0, chip->ecc.strength);
if (bf < 0) {
mtd->ecc_stats.failed++;
} else if (bf) {
mtd->ecc_stats.corrected += bf;
info->max_bitflips = max_t(unsigned int,
info->max_bitflips, bf);
info->retcode = ERR_CORERR;
} else {
info->retcode = ERR_NONE;
}
} else if (info->retcode == ERR_UNCORERR && !info->ecc_bch) {
/* Raw read is not supported with Hamming ECC engine */
if (is_buf_blank(buf, mtd->writesize))
info->retcode = ERR_NONE;
else
......@@ -1238,6 +1278,69 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
return info->max_bitflips;
}
static int pxa3xx_nand_read_page_raw(struct mtd_info *mtd,
struct nand_chip *chip, uint8_t *buf,
int oob_required, int page)
{
struct pxa3xx_nand_host *host = chip->priv;
struct pxa3xx_nand_info *info = host->info_data;
int chunk, ecc_off_buf;
if (!info->ecc_bch)
return -ENOTSUPP;
/*
* Set the force_raw boolean, then re-call ->cmdfunc() that will run
* pxa3xx_nand_start(), which will actually disable the ECC engine.
*/
info->force_raw = true;
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
ecc_off_buf = (info->nfullchunks * info->spare_size) +
info->last_spare_size;
for (chunk = 0; chunk < info->nfullchunks; chunk++) {
chip->read_buf(mtd,
buf + (chunk * info->chunk_size),
info->chunk_size);
chip->read_buf(mtd,
chip->oob_poi +
(chunk * (info->spare_size)),
info->spare_size);
chip->read_buf(mtd,
chip->oob_poi + ecc_off_buf +
(chunk * (info->ecc_size)),
info->ecc_size - 2);
}
if (info->ntotalchunks > info->nfullchunks) {
chip->read_buf(mtd,
buf + (info->nfullchunks * info->chunk_size),
info->last_chunk_size);
chip->read_buf(mtd,
chip->oob_poi +
(info->nfullchunks * (info->spare_size)),
info->last_spare_size);
chip->read_buf(mtd,
chip->oob_poi + ecc_off_buf +
(info->nfullchunks * (info->ecc_size)),
info->ecc_size - 2);
}
info->force_raw = false;
return 0;
}
static int pxa3xx_nand_read_oob_raw(struct mtd_info *mtd,
struct nand_chip *chip, int page)
{
/* Invalidate page cache */
chip->pagebuf = -1;
return chip->ecc.read_page_raw(mtd, chip, chip->buffers->databuf, true,
page);
}
static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd_to_nand(mtd);
......@@ -1488,7 +1591,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
info->chunk_size = 1024;
info->spare_size = 0;
info->last_chunk_size = 1024;
info->last_spare_size = 64;
info->last_spare_size = 32;
info->ecc_size = 32;
ecc->mode = NAND_ECC_HW;
ecc->size = info->chunk_size;
......@@ -1669,6 +1772,8 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info)
nand_set_controller_data(chip, host);
chip->ecc.read_page = pxa3xx_nand_read_page_hwecc;
chip->ecc.read_page_raw = pxa3xx_nand_read_page_raw;
chip->ecc.read_oob_raw = pxa3xx_nand_read_oob_raw;
chip->ecc.write_page = pxa3xx_nand_write_page_hwecc;
chip->controller = &info->controller;
chip->waitfunc = pxa3xx_nand_waitfunc;
......
......@@ -10,6 +10,7 @@
#include <spi_flash.h>
static struct mtd_info sf_mtd_info;
static bool sf_mtd_registered;
static char sf_mtd_name[8];
static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
......@@ -17,6 +18,9 @@ static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
struct spi_flash *flash = mtd->priv;
int err;
if (!flash)
return -ENODEV;
instr->state = MTD_ERASING;
err = spi_flash_erase(flash, instr->addr, instr->len);
......@@ -38,6 +42,9 @@ static int spi_flash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
struct spi_flash *flash = mtd->priv;
int err;
if (!flash)
return -ENODEV;
err = spi_flash_read(flash, from, len, buf);
if (!err)
*retlen = len;
......@@ -51,6 +58,9 @@ static int spi_flash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
struct spi_flash *flash = mtd->priv;
int err;
if (!flash)
return -ENODEV;
err = spi_flash_write(flash, to, len, buf);
if (!err)
*retlen = len;
......@@ -73,6 +83,17 @@ static int spi_flash_mtd_number(void)
int spi_flash_mtd_register(struct spi_flash *flash)
{
int ret;
if (sf_mtd_registered) {
ret = del_mtd_device(&sf_mtd_info);
if (ret)
return ret;
sf_mtd_registered = false;
}
sf_mtd_registered = false;
memset(&sf_mtd_info, 0, sizeof(sf_mtd_info));
sprintf(sf_mtd_name, "nor%d", spi_flash_mtd_number());
......@@ -94,10 +115,33 @@ int spi_flash_mtd_register(struct spi_flash *flash)
sf_mtd_info.numeraseregions = 0;
sf_mtd_info.erasesize = flash->sector_size;
return add_mtd_device(&sf_mtd_info);
ret = add_mtd_device(&sf_mtd_info);
if (!ret)
sf_mtd_registered = true;
return ret;
}
void spi_flash_mtd_unregister(void)
{
del_mtd_device(&sf_mtd_info);
int ret;
if (!sf_mtd_registered)
return;
ret = del_mtd_device(&sf_mtd_info);
if (!ret) {
sf_mtd_registered = false;
return;
}
/*
* Setting mtd->priv to NULL is the best we can do. Thanks to that,
* the MTD layer can still call mtd hooks without risking a
* use-after-free bug. Still, things should be fixed to prevent the
* spi_flash object from being destroyed when del_mtd_device() fails.
*/
sf_mtd_info.priv = NULL;
printf("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!",
sf_mtd_info.name);
}
......@@ -144,6 +144,14 @@ static int spi_flash_std_probe(struct udevice *dev)
return spi_flash_probe_slave(flash);
}
static int spi_flash_std_remove(struct udevice *dev)
{
#ifdef CONFIG_SPI_FLASH_MTD
spi_flash_mtd_unregister();
#endif
return 0;
}
static const struct dm_spi_flash_ops spi_flash_std_ops = {
.read = spi_flash_std_read,
.write = spi_flash_std_write,
......@@ -161,6 +169,7 @@ U_BOOT_DRIVER(spi_flash_std) = {
.id = UCLASS_SPI_FLASH,
.of_match = spi_flash_std_ids,
.probe = spi_flash_std_probe,
.remove = spi_flash_std_remove,
.priv_auto_alloc_size = sizeof(struct spi_flash),
.ops = &spi_flash_std_ops,
};
......
......@@ -77,9 +77,6 @@ static inline struct e1000_hw *e1000_hw_from_spi(struct spi_slave *spi)
return container_of(spi, struct e1000_hw, spi);
}
/* Not sure why all of these are necessary */
void spi_init(void) { /* Nothing to do */ }
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
......
......@@ -116,6 +116,20 @@ config ICH_SPI
access the SPI NOR flash on platforms embedding this Intel
ICH IP core.
config MESON_SPIFC
bool "Amlogic Meson SPI Flash Controller driver"
depends on ARCH_MESON
help
Enable the Amlogic Meson SPI Flash Controller SPIFC) driver.
This driver can be used to access the SPI NOR flash chips on
Amlogic Meson SoCs.
config MPC8XX_SPI
bool "MPC8XX SPI Driver"
depends on MPC8xx
help
Enable support for SPI on MPC8XX
config MT7621_SPI
bool "MediaTek MT7621 SPI driver"
depends on ARCH_MT7620
......@@ -124,6 +138,13 @@ config MT7621_SPI
the SPI NOR flash on platforms embedding this Ralink / MediaTek
SPI core, like MT7621/7628/7688.
config MTK_QSPI
bool "Mediatek QSPI driver"
help
Enable the Mediatek QSPI driver. This driver can be
used to access the SPI NOR flash on platforms embedding this
Mediatek QSPI IP core.
config MVEBU_A3700_SPI
bool "Marvell Armada 3700 SPI driver"
select CLK_ARMADA_3720
......@@ -328,12 +349,6 @@ config LPC32XX_SSP
help
Enable support for SPI on LPC32xx
config MPC8XX_SPI
bool "MPC8XX SPI Driver"
depends on MPC8xx
help
Enable support for SPI on MPC8XX
config MPC8XXX_SPI
bool "MPC8XXX SPI Driver"
help
......
......@@ -31,8 +31,10 @@ obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
obj-$(CONFIG_ICH_SPI) += ich.o
obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o
obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o
obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o
obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o
obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o
obj-$(CONFIG_MXC_SPI) += mxc_spi.o
......
......@@ -34,11 +34,6 @@ static int spi_has_wdrbt(struct atmel_spi_slave *slave)
return (ATMEL_SPI_VERSION_REV(ver) >= 0x210);
}
void spi_init()
{
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
......
......@@ -388,11 +388,6 @@ void spi_cs_deactivate(struct spi_slave *slave)
/* do nothing */
}
void spi_init(void)
{
/* do nothing */
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
......
......@@ -390,11 +390,6 @@ static int fsl_dspi_cfg_speed(struct fsl_dspi_priv *priv, uint speed)
return 0;
}
#ifndef CONFIG_DM_SPI
void spi_init(void)
{
/* Nothing to do */
}
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
......
......@@ -118,11 +118,6 @@ void spi_free_slave(struct spi_slave *slave)
free(fsl);
}
void spi_init(void)
{
}
int spi_claim_bus(struct spi_slave *slave)
{
struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
......
......@@ -47,15 +47,6 @@ static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave(
return container_of(slave, struct lpc32xx_spi_slave, slave);
}
/* spi_init is called during boot when CONFIG_CMD_SPI is defined */
void spi_init(void)
{
/*
* nothing to do: clocking was enabled in lpc32xx_ssp_enable()
* and configuration will be done in spi_setup_slave()
*/
}
/* the following is called in sequence by do_spi_xfer() */
struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
* Copyright (C) 2018 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
*
* Amlogic Meson SPI Flash Controller driver
*/
#include <common.h>
#include <spi.h>
#include <clk.h>
#include <dm.h>
#include <regmap.h>
#include <errno.h>
#include <asm/io.h>
#include <linux/bitfield.h>
/* register map */
#define REG_CMD 0x00
#define REG_ADDR 0x04
#define REG_CTRL 0x08
#define REG_CTRL1 0x0c
#define REG_STATUS 0x10
#define REG_CTRL2 0x14
#define REG_CLOCK 0x18
#define REG_USER 0x1c
#define REG_USER1 0x20
#define REG_USER2 0x24
#define REG_USER3 0x28
#define REG_USER4 0x2c
#define REG_SLAVE 0x30
#define REG_SLAVE1 0x34
#define REG_SLAVE2 0x38
#define REG_SLAVE3 0x3c
#define REG_C0 0x40
#define REG_B8 0x60
#define REG_MAX 0x7c
/* register fields */
#define CMD_USER BIT(18)
#define CTRL_ENABLE_AHB BIT(17)
#define CLOCK_SOURCE BIT(31)
#define CLOCK_DIV_SHIFT 12
#define CLOCK_DIV_MASK (0x3f << CLOCK_DIV_SHIFT)
#define CLOCK_CNT_HIGH_SHIFT 6
#define CLOCK_CNT_HIGH_MASK (0x3f << CLOCK_CNT_HIGH_SHIFT)
#define CLOCK_CNT_LOW_SHIFT 0
#define CLOCK_CNT_LOW_MASK (0x3f << CLOCK_CNT_LOW_SHIFT)
#define USER_DIN_EN_MS BIT(0)
#define USER_CMP_MODE BIT(2)
#define USER_CLK_NOT_INV BIT(7)
#define USER_UC_DOUT_SEL BIT(27)
#define USER_UC_DIN_SEL BIT(28)
#define USER_UC_MASK ((BIT(5) - 1) << 27)
#define USER1_BN_UC_DOUT_SHIFT 17
#define USER1_BN_UC_DOUT_MASK (0xff << 16)
#define USER1_BN_UC_DIN_SHIFT 8
#define USER1_BN_UC_DIN_MASK (0xff << 8)
#define USER4_CS_POL_HIGH BIT(23)
#define USER4_IDLE_CLK_HIGH BIT(29)
#define USER4_CS_ACT BIT(30)
#define SLAVE_TRST_DONE BIT(4)
#define SLAVE_OP_MODE BIT(30)
#define SLAVE_SW_RST BIT(31)
#define SPIFC_BUFFER_SIZE 64
struct meson_spifc_priv {
struct regmap *regmap;
struct clk clk;
};
/**
* meson_spifc_drain_buffer() - copy data from device buffer to memory
* @spifc: the Meson SPI device
* @buf: the destination buffer
* @len: number of bytes to copy
*/
static void meson_spifc_drain_buffer(struct meson_spifc_priv *spifc,
u8 *buf, int len)
{
u32 data;
int i = 0;
while (i < len) {
regmap_read(spifc->regmap, REG_C0 + i, &data);
if (len - i >= 4) {
*((u32 *)buf) = data;
buf += 4;
} else {
memcpy(buf, &data, len - i);
break;
}
i += 4;
}
}
/**
* meson_spifc_fill_buffer() - copy data from memory to device buffer
* @spifc: the Meson SPI device
* @buf: the source buffer
* @len: number of bytes to copy
*/
static void meson_spifc_fill_buffer(struct meson_spifc_priv *spifc,
const u8 *buf, int len)
{
u32 data = 0;
int i = 0;
while (i < len) {
if (len - i >= 4)
data = *(u32 *)buf;
else
memcpy(&data, buf, len - i);
regmap_write(spifc->regmap, REG_C0 + i, data);
buf += 4;
i += 4;
}
}
/**
* meson_spifc_txrx() - transfer a chunk of data
* @spifc: the Meson SPI device
* @dout: data buffer for TX
* @din: data buffer for RX
* @offset: offset of the data to transfer
* @len: length of the data to transfer
* @last_xfer: whether this is the last transfer of the message
* @last_chunk: whether this is the last chunk of the transfer
* Return: 0 on success, a negative value on error
*/
static int meson_spifc_txrx(struct meson_spifc_priv *spifc,
const u8 *dout, u8 *din, int offset,
int len, bool last_xfer, bool last_chunk)
{
bool keep_cs = true;
u32 data;
int ret;
if (dout)
meson_spifc_fill_buffer(spifc, dout + offset, len);
/* enable DOUT stage */
regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK,
USER_UC_DOUT_SEL);
regmap_write(spifc->regmap, REG_USER1,
(8 * len - 1) << USER1_BN_UC_DOUT_SHIFT);
/* enable data input during DOUT */
regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS,
USER_DIN_EN_MS);
if (last_chunk && last_xfer)
keep_cs = false;
regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT,
keep_cs ? USER4_CS_ACT : 0);
/* clear transition done bit */
regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0);
/* start transfer */
regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER);
/* wait for the current operation to terminate */
ret = regmap_read_poll_timeout(spifc->regmap, REG_SLAVE, data,
(data & SLAVE_TRST_DONE),
0, 5 * CONFIG_SYS_HZ);
if (!ret && din)
meson_spifc_drain_buffer(spifc, din + offset, len);
return ret;
}
/**
* meson_spifc_xfer() - perform a single transfer
* @dev: the SPI controller device
* @bitlen: length of the transfer
* @dout: data buffer for TX
* @din: data buffer for RX
* @flags: transfer flags
* Return: 0 on success, a negative value on error
*/
static int meson_spifc_xfer(struct udevice *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
struct meson_spifc_priv *spifc = dev_get_priv(slave->parent);
int blen = bitlen / 8;
int len, done = 0, ret = 0;
if (bitlen % 8)
return -EINVAL;
debug("xfer len %d (%d) dout %p din %p\n", bitlen, blen, dout, din);
regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0);
while (done < blen && !ret) {
len = min_t(int, blen - done, SPIFC_BUFFER_SIZE);
ret = meson_spifc_txrx(spifc, dout, din, done, len,
flags & SPI_XFER_END,
done + len >= blen);
done += len;
}
regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB,
CTRL_ENABLE_AHB);
return ret;
}
/**
* meson_spifc_set_speed() - program the clock divider
* @dev: the SPI controller device
* @speed: desired speed in Hz
*/
static int meson_spifc_set_speed(struct udevice *dev, uint speed)
{
struct meson_spifc_priv *spifc = dev_get_priv(dev);
unsigned long parent, value;
int n;
parent = clk_get_rate(&spifc->clk);
n = max_t(int, parent / speed - 1, 1);
debug("parent %lu, speed %u, n %d\n", parent, speed, n);
value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK;
value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK;
value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) &
CLOCK_CNT_HIGH_MASK;
regmap_write(spifc->regmap, REG_CLOCK, value);
return 0;
}
/**
* meson_spifc_set_mode() - setups the SPI bus mode
* @dev: the SPI controller device
* @mode: desired mode bitfield
* Return: 0 on success, -ENODEV on error
*/
static int meson_spifc_set_mode(struct udevice *dev, uint mode)
{
struct meson_spifc_priv *spifc = dev_get_priv(dev);
if (mode & (SPI_CPHA | SPI_RX_QUAD | SPI_RX_DUAL |
SPI_TX_QUAD | SPI_TX_DUAL))
return -ENODEV;
regmap_update_bits(spifc->regmap, REG_USER, USER_CLK_NOT_INV,
mode & SPI_CPOL ? USER_CLK_NOT_INV : 0);
regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_POL_HIGH,
mode & SPI_CS_HIGH ? USER4_CS_POL_HIGH : 0);
return 0;
}
/**
* meson_spifc_hw_init() - reset and initialize the SPI controller
* @spifc: the Meson SPI device
*/
static void meson_spifc_hw_init(struct meson_spifc_priv *spifc)
{
/* reset device */
regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST,
SLAVE_SW_RST);
/* disable compatible mode */
regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0);
/* set master mode */
regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0);
}
static const struct dm_spi_ops meson_spifc_ops = {
.xfer = meson_spifc_xfer,
.set_speed = meson_spifc_set_speed,
.set_mode = meson_spifc_set_mode,
};
static int meson_spifc_probe(struct udevice *dev)
{
struct meson_spifc_priv *priv = dev_get_priv(dev);
int ret;
ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
if (ret)
return ret;
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret)
return ret;
ret = clk_enable(&priv->clk);
if (ret)
return ret;
meson_spifc_hw_init(priv);
return 0;
}
static const struct udevice_id meson_spifc_ids[] = {
{ .compatible = "amlogic,meson-gxbb-spifc", },
{ }
};
U_BOOT_DRIVER(meson_spifc) = {
.name = "meson_spifc",
.id = UCLASS_SPI,
.of_match = meson_spifc_ids,
.ops = &meson_spifc_ops,
.probe = meson_spifc_probe,
.priv_auto_alloc_size = sizeof(struct meson_spifc_priv),
};
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 MediaTek, Inc.
* Author : Guochun.Mao@mediatek.com
*/
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <spi.h>
#include <asm/io.h>
#include <linux/iopoll.h>
#include <linux/ioport.h>
/* Register Offset */
struct mtk_qspi_regs {
u32 cmd;
u32 cnt;
u32 rdsr;
u32 rdata;
u32 radr[3];
u32 wdata;
u32 prgdata[6];
u32 shreg[10];
u32 cfg[2];
u32 shreg10;
u32 mode_mon;
u32 status[4];
u32 flash_time;
u32 flash_cfg;
u32 reserved_0[3];
u32 sf_time;
u32 pp_dw_data;
u32 reserved_1;
u32 delsel_0[2];
u32 intrstus;
u32 intren;
u32 reserved_2;
u32 cfg3;
u32 reserved_3;
u32 chksum;
u32 aaicmd;
u32 wrprot;
u32 radr3;
u32 dual;
u32 delsel_1[3];
};
struct mtk_qspi_platdata {
fdt_addr_t reg_base;
fdt_addr_t mem_base;
};
struct mtk_qspi_priv {
struct mtk_qspi_regs *regs;
unsigned long *mem_base;
u8 op;
u8 tx[3]; /* only record max 3 bytes paras, when it's address. */
u32 txlen; /* dout buffer length - op code length */
u8 *rx;
u32 rxlen;
};
#define MTK_QSPI_CMD_POLLINGREG_US 500000
#define MTK_QSPI_WRBUF_SIZE 256
#define MTK_QSPI_COMMAND_ENABLE 0x30
/* NOR flash controller commands */
#define MTK_QSPI_RD_TRIGGER BIT(0)
#define MTK_QSPI_READSTATUS BIT(1)
#define MTK_QSPI_PRG_CMD BIT(2)
#define MTK_QSPI_WR_TRIGGER BIT(4)
#define MTK_QSPI_WRITESTATUS BIT(5)
#define MTK_QSPI_AUTOINC BIT(7)
#define MTK_QSPI_MAX_RX_TX_SHIFT 0x6
#define MTK_QSPI_MAX_SHIFT 0x8
#define MTK_QSPI_WR_BUF_ENABLE 0x1
#define MTK_QSPI_WR_BUF_DISABLE 0x0
static int mtk_qspi_execute_cmd(struct mtk_qspi_priv *priv, u8 cmd)
{
u8 tmp;
u8 val = cmd & ~MTK_QSPI_AUTOINC;
writeb(cmd, &priv->regs->cmd);
return readb_poll_timeout(&priv->regs->cmd, tmp, !(val & tmp),
MTK_QSPI_CMD_POLLINGREG_US);
}
static int mtk_qspi_tx_rx(struct mtk_qspi_priv *priv)
{
int len = 1 + priv->txlen + priv->rxlen;
int i, ret, idx;
if (len > MTK_QSPI_MAX_SHIFT)
return -ERR_INVAL;
writeb(len * 8, &priv->regs->cnt);
/* start at PRGDATA5, go down to PRGDATA0 */
idx = MTK_QSPI_MAX_RX_TX_SHIFT - 1;
/* opcode */
writeb(priv->op, &priv->regs->prgdata[idx]);
idx--;
/* program TX data */
for (i = 0; i < priv->txlen; i++, idx--)
writeb(priv->tx[i], &priv->regs->prgdata[idx]);
/* clear out rest of TX registers */
while (idx >= 0) {
writeb(0, &priv->regs->prgdata[idx]);
idx--;
}
ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_PRG_CMD);
if (ret)
return ret;
/* restart at first RX byte */
idx = priv->rxlen - 1;
/* read out RX data */
for (i = 0; i < priv->rxlen; i++, idx--)
priv->rx[i] = readb(&priv->regs->shreg[idx]);
return 0;
}
static int mtk_qspi_read(struct mtk_qspi_priv *priv,
u32 addr, u8 *buf, u32 len)
{
memcpy(buf, (u8 *)priv->mem_base + addr, len);
return 0;
}
static void mtk_qspi_set_addr(struct mtk_qspi_priv *priv, u32 addr)
{
int i;
for (i = 0; i < 3; i++) {
writeb(addr & 0xff, &priv->regs->radr[i]);
addr >>= 8;
}
}
static int mtk_qspi_write_single_byte(struct mtk_qspi_priv *priv,
u32 addr, u32 length, const u8 *data)
{
int i, ret;
mtk_qspi_set_addr(priv, addr);
for (i = 0; i < length; i++) {
writeb(*data++, &priv->regs->wdata);
ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER);
if (ret < 0)
return ret;
}
return 0;
}
static int mtk_qspi_write_buffer(struct mtk_qspi_priv *priv, u32 addr,
const u8 *buf)
{
int i, data;
mtk_qspi_set_addr(priv, addr);
for (i = 0; i < MTK_QSPI_WRBUF_SIZE; i += 4) {
data = buf[i + 3] << 24 | buf[i + 2] << 16 |
buf[i + 1] << 8 | buf[i];
writel(data, &priv->regs->pp_dw_data);
}
return mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER);
}
static int mtk_qspi_write(struct mtk_qspi_priv *priv,
u32 addr, const u8 *buf, u32 len)
{
int ret;
/* setting pre-fetch buffer for page program */
writel(MTK_QSPI_WR_BUF_ENABLE, &priv->regs->cfg[1]);
while (len >= MTK_QSPI_WRBUF_SIZE) {
ret = mtk_qspi_write_buffer(priv, addr, buf);
if (ret < 0)
return ret;
len -= MTK_QSPI_WRBUF_SIZE;
addr += MTK_QSPI_WRBUF_SIZE;
buf += MTK_QSPI_WRBUF_SIZE;
}
/* disable pre-fetch buffer for page program */
writel(MTK_QSPI_WR_BUF_DISABLE, &priv->regs->cfg[1]);
if (len)
return mtk_qspi_write_single_byte(priv, addr, len, buf);
return 0;
}
static int mtk_qspi_claim_bus(struct udevice *dev)
{
/* nothing to do */
return 0;
}
static int mtk_qspi_release_bus(struct udevice *dev)
{
/* nothing to do */
return 0;
}
static int mtk_qspi_transfer(struct mtk_qspi_priv *priv, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
u32 bytes = DIV_ROUND_UP(bitlen, 8);
u32 addr;
if (!bytes)
return -ERR_INVAL;
if (dout) {
if (flags & SPI_XFER_BEGIN) {
/* parse op code and potential paras first */
priv->op = *(u8 *)dout;
if (bytes > 1)
memcpy(priv->tx, (u8 *)dout + 1,
bytes <= 4 ? bytes - 1 : 3);
priv->txlen = bytes - 1;
}
if (flags == SPI_XFER_ONCE) {
/* operations without receiving or sending data.
* for example: erase, write flash register or write
* enable...
*/
priv->rx = NULL;
priv->rxlen = 0;
return mtk_qspi_tx_rx(priv);
}
if (flags & SPI_XFER_END) {
/* here, dout should be data to be written.
* and priv->tx should be filled 3Bytes address.
*/
addr = priv->tx[0] << 16 | priv->tx[1] << 8 |
priv->tx[2];
return mtk_qspi_write(priv, addr, (u8 *)dout, bytes);
}
}
if (din) {
if (priv->txlen >= 3) {
/* if run to here, priv->tx[] should be the address
* where read data from,
* and, din is the buf to receive data.
*/
addr = priv->tx[0] << 16 | priv->tx[1] << 8 |
priv->tx[2];
return mtk_qspi_read(priv, addr, (u8 *)din, bytes);
}
/* should be reading flash's register */
priv->rx = (u8 *)din;
priv->rxlen = bytes;
return mtk_qspi_tx_rx(priv);
}
return 0;
}
static int mtk_qspi_xfer(struct udevice *dev, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
struct udevice *bus = dev->parent;
struct mtk_qspi_priv *priv = dev_get_priv(bus);
return mtk_qspi_transfer(priv, bitlen, dout, din, flags);
}
static int mtk_qspi_set_speed(struct udevice *bus, uint speed)
{
/* nothing to do */
return 0;
}
static int mtk_qspi_set_mode(struct udevice *bus, uint mode)
{
/* nothing to do */
return 0;
}
static int mtk_qspi_ofdata_to_platdata(struct udevice *bus)
{
struct resource res_reg, res_mem;
struct mtk_qspi_platdata *plat = bus->platdata;
int ret;
ret = dev_read_resource_byname(bus, "reg_base", &res_reg);
if (ret) {
debug("can't get reg_base resource(ret = %d)\n", ret);
return -ENOMEM;
}
ret = dev_read_resource_byname(bus, "mem_base", &res_mem);
if (ret) {
debug("can't get map_base resource(ret = %d)\n", ret);
return -ENOMEM;
}
plat->mem_base = res_mem.start;
plat->reg_base = res_reg.start;
return 0;
}
static int mtk_qspi_probe(struct udevice *bus)
{
struct mtk_qspi_platdata *plat = dev_get_platdata(bus);
struct mtk_qspi_priv *priv = dev_get_priv(bus);
priv->regs = (struct mtk_qspi_regs *)plat->reg_base;
priv->mem_base = (unsigned long *)plat->mem_base;
writel(MTK_QSPI_COMMAND_ENABLE, &priv->regs->wrprot);
return 0;
}
static const struct dm_spi_ops mtk_qspi_ops = {
.claim_bus = mtk_qspi_claim_bus,
.release_bus = mtk_qspi_release_bus,
.xfer = mtk_qspi_xfer,
.set_speed = mtk_qspi_set_speed,
.set_mode = mtk_qspi_set_mode,
};
static const struct udevice_id mtk_qspi_ids[] = {
{ .compatible = "mediatek,mt7629-qspi" },
{ }
};
U_BOOT_DRIVER(mtk_qspi) = {
.name = "mtk_qspi",
.id = UCLASS_SPI,
.of_match = mtk_qspi_ids,
.ops = &mtk_qspi_ops,
.ofdata_to_platdata = mtk_qspi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct mtk_qspi_platdata),
.priv_auto_alloc_size = sizeof(struct mtk_qspi_priv),
.probe = mtk_qspi_probe,
};
......@@ -400,10 +400,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
return mxc_spi_xfer_internal(mxcs, bitlen, dout, din, flags);
}
void spi_init(void)
{
}
/*
* Some SPI devices require active chip-select over multiple
* transactions, we achieve this using a GPIO. Still, the SPI
......
......@@ -39,10 +39,6 @@ static inline struct mxs_spi_slave *to_mxs_slave(struct spi_slave *slave)
return container_of(slave, struct mxs_spi_slave, slave);
}
void spi_init(void)
{
}
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
/* MXS SPI: 4 ports and 3 chip selects maximum */
......
......@@ -461,11 +461,6 @@ static inline struct omap3_spi_priv *to_omap3_spi(struct spi_slave *slave)
return container_of(slave, struct omap3_spi_priv, slave);
}
void spi_init(void)
{
/* do nothing */
}
void spi_free_slave(struct spi_slave *slave)
{
struct omap3_spi_priv *priv = to_omap3_spi(slave);
......
......@@ -9,16 +9,11 @@
* Driver for ARM PL022 SPI Controller.
*/
#include <asm/io.h>
#include <clk.h>
#include <common.h>
#include <dm.h>
#include <dm/platform_data/pl022_spi.h>
#include <fdtdec.h>
#include <linux/bitops.h>
#include <linux/bug.h>
#include <dm/platform_data/spi_pl022.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <spi.h>
#define SSP_CR0 0x000
......@@ -72,11 +67,7 @@
struct pl022_spi_slave {
void *base;
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct clk clk;
#else
unsigned int freq;
#endif
};
/*
......@@ -96,30 +87,13 @@ static int pl022_is_supported(struct pl022_spi_slave *ps)
return 0;
}
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
static int pl022_spi_ofdata_to_platdata(struct udevice *bus)
{
struct pl022_spi_pdata *plat = bus->platdata;
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(bus);
plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size);
return clk_get_by_index(bus, 0, &plat->clk);
}
#endif
static int pl022_spi_probe(struct udevice *bus)
{
struct pl022_spi_pdata *plat = dev_get_platdata(bus);
struct pl022_spi_slave *ps = dev_get_priv(bus);
ps->base = ioremap(plat->addr, plat->size);
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
ps->clk = plat->clk;
#else
ps->freq = plat->freq;
#endif
/* Check the PL022 version */
if (!pl022_is_supported(ps))
......@@ -240,11 +214,7 @@ static int pl022_spi_set_speed(struct udevice *bus, uint speed)
u16 scr = SSP_SCR_MIN, cr0 = 0, cpsr = SSP_CPSR_MIN, best_scr = scr,
best_cpsr = cpsr;
u32 min, max, best_freq = 0, tmp;
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
u32 rate = clk_get_rate(&ps->clk);
#else
u32 rate = ps->freq;
#endif
bool found = false;
max = spi_rate(rate, SSP_CPSR_MIN, SSP_SCR_MIN);
......@@ -316,6 +286,25 @@ static const struct dm_spi_ops pl022_spi_ops = {
};
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
static int pl022_spi_ofdata_to_platdata(struct udevice *bus)
{
struct pl022_spi_pdata *plat = bus->platdata;
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(bus);
struct clk clkdev;
int ret;
plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size);
ret = clk_get_by_index(bus, 0, &clkdev);
if (ret)
return ret;
plat->freq = clk_get_rate(&clkdev);
return 0;
}
static const struct udevice_id pl022_spi_ids[] = {
{ .compatible = "arm,pl022-spi" },
{ }
......@@ -327,11 +316,9 @@ U_BOOT_DRIVER(pl022_spi) = {
.id = UCLASS_SPI,
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.of_match = pl022_spi_ids,
#endif
.ops = &pl022_spi_ops,
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
.ofdata_to_platdata = pl022_spi_ofdata_to_platdata,
#endif
.ops = &pl022_spi_ops,
.platdata_auto_alloc_size = sizeof(struct pl022_spi_pdata),
.priv_auto_alloc_size = sizeof(struct pl022_spi_slave),
.probe = pl022_spi_probe,
......
......@@ -247,11 +247,6 @@ void spi_cs_deactivate(struct spi_slave *slave)
sh_qspi_cs_deactivate(ss);
}
void spi_init(void)
{
/* nothing to do */
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
......
......@@ -66,10 +66,6 @@ static int write_fifo_empty_wait(struct sh_spi *ss)
return 0;
}
void spi_init(void)
{
}
static void sh_spi_set_cs(struct sh_spi *ss, unsigned int cs)
{
unsigned long val = 0;
......
......@@ -36,13 +36,6 @@ static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
/* Public Functions */
/*=====================================================================*/
/*-----------------------------------------------------------------------
* Initialization
*/
void spi_init (void)
{
}
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
......
......@@ -126,8 +126,6 @@ int atmel_df_pow2(int argc, char * const argv[])
return 1;
}
spi_init();
while (1) {
struct spi_slave *slave;
char *line, *p;
......
......@@ -50,11 +50,9 @@
#endif
#if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI)
EXPORT_FUNC(dummy, void, spi_init, void)
EXPORT_FUNC(dummy, void, spi_setup_slave, void)
EXPORT_FUNC(dummy, void, spi_free_slave, void)
#else
EXPORT_FUNC(spi_init, void, spi_init, void)
EXPORT_FUNC(spi_setup_slave, struct spi_slave *, spi_setup_slave,
unsigned int, unsigned int, unsigned int, unsigned int)
EXPORT_FUNC(spi_free_slave, void, spi_free_slave, struct spi_slave *)
......
......@@ -287,13 +287,6 @@ int eeprom_write (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned c
# define CONFIG_SYS_DEF_EEPROM_ADDR CONFIG_SYS_I2C_EEPROM_ADDR
#endif
#if defined(CONFIG_MPC8XX_SPI)
extern void spi_init_f (void);
extern void spi_init_r (void);
extern ssize_t spi_read (uchar *, int, uchar *, int);
extern ssize_t spi_write (uchar *, int, uchar *, int);
#endif
/* $(BOARD)/$(BOARD).c */
int board_early_init_f (void);
int board_fix_fdt (void *rw_fdt_blob); /* manipulate the U-Boot fdt before its relocation */
......
......@@ -102,7 +102,6 @@
/* DSPI and Serial Flash */
#define CONFIG_CF_DSPI
#define CONFIG_HARD_SPI
#define CONFIG_SYS_SBFHDR_SIZE 0x7
#ifdef CONFIG_CMD_SPI
# define CONFIG_SYS_DSPI_CS2
......
......@@ -151,7 +151,6 @@
/* DSPI and Serial Flash */
#define CONFIG_CF_DSPI
#define CONFIG_SERIAL_FLASH
#define CONFIG_HARD_SPI
#define CONFIG_SYS_SBFHDR_SIZE 0x7
#ifdef CONFIG_CMD_SPI
......
......@@ -116,7 +116,6 @@
/* DSPI and Serial Flash */
#define CONFIG_CF_DSPI
#define CONFIG_SERIAL_FLASH
#define CONFIG_HARD_SPI
#define CONFIG_SYS_SBFHDR_SIZE 0x7
#ifdef CONFIG_CMD_SPI
......
......@@ -142,7 +142,6 @@
/* DSPI and Serial Flash */
#define CONFIG_CF_DSPI
#define CONFIG_HARD_SPI
#define CONFIG_SYS_SBFHDR_SIZE 0x13
#ifdef CONFIG_CMD_SPI
......
......@@ -370,11 +370,6 @@
#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
#define CONFIG_SYS_EEPROM_BUS_NUM 1
/*
* eSPI - Enhanced SPI
*/
#define CONFIG_HARD_SPI
#if defined(CONFIG_SPI_FLASH)
#define CONFIG_SF_DEFAULT_SPEED 10000000
#define CONFIG_SF_DEFAULT_MODE 0
......
......@@ -386,12 +386,6 @@
#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
#define CONFIG_SYS_EEPROM_BUS_NUM 1
/*
* eSPI - Enhanced SPI
*/
#define CONFIG_HARD_SPI
#define CONFIG_SF_DEFAULT_SPEED 10000000
#define CONFIG_SF_DEFAULT_MODE 0
......
......@@ -287,11 +287,6 @@
#define CONFIG_SYS_I2C_NCT72_ADDR 0x4C
#define CONFIG_SYS_I2C_IDT6V49205B 0x69
/*
* eSPI - Enhanced SPI
*/
#define CONFIG_HARD_SPI
#define CONFIG_SF_DEFAULT_SPEED 10000000
#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0
......
......@@ -182,10 +182,6 @@
#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
#ifndef CONFIG_TRAILBLAZER
/*
* eSPI - Enhanced SPI
*/
#define CONFIG_HARD_SPI
#define CONFIG_SF_DEFAULT_SPEED 10000000
#define CONFIG_SF_DEFAULT_MODE 0
......
......@@ -159,7 +159,6 @@
*/
#define CONFIG_TSEC1
#define CONFIG_TSEC2
#define CONFIG_HARD_SPI
/*
* NOR FLASH setup
......@@ -273,15 +272,6 @@
#define CONFIG_RTC_PCF8563
#define CONFIG_SYS_I2C_RTC_ADDR 0x51
/*
* SPI setup
*/
#ifdef CONFIG_HARD_SPI
#define CONFIG_SYS_GPIO1_PRELIM
#define CONFIG_SYS_GPIO1_DIR 0x00000001
#define CONFIG_SYS_GPIO1_DAT 0x00000001
#endif
/*
* Ethernet setup
*/
......
......@@ -43,7 +43,6 @@
#define CONFIG_MXC_UART
#define CONFIG_MXC_UART_BASE UART1_BASE
#define CONFIG_HARD_SPI
#define CONFIG_DEFAULT_SPI_BUS 1
#define CONFIG_DEFAULT_SPI_MODE (SPI_MODE_0 | SPI_CS_HIGH)
......
......@@ -143,7 +143,6 @@
/* SPI */
#ifdef CONFIG_CMD_SPI
#define CONFIG_HARD_SPI
#define CONFIG_SPI_HALF_DUPLEX
#endif
......
......@@ -576,11 +576,6 @@
#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 5
/*
* eSPI - Enhanced SPI
*/
#define CONFIG_HARD_SPI
#if defined(CONFIG_SPI_FLASH)
#define CONFIG_SF_DEFAULT_SPEED 10000000
#define CONFIG_SF_DEFAULT_MODE 0
......
......@@ -214,11 +214,6 @@ extern unsigned long get_board_sys_clk(unsigned long dummy);
#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 5
/*
* eSPI - Enhanced SPI
*/
#define CONFIG_HARD_SPI
#if defined(CONFIG_PCI)
/*
* General PCI
......
......@@ -66,7 +66,6 @@
#define CONFIG_CF_DSPI
#define CONFIG_SF_DEFAULT_SPEED 50000000
#define CONFIG_SERIAL_FLASH
#define CONFIG_HARD_SPI
#define CONFIG_ENV_SPI_BUS 0
#define CONFIG_ENV_SPI_CS 1
......
......@@ -42,11 +42,6 @@
#define CONFIG_MXC_UART
#define CONFIG_MXC_UART_BASE UART1_BASE
/*
* SPI Configs
* */
#define CONFIG_HARD_SPI /* puts SPI: ready */
/*
* MMC Configs
* */
......
......@@ -7,22 +7,15 @@
* in ofdata_to_platdata.
*/
#ifndef __PL022_SPI_H__
#define __PL022_SPI_H__
#ifndef __spi_pl022_h
#define __spi_pl022_h
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
#include <clk.h>
#endif
#include <fdtdec.h>
struct pl022_spi_pdata {
fdt_addr_t addr;
fdt_size_t size;
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct clk clk;
#else
unsigned int freq;
#endif
};
#endif
#endif /* __spi_pl022_h */
......@@ -366,6 +366,8 @@ static inline bool mtd_has_partitions(const struct mtd_info *mtd)
return !list_empty(&mtd->partitions);
}
bool mtd_partitions_used(struct mtd_info *master);
int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobecc);
int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
......@@ -562,8 +564,23 @@ unsigned mtd_mmap_capabilities(struct mtd_info *mtd);
/* drivers/mtd/mtdcore.h */
int add_mtd_device(struct mtd_info *mtd);
int del_mtd_device(struct mtd_info *mtd);
#ifdef CONFIG_MTD_PARTITIONS
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
#else
static inline int add_mtd_partitions(struct mtd_info *mtd,
const struct mtd_partition *parts,
int nparts)
{
return 0;
}
static inline int del_mtd_partitions(struct mtd_info *mtd)
{
return 0;
}
#endif
struct mtd_info *__mtd_next_device(int i);
#define mtd_for_each_device(mtd) \
......@@ -581,6 +598,7 @@ int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
const uint64_t length, uint64_t *len_incl_bad,
int *truncated);
bool mtd_dev_list_updated(void);
/* drivers/mtd/mtd_uboot.c */
int mtd_search_alternate_name(const char *mtdname, char *altname,
......
......@@ -239,6 +239,44 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
#define regmap_get(map, type, member, valp) \
regmap_range_get(map, 0, type, member, valp)
/**
* regmap_read_poll_timeout - Poll until a condition is met or a timeout occurs
*
* @map: Regmap to read from
* @addr: Offset to poll
* @val: Unsigned integer variable to read the value into
* @cond: Break condition (usually involving @val)
* @sleep_us: Maximum time to sleep between reads in us (0 tight-loops).
* @timeout_ms: Timeout in ms, 0 means never timeout
*
* Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_read
* error return value in case of a error read. In the two former cases,
* the last read value at @addr is stored in @val. Must not be called
* from atomic context if sleep_us or timeout_us are used.
*
* This is modelled after the regmap_read_poll_timeout macros in linux but
* with millisecond timeout.
*/
#define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_ms) \
({ \
unsigned long __start = get_timer(0); \
int __ret; \
for (;;) { \
__ret = regmap_read((map), (addr), &(val)); \
if (__ret) \
break; \
if (cond) \
break; \
if ((timeout_ms) && get_timer(__start) > (timeout_ms)) { \
__ret = regmap_read((map), (addr), &(val)); \
break; \
} \
if ((sleep_us)) \
udelay((sleep_us)); \
} \
__ret ?: ((cond) ? 0 : -ETIMEDOUT); \
})
/**
* regmap_update_bits() - Perform a read/modify/write using a mask
*
......
......@@ -117,13 +117,6 @@ struct spi_slave {
#define SPI_XFER_MMAP_END BIT(3) /* Memory Mapped End */
};
/**
* Initialization, must be called once on start up.
*
* TODO: I don't think we really need this.
*/
void spi_init(void);
/**
* spi_do_alloc_slave - Allocate a new SPI slave (internal)
*
......
......@@ -750,7 +750,6 @@ CONFIG_G_DNL_UMS_PRODUCT_NUM
CONFIG_G_DNL_UMS_VENDOR_NUM
CONFIG_H264_FREQ
CONFIG_H8300
CONFIG_HARD_SPI
CONFIG_HAS_ETH0
CONFIG_HAS_ETH1
CONFIG_HAS_ETH2
......
......@@ -144,3 +144,29 @@ static int dm_test_regmap_getset(struct unit_test_state *uts)
}
DM_TEST(dm_test_regmap_getset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Read polling test */
static int dm_test_regmap_poll(struct unit_test_state *uts)
{
struct udevice *dev;
struct regmap *map;
uint reg;
unsigned long start;
ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
map = syscon_get_regmap(dev);
ut_assertok_ptr(map);
start = get_timer(0);
ut_asserteq(-ETIMEDOUT,
regmap_read_poll_timeout(map, 0, reg,
(reg == 0xcacafafa),
1, 5 * CONFIG_SYS_HZ));
ut_assert(get_timer(start) > (5 * CONFIG_SYS_HZ));
return 0;
}
DM_TEST(dm_test_regmap_poll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册