blob: 455f354d1ac00cb66a96a43e7df43941533081f1 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <common.h>
#include <dm.h>
#include <spi.h>
//#include <nand.h>
#include <dm/device-internal.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <amlogic/storage.h>
#include <amlogic/aml_mtd.h>
#include <linux/mtd/spinand.h>
#include <dm/pinctrl.h>
static struct storage_t *snand_storage;
extern void mtd_store_set(struct mtd_info *mtd, int dev);
extern void mtd_store_mount_ops(struct storage_t *store);
extern int spinand_add_partitions(struct mtd_info *mtd,
const struct mtd_partition *parts,
int nbparts);
static inline void set_snand_storage(struct storage_t *snand)
{
snand_storage = snand;
}
static inline struct storage_t *get_snand_storage(void)
{
return snand_storage;
}
int board_nand_init(void)
{
u32 bus = 0, cs = 1, speed = 0, mode = 0;
struct spi_slave *slave;
struct udevice *dev;
int ret;
ret = spi_get_bus_and_cs(bus, cs, speed, mode,
NULL, NULL, &dev, &slave);
if (ret) {
printf("%s %d probe spi nand fail!\n",
__func__, __LINE__);
return 1;
}
return 0;
}
int spinand_fit_storage(struct mtd_info *info, char *name, u8 *id)
{
struct storage_t *spi_nand = NULL;
struct mtd_info *mtd = info;
int ret = 0;
if (get_snand_storage())
return 0;
spi_nand = kzalloc(sizeof(*spi_nand), GFP_KERNEL);
if (!spi_nand) {
debug("%s %d no enough memory!\n", __func__, __LINE__);
return -ENOMEM;
}
spi_nand->type = BOOT_SNAND;
spi_nand->init_flag = 0;
/* TODO:set name and id parameter */
memcpy(spi_nand->info.name,
name, strlen(name) > 32 ? 32 : strlen(name));
memcpy(spi_nand->info.id, id, NAND_MAX_ID_LEN);
spi_nand->info.read_unit = mtd->writesize;
spi_nand->info.write_unit = mtd->writesize;
spi_nand->info.erase_unit = mtd->erasesize;
spi_nand->info.caps = mtd->size;
spi_nand->info.mode = 1;
set_snand_storage(spi_nand);
mtd_store_mount_ops(spi_nand);
ret = store_register(spi_nand);
if (ret)
return ret;
mtd_store_set(mtd, 0);
return ret;
}
int spi_nand_pre(void)
{
struct storage_t *spi_nand = get_snand_storage();
if (spi_nand)
return 0;
return board_nand_init();
}
int spi_nand_probe(u32 init_flag)
{
struct spinand_device *spinand_dev;
struct storage_t *spi_nand = get_snand_storage();
const struct mtd_partition *spinand_partitions;
struct mtd_info *mtd;
int partition_count, ret;
static int probe_flag;
/* Maybe pinmux be modified by emmc, set again here */
extern struct mtd_info *mtd_store_get(int dev);
mtd = mtd_store_get(0);
spinand_dev = mtd_to_spinand(mtd);
//dm_spi_claim_bus(spinand_dev->slave->dev);
ret = pinctrl_select_state(spinand_dev->slave->dev->parent, "default");
if (ret) {
pr_err("select state %s failed\n", "default");
return 1;
}
if (probe_flag)
return 0;
#ifdef CONFIG_AML_MTDPART
extern const struct mtd_partition *get_spinand_partition_table(int *partitions);
spinand_partitions = get_spinand_partition_table(&partition_count);
ret = spinand_add_partitions(mtd, spinand_partitions,
partition_count);
if (ret) {
printf("%s %d can not add spinand partition!\n",
__func__, __LINE__);
return 1;
}
#endif
spi_nand = get_snand_storage();
if (!spi_nand) {
printf("%s %d can not get spi nand!\n",
__func__, __LINE__);
return 1;
}
spi_nand->init_flag = init_flag;
probe_flag = 1;
return 0;
}