blob: fc9b3dcfd82d4f5802f0eca68548ceed381fba45 [file] [log] [blame]
#include <common.h>
#include <environment.h>
#include <nand.h>
#include <asm/io.h>
#include <malloc.h>
#include "aml_mtd.h"
#if ENABLE_RSV_DTB
#ifndef AML_NAND_UBOOT
#include<linux/cdev.h>
#include <linux/device.h>
#define DTB_NAME "amlnf_dtb"
static dev_t amlnf_dtb_no;
struct cdev amlnf_dtb;
struct device *dtb_dev = NULL;
struct class *amlnf_dtb_class = NULL;
#endif /* AML_NAND_UBOOT */
int dtb_erase_blk = -1;
extern int get_partition_from_dts(unsigned char * buffer);
struct aml_nand_chip *aml_chip_dtb = NULL;
int amlnf_dtb_save(u8 *buf, unsigned int len)
{
u8 *dtb_buf = NULL;
int ret = 0;
printk("%s: ####\n", __func__);
if (aml_chip_dtb == NULL) {
printk("%s: amlnf not init yet!\n", __func__);
return -EFAULT;
}
if (len > aml_chip_dtb->dtbsize) {
printk("warnning!!! %s: length too much\n", __func__);
len = aml_chip_dtb->dtbsize;
/*return -EFAULT;*/
}
dtb_buf = kzalloc(aml_chip_dtb->dtbsize, GFP_KERNEL);
if (dtb_buf == NULL) {
printk("%s: malloc failed\n", __func__);
ret = -1;
goto exit_err;
}
memset(dtb_buf, 0, aml_chip_dtb->dtbsize);
memcpy(dtb_buf, buf, len);
#if 0 //fixit
ret = amlnand_save_info_by_name(aml_chip_dtb,
(u8 *)&(aml_chip_dtb->amlnf_dtb),
dtb_buf,
(u8 *)DTD_INFO_HEAD_MAGIC,
aml_chip_dtb->dtbsize);
if (ret) {
printk("%s: nand dtd save failed\n", __func__);
ret = -EFAULT;
goto exit_err;
}
#else
struct mtd_info *mtd = &aml_chip_dtb->mtd;
aml_nand_save_dtb(mtd, dtb_buf);
#endif
exit_err:
if (dtb_buf) {
/* kfree(dtb_buf); */
kfree(dtb_buf);
dtb_buf = NULL;
}
return ret;
}
int amlnf_dtb_erase(void)
{
int ret = 0;
struct mtd_info *mtd = &aml_chip_dtb->mtd;
if (aml_chip_dtb == NULL) {
printk("%s amlnf not ready yet!\n", __func__);
return -1;
}
ret = aml_nand_erase_dtb(mtd);
if (ret) {
printk("erase dtb error,%s\n", __func__);
ret = -EFAULT;
}
return ret;
}
int amlnf_dtb_read(u8 *buf, int len)
{
u8 *dtb_buf = NULL;
int ret = 0;
printk("%s: ####\n", __func__);
if (len > aml_chip_dtb->dtbsize) {
printk("warnning!!! %s dtd length too much\n", __func__);
len = aml_chip_dtb->dtbsize;
/*return -EFAULT;*/
}
if (aml_chip_dtb == NULL) {
memset(buf, 0x0, len);
printk("%s amlnf not ready yet!\n", __func__);
return 0;
}
#if 0 //fixit
if (aml_chip_dtb->amlnf_dtb.arg_valid == 0) {
memset(buf, 0x0, len);
printk("%s arg_valid = 0 invalid\n", __func__);
return 0;
}
#endif
dtb_buf = kzalloc(aml_chip_dtb->dtbsize, GFP_KERNEL);
if (dtb_buf == NULL) {
printk("%s: malloc failed\n", __func__);
ret = -1;
goto exit_err;
}
memset(dtb_buf, 0, aml_chip_dtb->dtbsize);
#if 0 //fixit
ret = amlnand_read_info_by_name(aml_chip_dtb,
(u8 *)&(aml_chip_dtb->amlnf_dtb),
(u8 *)dtb_buf,
(u8 *)DTD_INFO_HEAD_MAGIC,
aml_chip_dtb->dtbsize);
if (ret) {
printk("dtb error,%s\n", __func__);
ret = -EFAULT;
goto exit_err;
}
#else
struct mtd_info *mtd = &aml_chip_dtb->mtd;
size_t offset = 0;
ret = aml_nand_read_dtb(mtd, offset, (u8 *)dtb_buf);
#endif
memcpy(buf, dtb_buf, len);
exit_err:
if (dtb_buf) {
/* kfree(dtb_buf); */
kfree(dtb_buf);
dtb_buf = NULL;
}
return ret;
}
/* under kernel */
#ifndef AML_NAND_UBOOT
ssize_t dtb_show(struct class *class, struct class_attribute *attr,
char *buf)
{
printk("dtb_show : #####\n");
/* fixme, read back and show in log! */
return 0;
}
ssize_t dtb_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
u8 *dtb_ptr = NULL;
printk("dtb_store : #####\n");
dtb_ptr = kzalloc(aml_chip_dtb->dtbsize, GFP_KERNEL);
if (dtb_ptr == NULL) {
printk("%s: malloc buf failed\n ", __func__);
return -ENOMEM;
}
/* fixme, why read back then write? */
ret = amlnf_dtb_read(dtb_ptr, aml_chip_dtb->dtbsize);
if (ret) {
printk("%s: read failed\n", __func__);
kfree(dtb_ptr);
return -EFAULT;
}
ret = amlnf_dtb_save(dtb_ptr, (unsigned int)aml_chip_dtb->dtbsize);
if (ret) {
printk("%s: save failed\n", __func__);
kfree(dtb_ptr);
return -EFAULT;
}
printk("dtb_store : OK #####\n");
return count;
}
static CLASS_ATTR(amlnf_dtb, S_IWUSR | S_IRUGO, dtb_show, dtb_store);
int dtb_open(struct inode *node, struct file *file)
{
return 0;
}
ssize_t dtb_read(struct file *file,
char __user *buf,
size_t count,
loff_t *ppos)
{
u8 *dtb_ptr = NULL;
struct nand_flash *flash = &aml_chip_dtb->flash;
ssize_t read_size = 0;
int ret = 0;
if (*ppos == aml_chip_dtb->dtbsize)
return 0;
if (*ppos >= aml_chip_dtb->dtbsize) {
printk("%s:data access out of space!\n", __func__);
return -EFAULT;
}
dtb_ptr = vmalloc(aml_chip_dtb->dtbsize + flash->pagesize);
if (dtb_ptr == NULL) {
printk("%s: malloc buf failed\n", __func__);
return -ENOMEM;
}
amlnand_get_device(aml_chip_dtb, CHIP_READING);
ret = amlnf_dtb_read((u8 *)dtb_ptr, aml_chip_dtb->dtbsize);
if (ret) {
printk("%s: read failed:%d\n", __func__, ret);
ret = -EFAULT;
goto exit;
}
if ((*ppos + count) > aml_chip_dtb->dtbsize)
read_size = aml_chip_dtb->dtbsize - *ppos;
else
read_size = count;
ret = copy_to_user(buf, (dtb_ptr + *ppos), read_size);
*ppos += read_size;
exit:
amlnand_release_device(aml_chip_dtb);
/* kfree(dtb_ptr); */
vfree(dtb_ptr);
return read_size;
}
ssize_t dtb_write(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
u8 *dtb_ptr = NULL;
ssize_t write_size = 0;
struct nand_flash *flash = &aml_chip_dtb->flash;
int ret = 0;
if (*ppos == aml_chip_dtb->dtbsize)
return 0;
if (*ppos >= aml_chip_dtb->dtbsize) {
printk("%s: data access out of space!\n", __func__);
return -EFAULT;
}
dtb_ptr = vmalloc(aml_chip_dtb->dtbsize + flash->pagesize);
if (dtb_ptr == NULL) {
printk("%s: malloc buf failed\n", __func__);
return -ENOMEM;
}
amlnand_get_device(aml_chip_dtb, CHIP_WRITING);
ret = amlnf_dtb_read((u8 *)dtb_ptr, aml_chip_dtb->dtbsize);
if (ret) {
printk("%s: read failed\n", __func__);
ret = -EFAULT;
goto exit;
}
if ((*ppos + count) > aml_chip_dtb->dtbsize)
write_size = aml_chip_dtb->dtbsize - *ppos;
else
write_size = count;
ret = copy_from_user((dtb_ptr + *ppos), buf, write_size);
ret = amlnf_dtb_save(dtb_ptr, (unsigned int)aml_chip_dtb->dtbsize);
if (ret) {
printk("%s: read failed\n", __func__);
ret = -EFAULT;
goto exit;
}
*ppos += write_size;
exit:
amlnand_release_device(aml_chip_dtb);
/* kfree(dtb_ptr); */
vfree(dtb_ptr);
return write_size;
}
long dtb_ioctl(struct file *file, u32 cmd, u32 args)
{
return 0;
}
static const struct file_operations dtb_ops = {
.open = dtb_open,
.read = dtb_read,
.write = dtb_write,
.unlocked_ioctl = dtb_ioctl,
};
#endif /* AML_NAND_UBOOT */
int amlnf_dtb_init(struct aml_nand_chip *aml_chip)
{
int ret = 0;
u8 *dtb_buf = NULL;
aml_chip_dtb = aml_chip;
//aml_chip->dtbsize = 0x20000; //fixit
dtb_buf = kzalloc(aml_chip_dtb->dtbsize, GFP_KERNEL);
if (dtb_buf == NULL) {
printk("nand malloc for dtb_buf failed\n");
ret = -1;
goto exit_err;
}
memset(dtb_buf, 0x0, aml_chip_dtb->dtbsize);
#if 0 //fixit
printk("nand dtb: probe.\n");
ret = amlnand_info_init(aml_chip,
(u8 *)&(aml_chip->amlnf_dtb),
dtb_buf,
(u8 *)DTD_INFO_HEAD_MAGIC,
aml_chip_dtb->dtbsize);
if (ret < 0) {
printk("%s failed\n", __func__);
ret = -1;
goto exit_err;
}
#endif
#ifndef AML_NAND_UBOOT
printk("%s: register dtb cdev\n", __func__);
ret = alloc_chrdev_region(&amlnf_dtb_no, 0, 1, DTB_NAME);
if (ret < 0) {
printk("%s alloc dtb dev_t number failed\n", __func__);
ret = -1;
goto exit_err;
}
cdev_init(&amlnf_dtb, &dtb_ops);
amlnf_dtb.owner = THIS_MODULE;
ret = cdev_add(&amlnf_dtb, amlnf_dtb_no, 1);
if (ret) {
printk("%s amlnf dtd dev add failed\n", __func__);
ret = -1;
goto exit_err1;
}
amlnf_dtb_class = class_create(THIS_MODULE, DTB_NAME);
if (IS_ERR(amlnf_dtb_class)) {
printk("%s: amlnf dtd class add failed\n", __func__);
ret = -1;
goto exit_err2;
}
ret = class_create_file(amlnf_dtb_class, &class_attr_env);
if (ret) {
printk("%s dev add failed\n", __func__);
ret = -1;
goto exit_err2;
}
dtb_dev = device_create(amlnf_dtb_class,
NULL,
amlnf_dtb_no,
NULL,
DTB_NAME);
if (IS_ERR(dtb_dev)) {
printk("%s: device_create failed\n", __func__);
ret = -1;
goto exit_err3;
}
printk("%s: register dtd cdev OK\n", __func__);
kfree(dtb_buf);
dtb_buf = NULL;
return ret;
exit_err3:
class_remove_file(amlnf_dtb_class, &class_attr_env);
class_destroy(amlnf_dtb_class);
exit_err2:
cdev_del(&amlnf_dtb);
exit_err1:
unregister_chrdev_region(amlnf_dtb_no, 1);
#endif /* AML_NAND_UBOOT */
exit_err:
if (dtb_buf) {
kfree(dtb_buf);
dtb_buf = NULL;
}
return ret;
}
int amlnf_dtb_init_partitions(struct aml_nand_chip *aml_chip)
{
int ret = 0;
u8 *dtb_buf = NULL;
aml_chip_dtb = aml_chip;
dtb_buf = kzalloc(aml_chip_dtb->dtbsize, GFP_KERNEL);
if (dtb_buf == NULL) {
printk("nand malloc for dtb_buf failed\n");
ret = -1;
goto exit_err;
}
memset(dtb_buf, 0x0, aml_chip_dtb->dtbsize);
#if 0 //fixit
printk("%s: probe. \n", __func__);
ret = amlnand_info_init(aml_chip,
(u8 *)&(aml_chip->amlnf_dtb),
dtb_buf,
(u8 *)DTD_INFO_HEAD_MAGIC,
aml_chip_dtb->dtbsize);
if (ret < 0) {
printk("%s failed\n", __func__);
ret = -1;
goto exit_err;
}
#endif
/*parse partitions table */
ret = get_partition_from_dts(dtb_buf);
if (ret) {
printk("%s get_partition_from_dts failed\n", __func__);
}
exit_err:
if (dtb_buf) {
kfree(dtb_buf);
dtb_buf = NULL;
}
return ret;
}
/*****************************************************************************
Prototype : amlnf_detect_dtb_partitions
Description : if 'dtb, write the bad block, we can't erase this block.
So we have to find the 'dtb' address in flash and flag it.
Input : struct amlnand_chip *aml_chip
Output : NULL
Return Value : ret
Called By : amlnand_get_partition_table
History :
1.Date : 2015/10/15
Author : Fly Mo
Modification : Created function
*****************************************************************************/
int amlnf_detect_dtb_partitions(struct aml_nand_chip *aml_chip)
{
#if 0 //fixit
int ret = 0;
u8 *dtb_buf = NULL;
aml_chip_dtb = aml_chip;
struct nand_arg_info test_amlnf_dtb;
memset(&test_amlnf_dtb, 0, sizeof(test_amlnf_dtb));
dtb_erase_blk = -1;
dtb_buf = aml_nand_malloc(aml_chip_dtb->dtbsize);
if (dtb_buf == NULL) {
printk("nand malloc for dtb_buf failed\n");
ret = -1;
goto exit_err;
}
memset(dtb_buf, 0x0, aml_chip_dtb->dtbsize);
test_amlnf_dtb.arg_type = aml_chip->amlnf_dtb.arg_type;
ret = amlnand_info_init(aml_chip,
(u8 *)&(test_amlnf_dtb),
dtb_buf,
(u8 *)DTD_INFO_HEAD_MAGIC,
aml_chip_dtb->dtbsize);
if (test_amlnf_dtb.arg_valid == 1) {
dtb_erase_blk = test_amlnf_dtb.valid_blk_addr;
}
printk("%s:dtb_erase_blk:%d\n", __func__,dtb_erase_blk);
exit_err:
if (dtb_buf) {
kfree(dtb_buf);
dtb_buf = NULL;
}
return ret;
#else
return 0;
#endif
}
/* for blank positions... */
int aml_nand_update_dtb(struct aml_nand_chip *aml_chip, char *dtb_ptr)
{
#if 0 //fixit
int ret = 0;
char malloc_flag = 0;
char *dtb_buf = NULL;
if (dtb_buf == NULL) {
dtb_buf = kzalloc(aml_chip_dtb->dtbsize, GFP_KERNEL);
malloc_flag = 1;
if (dtb_buf == NULL)
return -ENOMEM;
memset(dtb_buf, 0, aml_chip_dtb->dtbsize);
ret = amlnand_read_info_by_name(aml_chip,
(u8 *)&(aml_chip->amlnf_dtb),
(u8 *)dtb_buf,
(u8 *)DTD_INFO_HEAD_MAGIC,
aml_chip_dtb->dtbsize);
if (ret) {
printk("read dtb error,%s\n", __func__);
ret = -EFAULT;
goto exit;
}
} else
dtb_buf = dtb_ptr;
ret = amlnand_save_info_by_name(aml_chip,
(u8 *)&(aml_chip->amlnf_dtb),
(u8 *)dtb_buf,
(u8 *)DTD_INFO_HEAD_MAGIC,
aml_chip_dtb->dtbsize);
if (ret < 0)
printk("%s: update failed\n", __func__);
exit:
if (malloc_flag && (dtb_buf)) {
kfree(dtb_buf);
dtb_buf = NULL;
}
#endif
return 0;
}
#endif