#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
-#include <linux/dma-contiguous.h>
-
+#include <linux/vmalloc.h>
#include <linux/mmc/emmc_partitions.h>
#include <linux/amlogic/cpu_version.h>
#include <linux/amlogic/iomap.h>
#define EMMC_BLOCK_SIZE (0x100)
#define MAX_EMMC_BLOCK_SIZE (128*1024)
-static dev_t amlmmc_dtb_no;
-struct cdev amlmmc_dtb;
-struct device *dtb_dev;
-struct class *amlmmc_dtb_class;
-struct mmc_card *card_dtb;
-struct mmc_partitions_fmt *pt_fmt;
-
-/*
- * 2 copies dtb were stored in dtb area.
- * each is 256K.
- * timestamp&checksum are in the tail.
- * |<--------------DTB Area-------------->|
- * |<------DTB1------->|<------DTB2------>|
- */
-
#define DTB_RESERVE_OFFSET (4 * SZ_1M)
#define DTB_BLK_SIZE (0x200)
#define DTB_BLK_CNT (512)
#define MAX_TRANS_BLK (256)
#define MAX_TRANS_SIZE (MAX_TRANS_BLK * DTB_BLK_SIZE)
#define stamp_after(a, b) ((int)(b) - (int)(a) < 0)
+
struct aml_dtb_rsv {
u8 data[DTB_BLK_SIZE*DTB_BLK_CNT - 4*sizeof(unsigned int)];
unsigned int magic;
u8 valid[2];
};
+static dev_t amlmmc_dtb_no;
+struct cdev amlmmc_dtb;
+struct device *dtb_dev;
+struct class *amlmmc_dtb_class;
+struct mmc_card *card_dtb;
static struct aml_dtb_info dtb_infos = {{0, 0}, {0, 0} };
+struct mmc_partitions_fmt *pt_fmt;
+
/* dtb read&write operation with backup updates */
static unsigned int _calc_dtb_checksum(struct aml_dtb_rsv *dtb)
{
buffer = (unsigned int *) dtb;
while (i < size)
checksum += buffer[i++];
+
return checksum;
}
return !(checksum == dtb->checksum);
}
+static int _dtb_write(struct mmc_card *mmc,
+ int blk, unsigned char *buf)
+{
+ int ret = 0;
+ unsigned char *src = NULL;
+ int bit = mmc->csd.read_blkbits;
+ int cnt = CONFIG_DTB_SIZE >> bit;
+
+ src = (unsigned char *)buf;
+
+ mmc_claim_host(mmc->host);
+ do {
+ ret = mmc_write_internal(mmc, blk, MAX_TRANS_BLK, src);
+ if (ret) {
+ pr_err("%s: save dtb error", __func__);
+ ret = -EFAULT;
+ break;
+ }
+ blk += MAX_TRANS_BLK;
+ cnt -= MAX_TRANS_BLK;
+ src = (unsigned char *)buf + MAX_TRANS_SIZE;
+ } while (cnt != 0);
+ mmc_release_host(mmc->host);
+
+ return ret;
+}
static int _dtb_read(struct mmc_card *mmc,
int blk, unsigned char *buf)
int cpy = 1, valid = 0;
int bit = mmc->csd.read_blkbits;
int blk;
- unsigned int pgcnt;
- struct page *page = NULL;
- pgcnt = PAGE_ALIGN(CONFIG_DTB_SIZE) >> PAGE_SHIFT;
- page = dma_alloc_from_contiguous(NULL,
- pgcnt, get_order(CONFIG_DTB_SIZE));
-
- if (!page)
+ /* malloc a buffer. */
+ dtb = kmalloc(CONFIG_DTB_SIZE, GFP_KERNEL);
+ if (dtb == NULL) {
+ /*pr_err("%s: malloc buf failed", __func__);*/
return -ENOMEM;
- dtb = page_address(page);
+ }
/* read dtb2 1st, for compatibility without checksum. */
while (cpy >= 0) {
}
pr_info("total valid %d\n", valid);
- dma_release_from_contiguous(NULL, page, pgcnt);
+ kfree(dtb);
return ret;
}
-int amlmmc_dtb_write(struct mmc_card *card,
+int amlmmc_dtb_write(struct mmc_card *mmc,
unsigned char *buf, int len)
{
- int ret = 0, start_blk, size, blk_cnt;
- int bit = card->csd.read_blkbits;
- unsigned char *src = NULL;
- unsigned char *buffer = NULL;
+ int ret = 0, blk;
+ int bit = mmc->csd.read_blkbits;
+ int cpy, valid;
+ struct aml_dtb_rsv *dtb = (struct aml_dtb_rsv *) buf;
+ struct aml_dtb_info *info = &dtb_infos;
if (len > CONFIG_DTB_SIZE) {
pr_err("%s dtb data len too much", __func__);
return -EFAULT;
}
- start_blk = MMC_DTB_PART_OFFSET;
- if (start_blk < 0) {
- ret = -EINVAL;
- return ret;
- }
-
- buffer = kmalloc(DTB_CELL_SIZE, GFP_KERNEL);
- if (buffer == NULL) {
- pr_err("%s kmalloc dtb cell failed\n", __func__);
- buffer = kmalloc(DTB_CELL_SIZE, GFP_DMA);
- if (buffer == NULL) {
- pr_err("%s retry kmalloc dtb cell failed\n", __func__);
- return -ENOMEM;
- }
+ /* set info */
+ valid = info->valid[0] + info->valid[1];
+ if (valid == 0)
+ dtb->timestamp = 0;
+ else if (valid == 1) {
+ dtb->timestamp = 1 + info->stamp[info->valid[0]?0:1];
+ } else {
+ /* both are valid */
+ if (info->stamp[0] != info->stamp[1]) {
+ pr_info("timestamp are not same %d:%d\n",
+ info->stamp[0], info->stamp[1]);
+ dtb->timestamp = 1 +
+ stamp_after(info->stamp[1], info->stamp[0]) ?
+ info->stamp[1]:info->stamp[0];
+ } else
+ dtb->timestamp = 1 + info->stamp[0];
}
- start_blk >>= bit;
- size = CONFIG_DTB_SIZE;
- blk_cnt = size>>bit;
- src = (unsigned char *)buffer;
- while (blk_cnt != 0) {
- memcpy(src, buf, DTB_CELL_SIZE);
- ret = mmc_write_internal(card, start_blk, (DTB_CELL_SIZE>>bit), src);
- if (ret) {
- pr_err("%s: save dtb error", __func__);
- ret = -EFAULT;
- kfree(buffer);
- return ret;
- }
- start_blk += (DTB_CELL_SIZE>>bit);
- blk_cnt -= (DTB_CELL_SIZE>>bit);
- buf += DTB_CELL_SIZE;
+ /*setting version and magic*/
+ dtb->version = 1; /* base version */
+ dtb->magic = 0x00447e41; /*A~D\0*/
+ dtb->checksum = _calc_dtb_checksum(dtb);
+ pr_info("stamp %d, checksum 0x%x, version %d, magic %s\n",
+ dtb->timestamp, dtb->checksum,
+ dtb->version, (char *)&dtb->magic);
+ /* write down... */
+ for (cpy = 0; cpy < DTB_COPIES; cpy++) {
+ blk = ((get_reserve_partition_off_from_tbl()
+ + DTB_RESERVE_OFFSET) >> bit)
+ + cpy * DTB_BLK_CNT;
+ ret |= _dtb_write(mmc, blk, buf);
}
- kfree(buffer);
+
return ret;
}
unsigned char *dtb_ptr = NULL;
ssize_t read_size = 0;
int ret = 0;
- unsigned int pgcnt;
- struct page *page = NULL;
if (*ppos == CONFIG_DTB_SIZE)
return 0;
return -EFAULT;
}
- pgcnt = PAGE_ALIGN(CONFIG_DTB_SIZE) >> PAGE_SHIFT;
-
- page = dma_alloc_from_contiguous(NULL,
- pgcnt, get_order(CONFIG_DTB_SIZE));
- if (!page)
+ dtb_ptr = vmalloc(CONFIG_DTB_SIZE);
+ if (dtb_ptr == NULL)
return -ENOMEM;
- dtb_ptr = page_address(page);
mmc_claim_host(card_dtb->host);
ret = amlmmc_dtb_read(card_dtb,
*ppos += read_size;
exit:
- dma_release_from_contiguous(NULL, page, pgcnt);
+ mmc_release_host(card_dtb->host);
+ vfree(dtb_ptr);
return read_size;
}
unsigned char *dtb_ptr = NULL;
ssize_t write_size = 0;
int ret = 0;
- unsigned int pgcnt = PAGE_ALIGN(CONFIG_DTB_SIZE) >> PAGE_SHIFT;
- struct page *page = NULL;
if (*ppos == CONFIG_DTB_SIZE)
return 0;
return -EFAULT;
}
- page = dma_alloc_from_contiguous(NULL,
- pgcnt, get_order(CONFIG_DTB_SIZE));
- if (!page)
+ dtb_ptr = kmalloc(CONFIG_DTB_SIZE, GFP_KERNEL);
+ if (dtb_ptr == NULL)
return -ENOMEM;
- dtb_ptr = page_address(page);
+
+ mmc_claim_host(card_dtb->host);
if ((*ppos + count) > CONFIG_DTB_SIZE)
write_size = CONFIG_DTB_SIZE - *ppos;
*ppos += write_size;
exit:
- dma_release_from_contiguous(NULL, page, pgcnt);
+ mmc_release_host(card_dtb->host);
+ kfree(dtb_ptr);
return write_size;
}
int amlmmc_dtb_init(struct mmc_card *card)
{
int ret = 0;
-
card_dtb = card;
pr_info("%s: register dtb chardev", __func__);
static int mmc_transfer(struct mmc_card *card, unsigned int dev_addr,
unsigned int blocks, void *buf, int write)
{
+ u8 original_part_config;
+ u8 user_part_number = 0;
+ u8 cur_part_number;
+ bool switch_partition = false;
unsigned int size;
struct scatterlist sg;
struct mmc_request mrq = {0};
struct mmc_command stop = {0};
struct mmc_data data = {0};
int ret;
+ cur_part_number = card->ext_csd.part_config
+ &EXT_CSD_PART_CONFIG_ACC_MASK;
+ if (cur_part_number != user_part_number) {
+ switch_partition = true;
+ original_part_config = card->ext_csd.part_config;
+ cur_part_number = original_part_config
+ &(~EXT_CSD_PART_CONFIG_ACC_MASK);
+ ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PART_CONFIG, cur_part_number,
+ card->ext_csd.part_time);
+ if (ret)
+ return ret;
+ card->ext_csd.part_config = cur_part_number;
+ }
if ((dev_addr + blocks) >= mmc_capacity(card)) {
pr_info("[%s] %s range exceeds device capacity!\n",
__func__, write?"write":"read");
mmc_wait_for_req(card->host, &mrq);
ret = mmc_check_result(&mrq);
+ if (switch_partition == true) {
+ ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PART_CONFIG, original_part_config,
+ card->ext_csd.part_time);
+ if (ret)
+ return ret;
+ card->ext_csd.part_config = original_part_config;
+ }
+
return ret;
}