SmartAudio/lichee/brandy/u-boot-2011.09/drivers/mmc/mmc.c

5853 lines
163 KiB
C

/*
* Copyright 2008, Freescale Semiconductor, Inc
* Andy Fleming
*
* Based vaguely on the Linux code
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <common.h>
#include <command.h>
#include <mmc.h>
#include <part.h>
#include <malloc.h>
#include <linux/list.h>
#include <div64.h>
#include "mmc_def.h"
#include <sys_config.h>
#include <asm/arch/clock.h>
#include "mmc_test.h"
DECLARE_GLOBAL_DATA_PTR;
/* Set block count limit because of 16 bit register limit on some hardware*/
#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
#endif
extern int sunxi_mmc_exit(int sdc_no);
//static struct list_head mmc_devices;
//static int cur_dev_num = -1;
static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst);
static ulong mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src);
int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd);
static int mmc_decode_ext_csd(struct mmc *mmc,struct mmc_ext_csd *dec_ext_csd, u8 *ext_csd);
int mmc_do_switch(struct mmc *mmc, u8 set, u8 index, u8 value, u32 timeout);
LIST_HEAD(mmc_devices);
static const unsigned int tacc_exp[] = {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};
static const unsigned int tacc_mant[] = {
0, 10, 12, 13, 15, 20, 25, 30,
35, 40, 45, 50, 55, 60, 70, 80,
};
int __board_mmc_getcd(u8 *cd, struct mmc *mmc) {
return -1;
}
int board_mmc_getcd(u8 *cd, struct mmc *mmc)__attribute__((weak,
alias("__board_mmc_getcd")));
int mmc_update_phase(struct mmc *mmc)
{
return mmc->update_phase(mmc);
}
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
{
#ifdef CONFIG_MMC_TRACE
int ret;
int i;
u8 *ptr;
MMCDBG("CMD_SEND:%d\n", cmd->cmdidx);
MMCDBG("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
MMCDBG("\t\tFLAG\t\t\t %d\n", cmd->flags);
ret = mmc->send_cmd(mmc, cmd, data);
switch (cmd->resp_type) {
case MMC_RSP_NONE:
MMCDBG("\t\tMMC_RSP_NONE\n");
break;
case MMC_RSP_R1:
MMCDBG("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
cmd->response[0]);
break;
case MMC_RSP_R1b:
MMCDBG("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
cmd->response[0]);
break;
case MMC_RSP_R2:
MMCDBG("\t\tMMC_RSP_R2\t\t 0x%08X \n",
cmd->response[0]);
MMCDBG("\t\t \t\t 0x%08X \n",
cmd->response[1]);
MMCDBG("\t\t \t\t 0x%08X \n",
cmd->response[2]);
MMCDBG("\t\t \t\t 0x%08X \n",
cmd->response[3]);
MMCMSG("\n");
MMCDBG("\t\t\t\t\tDUMPING DATA\n");
for (i = 0; i < 4; i++) {
int j;
MMCMSG("\t\t\t\t\t%03d - ", i*4);
ptr = (u8 *)(&cmd->response[i]);
ptr += 3;
for (j = 0; j < 4; j++)
MMCMSG("%02X ", *ptr--);
MMCMSG("\n");
}
break;
case MMC_RSP_R3:
MMCDBG("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
cmd->response[0]);
break;
default:
MMCDBG("\t\tERROR MMC rsp not supported\n");
break;
}
return ret;
#else
return mmc->send_cmd(mmc, cmd, data);
#endif
}
int mmc_send_status(struct mmc *mmc, int timeout)
{
struct mmc_cmd cmd;
int err;
#ifdef CONFIG_MMC_TRACE
int status;
#endif
#if defined(CONFIG_ARCH_SUN9IW1P1)
if(gd->securemode == SUNXI_SECURE_MODE_NO_SECUREOS)
return 0;
#endif
cmd.cmdidx = MMC_CMD_SEND_STATUS;
cmd.resp_type = MMC_RSP_R1;
if (!mmc_host_is_spi(mmc))
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
do {
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("Send status failed\n");
return err;
}
else if (cmd.response[0] & MMC_STATUS_RDY_FOR_DATA)
break;
udelay(1000);
if (cmd.response[0] & MMC_STATUS_MASK) {
MMCINFO("Status Error: 0x%08X\n", cmd.response[0]);
return COMM_ERR;
}
} while (timeout--);
#ifdef CONFIG_MMC_TRACE
status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
status = status;//avoid warning
MMCDBG("CURR STATE:%d\n", status);
#endif
if (timeout < 0) {
MMCINFO("Timeout waiting card ready\n");
return TIMEOUT;
}
return 0;
}
int mmc_set_blocklen(struct mmc *mmc, int len)
{
struct mmc_cmd cmd;
/*ddr mode not send blocklenth*/
if(mmc->io_mode == MMC_MODE_DDR_52MHz ){
return 0;
}
cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = len;
cmd.flags = 0;
return mmc_send_cmd(mmc, &cmd, NULL);
}
int mmc_set_erase_start_addr(struct mmc *mmc, unsigned int address)
{
struct mmc_cmd cmd;
int err = 0;
int timeout = 300; //ms
cmd.cmdidx = MMC_CMD_ERASE_GROUP_START;
cmd.resp_type = MMC_RSP_R1;
cmd.flags = 0;
if (mmc->high_capacity)
cmd.cmdarg = address;
else
cmd.cmdarg = address * mmc->write_bl_len;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err) {
MMCINFO("%s: send erase start addr failed\n", __FUNCTION__);
goto ERR_RET;
}
err = mmc_send_status(mmc, timeout); //ms
ERR_RET:
return err;
}
int mmc_set_erase_end_addr(struct mmc *mmc, unsigned int address)
{
struct mmc_cmd cmd;
int err = 0;
int timeout = 300; //ms
cmd.cmdidx = MMC_CMD_ERASE_GROUP_END;
cmd.resp_type = MMC_RSP_R1;
cmd.flags = 0;
if (mmc->high_capacity)
cmd.cmdarg = address;
else
cmd.cmdarg = address * mmc->write_bl_len;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err) {
MMCINFO("%s: send erase end addr failed\n", __FUNCTION__);
goto ERR_RET;
}
err = mmc_send_status(mmc, timeout); //ms
ERR_RET:
return err;
}
int mmc_launch_erase(struct mmc *mmc, unsigned int erase_arg)
{
struct mmc_cmd cmd;
cmd.cmdidx = MMC_CMD_ERASE;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = erase_arg;
cmd.flags = 0;
return mmc_send_cmd(mmc, &cmd, NULL);
}
unsigned int mmc_sd_erase_timeout(struct mmc *mmc, unsigned int erase_arg,
unsigned int qty)
{
return 0xffffff;
}
/* calculate erase timeout based on CSD and current card clock frequency */
unsigned int mmc_mmc_def_erase_timeout(struct mmc *mmc)
{
unsigned int erase_timeout = 0;
unsigned int r2w_factor = (mmc->csd[3]>>26)&0x7; //28:26
unsigned int tacc_clks = ((mmc->csd[0]>>8)&0xFF)*100; //111:104
unsigned int e = (mmc->csd[3]>>16)&0x7;
unsigned int m = (mmc->csd[3]>>19)&0xF;
unsigned int tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
unsigned int mult = 10 << r2w_factor;
unsigned int timeout_clks = tacc_clks * mult;
unsigned int timeout_us;
/* Avoid overflow: e.g. tacc_ns=80000000 mult=1280 */
if (tacc_ns < 1000000)
timeout_us = (tacc_ns * mult) / 1000;
else
timeout_us = (tacc_ns / 1000) * mult;
/*
* ios.clock is only a target. The real clock rate might be
* less but not that much less, so fudge it by multiplying by 2.
*/
timeout_clks <<= 1;
timeout_us += (timeout_clks * 1000) / (mmc->clock / 1000);
erase_timeout = timeout_us / 1000;
/*
* Theoretically, the calculation could underflow so round up
* to 1ms in that case.
*/
if (!erase_timeout)
erase_timeout = 1;
return erase_timeout;
}
unsigned int mmc_mmc_update_timeout(struct mmc *mmc)
{
int ret = 0;
char ext_csd[512];
struct mmc_ext_csd mmc_ext_csd;
MMCDBG("+++%s\n", __FUNCTION__);
ret = mmc_send_ext_csd(mmc, ext_csd);
if (ret) {
MMCINFO("send ext_csd failed\n");
goto ERR_RET;
}
ret = mmc_decode_ext_csd(mmc, &mmc_ext_csd, (unsigned char *)ext_csd);
if (ret) {
MMCINFO("decode ext_csd failed\n");
goto ERR_RET;
}
if (mmc_ext_csd.rev >= 4)
{
if (mmc_ext_csd.erase_group_def && mmc_ext_csd.hc_erase_timeout)
mmc->erase_timeout = mmc_ext_csd.hc_erase_timeout;
else
mmc->erase_timeout = mmc_mmc_def_erase_timeout(mmc);
mmc->trim_discard_timeout = mmc_ext_csd.trim_timeout;
mmc->secure_erase_timeout = mmc->erase_timeout * mmc_ext_csd.sec_erase_mult;
mmc->secure_trim_timeout = mmc->erase_timeout * mmc_ext_csd.sec_trim_mult;
}
else
{
if (mmc_ext_csd.rev == 3) {
if (mmc_ext_csd.erase_group_def && mmc_ext_csd.hc_erase_timeout)
mmc->erase_timeout = mmc_ext_csd.hc_erase_timeout;
else
mmc->erase_timeout = mmc_mmc_def_erase_timeout(mmc);
} else {
mmc->erase_timeout = mmc_mmc_def_erase_timeout(mmc);
}
mmc->trim_discard_timeout = 0x0;
mmc->secure_erase_timeout = 0x0;
mmc->secure_trim_timeout = 0x0;
}
ERR_RET:
MMCDBG("---%s %d\n", __FUNCTION__, ret);
return ret;
}
unsigned int mmc_mmc_erase_timeout(struct mmc *mmc, unsigned int arg,
unsigned int qty)
{
unsigned int erase_timeout = 0;
if (arg == MMC_DISCARD_ARG || arg == MMC_TRIM_ARG) {
if (!mmc->trim_discard_timeout) {
MMCINFO("invalid trim_discard_timeout is %d\n", mmc->trim_discard_timeout);
goto ERR_RET;
}
erase_timeout = mmc->trim_discard_timeout;
} else if (arg == MMC_ERASE_ARG) {
if (!mmc->erase_timeout) {
MMCINFO("invalid erase_timeout is %d\n", mmc->erase_timeout);
goto ERR_RET;
}
erase_timeout = mmc->erase_timeout;
} else if (arg == MMC_SECURE_ERASE_ARG) {
if (!mmc->secure_erase_timeout) {
MMCINFO("invalid secure_erase_timeout is %d\n", mmc->secure_erase_timeout);
goto ERR_RET;
}
erase_timeout = mmc->secure_erase_timeout;
} else if (arg == MMC_SECURE_TRIM1_ARG || arg == MMC_SECURE_TRIM2_ARG) {
if (!mmc->secure_trim_timeout) {
MMCINFO("invalid secure_trim_timeout is %d\n", mmc->secure_trim_timeout);
goto ERR_RET;
}
erase_timeout = mmc->secure_trim_timeout;
} else {
MMCINFO("Unknown erase argument 0x%x\n", arg);
goto ERR_RET;
}
erase_timeout *= qty;
return erase_timeout;
ERR_RET:
return 0;
}
unsigned int mmc_erase_timeout(struct mmc *mmc, unsigned int erase_arg,
unsigned int qty)
{
if (IS_SD(mmc))
return mmc_sd_erase_timeout(mmc, erase_arg, qty);
else {
return mmc_mmc_erase_timeout(mmc, erase_arg, qty);
}
}
int mmc_do_erase(struct mmc *mmc, unsigned int from,
unsigned int to, unsigned int erase_arg)
{
int err = 0;
unsigned int timeout = 0;
unsigned int qty = 0;
MMCDBG("+++%s\n", __FUNCTION__);
mmc_mmc_update_timeout(mmc);
err = mmc_set_erase_start_addr(mmc, from);
if (err) {
MMCINFO("set erase start addr failed\n");
goto ERR_RET;
}
err = mmc_set_erase_end_addr(mmc, to);
if (err) {
MMCINFO("set erase end addr failed\n");
goto ERR_RET;
}
err = mmc_launch_erase(mmc, erase_arg);
if (err) {
MMCINFO("launch erase failed\n");
goto ERR_RET;
}
if (IS_SD(mmc)) {
qty = to - from + 1;
} else {
qty = (to - from)/mmc->erase_grp_size + 1;
}
timeout = mmc_erase_timeout(mmc, erase_arg, qty);
if (!timeout) {
MMCINFO("calculate timeout failed\n");
err = -1;
goto ERR_RET;
}
err = mmc_send_status(mmc, timeout); //ms
ERR_RET:
MMCDBG("---%s %d\n", __FUNCTION__, err);
return err;
}
int mmc_erase_group_aligned(struct mmc *mmc, unsigned int from,
unsigned int nr)
{
if (!mmc->erase_grp_size)
return 0;
if (from % mmc->erase_grp_size || nr % mmc->erase_grp_size)
return 0;
return 1;
}
void mmc_align_erase_group(struct mmc *mmc, unsigned int from,
unsigned int nr, unsigned int *align_from, unsigned int *align_nr)
{
unsigned int rem, start, cnt;
MMCDBG("---start erase addr adjust... \n");
MMCDBG("--1-- from: %d, nr: %d, erase_group: %d\n", from, nr, mmc->erase_grp_size);
start = from;
cnt = nr;
rem = start % mmc->erase_grp_size;
if (rem) {
rem = mmc->erase_grp_size - rem;
start += rem;
if (cnt > rem)
cnt -= rem;
else {
MMCINFO("after adjust start addr, no more space need to erase!!\n");
goto RET;
}
}
rem = cnt % mmc->erase_grp_size;
if (rem)
cnt -= rem;
if (cnt == 0) {
MMCINFO("after adjust nr, no more space need to erase!!\n");
}
RET:
MMCDBG("--2-- from: %d, nr: %d, erase_group: %d\n", start, cnt, mmc->erase_grp_size);
*align_from = start;
*align_nr = cnt;
return ;
}
int mmc_erase(struct mmc *mmc, unsigned int from,
unsigned int nr, unsigned int erase_arg)
{
int ret;
MMCDBG("+++%s\n", __FUNCTION__);
if (nr == 0) {
ret = 0;
MMCINFO("No space need to be erased !\n");
goto ERR_RET;
}
if (!IS_SD(mmc))
{
if ((erase_arg != MMC_ERASE_ARG)
&& (erase_arg != MMC_SECURE_ERASE_ARG)
&& (erase_arg != MMC_TRIM_ARG)
&& (erase_arg != MMC_DISCARD_ARG)
&& (erase_arg != MMC_SECURE_TRIM1_ARG)) {
ret = -1;
MMCINFO("Unknown erase type!\n");
goto ERR_RET;
}
if ((erase_arg == MMC_ERASE_ARG)
||(erase_arg == MMC_SECURE_ERASE_ARG)) {
ret = mmc_erase_group_aligned(mmc, from, nr);
if (!ret) {
ret = -1;
MMCINFO("Erase addr is not erase group alignment!\n");
goto ERR_RET;
}
}
MMCINFO("erase from: %d, to: %d, cnt: %d, erase_group: %d\n",
from, from+nr-1, nr, mmc->erase_grp_size);
ret = mmc_do_erase(mmc, from, from+nr-1, erase_arg);
if (ret) {
ret = -1;
MMCINFO("Do erase failed!\n");
goto ERR_RET;
}
if (erase_arg == MMC_SECURE_TRIM1_ARG)
{
ret = mmc_do_erase(mmc, from, from+nr-1, MMC_SECURE_TRIM2_ARG);
if (ret) {
ret = -1;
MMCINFO("Do secure trim step 2 failed!\n");
goto ERR_RET;
}
}
}
else
{
MMCINFO("Don't support to erase SD card\n");
ret = -1;
}
ERR_RET:
MMCDBG("--%s ret%d\n", __FUNCTION__, ret);
return ret;
}
#define MMC_SANITIZE_REQ_TIMEOUT 240000
int mmc_do_sanitize(struct mmc *mmc)
{
int ret;
MMCINFO("%s: start emmc sanitize...\n", __FUNCTION__);
ret = mmc_do_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_SANITIZE_START, 1,
MMC_SANITIZE_REQ_TIMEOUT);
MMCINFO("%s end emmc sanitzie, ret %d\n", __FUNCTION__, ret);
return ret;
}
void mmc_add_skip_space(unsigned int *skip_space, int index,
unsigned int from, unsigned int nr)
{
MMCDBG("%s: %d from %d nr %d\n", __FUNCTION__, index, from, nr);
skip_space[0] |= 0x1<<index;
skip_space[index*2 + 1] = from;
skip_space[index*2 + 2] = nr;
}
int mmc_insecure_secure_erase(struct mmc *mmc, unsigned int from,
unsigned int nr, unsigned int *skip_space, int secure)
{
int ret = 0;
unsigned int align_from = from, align_nr = nr;
int skip;
unsigned int last_skip_len;
unsigned arg;
skip = 0;
last_skip_len = 0;
skip_space[0] = 0x0;
MMCDBG("%d %s: start erase, seucre %d...\n", __LINE__, __FUNCTION__, secure);
ret = mmc_erase_group_aligned(mmc, from, nr);
if (!ret) {
mmc_align_erase_group(mmc, from, nr, &align_from, &align_nr);
}
if (align_nr == 0)
{
MMCINFO("after align erase group, no space need to erase, erase failed\n");
mmc_add_skip_space(skip_space, skip, from, nr);
ret = -1;
}
else
{
if (secure)
arg = MMC_SECURE_ERASE_ARG;
else
arg = MMC_ERASE_ARG;
ret = mmc_erase(mmc, align_from, align_nr, arg);
if (ret) {
MMCINFO("erase failed, range %d - %d \n",
align_from, (align_from+align_nr));
mmc_add_skip_space(skip_space, skip, from, nr);
} else {
if (align_from - from)
mmc_add_skip_space(skip_space, skip++, from, (align_from-from));
if (skip)
last_skip_len = skip_space[2];
else
last_skip_len = 0;
if (nr - align_nr - last_skip_len)
mmc_add_skip_space(skip_space, skip++, (align_from+align_nr), (nr-align_nr-last_skip_len));
}
}
return ret;
}
int mmc_do_secure_wipe(struct mmc *mmc, unsigned int from, unsigned int nr,
unsigned int *skip_space)
{
int ret = 0;
int skip, not_support_wipe = 0;
MMCINFO("+++%s\n", __FUNCTION__);
if (nr == 0) {
MMCINFO("%s: on space need to erase, nr %d\n", __FUNCTION__, nr);
return 0;
}
if (IS_SD(mmc)) {
MMCINFO("%s: no mmc, do nothing\n", __FUNCTION__);
ret = -2;
goto ERR_RET;
}
skip = 0;
skip_space[0] = 0x0;
if (mmc->version <= MMC_VERSION_4_41) //ver 4.41 or older
{
if (mmc->secure_feature & EXT_CSD_SEC_ER_EN)
{
//support secure purge operation
if (mmc->secure_feature & EXT_CSD_SEC_GB_CL_EN) {
//support trim
MMCDBG("%d %s: start secure trim...\n", __LINE__, __FUNCTION__);
ret = mmc_erase(mmc, from, nr, MMC_SECURE_TRIM1_ARG);
if (ret) {
MMCINFO("secure trim failed, range %d - %d \n",
from, (from+nr));
mmc_add_skip_space(skip_space, skip, from, nr);
}
} else {
ret = mmc_insecure_secure_erase(mmc, from, nr, skip_space, 1);
}
}
else if (mmc->secure_feature & EXT_CSD_SEC_GB_CL_EN)
{
//support insecure trim operation
MMCDBG("%d %s: start trim...\n", __LINE__, __FUNCTION__);
ret = mmc_erase(mmc, from, nr, MMC_TRIM_ARG);
if (ret) {
MMCINFO("trim failed, range %d - %d \n", from, (from+nr));
mmc_add_skip_space(skip_space, skip, from, nr);
}
}
else
{
//is currently not an acceptable solution. writing of zeroes to the user data partition as a third option
MMCINFO("no method to wipe data (emmc <= v4.41)!\n ");
not_support_wipe = 1;
mmc_add_skip_space(skip_space, skip, from, nr);
}
}
else if (mmc->version <= MMC_VERSION_5_0) //v4.5 or newer
{
if (mmc->secure_feature & EXT_CSD_SEC_SANITIZE)
{
//support sanitize
if (mmc->secure_feature & EXT_CSD_SEC_GB_CL_EN) {
//support trim
MMCDBG("%d %s: start trim...\n", __LINE__, __FUNCTION__);
ret = mmc_erase(mmc, from, nr, MMC_TRIM_ARG);
if (ret) {
MMCINFO("trim failed, range %d - %d \n", from, (from+nr));
mmc_add_skip_space(skip_space, skip, from, nr);
goto ERR_RET;
}
} else {
ret = mmc_insecure_secure_erase(mmc, from, nr, skip_space, 0);
if (ret) {
MMCINFO("erase failed, range %d - %d \n", from, (from+nr));
goto ERR_RET;
}
}
MMCDBG("%d %s: start sanitize...\n", __LINE__, __FUNCTION__);
ret = mmc_do_sanitize(mmc);
if (ret) {
MMCINFO("do sanitize failed!!\n");
skip = 0;
skip_space[0] = 0x0;
mmc_add_skip_space(skip_space, skip, from, nr);
}
}
else
{
//If the eMMC 4.5 part does not expose the required command set, there is currently not an acceptable solution to sanitize this part for re-use
not_support_wipe = 1;
MMCINFO("no method to wipe data for current (emmc >v4.5)!\n ");
mmc_add_skip_space(skip_space, skip, from, nr);
}
}
else
{
MMCINFO("Unknown mmc version 0x%x\n", mmc->version);
ret = -3;
}
if (not_support_wipe)
ret = -2;
ERR_RET:
MMCINFO("---%s ret %d\n", __FUNCTION__, ret);
return ret;
}
int mmc_secure_wipe(int dev_num, unsigned int start,
unsigned int blkcnt, unsigned int *skip_space)
{
int ret = 0;
struct mmc *mmc = find_mmc_device(dev_num);
MMCINFO("========start %s\n", __FUNCTION__);
if (mmc->drv_wipe_feature & DRV_PARA_DISABLE_SECURE_WIPE) {
MMCINFO("driver do not support secure wipe operation\n");
return -1;
}
ret = mmc_do_secure_wipe(mmc, start, blkcnt, skip_space);
if (ret == -1) {
MMCINFO("erase failed!!!!!!\n");
} else if ((ret == -2) || (ret == -3)) {
MMCINFO("do not erase!!!!!!\n");
ret = -1;
} else if (skip_space[0]){
MMCINFO("skip some space when align erase group, need to write zeros.\n");
ret = 1;
} else {
MMCINFO("erase ok\n");
ret = 0;
}
MMCINFO("========end %s %d\n", __FUNCTION__, ret);
return ret;
}
int mmc_mmc_erase(int dev_num, unsigned int start,
unsigned int blkcnt, unsigned int *skip_space)
{
struct mmc *mmc = find_mmc_device(dev_num);
int i, ret1, ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support erase\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (mmc->drv_erase_feature & DRV_PARA_DISABLE_EMMC_ERASE) {
MMCINFO("%s: driver don't support erase\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (blkcnt == 0) {
MMCINFO("%s: no space need to erase, from:%d nr:%d\n",
__FUNCTION__, start, blkcnt);
ret = 0;
goto ERR_RET;
}
if ((start+blkcnt) > mmc->block_dev.lba) {
MMCINFO("%s: input lenght error!!!\n", __FUNCTION__);
blkcnt = mmc->block_dev.lba - start;
MMCINFO("%s: after clip, from: %d, nr: %d\n",
__FUNCTION__, start, blkcnt);
}
ret = mmc_insecure_secure_erase(mmc, start, blkcnt, skip_space, 0);
if (ret) {
MMCINFO("%s: erase emmc fail!\n", __FUNCTION__);
}
if (skip_space[0]) {
ret = 1;
MMCINFO("%s: some sectors in emmc are ignored!\n", __FUNCTION__);
for (i=0; i<2; i++)
if (skip_space[0] & (1<<i))
MMCINFO("--%d: from%d nr%d \n", i,
(int)skip_space[i*2+1], (int)skip_space[i*2+2]);
}
if ((mmc->drv_erase_feature & DRV_PARA_ENABLE_EMMC_SANITIZE_WHEN_ERASE)
&& (mmc->secure_feature & EXT_CSD_SEC_SANITIZE))
{
ret1 = mmc_do_sanitize(mmc);
if (ret1) {
MMCINFO("%s: emmc sanitize fail. ignore this error and continue...\n", __FUNCTION__);
}
}
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
int mmc_mmc_sanitize(int dev_num)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support erase\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (!(mmc->secure_feature & EXT_CSD_SEC_SANITIZE)) {
MMCINFO("%s: driver don't support sanitize\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
ret = mmc_do_sanitize(mmc);
if (ret) {
ret = -1;
MMCINFO("%s: sanitize fail!\n", __FUNCTION__);
}
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
int mmc_mmc_trim(int dev_num, unsigned int start, unsigned int blkcnt)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support trim\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (blkcnt == 0) {
MMCINFO("%s: no space need to erase, from:%d nr:%d\n",
__FUNCTION__, start, blkcnt);
ret = 0;
goto ERR_RET;
}
if ((start+blkcnt) > mmc->block_dev.lba) {
MMCINFO("%s: input lenght error!!!\n", __FUNCTION__);
blkcnt = mmc->block_dev.lba - start;
MMCINFO("%s: after clip, from: %d, nr: %d\n",
__FUNCTION__, start, blkcnt);
}
if (mmc->secure_feature & EXT_CSD_SEC_GB_CL_EN)
{
ret = mmc_erase(mmc, start, blkcnt, MMC_TRIM_ARG);
if (ret) {
MMCINFO("trim failed, range %d - %d\n", start, (start+blkcnt));
}
} else {
MMCINFO("%s: don't support trim!\n", __FUNCTION__);
ret = -1;
}
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
int mmc_mmc_discard(int dev_num, unsigned int start, unsigned int blkcnt)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support discard\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (blkcnt == 0) {
MMCINFO("%s: no space need to erase, from:%d nr:%d\n",
__FUNCTION__, start, blkcnt);
ret = 0;
goto ERR_RET;
}
if ((start+blkcnt) > mmc->block_dev.lba) {
MMCINFO("%s: input lenght error!!!\n", __FUNCTION__);
blkcnt = mmc->block_dev.lba - start;
MMCINFO("%s: after clip, from: %d, nr: %d\n",
__FUNCTION__, start, blkcnt);
}
/* eMMC v4.5 or later */
if (mmc->version >= MMC_VERSION_4_5)
{
ret = mmc_erase(mmc, start, blkcnt, MMC_DISCARD_ARG);
if (ret) {
MMCINFO("trim failed, range %d - %d\n", start, (start+blkcnt));
}
} else {
MMCINFO("%s: don't support discard!\n", __FUNCTION__);
ret = -1;
}
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
int mmc_mmc_secure_erase(int dev_num, unsigned int start,
unsigned int blkcnt, unsigned int *skip_space)
{
struct mmc *mmc = find_mmc_device(dev_num);
int i, ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support secure erase!\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (blkcnt == 0) {
MMCINFO("%s: no space need to erase, from:%d nr:%d\n",
__FUNCTION__, start, blkcnt);
ret = 0;
goto ERR_RET;
}
if ((start+blkcnt) > mmc->block_dev.lba) {
MMCINFO("%s: input lenght error!!!\n", __FUNCTION__);
blkcnt = mmc->block_dev.lba - start;
MMCINFO("%s: after clip, from: %d, nr: %d\n",
__FUNCTION__, start, blkcnt);
}
if (!(mmc->secure_feature & EXT_CSD_SEC_ER_EN)) {
MMCINFO("%s: don't support secure erase!\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
ret = mmc_insecure_secure_erase(mmc, start, blkcnt, skip_space,1);
if (ret) {
MMCINFO("%s: erase emmc fail!\n", __FUNCTION__);
}
if (skip_space[0]) {
MMCDBG("%s: some sectors in emmc are ignored!\n\n", __FUNCTION__);
for (i=0; i<2; i++)
if (skip_space[0] & (1<<i))
MMCDBG("--%d: from%d nr%d \n",
skip_space[i*2+1], skip_space[i*2+2]);
}
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
int mmc_mmc_secure_trim(int dev_num, unsigned int start, unsigned int blkcnt)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret = 0;
MMCDBG("start %s ...\n", __FUNCTION__);
if (IS_SD(mmc)) {
MMCINFO("%s: sd card don't support secure trim!\n", __FUNCTION__);
ret = -1;
goto ERR_RET;
}
if (blkcnt == 0) {
MMCINFO("%s: no space need to erase, from:%d nr:%d\n",
__FUNCTION__, start, blkcnt);
ret = 0;
goto ERR_RET;
}
if ((start+blkcnt) > mmc->block_dev.lba) {
MMCINFO("%s: input lenght error!!!\n", __FUNCTION__);
blkcnt = mmc->block_dev.lba - start;
MMCINFO("%s: after clip, from: %d, nr: %d\n",
__FUNCTION__, start, blkcnt);
}
if ((mmc->secure_feature & EXT_CSD_SEC_ER_EN)
&& (mmc->secure_feature & EXT_CSD_SEC_GB_CL_EN))
{
ret = mmc_erase(mmc, start, blkcnt, MMC_SECURE_TRIM1_ARG);
if (ret) {
MMCINFO("secure trim failed, range %d - %d\n", start, (start+blkcnt));
}
} else {
MMCINFO("%s: don't support secure trim!\n", __FUNCTION__);
ret = -1;
}
ERR_RET:
MMCDBG("end %s %d\n", __FUNCTION__, ret);
return ret;
}
#if 0
/* only clear first 128KB of boot part 0 to zeros */
int mmc_mmc_clear_boot_part1(int dev_num)
{
struct mmc *mmc = find_mmc_device(dev_num);
int err = 0;
void *src, *dst;
unsigned int blkcnt = 128 * 1024 * 2; //128KB
if (!(mmc->boot_support))
{
MMCINFO("Card doesn't support boot part\n");
return 0;
}
src = malloc(blkcnt * mmc->write_bl_len);
if (src == NULL) {
MMCINFO("%s: malloc mem failed\n", __FUNCTION__);
return -1;
}
memset(src, 0, blkcnt * mmc->write_bl_len);
dst = malloc(blkcnt * mmc->write_bl_len);
if (dst == NULL){
MMCINFO("%s: malloc mem failed\n", __FUNCTION__);
goto ERR_RET1;
}
err = mmc_switch_boot_bus_cond(dev_num,
MMC_SWITCH_BOOT_SDR_NORMAL,
MMC_SWITCH_BOOT_RST_BUS_COND,
MMC_SWITCH_BOOT_BUS_SDRx4_DDRx4);
if (err) {
MMCINFO("mmc switch boot bus condition failed\n");
goto ERR_RET;
}
MMCDBG("mmc switch boot bus condition succeed\n");
err = mmc_switch_boot_part(dev_num,
MMC_SWITCH_PART_BOOT_ACK_ENB,
MMC_SWITCH_PART_BOOT_PART_1);
if (err) {
MMCINFO("mmc switch boot part failed\n");
err = -1;
goto ERR_RET;
}
MMCDBG("mmc switch boot part succeed\n");
//switch to boot partition 1
if (mmc_switch_part(dev_num, MMC_SWITCH_PART_BOOT_PART_1)) {
MMCINFO("switch to boot1 partition failed\n");
err = -1;
goto ERR_RET;
}
mmc_bwrite(dev_num, 0, blkcnt, src);
mmc_bread(dev_num, 0, blkcnt, dst);
if (memcmp(src, dst, blkcnt*mmc->write_bl_len))
err = -1;
//switch back to user partiton 1
if (mmc_switch_part(dev_num, 0)) {
MMCINFO("switch to boot1 partition failed\n");
err = -1;
}
ERR_RET:
free(dst);
ERR_RET1:
free(src);
return err;
}
static unsigned long
mmc_berase_mass_pro(int dev_num)
{
int i, ret = 0, boot_ret;
struct mmc *mmc = find_mmc_device(dev_num);
unsigned long tmp_skip_space[1+2*2] = {0};
if (!IS_SD(mmc))
{
//erase boot part
boot_ret = mmc_mmc_clear_boot_part1(dev_num);
if (boot_ret) {
MMCINFO("%s: erase boot part 1 fail\n", __FUNCTION__);
}
//erase user part
ret = _mmc_insecure_secure_erase(mmc, 0, mmc->block_dev.lba, tmp_skip_space, 0);
if (ret) {
MMCINFO("%s: erase emmc user part fail!\n", __FUNCTION__);
}
if (tmp_skip_space[0]) {
MMCINFO("%s: some sectors in emmc part are ignored!\n\n", __FUNCTION__);
for (i=0; i<2; i++)
if (tmp_skip_space[0] & (1<<i))
MMCINFO("--%d: from%d nr%d \n",
tmp_skip_space[i*2+1], tmp_skip_space[i*2+2]);
}
}
else
{
MMCINFO("%s: don't support SD card\n", __FUNCTION__);
ret = -1;
}
return (ret | boot_ret);
}
#endif
int mmc_send_manual_stop(struct mmc *mmc)
{
struct mmc_cmd cmd;
int ret = 0;
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
cmd.flags = MMC_CMD_MANUAL;//let bsp send cmd12
ret = mmc_send_cmd(mmc, &cmd, NULL);
if (ret) {
MMCINFO("mmc fail to send manual stop cmd\n");
return ret;
}
return 0;
}
struct mmc *find_mmc_device(int dev_num)
{
struct mmc *m;
struct list_head *entry;
list_for_each(entry, &mmc_devices) {
m = list_entry(entry, struct mmc, link);
if (m->block_dev.dev == dev_num)
return m;
}
MMCINFO("MMC Device %d not found\n", dev_num);
return NULL;
}
//static ulong mmc_erase_t(struct mmc *mmc, ulong start, lbaint_t blkcnt)
//{
// struct mmc_cmd cmd;
// ulong end;
// int err, start_cmd, end_cmd;
//
// if (mmc->high_capacity)
// end = start + blkcnt - 1;
// else {
// end = (start + blkcnt - 1) * mmc->write_bl_len;
// start *= mmc->write_bl_len;
// }
//
// if (IS_SD(mmc)) {
// start_cmd = SD_CMD_ERASE_WR_BLK_START;
// end_cmd = SD_CMD_ERASE_WR_BLK_END;
// } else {
// start_cmd = MMC_CMD_ERASE_GROUP_START;
// end_cmd = MMC_CMD_ERASE_GROUP_END;
// }
//
// cmd.cmdidx = start_cmd;
// cmd.cmdarg = start;
// cmd.resp_type = MMC_RSP_R1;
// cmd.flags = 0;
//
// err = mmc_send_cmd(mmc, &cmd, NULL);
// if (err)
// goto err_out;
//
// cmd.cmdidx = end_cmd;
// cmd.cmdarg = end;
//
// err = mmc_send_cmd(mmc, &cmd, NULL);
// if (err)
// goto err_out;
//
// cmd.cmdidx = MMC_CMD_ERASE;
// cmd.cmdarg = SECURE_ERASE;
// cmd.resp_type = MMC_RSP_R1b;
//
// err = mmc_send_cmd(mmc, &cmd, NULL);
// if (err)
// goto err_out;
//
// return 0;
//
//err_out:
// puts("mmc erase failed\n");
// return err;
//}
static unsigned long
mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt)
{
int err = 0;
struct mmc *mmc = find_mmc_device(dev_num);
// unsigned blk = 0, blk_r = 0;
void* src = malloc(blkcnt * mmc->write_bl_len);
if(src == NULL){
printf("erase malloc failed\n");
return -1;
}
if (!mmc){
MMCINFO("Can not find mmc dev\n");
free(src);
return -1;
}
memset(src, 0, mmc->write_bl_len*blkcnt);
MMCINFO("erase blk %ld ~ %ld\n", start, start + blkcnt - 1);
err = mmc_bwrite(dev_num, start, blkcnt, src);
//mmcinfo("erase flag%d",err);
if(!err){
MMCINFO("erase failed\n");
}
free(src);
return err;
/*
if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size))
mmcdbg("\n\nCaution! Your devices Erase group is 0x%x\n"
"The erase range would be change to 0x%x~0x%x\n\n",
mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1),
((start + blkcnt + mmc->erase_grp_size)
& ~(mmc->erase_grp_size - 1)) - 1);
while (blk < blkcnt) {
blk_r = ((blkcnt - blk) > mmc->erase_grp_size) ?
mmc->erase_grp_size : (blkcnt - blk);
err = mmc_erase_t(mmc, start + blk, blk_r);
if (err)
break;
blk += blk_r;
}
return blk;
*/
}
#if defined(CONFIG_ARCH_SUN8IW5P1) || defined(CONFIG_ARCH_SUN8IW6P1) || defined(CONFIG_ARCH_SUN8IW8P1)||(defined CONFIG_ARCH_SUN8IW7P1)
/*
* 1. 18=3*6, each phase config try 3 times; don't try tx phase 2.
* 2. {1,1} is the best phase config to compile most of emmc
* 3. if retry ok, keep current phase and exit. use this new phase config for following operation.
* if retry fail, set phase to defaul value.
*/
#define MAX_RETRY_CNT 18
static int mmc_retry_request(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
{
//char sunxi_phase[9][2]={{1,1},{0,0},{1,0},{0,1},{1,2},{0,2},{2,0},{2,1},{2,2}};
char sunxi_phase[9][2]={{1,1},{0,0},{1,0},{0,1},{1,2},{0,2}};
//char sunxi_phase[9][2]={{0,1}, {1,1},{0,0},{1,0}, {1,2},{0,2}};
int retry_cnt;
int ret, err = 0;
u32 timeout = 1000;
if (!mmc->set_phase) {
return -1;
}
/* send manual stop */
mmc_send_manual_stop(mmc);
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
retry_cnt = 0;
do
{
/* set phase */
ret = mmc->set_phase(mmc, sunxi_phase[retry_cnt/3][0], sunxi_phase[retry_cnt/3][1]);
if (ret) {
MMCINFO("set phase fail, retry fail\n");
err = -1;
break;
}
/* retry */
err = mmc->send_cmd(mmc, cmd, data);
if (!err) {
/* if retry ok, keep current phase and exit. */
MMCINFO("retry ok! retry cnt %d\n", retry_cnt);
break;
} else {
/* send manual stop */
mmc_send_manual_stop(mmc);
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
}
retry_cnt++;
} while (retry_cnt < MAX_RETRY_CNT);
/* reset to default phase if retry fail */
if (err)
{
mmc->set_phase(mmc, sunxi_phase[0][0], sunxi_phase[0][1]);
if (ret) {
MMCINFO("retry fail, set phase to default fail\n");
}
}
return err;
}
#endif
static ulong
mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src)
{
struct mmc_cmd cmd;
struct mmc_data data;
int timeout = 1000;
if ((start + blkcnt) > mmc->block_dev.lba) {
MMCINFO("MMC: block number 0x%lx exceeds max(0x%lx)\n",
start + blkcnt, mmc->block_dev.lba);
return 0;
}
if (blkcnt > 1)
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
else
cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
if (mmc->high_capacity)
cmd.cmdarg = start;
else
cmd.cmdarg = start * mmc->write_bl_len;
cmd.resp_type = MMC_RSP_R1;
cmd.flags = 0;
data.src = src;
data.blocks = blkcnt;
data.blocksize = mmc->write_bl_len;
data.flags = MMC_DATA_WRITE;
if (mmc_send_cmd(mmc, &cmd, &data)) {
MMCINFO("mmc write failed\n");
#if defined(CONFIG_ARCH_SUN8IW5P1) || \
defined(CONFIG_ARCH_SUN8IW6P1) || \
defined (CONFIG_ARCH_SUN8IW8P1)|| \
(defined CONFIG_ARCH_SUN8IW7P1)
MMCINFO("mmc write: start retry....\n");
if (mmc_retry_request(mmc, &cmd, &data)) {
MMCINFO("mmc write: retry fail\n");
return 0;
} else {
MMCINFO("mmc write: retry ok\n");
}
#else
return 0;
#endif
}
/* SPI multiblock writes terminate using a special
* token, not a STOP_TRANSMISSION request.
*/
if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
cmd.flags = 0;
if (mmc_send_cmd(mmc, &cmd, NULL)) {
MMCINFO("mmc fail to send stop cmd\n");
return 0;
}
}
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
return blkcnt;
}
static ulong
mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
{
lbaint_t cur, blocks_todo = blkcnt;
struct mmc *mmc = find_mmc_device(dev_num);
if (blkcnt == 0){
MMCINFO("blkcnt should not be 0\n");
return 0;
}
if (!mmc){
MMCINFO("Can not found device\n");
return 0;
}
if (mmc_set_blocklen(mmc, mmc->write_bl_len)){
MMCINFO("set block len failed\n");
return 0;
}
do {
cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo;
if(mmc_write_blocks(mmc, start, cur, src) != cur){
MMCINFO("write block failed\n");
return 0;
}
blocks_todo -= cur;
start += cur;
// src += cur * mmc->write_bl_len;
src = (char*)src + cur * mmc->write_bl_len;
} while (blocks_todo > 0);
return blkcnt;
}
static ulong
mmc_bwrite_mass_pro(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
{
lbaint_t blocks_do = 0;
ulong start_todo = start;
signed int err = 0;
struct mmc *mmc = find_mmc_device(dev_num);
#ifdef USE_EMMC_BOOT_PART
MMCINFO("mmc start mass pro boot part...\n");
do{
if((start != BOOT0_SDMMC_START_ADDR)) {
MMCINFO("boot0 start address %d\n", start);
break;
}
if (!(mmc->boot_support)) //!(mmc->part_support & PART_SUPPORT)
{
MMCINFO("Card doesn't support boot part\n");
break;
}
err = mmc_switch_boot_bus_cond(dev_num, MMC_SWITCH_BOOT_SDR_NORMAL, MMC_SWITCH_BOOT_RST_BUS_COND, MMC_SWITCH_BOOT_BUS_SDRx4_DDRx4);
if (err) {
MMCINFO("mmc switch boot bus condition failed\n");
return err;
}
MMCDBG("mmc switch boot bus condition succeed\n");
err = mmc_switch_boot_part(dev_num, MMC_SWITCH_PART_BOOT_ACK_ENB, MMC_SWITCH_PART_BOOT_PART_1);
if (err) {
MMCINFO("mmc switch boot part failed\n");
return err;
}
MMCDBG("mmc switch boot part succeed\n");
}while(0);
#else
do{
if((start != BOOT0_SDMMC_START_ADDR)) {
MMCINFO("boot0 start address %d\n", start);
break;
}
if (!(mmc->boot_support)) //!(mmc->part_support & PART_SUPPORT)
{
MMCINFO("Card doesn't support boot part\n");
break;
}
err = mmc_switch_boot_part(dev_num, 0, MMC_SWITCH_PART_BOOT_PART_NONE); //disable boot mode
if (err) {
MMCINFO("mmc disable boot mode failed\n");
return err;
}
MMCDBG("mmc disable boot mode succeed\n");
}while(0);
#endif
#ifdef USE_EMMC_BOOT_PART
//write boot0.bin to boot partition
if ( (mmc->boot_support) && (start == BOOT0_SDMMC_START_ADDR) )//(mmc->part_support & PART_SUPPORT)
{
if (mmc_switch_part(dev_num, MMC_SWITCH_PART_BOOT_PART_1)) {
MMCINFO("switch to boot1 partition failed\n");
return 0;
}
//In eMMC boot partition,boot0.bin start from 0 sector,so we must change start form 16 to 0;
start_todo= 0;
}
#endif
blocks_do = mmc_bwrite(dev_num, start_todo, blkcnt, src);
//check boot0
if(start == BOOT0_SDMMC_START_ADDR){
u32 rblk = 0;
s32 err = 0;
void *dst = malloc(blkcnt * mmc->write_bl_len);
MMCDBG("try to check boot0\n");
if(dst == NULL){
MMCINFO("malloc mem failed\n");
return 0;
}
rblk = mmc_bread(dev_num, start_todo, blkcnt, dst);
if(rblk){
if(memcmp(src,dst,blkcnt * mmc->write_bl_len)){
err = -1;
}
}else{
err = -1;
}
free(dst);
if(err){
MMCINFO("check boot0 failded\n");
return 0;
}
MMCDBG("check boot0 ok\n");
}
#ifdef USE_EMMC_BOOT_PART
//
if ((mmc->boot_support) && (start == BOOT0_SDMMC_START_ADDR) )//(mmc->part_support & PART_SUPPORT)
{
//switch back to user partiton
if (mmc_switch_part(dev_num, 0)) {
MMCINFO("switch to boot1 partition failed\n");
return 0;
}
#ifdef USE_EMMC_USER_WHEN_USE_BOOT_PART//use eMMC boot and user part at the same time
MMCINFO("mmc start write user part after write boot part...\n");
blocks_do = mmc_bwrite(dev_num, start, blkcnt, src);
//check boot0
{
u32 rblk = 0;
s32 err = 0;
void *dst = malloc(blkcnt * mmc->write_bl_len);
MMCDBG("try to check boot0 in user part when use eMMC boot and user part at the same time\n");
if(dst == NULL){
MMCINFO("malloc mem failed\n");
return 0;
}
rblk = mmc_bread(dev_num, start, blkcnt, dst);
if(rblk){
if(memcmp(src,dst,blkcnt * mmc->write_bl_len)){
err = -1;
}
}else{
err = -1;
}
free(dst);
if(err){
MMCINFO("check boot0 in user part failded when use eMMC boot and user part at the same time\n");
return 0;
}
MMCDBG("check boot0 in user part ok when use eMMC boot and user part at the same time\n");
}
#endif
}
#endif
return blocks_do;
}
int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, lbaint_t blkcnt)
{
struct mmc_cmd cmd;
struct mmc_data data;
int timeout = 1000;
if (blkcnt > 1)
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
else
cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
if (mmc->high_capacity)
cmd.cmdarg = start;
else
cmd.cmdarg = start * mmc->read_bl_len;
cmd.resp_type = MMC_RSP_R1;
cmd.flags = 0;
data.dest = dst;
data.blocks = blkcnt;
data.blocksize = mmc->read_bl_len;
data.flags = MMC_DATA_READ;
if (mmc_send_cmd(mmc, &cmd, &data)) {
MMCINFO(" read block failed\n");
#if defined(CONFIG_ARCH_SUN8IW5P1) || \
defined(CONFIG_ARCH_SUN8IW6P1) || \
defined (CONFIG_ARCH_SUN8IW8P1)|| \
(defined CONFIG_ARCH_SUN8IW7P1)
MMCINFO("mmc read: start retry....\n");
if (mmc_retry_request(mmc, &cmd, &data)) {
MMCINFO("mmc read: retry fail\n");
return 0;
} else {
MMCINFO("mmc read: retry ok\n");
}
#else
return 0;
#endif
}
if (blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
cmd.flags = 0;
if (mmc_send_cmd(mmc, &cmd, NULL)) {
MMCINFO("mmc fail to send stop cmd\n");
return 0;
}
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
}
return blkcnt;
}
static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
lbaint_t cur, blocks_todo = blkcnt;
if (blkcnt == 0){
MMCINFO("blkcnt should not be 0\n");
return 0;
}
struct mmc *mmc = find_mmc_device(dev_num);
if (!mmc){
MMCINFO("Can not find mmc dev\n");
return 0;
}
if ((start + blkcnt) > mmc->block_dev.lba) {
MMCINFO("MMC: block number 0x%lx exceeds max(0x%lx)\n",
start + blkcnt, mmc->block_dev.lba);
return 0;
}
if (mmc_set_blocklen(mmc, mmc->read_bl_len)){
MMCINFO("Set block len failed\n");
return 0;
}
do {
cur = (blocks_todo > mmc->b_max) ? mmc->b_max : blocks_todo;
if(mmc_read_blocks(mmc, dst, start, cur) != cur){
MMCINFO("block read failed\n");
return 0;
}
blocks_todo -= cur;
start += cur;
// dst += cur * mmc->read_bl_len;
dst = (char*)dst + cur * mmc->read_bl_len;
} while (blocks_todo > 0);
return blkcnt;
}
static ulong mmc_bread_mass_pro(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
lbaint_t blocks_do = 0;
ulong start_todo = start;
#ifdef USE_EMMC_BOOT_PART
struct mmc *mmc = find_mmc_device(dev_num);
//write boot0.bin to boot partition
if ((mmc->boot_support) && (start == BOOT0_SDMMC_START_ADDR) )//(mmc->part_support & PART_SUPPORT)
{
if (mmc_switch_part(dev_num, MMC_SWITCH_PART_BOOT_PART_1))
{
MMCINFO("switch to boot1 partition failed\n");
return 0;
}
//In eMMC boot partition,boot0.bin start from 0 sector,so we must change start form 16 to 0;
start_todo= 0;
}
#endif
blocks_do = mmc_bread(dev_num, start_todo, blkcnt, dst);
#ifdef USE_EMMC_BOOT_PART
//
if ( (mmc->boot_support) && (start == BOOT0_SDMMC_START_ADDR) )//(mmc->part_support & PART_SUPPORT)
{
//switch back to user partiton
if (mmc_switch_part(dev_num, 0)) {
MMCINFO("switch to boot1 partition failed\n");
return 0;
}
}
#endif
return blocks_do;
}
#ifdef CONFIG_SUNXI_SECURE_STORAGE
static int check_secure_area(ulong start, lbaint_t blkcnt)
{
u32 sta_add = start;
u32 end_add = start + blkcnt -1;
u32 se_sta_add = SDMMC_SECURE_STORAGE_START_ADD;
u32 se_end_add = SDMMC_SECURE_STORAGE_START_ADD+(SDMMC_ITEM_SIZE*2*MAX_SECURE_STORAGE_MAX_ITEM)-1;
if(blkcnt<=(SDMMC_ITEM_SIZE*2*MAX_SECURE_STORAGE_MAX_ITEM)){
if(((sta_add >= se_sta_add)&&(sta_add <= se_end_add))
||((end_add >= se_sta_add)&&(end_add <= se_end_add))){
return 1;
}
}else{
if(((se_sta_add >= sta_add)&&(se_sta_add <= end_add))
||((se_end_add >= sta_add)&&(se_end_add <= end_add))){
return 1;
}
}
return 0;
}
static ulong
mmc_bwrite_mass_pro_secure(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_bwrite_mass_pro(dev_num, start, blkcnt, src);
}
static ulong mmc_bread_mass_pro_secure(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_bread_mass_pro(dev_num, start, blkcnt, dst);
}
static unsigned long
mmc_berase_secure(int dev_num, unsigned long start, lbaint_t blkcnt)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_berase(dev_num, start, blkcnt);
}
int mmc_secure_wipe_secure(int dev_num, unsigned int start, unsigned int blkcnt, unsigned int *skip_space)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_secure_wipe(dev_num, start, blkcnt, skip_space);
}
static ulong mmc_bread_secure(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_bread(dev_num, start, blkcnt, dst);
}
int mmc_mmc_erase_secure(int dev_num, unsigned int start, unsigned int blkcnt, unsigned int *skip_space)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_mmc_erase(dev_num, start, blkcnt, skip_space);
}
int mmc_mmc_trim_secure(int dev_num, unsigned int start, unsigned int blkcnt)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_mmc_trim(dev_num, start, blkcnt);
}
int mmc_mmc_discard_secure(int dev_num, unsigned int start, unsigned int blkcnt)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_mmc_discard(dev_num, start, blkcnt);
}
int mmc_mmc_sanitize_secure(int dev_num)
{
return mmc_mmc_sanitize(dev_num);
}
int mmc_mmc_secure_erase_secure(int dev_num, unsigned int start, unsigned int blkcnt, unsigned int *skip_space)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_mmc_secure_erase(dev_num, start, blkcnt, skip_space);
}
int mmc_mmc_secure_trim_secure(int dev_num, unsigned int start, unsigned int blkcnt)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_mmc_secure_trim(dev_num, start, blkcnt);
}
static ulong
mmc_bwrite_secure(int dev_num, ulong start, lbaint_t blkcnt, const void*src)
{
if(check_secure_area(start,blkcnt)){
MMCINFO("Should not w/r secure area in fun %s,line,%d in start %d,end %d\n",\
__FUNCTION__,__LINE__ ,start,start + blkcnt-1);
return -1;
}
return mmc_bwrite(dev_num, start, blkcnt, src);
}
static int get_sdmmc_secure_storage_max_item(void){
return MAX_SECURE_STORAGE_MAX_ITEM;
}
static int sdmmc_secure_storage_write(s32 dev_num,u32 item,u8 *buf , lbaint_t blkcnt)
{
s32 ret = 0;
if(buf == NULL){
MMCINFO("intput buf is NULL %d\n");
return -1;
}
if(item > MAX_SECURE_STORAGE_MAX_ITEM){
MMCINFO("item exceed %d\n",MAX_SECURE_STORAGE_MAX_ITEM);
return -1;
}
if(blkcnt > SDMMC_ITEM_SIZE){
MMCINFO("block count exceed %d\n",SDMMC_ITEM_SIZE);
return -1;
}
//first backups
ret = mmc_bwrite(dev_num,SDMMC_SECURE_STORAGE_START_ADD+SDMMC_ITEM_SIZE*2*item,blkcnt,buf);
if(ret != blkcnt){
MMCINFO("Write first backup failed\n");
return -1;
}
//second backups
ret = mmc_bwrite(dev_num,SDMMC_SECURE_STORAGE_START_ADD+SDMMC_ITEM_SIZE*2*item+SDMMC_ITEM_SIZE,blkcnt,buf);
if(ret != blkcnt){
MMCINFO("Write second backup failed\n");
return -1;
}
return blkcnt;
}
static int sdmmc_secure_storage_read(s32 dev_num,u32 item,u8 *buf , lbaint_t blkcnt)
{
s32 ret = 0;
s32 *fst_bak = (s32 *)buf;
if(buf == NULL){
MMCINFO("intput buf is NULL %d\n");
ret = -1;
goto out;
}
if(item > MAX_SECURE_STORAGE_MAX_ITEM){
MMCINFO("item exceed %d\n",MAX_SECURE_STORAGE_MAX_ITEM);
ret = -1;
goto out;
}
if(blkcnt > SDMMC_ITEM_SIZE){
MMCINFO("block count exceed %d\n",SDMMC_ITEM_SIZE);
ret = -1;
goto out;
}
//first backups
ret = mmc_bread(dev_num,SDMMC_SECURE_STORAGE_START_ADD+SDMMC_ITEM_SIZE*2*item,blkcnt,fst_bak);
if(ret != blkcnt){
MMCINFO("read first backup failed in fun %s line %d\n",__FUNCTION__,__LINE__);
ret = -1;
}
out:
return ret;
}
static int sdmmc_secure_storage_read_backup(s32 dev_num,u32 item,u8 *buf , lbaint_t blkcnt)
{
s32 ret = 0;
s32 *sec_bak = (s32 *)buf;
if(buf == NULL){
MMCINFO("intput buf is NULL %d\n");
ret = -1;
goto out;
}
if(item > MAX_SECURE_STORAGE_MAX_ITEM){
MMCINFO("item exceed %d\n",MAX_SECURE_STORAGE_MAX_ITEM);
ret = -1;
goto out;
}
if(blkcnt > SDMMC_ITEM_SIZE){
MMCINFO("block count exceed %d\n",SDMMC_ITEM_SIZE);
ret = -1;
goto out;
}
//second backups
ret = mmc_bread(dev_num,SDMMC_SECURE_STORAGE_START_ADD+SDMMC_ITEM_SIZE*2*item+SDMMC_ITEM_SIZE,blkcnt,sec_bak);
if(ret != blkcnt){
MMCINFO("read second backup failed fun %s line %d\n",__FUNCTION__,__LINE__);
ret = -1;
}
out:
return ret;
}
#endif
int mmc_go_idle(struct mmc* mmc)
{
struct mmc_cmd cmd;
int err;
udelay(1000);
cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_NONE;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("go idle failed\n");
return err;
}
udelay(2000);
return 0;
}
int
sd_send_op_cond(struct mmc *mmc)
{
int timeout = 1000;
int err;
struct mmc_cmd cmd;
do {
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("send app cmd failed\n");
return err;
}
cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
/*
* Most cards do not answer if some reserved bits
* in the ocr are set. However, Some controller
* can set bit 7 (reserved for low voltages), but
* how to manage low voltages SD card is not yet
* specified.
*/
cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
(mmc->voltages & 0xff8000);
if (mmc->version == SD_VERSION_2)
cmd.cmdarg |= OCR_HCS;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("send cmd41 failed\n");
return err;
}
udelay(1000);
} while ((!(cmd.response[0] & OCR_BUSY)) && timeout--);
if (timeout < 0){
MMCINFO("wait card init failed\n");
return UNUSABLE_ERR;
}
if (mmc->version != SD_VERSION_2)
mmc->version = SD_VERSION_1_0;
if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("spi read ocr failed\n");
return err;
}
}
mmc->ocr = cmd.response[0];
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
mmc->rca = 0;
return 0;
}
int mmc_send_op_cond(struct mmc *mmc)
{
int timeout = 10000;
struct mmc_cmd cmd;
int err;
/* Some cards seem to need this */
mmc_go_idle(mmc);
/* Asking to the card its capabilities */
cmd.cmdidx = MMC_CMD_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = 0x40ff8000;//foresee
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("mmc send op cond failed\n");
return err;
}
udelay(1000);
do {
cmd.cmdidx = MMC_CMD_SEND_OP_COND;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = (mmc_host_is_spi(mmc) ? 0 :
(mmc->voltages &
(cmd.response[0] & OCR_VOLTAGE_MASK)) |
(cmd.response[0] & OCR_ACCESS_MODE));
if (mmc->host_caps & MMC_MODE_HC)
cmd.cmdarg |= OCR_HCS;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("mmc send op cond failed\n");
return err;
}
udelay(1000);
} while (!(cmd.response[0] & OCR_BUSY) && timeout--);
if (timeout < 0){
MMCINFO("wait for mmc init failed\n");
return UNUSABLE_ERR;
}
if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
cmd.resp_type = MMC_RSP_R3;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("spi read ocr failed\n");
return err;
}
}
mmc->version = MMC_VERSION_UNKNOWN;
mmc->ocr = cmd.response[0];
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
mmc->rca = 1;
return 0;
}
int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
{
struct mmc_cmd cmd;
struct mmc_data data;
int err;
/* Get the Card Status Register */
cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
cmd.flags = 0;
data.dest = ext_csd;
data.blocks = 1;
data.blocksize = 512;
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
if(err)
MMCINFO("mmc send ext csd failed\n");
return err;
}
/* decode ext_csd */
static int mmc_decode_ext_csd(struct mmc *mmc,
struct mmc_ext_csd *dec_ext_csd, u8 *ext_csd)
{
int err = 0;
if ((!ext_csd) || !(dec_ext_csd))
return 0;
/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
dec_ext_csd->raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
dec_ext_csd->rev = ext_csd[EXT_CSD_REV];
if (dec_ext_csd->rev > 8) {
MMCINFO("unrecognised EXT_CSD revision %d, maybe ver5.2 or later version!\n", dec_ext_csd->rev);
//err = -1;
//goto out;
}
dec_ext_csd->raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
dec_ext_csd->raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
dec_ext_csd->raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
dec_ext_csd->raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3];
if (dec_ext_csd->rev >= 2) {
dec_ext_csd->sectors =
ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
}
dec_ext_csd->raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
dec_ext_csd->raw_erase_timeout_mult =
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
dec_ext_csd->raw_hc_erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
if (dec_ext_csd->rev >= 3) {
dec_ext_csd->erase_group_def =
ext_csd[EXT_CSD_ERASE_GROUP_DEF];
dec_ext_csd->hc_erase_timeout = 300 *
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
dec_ext_csd->hc_erase_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
}
dec_ext_csd->raw_hc_erase_gap_size =
ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
dec_ext_csd->raw_sec_trim_mult =
ext_csd[EXT_CSD_SEC_TRIM_MULT];
dec_ext_csd->raw_sec_erase_mult =
ext_csd[EXT_CSD_SEC_ERASE_MULT];
dec_ext_csd->raw_sec_feature_support =
ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
dec_ext_csd->raw_trim_mult =
ext_csd[EXT_CSD_TRIM_MULT];
if (dec_ext_csd->rev >= 4) {
dec_ext_csd->sec_trim_mult =
ext_csd[EXT_CSD_SEC_TRIM_MULT];
dec_ext_csd->sec_erase_mult =
ext_csd[EXT_CSD_SEC_ERASE_MULT];
dec_ext_csd->sec_feature_support =
ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
dec_ext_csd->trim_timeout = 300 *
ext_csd[EXT_CSD_TRIM_MULT];
}
dec_ext_csd->raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
/* eMMC v4.5 or later */
if (dec_ext_csd->rev >= 6) {
dec_ext_csd->generic_cmd6_time = 10 *
ext_csd[EXT_CSD_GENERIC_CMD6_TIME];
dec_ext_csd->power_off_longtime = 10 *
ext_csd[EXT_CSD_POWER_OFF_LONG_TIME];
} else {
dec_ext_csd->data_sector_size = 512;
}
//out:
return err;
}
int mmc_do_switch(struct mmc *mmc, u8 set, u8 index, u8 value, u32 timeout)
{
struct mmc_cmd cmd;
int ret;
cmd.cmdidx = MMC_CMD_SWITCH;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) |
(value << 8);
cmd.flags = 0;
ret = mmc_send_cmd(mmc, &cmd, NULL);
if(ret){
MMCINFO("mmc switch failed\n");
}
ret = mmc_update_phase(mmc);
if (ret)
{
MMCINFO("update clock failed after send switch cmd\n");
return ret;
}
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
return ret;
}
int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
{
int timeout = 1000;
return mmc_do_switch(mmc, set, index, value, timeout);
}
static int mmc_en_emmc_hw_rst(struct mmc *mmc)
{
char ext_csd[512] = {0};
int err;
err = mmc_send_ext_csd(mmc, ext_csd);
if (err) {
MMCINFO("mmc get extcsd fail -0\n");
return err;
}
if (ext_csd[162] & 0x1) {
MMCINFO("hw rst already enabled\n");
goto OUT;
}
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, \
EXT_CSD_RST_N_FUNCTION, EXT_CSD_RST_N_ENABLE);
if (err) {
MMCINFO("mmc enable hw rst fail\n");
return err;
}
err = mmc_send_ext_csd(mmc, ext_csd);
if (err) {
MMCINFO("mmc get extcsd fail -1\n");
return err;
}
if (!(ext_csd[162] & 0x1)) {
MMCINFO("en hw rst fail, 0x%x\n", ext_csd[162]);
return -1;
} else {
MMCINFO("en hw rst ok, 0x%x\n", ext_csd[162]);
}
OUT:
return 0;
}
static int mmc_chk_emmc_hw_rst(struct mmc *mmc)
{
char ext_csd[512] = {0};
int err;
err = mmc_send_ext_csd(mmc, ext_csd);
if (err) {
MMCINFO("mmc get extcsd fail -0\n");
return err;
}
if (ext_csd[162] & 0x1)
MMCINFO("Warining:hw rst already enabled!!!!!\n");
return 0;
}
int mmc_change_freq(struct mmc *mmc)
{
char ext_csd[512];
char cardtype;
int err;
int retry = 5;
mmc->card_caps = 0;
if (mmc_host_is_spi(mmc))
return 0;
/* Only version 4 supports high-speed */
if (mmc->version < MMC_VERSION_4)
return 0;
//here we assume eMMC support 8 bit
mmc->card_caps |= MMC_MODE_4BIT|MMC_MODE_8BIT;
err = mmc_send_ext_csd(mmc, ext_csd);
if (err){
MMCINFO("mmc get ext csd failed\n");
return err;
}
cardtype = ext_csd[196] & 0xf;
//retry for Toshiba emmc;for the first time Toshiba emmc change to HS
//it will return response crc err,so retry
do{
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
if(!err){
break;
}
MMCINFO("retry mmc switch(cmd6)\n");
}while(retry--);
if (err){
MMCINFO("mmc change to hs failed\n");
return err;
}
err = mmc_update_phase(mmc);
if (err)
{
MMCINFO("update clock failed\n");
return err;
}
/* Now check to see that it worked */
err = mmc_send_ext_csd(mmc, ext_csd);
if (err){
MMCINFO("send ext csd faild\n");
return err;
}
/* No high-speed support */
if (!ext_csd[185])
return 0;
/* High Speed is set, there are two types: 52MHz and 26MHz */
if (cardtype & MMC_HS_52MHZ)
mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
else
mmc->card_caps |= MMC_MODE_HS;
if (cardtype & MMC_DDR_52MHZ){
mmc->card_caps |= MMC_MODE_DDR_52MHz;
MMCDBG("get ddr OK!\n");
}else{
MMCINFO("get ddr fail!\n");
}
return 0;
}
int mmc_switch_boot_bus_cond(int dev_num, u32 boot_mode, u32 rst_bus_cond, u32 bus_width)
{
char ext_csd[512]={0};
unsigned char boot_bus_cond = 0;
int ret = 0;
struct mmc *mmc = find_mmc_device(dev_num);
if (!mmc){
MMCINFO("can not find mmc device\n");
return -1;
}
boot_bus_cond = (mmc->boot_bus_cond &
(~MMC_SWITCH_BOOT_MODE_MASK) & (~MMC_SWITCH_BOOT_RST_BUS_COND_MASK) & (~MMC_SWITCH_BOOT_BUS_WIDTH_MASK))
| ((boot_mode << 3) & MMC_SWITCH_BOOT_MODE_MASK)
| ((rst_bus_cond << 2) & MMC_SWITCH_BOOT_RST_BUS_COND_MASK)
| ((bus_width) & MMC_SWITCH_BOOT_BUS_WIDTH_MASK);
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_COND,boot_bus_cond);
if(ret){
MMCINFO("switch bus cond failed\n");
return -1;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if(ret){
MMCINFO("send ext csd failed\n");
return -1;
}
MMCDBG("boot bus cond:0x%x\n",ext_csd[EXT_CSD_BOOT_BUS_COND]);
if(boot_bus_cond!=ext_csd[EXT_CSD_BOOT_BUS_COND]) {
MMCINFO("Set boot bus cond failed,now bus con is 0x%x\n",ext_csd[EXT_CSD_BOOT_BUS_COND]);
return -1;
}
mmc->boot_bus_cond = boot_bus_cond;
return ret;
}
int mmc_switch_boot_part(int dev_num, u32 boot_ack, u32 boot_part)
{
char ext_csd[512]={0};
unsigned char part_config = 0;
int ret = 0;
struct mmc *mmc = find_mmc_device(dev_num);
if (!mmc){
MMCINFO("can not find mmc device\n");
return -1;
}
part_config = (mmc->part_config & (~MMC_SWITCH_PART_BOOT_PART_MASK) & (~MMC_SWITCH_PART_BOOT_ACK_MASK))
| ((boot_part << 3) & MMC_SWITCH_PART_BOOT_PART_MASK) | (boot_ack << 6);
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,part_config);
if(ret){
MMCINFO("switch boot partd failed\n");
return -1;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if(ret){
MMCINFO("send ext csd failed\n");
return -1;
}
MMCDBG("part conf:0x%x\n",ext_csd[EXT_CSD_PART_CONF]);
if(part_config!=ext_csd[EXT_CSD_PART_CONF]) {
MMCINFO("switch boot part failed,now part conf is 0x%x\n",ext_csd[EXT_CSD_PART_CONF]);
return -1;
}
mmc->part_config = part_config;
return ret;
}
int mmc_switch_part(int dev_num, unsigned int part_num)
{
char ext_csd[512]={0};
unsigned char part_config = 0;
int ret = 0;
struct mmc *mmc = find_mmc_device(dev_num);
MMCDBG("Try to switch part \n");
if (!mmc){
MMCINFO("can not find mmc device\n");
return -1;
}
part_config = (mmc->part_config & ~PART_ACCESS_MASK)
| (part_num & PART_ACCESS_MASK);
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,part_config);
if(ret){
MMCINFO("mmc switch part failed\n");
return -1;
}
ret = mmc_send_ext_csd(mmc, ext_csd);
if(ret){
MMCINFO("send ext csd failed\n");
return -1;
}
MMCDBG("part conf:0x%x\n",ext_csd[EXT_CSD_PART_CONF]);
if(part_config!=ext_csd[EXT_CSD_PART_CONF]) {
MMCINFO("switch boot part failed,now bus con is 0x%x\n",ext_csd[EXT_CSD_PART_CONF]);
return -1;
}
mmc->part_config = part_config;
MMCDBG("switch part succeed\n");
return ret;
}
int mmc_select_hwpart(int dev_num, int hwpart)
{
struct mmc *mmc = find_mmc_device(dev_num);
int ret;
if (!mmc)
return -1;
if (mmc->part_num == hwpart)
return 0;
if (mmc->part_config == MMCPART_NOAVAILABLE) {
printf("Card doesn't support part_switch\n");
return -1;
}
ret = mmc_switch_part(dev_num, hwpart);
if (ret)
return ret;
mmc->part_num = hwpart;
return 0;
}
int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
{
struct mmc_cmd cmd;
struct mmc_data data;
/* Switch the frequency */
cmd.cmdidx = SD_CMD_SWITCH_FUNC;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = (mode << 31) | 0xffffff;
cmd.cmdarg &= ~(0xf << (group * 4));
cmd.cmdarg |= value << (group * 4);
cmd.flags = 0;
data.dest = (char *)resp;
data.blocksize = 64;
data.blocks = 1;
data.flags = MMC_DATA_READ;
return mmc_send_cmd(mmc, &cmd, &data);
}
int sd_change_freq(struct mmc *mmc)
{
int err;
struct mmc_cmd cmd;
uint scr[2];
uint switch_status[16];
struct mmc_data data;
int timeout;
mmc->card_caps = 0;
if (mmc_host_is_spi(mmc))
return 0;
/* Read the SCR to find out if this card supports higher speeds */
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("Send app cmd failed\n");
return err;
}
cmd.cmdidx = SD_CMD_APP_SEND_SCR;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
cmd.flags = 0;
timeout = 3;
retry_scr:
data.dest = (char *)&scr;
data.blocksize = 8;
data.blocks = 1;
data.flags = MMC_DATA_READ;
err = mmc_send_cmd(mmc, &cmd, &data);
if (err) {
if (timeout--)
goto retry_scr;
MMCINFO("Send scr failed\n");
return err;
}
mmc->scr[0] = __be32_to_cpu(scr[0]);
mmc->scr[1] = __be32_to_cpu(scr[1]);
switch ((mmc->scr[0] >> 24) & 0xf) {
case 0:
mmc->version = SD_VERSION_1_0;
break;
case 1:
mmc->version = SD_VERSION_1_10;
break;
case 2:
mmc->version = SD_VERSION_2;
break;
default:
mmc->version = SD_VERSION_1_0;
break;
}
if (mmc->scr[0] & SD_DATA_4BIT)
mmc->card_caps |= MMC_MODE_4BIT;
/* Version 1.0 doesn't support switching */
if (mmc->version == SD_VERSION_1_0)
return 0;
timeout = 4;
while (timeout--) {
err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
(u8 *)&switch_status);
if (err){
MMCINFO("Check high speed status faild\n");
return err;
}
/* The high-speed function is busy. Try again */
if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
break;
}
/* If high-speed isn't supported, we return */
if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
return 0;
err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)&switch_status);
if (err){
MMCINFO("switch to high speed failed\n");
return err;
}
err = mmc_update_phase(mmc);
if (err)
{
MMCINFO("update clock failed\n");
return err;
}
if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
mmc->card_caps |= MMC_MODE_HS;
return 0;
}
/* frequency bases */
/* divided by 10 to be nice to platforms without floating point */
static const int fbase[] = {
10000,
100000,
1000000,
10000000,
};
/* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice
* to platforms without floating point.
*/
static const int multipliers[] = {
0, /* reserved */
10,
12,
13,
15,
20,
25,
30,
35,
40,
45,
50,
55,
60,
70,
80,
};
void mmc_set_ios(struct mmc *mmc)
{
mmc->set_ios(mmc);
}
void mmc_set_clock(struct mmc *mmc, uint clock)
{
if (clock > mmc->f_max)
clock = mmc->f_max;
if (clock < mmc->f_min)
clock = mmc->f_min;
mmc->clock = clock;
mmc_set_ios(mmc);
}
void mmc_set_bus_width(struct mmc *mmc, uint width)
{
mmc->bus_width = width;
mmc_set_ios(mmc);
}
int mmc_startup(struct mmc *mmc)
{
int err;
uint mult, freq;
u64 cmult, csize, capacity;
struct mmc_cmd cmd;
char ext_csd[512];
int timeout = 1000;
#ifdef CONFIG_MMC_SPI_CRC_ON
if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 1;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("Spi crc on off failed\n");
return err;
}
}
#endif
/* Put the Card in Identify Mode */
cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = 0;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("Put the Card in Identify Mode failed\n");
return err;
}
memcpy(mmc->cid, cmd.response, 16);
/*
* For MMC cards, set the Relative Address.
* For SD cards, get the Relatvie Address.
* This also puts the cards into Standby State
*/
if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
cmd.cmdarg = mmc->rca << 16;
cmd.resp_type = MMC_RSP_R6;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("send rca failed\n");
return err;
}
if (IS_SD(mmc))
mmc->rca = (cmd.response[0] >> 16) & 0xffff;
}
/* Get the Card-Specific Data */
cmd.cmdidx = MMC_CMD_SEND_CSD;
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
/* Waiting for the ready status */
mmc_send_status(mmc, timeout);
if (err){
MMCINFO("get csd failed\n");
return err;
}
mmc->csd[0] = cmd.response[0];
mmc->csd[1] = cmd.response[1];
mmc->csd[2] = cmd.response[2];
mmc->csd[3] = cmd.response[3];
if (mmc->version == MMC_VERSION_UNKNOWN) {
int version = (cmd.response[0] >> 26) & 0xf;
switch (version) {
case 0:
mmc->version = MMC_VERSION_1_2;
break;
case 1:
mmc->version = MMC_VERSION_1_4;
break;
case 2:
mmc->version = MMC_VERSION_2_2;
break;
case 3:
mmc->version = MMC_VERSION_3;
break;
case 4:
mmc->version = MMC_VERSION_4;
break;
default:
mmc->version = MMC_VERSION_1_2;
break;
}
}
/* divide frequency by 10, since the mults are 10x bigger */
freq = fbase[(cmd.response[0] & 0x7)];
mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
mmc->tran_speed = freq * mult;
mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
if (IS_SD(mmc))
mmc->write_bl_len = mmc->read_bl_len;
else
mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
if (mmc->high_capacity) {
csize = (mmc->csd[1] & 0x3f) << 16
| (mmc->csd[2] & 0xffff0000) >> 16;
cmult = 8;
} else {
csize = (mmc->csd[1] & 0x3ff) << 2
| (mmc->csd[2] & 0xc0000000) >> 30;
cmult = (mmc->csd[2] & 0x00038000) >> 15;
}
mmc->capacity = (csize + 1) << (cmult + 2);
mmc->capacity *= mmc->read_bl_len;
if (mmc->read_bl_len > 512)
mmc->read_bl_len = 512;
if (mmc->write_bl_len > 512)
mmc->write_bl_len = 512;
/* Select the card, and put it into Transfer Mode */
if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
cmd.cmdidx = MMC_CMD_SELECT_CARD;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("Select the card failed\n");
return err;
}
}
/*
* For SD, its erase group is always one sector
*/
mmc->erase_grp_size = 1;
mmc->part_config = MMCPART_NOAVAILABLE;
if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
/* check ext_csd version and capacity */
err = mmc_send_ext_csd(mmc, ext_csd);
if(!err){
/* update mmc version */
switch (ext_csd[192]) {
case 0:
mmc->version = MMC_VERSION_4;
break;
case 1:
mmc->version = MMC_VERSION_4_1;
break;
case 2:
mmc->version = MMC_VERSION_4_2;
break;
case 3:
mmc->version = MMC_VERSION_4_3;
break;
case 5:
mmc->version = MMC_VERSION_4_41;
break;
case 6:
mmc->version = MMC_VERSION_4_5;
break;
case 7:
mmc->version = MMC_VERSION_5_0;
break;
case 8:
mmc->version = MMC_VERSION_5_1;
break;
default:
if (ext_csd[EXT_CSD_REV] > 8)
mmc->version = MMC_VERSION_NEW_VER;
else
MMCINFO("Invalid ext_csd revision %d\n", ext_csd[192]);
break;
}
}
if (!err & (ext_csd[192] >= 2)) {
/*
* According to the JEDEC Standard, the value of
* ext_csd's capacity is valid if the value is more
* than 2GB
*/
capacity = ext_csd[212] << 0 | ext_csd[213] << 8 |
ext_csd[214] << 16 | ext_csd[215] << 24;
capacity *= 512;
if ((capacity >> 20) > 2 * 1024)
mmc->capacity = capacity;
}
/*
* Get timeout value
*/
mmc_mmc_update_timeout(mmc);
/*
* Check whether GROUP_DEF is set, if yes, read out
* group size from ext_csd directly, or calculate
* the group size from the csd value.
*
* WJQ, 20141022
* take write block as the unit of erase group
*/
{
int erase_gsz, erase_gmul;
int def_erase_grp_size, hc_erase_gpr_size;
int hc_erase_timeout;
erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
def_erase_grp_size = (erase_gsz + 1) * (erase_gmul + 1);
hc_erase_gpr_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 512 * 1024;
hc_erase_gpr_size = hc_erase_gpr_size / mmc->write_bl_len;
hc_erase_timeout = 300 * ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] && hc_erase_gpr_size && hc_erase_timeout)
mmc->erase_grp_size = hc_erase_gpr_size;
else
mmc->erase_grp_size = def_erase_grp_size;
}
mmc->secure_feature = ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
mmc->secure_removal_type = ext_csd[EXT_CSD_SECURE_REMOAL_TYPE];
/* store the partition info of emmc */
if (ext_csd[226])//ext_csd[160] & PART_SUPPORT
{
mmc->boot_support = 1;//lwj
mmc->part_support = ext_csd[160];
mmc->part_config = ext_csd[179];
mmc->boot1_lba = 128000*ext_csd[226]/512;
mmc->boot2_lba = 128000*ext_csd[226]/512;
mmc->boot_bus_cond = ext_csd[177];
MMCDBG("PART_SUPPORT mmc->boot1_lba = %d\n",mmc->boot1_lba);
}
else
{
MMCDBG("not PART_SUPPORT ext_csd[226] = %d\n",ext_csd[226]);
}
}
mmc_set_clock(mmc,25000000);
if (IS_SD(mmc))
err = sd_change_freq(mmc);
else
err = mmc_change_freq(mmc);
if (err){
MMCINFO("Change speed mode failed\n");
return err;
}
/* for re-update sample phase */
err = mmc_update_phase(mmc);
if (err)
{
MMCINFO("update clock failed\n");
return err;
}
/* Restrict card's capabilities by what the host can do */
mmc->card_caps &= mmc->host_caps;
if (IS_SD(mmc)) {
if (mmc->card_caps & MMC_MODE_4BIT) {
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->rca << 16;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("send app cmd failed\n");
return err;
}
cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 2;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("sd set bus width failed\n");
return err;
}
mmc_set_bus_width(mmc, 4);
}
if (mmc->card_caps & MMC_MODE_HS)
mmc_set_clock(mmc, 50000000);
else
mmc_set_clock(mmc, 25000000);
} else {
if (mmc->card_caps & MMC_MODE_8BIT) {
if( (mmc->card_caps & MMC_MODE_DDR_52MHz) ){
MMCINFO("ddr8 \n");
/* Set the card to use 8 bit ddr*/
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_DDR_8);
if (err){
MMCINFO("mmc switch bus width failed\n");
return err;
}
mmc_set_bus_width(mmc, 8);
}else{
/* Set the card to use 8 bit*/
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8);
if (err){
MMCINFO("mmc switch bus width8 failed\n");
return err;
}
mmc_set_bus_width(mmc, 8);
}
}else if (mmc->card_caps & MMC_MODE_4BIT) {
if ( (mmc->card_caps & MMC_MODE_DDR_52MHz) ){
MMCINFO("ddr4 \n");
/* Set the card to use 4 bit ddr*/
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_DDR_4);
if (err){
MMCINFO("mmc switch bus width failed\n");
return err;
}
mmc_set_bus_width(mmc, 4);
}else{
/* Set the card to use 4 bit*/
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_4);
if (err){
MMCINFO("mmc switch bus width failed\n");
return err;
}
mmc_set_bus_width(mmc, 4);
}
}
if( (mmc->card_caps & MMC_MODE_DDR_52MHz) ){
mmc->io_mode = MMC_MODE_DDR_52MHz;
MMCDBG("mmc mmc->io_mode = %x\n",mmc->io_mode);
mmc_set_clock(mmc, 50000000);
}else if (mmc->card_caps & MMC_MODE_HS) {
if (mmc->card_caps & MMC_MODE_HS_52MHz)
mmc_set_clock(mmc, 52000000);
else
mmc_set_clock(mmc, 26000000);
} else{
mmc_set_clock(mmc, 20000000);
}
}
/* fill in device description */
mmc->block_dev.lun = 0;
mmc->block_dev.type = 0;
mmc->block_dev.blksz = mmc->read_bl_len;
mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
if (IS_SD(mmc)){
sprintf(mmc->block_dev.vendor, "MID %06x PSN %08x",
mmc->cid[0] >> 24, (mmc->cid[2] << 8) | (mmc->cid[3] >> 24));
sprintf(mmc->block_dev.product, "PNM %c%c%c%c%c", mmc->cid[0] & 0xff,
(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
sprintf(mmc->block_dev.revision, "PRV %d.%d", mmc->cid[2] >> 28,
(mmc->cid[2] >> 24) & 0xf);
} else {
sprintf(mmc->block_dev.vendor, "MID %06x PSN %04x%04x",
mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
(mmc->cid[3] >> 16) & 0xffff);
sprintf(mmc->block_dev.product, "PNM %c%c%c%c%c%c", mmc->cid[0] & 0xff,
(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
(mmc->cid[2] >> 24) & 0xff);
sprintf(mmc->block_dev.revision, "PRV %d.%d", (mmc->cid[2] >> 20) & 0xf,
(mmc->cid[2] >> 16) & 0xf);
}
MMCDBG("%s\n", mmc->block_dev.vendor);
MMCDBG("%s -- 0x%02x-%02x-%02x-%02x-%02x-%02x\n", mmc->block_dev.product,
mmc->cid[0] & 0xff, (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
MMCDBG("%s\n", mmc->block_dev.revision);
if (IS_SD(mmc)){
MMCDBG("MDT m-%d y-%d\n", ((mmc->cid[3] >> 8) & 0xF), (((mmc->cid[3] >> 12) & 0xFF) + 2000));
} else {
if (ext_csd[192] > 4) {
MMCDBG("MDT m-%d y-%d\n", ((mmc->cid[3] >> 12) & 0xF),
(((mmc->cid[3] >> 8) & 0xF) < 13) ? (((mmc->cid[3] >> 8) & 0xF) + 2013) : (((mmc->cid[3] >> 8) & 0xF) + 1997));
} else {
MMCDBG("MDT m-%d y-%d\n", ((mmc->cid[3] >> 12) & 0xF), (((mmc->cid[3] >> 8) & 0xF) + 1997));
}
}
MMCINFO("CID 0x%x 0x%x 0x%x 0x%x\n",mmc->cid[0],mmc->cid[1],mmc->cid[2],mmc->cid[3]);
/*printf("---------------ext_csd[192] = %d--------------\n", ext_csd[192]);*/
if(!IS_SD(mmc)){
switch(mmc->version)
{
case MMC_VERSION_1_2:
MMCINFO("MMC ver 1.2\n");
break;
case MMC_VERSION_1_4:
MMCINFO("MMC ver 1.4\n");
break;
case MMC_VERSION_2_2:
MMCINFO("MMC ver 2.2\n");
break;
case MMC_VERSION_3:
MMCINFO("MMC ver 3.0\n");
break;
case MMC_VERSION_4:
MMCINFO("MMC ver 4.0\n");
break;
case MMC_VERSION_4_1:
MMCINFO("MMC ver 4.1\n");
break;
case MMC_VERSION_4_2:
MMCINFO("MMC ver 4.2\n");
break;
case MMC_VERSION_4_3:
MMCINFO("MMC ver 4.3\n");
break;
case MMC_VERSION_4_41:
MMCINFO("MMC ver 4.41\n");
break;
case MMC_VERSION_4_5:
MMCINFO("MMC ver 4.5\n");
break;
case MMC_VERSION_5_0:
MMCINFO("MMC ver 5.0\n");
break;
case MMC_VERSION_5_1:
MMCINFO("MMC v5.1\n");
break;
case MMC_VERSION_NEW_VER:
MMCINFO("MMC v5.2 or later version\n");
break;
default:
MMCINFO("Unknow MMC ver\n");
break;
}
}
mmc->clock_after_init = mmc->clock;/*back up clock after mmc init*/
if (!IS_SD(mmc)) {
if (mmc->drv_hwrst_feature & DRV_PARA_ENABLE_EMMC_HWRST) {
err = mmc_en_emmc_hw_rst(mmc);
if (err)
return err;
} else {
err = mmc_chk_emmc_hw_rst(mmc);
if (err)
return err;
}
}
MMCINFO("mmc clk %d\n", mmc->clock);
//MMCINFO("---mmc bus_width %d---\n", mmc->bus_width);
MMCINFO("SD/MMC Card: %dbit, capacity: %ldMB\n",(mmc->card_caps & MMC_MODE_8BIT)?8:(mmc->card_caps & MMC_MODE_4BIT ? 4 : 1), mmc->block_dev.lba>>11);
MMCINFO("boot0 capacity: %dKB,boot1 capacity: %dKB\n"
,mmc->boot1_lba*512/1024,mmc->boot2_lba*512/1024);
MMCINFO("***SD/MMC %d init OK!!!***\n", mmc->control_num);
//init_part(&mmc->block_dev);
return 0;
}
int mmc_send_if_cond(struct mmc *mmc)
{
struct mmc_cmd cmd;
int err;
cmd.cmdidx = SD_CMD_SEND_IF_COND;
/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
cmd.cmdarg = ((mmc->voltages & 0xff8000) != 0) << 8 | 0xaa;
cmd.resp_type = MMC_RSP_R7;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
if (err){
MMCINFO("mmc send if cond failed\n");
return err;
}
if ((cmd.response[0] & 0xff) != 0xaa)
return UNUSABLE_ERR;
else
mmc->version = SD_VERSION_2;
return 0;
}
int mmc_register(struct mmc *mmc)
{
/* Setup the universal parts of the block interface just once */
mmc->block_dev.if_type = IF_TYPE_MMC;
//mmc->block_dev.dev = cur_dev_num++;
mmc->block_dev.dev = mmc->control_num;
mmc->block_dev.removable = 1;
//#if 0
#ifndef CONFIG_SUNXI_SECURE_STORAGE
mmc->block_dev.block_read = mmc_bread;
mmc->block_dev.block_write = mmc_bwrite;
mmc->block_dev.block_erase = mmc_berase;
mmc->block_dev.block_secure_wipe = mmc_secure_wipe;
mmc->block_dev.block_read_mass_pro = mmc_bread_mass_pro;
mmc->block_dev.block_write_mass_pro = mmc_bwrite_mass_pro;
//mmc->block_dev.block_erase_mass_pro = mmc_berase_mass_pro;
mmc->block_dev.block_read_secure = NULL;
mmc->block_dev.block_write_secure = NULL;
mmc->block_dev.block_get_item_secure= NULL;
mmc->block_dev.block_mmc_erase = mmc_mmc_erase;
mmc->block_dev.block_mmc_trim = mmc_mmc_trim;
mmc->block_dev.block_mmc_discard = mmc_mmc_discard;
mmc->block_dev.block_mmc_sanitize = mmc_mmc_sanitize;
mmc->block_dev.block_mmc_secure_erase = mmc_mmc_secure_erase;
mmc->block_dev.block_mmc_secure_trim = mmc_mmc_secure_trim;
#else
mmc->block_dev.block_read = mmc_bread_secure;
mmc->block_dev.block_write = mmc_bwrite_secure;
mmc->block_dev.block_erase = mmc_berase_secure;
mmc->block_dev.block_secure_wipe = mmc_secure_wipe_secure;
mmc->block_dev.block_read_mass_pro = mmc_bread_mass_pro_secure;
mmc->block_dev.block_write_mass_pro = mmc_bwrite_mass_pro_secure;
mmc->block_dev.block_read_secure = sdmmc_secure_storage_read;
mmc->block_dev.block_read_secure_backup = sdmmc_secure_storage_read_backup;
mmc->block_dev.block_write_secure = sdmmc_secure_storage_write;
mmc->block_dev.block_get_item_secure= get_sdmmc_secure_storage_max_item;
mmc->block_dev.block_mmc_erase = mmc_mmc_erase_secure;
mmc->block_dev.block_mmc_trim = mmc_mmc_trim_secure;
mmc->block_dev.block_mmc_discard = mmc_mmc_discard_secure;
mmc->block_dev.block_mmc_sanitize = mmc_mmc_sanitize_secure;
mmc->block_dev.block_mmc_secure_erase = mmc_mmc_secure_erase_secure;
mmc->block_dev.block_mmc_secure_trim = mmc_mmc_secure_trim_secure;
#endif
if (!mmc->b_max)
mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
INIT_LIST_HEAD (&mmc->link);
list_add_tail (&mmc->link, &mmc_devices);
return 0;
}
int mmc_unregister(int sdc_no)
{
return 0;
}
#ifdef CONFIG_PARTITIONS
block_dev_desc_t *mmc_get_dev(int dev)
{
struct mmc *mmc = find_mmc_device(dev);
return mmc ? &mmc->block_dev : NULL;
}
#endif
/*
int sunxi_need_retry(struct mmc *mmc)
{
if(mmc->decide_retry && mmc->update_sdly){
uint sdly = 0;
int ret = 0;
ret = mmc->decide_retry(mmc,&sdly,0);
if(ret){
MMCINFO("need retry next dly %d,clk %d\n",sdly,mmc->clock);
mmc->update_sdly(mmc,sdly);
return 1;
}
}
return 0;
}
*/
int sunxi_need_rty(struct mmc *mmc)
{
if(mmc->decide_retry ){
int ret = 0;
u32 err_no = 0;
err_no = mmc->get_detail_errno(mmc);
ret = mmc->decide_retry(mmc,err_no,0);
if(!ret){
MMCINFO("need retry next clk %d\n",mmc->clock);
return 0;
}
}
return -1;
}
static const char tuning_blk_4b[TUNING_LEN*512] = {
/*hs200/uhs*/
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
/*0xf*/
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
/*0x1e*/
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
/*0x5a*/
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a,
/*wifi*/
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
/*0xf1*/
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1,
/*0xd2(change form 0xe1/0x1e)*/
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2,
/*0xb4(change form 0xe1/0x1e)*/
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
/*0x78(change form 0xe1/0x1e)*/
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
/*rand*/
0xe4, 0x4f, 0x76, 0xbb, 0xf0, 0xb7, 0xe0, 0xdb,
0xb9, 0x1f, 0x9f, 0xfb, 0x7e, 0x9b, 0x03, 0x7d,
0x2e, 0x32, 0x8f, 0x29, 0x7a, 0x9b, 0xab, 0x16,
0x2f, 0x44, 0x99, 0xce, 0xc3, 0x99, 0xaa, 0xad,
0x2d, 0x82, 0xb2, 0x8a, 0xfa, 0x2d, 0xb9, 0x9a,
0x9e, 0x0f, 0xf3, 0x90, 0x08, 0x25, 0xf3, 0x09,
0x79, 0x80, 0x1b, 0x28, 0x95, 0x00, 0x57, 0x7d,
0xbb, 0x60, 0x0b, 0x2c, 0x92, 0x72, 0x49, 0x4b,
0xe4, 0xac, 0x48, 0x8b, 0xb0, 0xe4, 0x11, 0x1b,
0x7a, 0x58, 0x7c, 0xc9, 0xe6, 0xf1, 0x5b, 0x6b,
0x85, 0xc9, 0xf5, 0x7d, 0xef, 0xea, 0xb6, 0x0b,
0x12, 0x59, 0x24, 0xd2, 0xc9, 0x53, 0x15, 0xa2,
0xb1, 0xd6, 0x1f, 0x06, 0x38, 0x63, 0x51, 0x27,
0xf6, 0x03, 0x20, 0xee, 0x41, 0x88, 0xa4, 0x69,
0xfb, 0x15, 0x05, 0x70, 0xaf, 0xe0, 0x30, 0x88,
0xdc, 0x37, 0xce, 0x07, 0x91, 0xc1, 0x76, 0x79,
0x3a, 0x07, 0x21, 0x43, 0xba, 0x32, 0xdf, 0x86,
0xba, 0x16, 0xc9, 0x46, 0x40, 0x70, 0x37, 0xcc,
0x83, 0x6c, 0x33, 0x48, 0xfe, 0x6b, 0x2d, 0xbb,
0xc3, 0x02, 0xf0, 0x14, 0x12, 0x46, 0xd4, 0x99,
0x2a, 0x47, 0x35, 0x89, 0x5f, 0xda, 0x25, 0x00,
0x6d, 0x9c, 0x5e, 0x1a, 0x0c, 0x33, 0x7a, 0x5b,
0xc4, 0xd7, 0x67, 0x4f, 0x03, 0x12, 0x15, 0x6d,
0x6d, 0xc3, 0x71, 0x41, 0x73, 0x69, 0x97, 0xcb,
0x27, 0x9e, 0x43, 0x22, 0x4e, 0xe2, 0x89, 0x5c,
0xb7, 0x9a, 0xc7, 0xb2, 0xcc, 0x58, 0xd7, 0xe0,
0x67, 0x5d, 0x89, 0xcb, 0xe7, 0x5d, 0x50, 0x66,
0x82, 0x82, 0x3b, 0xd6, 0xdd, 0xb3, 0x27, 0xd5,
0xd9, 0x15, 0x34, 0x54, 0xb0, 0xd2, 0x75, 0x64,
0x42, 0x1a, 0xec, 0x56, 0xa9, 0x68, 0xb5, 0x21,
0x13, 0x07, 0x81, 0x05, 0xd1, 0xd4, 0x46, 0x6e,
0xab, 0x45, 0x35, 0x1b, 0x77, 0xaa, 0xed, 0x7f,
0xea, 0xb3, 0xee, 0x68, 0xad, 0x33, 0x50, 0xde,
0xb3, 0x23, 0xb5, 0x4e, 0xcb, 0xea, 0x7c, 0xe8,
0x71, 0xdc, 0x37, 0x45, 0xea, 0x00, 0x5f, 0x4d,
0x90, 0x16, 0x47, 0x58, 0x6a, 0xd8, 0x4f, 0x93,
0xff, 0x81, 0x5a, 0xa6, 0x6c, 0x8c, 0x82, 0x93,
0xb5, 0xbe, 0x0a, 0xe1, 0x59, 0x66, 0x93, 0xfb,
0x29, 0xe4, 0x93, 0xd3, 0x59, 0x68, 0x04, 0xca,
0xd8, 0xfc, 0x59, 0xd4, 0xdd, 0xc5, 0xb6, 0xd7,
0xc3, 0x85, 0x60, 0x55, 0x16, 0x65, 0x73, 0x4b,
0xee, 0xf2, 0xd3, 0x59, 0x7b, 0x65, 0x64, 0x22,
0xe2, 0x27, 0x7e, 0xf6, 0x47, 0x94, 0x9b, 0xaf,
0x2b, 0x00, 0x53, 0xd8, 0xf9, 0xf7, 0x8b, 0x15,
0xdb, 0xc9, 0xe9, 0xbe, 0xd2, 0x46, 0x8b, 0xce,
0x06, 0xc7, 0xf8, 0xfc, 0x5b, 0x6e, 0x56, 0x27,
0x44, 0xae, 0xde, 0xf7, 0xdc, 0x0d, 0x8e, 0xc2,
0x33, 0x28, 0x1d, 0xac, 0xe5, 0xf8, 0x34, 0x13,
0xf2, 0x55, 0xdb, 0x2a, 0xc9, 0xb8, 0x32, 0xe3,
0xa6, 0x45, 0x61, 0x13, 0x1e, 0x09, 0xd1, 0xd1,
0xf9, 0x80, 0x9d, 0x1e, 0x3f, 0x5a, 0x43, 0xcc,
0x95, 0x7e, 0xa0, 0x98, 0xca, 0x50, 0x1b, 0x9a,
0xae, 0x2f, 0x20, 0xdf, 0x23, 0x42, 0xd0, 0x54,
0x76, 0x75, 0xf6, 0xe5, 0xef, 0xbe, 0x3d, 0xe7,
0xa6, 0xa5, 0xa1, 0xb3, 0x99, 0x03, 0x24, 0x94,
0xfc, 0x0a, 0xc2, 0xe4, 0xd0, 0x85, 0xa6, 0x71,
0xb7, 0x61, 0x9e, 0x26, 0x07, 0x6d, 0xcd, 0xe7,
0x1d, 0x5e, 0xa0, 0xbc, 0xf4, 0x16, 0x03, 0x32,
0xf6, 0x26, 0xd4, 0xfe, 0x11, 0x91, 0x97, 0xe4,
0x0e, 0xd3, 0x6c, 0xd7, 0x1e, 0x21, 0x3f, 0x62,
0xb6, 0xf3, 0x3f, 0x46, 0x9d, 0xc0, 0x91, 0x65,
0x44, 0x08, 0x45, 0xde, 0x55, 0x98, 0x89, 0x7a,
0x8e, 0x0a, 0x1c, 0x47, 0xd0, 0x8b, 0x06, 0x82,
0x73, 0xe1, 0x87, 0xba, 0xdd, 0xac, 0x4d, 0x33,
};
static const char tuning_blk_8b[TUNING_LEN*512] = {
/*hs200/uhs*/
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
/*0xf*/
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
/*0x1e*/
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE,
/*0x5a*/
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
/*wifi*/
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x18,
0xc5, 0x00, 0x10, 0x18, 0x01, 0x12, 0xf8, 0x4b,
0x11, 0x42, 0x00, 0x19, 0x03, 0x01, 0x00, 0x00,
0x05, 0x10, 0x00, 0x18, 0xc5, 0x10, 0x10, 0x18,
0x30, 0x43, 0x04, 0x16, 0x00, 0x90, 0x10, 0x18,
0x01, 0x00, 0xf8, 0x4b, 0x11, 0x42, 0x00, 0x27,
/*0xf1*/
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01,
/*0xd2(change form 0xe1/0x1e)*/
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02, 0xfd, 0x02,
/*0xb4(change form 0xe1/0x1e)*/
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04, 0xfb, 0x04,
/*0x78(change form 0xe1/0x1e)*/
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x80,
/*rand*/
0xe4, 0x4f, 0x76, 0xbb, 0xf0, 0xb7, 0xe0, 0xdb,
0xb9, 0x1f, 0x9f, 0xfb, 0x7e, 0x9b, 0x03, 0x7d,
0x2e, 0x32, 0x8f, 0x29, 0x7a, 0x9b, 0xab, 0x16,
0x2f, 0x44, 0x99, 0xce, 0xc3, 0x99, 0xaa, 0xad,
0x2d, 0x82, 0xb2, 0x8a, 0xfa, 0x2d, 0xb9, 0x9a,
0x9e, 0x0f, 0xf3, 0x90, 0x08, 0x25, 0xf3, 0x09,
0x79, 0x80, 0x1b, 0x28, 0x95, 0x00, 0x57, 0x7d,
0xbb, 0x60, 0x0b, 0x2c, 0x92, 0x72, 0x49, 0x4b,
0xe4, 0xac, 0x48, 0x8b, 0xb0, 0xe4, 0x11, 0x1b,
0x7a, 0x58, 0x7c, 0xc9, 0xe6, 0xf1, 0x5b, 0x6b,
0x85, 0xc9, 0xf5, 0x7d, 0xef, 0xea, 0xb6, 0x0b,
0x12, 0x59, 0x24, 0xd2, 0xc9, 0x53, 0x15, 0xa2,
0xb1, 0xd6, 0x1f, 0x06, 0x38, 0x63, 0x51, 0x27,
0xf6, 0x03, 0x20, 0xee, 0x41, 0x88, 0xa4, 0x69,
0xfb, 0x15, 0x05, 0x70, 0xaf, 0xe0, 0x30, 0x88,
0xdc, 0x37, 0xce, 0x07, 0x91, 0xc1, 0x76, 0x79,
0x3a, 0x07, 0x21, 0x43, 0xba, 0x32, 0xdf, 0x86,
0xba, 0x16, 0xc9, 0x46, 0x40, 0x70, 0x37, 0xcc,
0x83, 0x6c, 0x33, 0x48, 0xfe, 0x6b, 0x2d, 0xbb,
0xc3, 0x02, 0xf0, 0x14, 0x12, 0x46, 0xd4, 0x99,
0x2a, 0x47, 0x35, 0x89, 0x5f, 0xda, 0x25, 0x00,
0x6d, 0x9c, 0x5e, 0x1a, 0x0c, 0x33, 0x7a, 0x5b,
0xc4, 0xd7, 0x67, 0x4f, 0x03, 0x12, 0x15, 0x6d,
0x6d, 0xc3, 0x71, 0x41, 0x73, 0x69, 0x97, 0xcb,
0x27, 0x9e, 0x43, 0x22, 0x4e, 0xe2, 0x89, 0x5c,
0xb7, 0x9a, 0xc7, 0xb2, 0xcc, 0x58, 0xd7, 0xe0,
0x67, 0x5d, 0x89, 0xcb, 0xe7, 0x5d, 0x50, 0x66,
0x82, 0x82, 0x3b, 0xd6, 0xdd, 0xb3, 0x27, 0xd5,
0xd9, 0x15, 0x34, 0x54, 0xb0, 0xd2, 0x75, 0x64,
0x42, 0x1a, 0xec, 0x56, 0xa9, 0x68, 0xb5, 0x21,
0x13, 0x07, 0x81, 0x05, 0xd1, 0xd4, 0x46, 0x6e,
0xab, 0x45, 0x35, 0x1b, 0x77, 0xaa, 0xed, 0x7f,
0xea, 0xb3, 0xee, 0x68, 0xad, 0x33, 0x50, 0xde,
0xb3, 0x23, 0xb5, 0x4e, 0xcb, 0xea, 0x7c, 0xe8,
0x71, 0xdc, 0x37, 0x45, 0xea, 0x00, 0x5f, 0x4d,
0x90, 0x16, 0x47, 0x58, 0x6a, 0xd8, 0x4f, 0x93,
0xff, 0x81, 0x5a, 0xa6, 0x6c, 0x8c, 0x82, 0x93,
0xb5, 0xbe, 0x0a, 0xe1, 0x59, 0x66, 0x93, 0xfb,
0x29, 0xe4, 0x93, 0xd3, 0x59, 0x68, 0x04, 0xca,
0xd8, 0xfc, 0x59, 0xd4, 0xdd, 0xc5, 0xb6, 0xd7,
0xc3, 0x85, 0x60, 0x55, 0x16, 0x65, 0x73, 0x4b,
0xee, 0xf2, 0xd3, 0x59, 0x7b, 0x65, 0x64, 0x22,
0xe2, 0x27, 0x7e, 0xf6, 0x47, 0x94, 0x9b, 0xaf,
0x2b, 0x00, 0x53, 0xd8, 0xf9, 0xf7, 0x8b, 0x15,
0xdb, 0xc9, 0xe9, 0xbe, 0xd2, 0x46, 0x8b, 0xce,
0x06, 0xc7, 0xf8, 0xfc, 0x5b, 0x6e, 0x56, 0x27,
0x44, 0xae, 0xde, 0xf7, 0xdc, 0x0d, 0x8e, 0xc2,
0x33, 0x28, 0x1d, 0xac, 0xe5, 0xf8, 0x34, 0x13,
0xf2, 0x55, 0xdb, 0x2a, 0xc9, 0xb8, 0x32, 0xe3,
0xa6, 0x45, 0x61, 0x13, 0x1e, 0x09, 0xd1, 0xd1,
0xf9, 0x80, 0x9d, 0x1e, 0x3f, 0x5a, 0x43, 0xcc,
0x95, 0x7e, 0xa0, 0x98, 0xca, 0x50, 0x1b, 0x9a,
0xae, 0x2f, 0x20, 0xdf, 0x23, 0x42, 0xd0, 0x54,
0x76, 0x75, 0xf6, 0xe5, 0xef, 0xbe, 0x3d, 0xe7,
0xa6, 0xa5, 0xa1, 0xb3, 0x99, 0x03, 0x24, 0x94,
0xfc, 0x0a, 0xc2, 0xe4, 0xd0, 0x85, 0xa6, 0x71,
0xb7, 0x61, 0x9e, 0x26, 0x07, 0x6d, 0xcd, 0xe7,
0x1d, 0x5e, 0xa0, 0xbc, 0xf4, 0x16, 0x03, 0x32,
0xf6, 0x26, 0xd4, 0xfe, 0x11, 0x91, 0x97, 0xe4,
0x0e, 0xd3, 0x6c, 0xd7, 0x1e, 0x21, 0x3f, 0x62,
0xb6, 0xf3, 0x3f, 0x46, 0x9d, 0xc0, 0x91, 0x65,
0x44, 0x08, 0x45, 0xde, 0x55, 0x98, 0x89, 0x7a,
0x8e, 0x0a, 0x1c, 0x47, 0xd0, 0x8b, 0x06, 0x82,
0x73, 0xe1, 0x87, 0xba, 0xdd, 0xac, 0x4d, 0x33,
};
/*
#define isascii(c) (((unsigned char)(c))<=0x7f)
#define isprint(c) ((((unsigned char)(c))>=32 && ((unsigned char)(c))<=126) \
|| (((unsigned char)(c))>=160 && ((unsigned char)(c))<=255))
#define DBG_DUMP_BUF_LEN (128)
#define MAX_DUMP_PER_LINE (16)
#define MAX_DUMP_PER_LINE_HALF (MAX_DUMP_PER_LINE >> 1)
void hexdump(char *prompt, char *buf, int len)
{
int i, j;
int head = 0;
printf("Dump (%s): len %d\n", prompt, len);
for (i = 0; i < len;) {
if (i % MAX_DUMP_PER_LINE == 0) {
printf("%08x ", i);
head = i;
}
printf("%02x ", buf[i]&0xff);
if (i % MAX_DUMP_PER_LINE == MAX_DUMP_PER_LINE_HALF-1)
printf(" ");
if (i % MAX_DUMP_PER_LINE == MAX_DUMP_PER_LINE-1
|| i==len-1) {
for (j=i-head+1; j<MAX_DUMP_PER_LINE; j++)
printf(" ");
printf(" |");
for (j=head; j<=i; j++) {
if (isascii(buf[j]) && isprint(buf[j]))
printf("%c", buf[j]);
else
printf(".");
}
printf("|\n");
}
i++;
}
printf("\n");
}
s16 aw_rand(s32 *seed)
{
s32 RandMax = 0x7fff;
s32 tmp;
tmp = (*seed) * 0x000343FD;
tmp+= 0x00269EC3;
*seed = tmp;
tmp >>= 16;
tmp &= RandMax;
return (s16)tmp;
}
void print_rand(void)
{
int i =0;
int seed = 0x55aa;
char rand[512]={0};
for(i=0;i<512;i++){
rand[i]=aw_rand(&seed);
}
hexdump("rand data", (void*)rand, 512);
}
*/
static int write_tuning_try_freq(struct mmc *mmc,u32 clk)
{
int ret = 0;
const char *std_pattern = NULL;
char *rcv_pattern = malloc(TUNING_LEN*512);
u32 err_no = 0;
if(rcv_pattern == NULL){
return -1;
}
if(mmc->bus_width == 4){
std_pattern = tuning_blk_4b;
}else if(mmc->bus_width == 8){
std_pattern = tuning_blk_8b;
}else if(mmc->bus_width == 1){
MMCINFO("Not support 1 bit tuning now\n");
ret = -1;
goto out;
}
do{
mmc_set_clock(mmc, clk);
ret = mmc_bwrite(mmc->control_num,
TUNING_ADD,
TUNING_LEN,
std_pattern);
MMCDBG("Write pattern ret = %d\n",ret);
if(ret != TUNING_LEN){//failed
MMCINFO(" write failed\n");
err_no = mmc->get_detail_errno(mmc);
//if write failed and block len>1,send stop for next try
//no care if it is successed
if(TUNING_LEN>1){
MMCINFO(" Send stop\n");
mmc_send_manual_stop(mmc);
}
}else{//ok
MMCINFO(" write ok\n");
//read pattern and compare with the pattern show sent
ret = mmc_bread(mmc->control_num,
TUNING_ADD,
TUNING_LEN,
rcv_pattern);
if(ret != TUNING_LEN){
MMCINFO(" read failed\n");
err_no = mmc->get_detail_errno(mmc);
//if read failedand block len>1,send stop for next try
//no care if it is successed
if(TUNING_LEN>1){
MMCINFO(" Send stop\n");
mmc_send_manual_stop(mmc);
}
}else{
ret = memcmp(std_pattern, rcv_pattern, TUNING_LEN*512);
if(ret){
MMCINFO(" pattern compare fail\n");
err_no = 0xffffffff;//force retry
}else{
MMCINFO(" Pattern compare ok\n");
MMCINFO(" Write tuning pattern ok\n");
goto out;
}
}
}
}while(!mmc->decide_retry(mmc,err_no,0));
MMCINFO(" Write tuning pattern failded\n");
ret = -1;
out:
free(rcv_pattern);
return ret;
}
static int sunxi_write_tuning(struct mmc *mmc)
{
u32 freqs[] = { 400000, 25*1000*1000, 50*1000*1000};
int i = 0;
int ret = -1;
int clk_bak = mmc->clock;
if(mmc->decide_retry==NULL){
MMCINFO("NO support tuning\n");
return 0;
}
//reset rety count
mmc->decide_retry(mmc,0,1);
for(i=0;i<sizeof(freqs)/sizeof(freqs[0]);i++){
ret = write_tuning_try_freq(mmc,freqs[i]);
if(!ret){
//recover the clock before wiite patten
mmc_set_clock(mmc, clk_bak);
return ret;
}
}
return ret;
}
static ulong sunxi_read_tuning(int dev_num, ulong start, lbaint_t blkcnt, void *dst)
{
lbaint_t cur, blocks_todo = blkcnt;
if (blkcnt == 0){
MMCINFO("blkcnt should not be 0\n");
return 0;
}
struct mmc *mmc = find_mmc_device(dev_num);
if (!mmc){
MMCINFO("Can not find mmc dev\n");
return 0;
}
if ((start + blkcnt) > mmc->block_dev.lba) {
MMCINFO("MMC: block number 0x%lx exceeds max(0x%lx)\n",
start + blkcnt, mmc->block_dev.lba);
return 0;
}
if (mmc_set_blocklen(mmc, mmc->read_bl_len)){
MMCINFO("Set block len failed\n");
return 0;
}
do {
cur =1;//force to read 1 block a time
if(mmc_read_blocks(mmc, dst, start, cur) != cur){
MMCINFO("block read failed\n");
return 0;
}
blocks_todo -= cur;
start += cur;
dst = (char*)dst + cur * mmc->read_bl_len;
} while (blocks_todo > 0);
return blkcnt;
}
static int sunxi_get_sdly_win(struct mmc *mmc,int start_in,
int end_in,int *start_out,
int *end_out,s8 *sdly,
const char *std_pat,
int repeat_times)
{
int i = 0;
int j = 0;
int ret = 0;
char *rcv_pat = malloc(TUNING_LEN*512);
if(rcv_pat == NULL){
MMCINFO(" malloc mem failed\n");
ret = -1;
return ret;
}
if((start_in>end_in)
||(start_out==NULL)
||(end_out==NULL)
||(std_pat==NULL)){
MMCINFO("Input parameter error\n");
ret = -1;
goto out;
}
/*
tick_printf("[mmc]:*************************Try delay win[");
for(i=start_in;i<=end_in;i++){
printf("%d",sdly[i]);
}
printf("]*************************\n");
*/
/**********find start point************/
for(i=start_in;i<=end_in;i++){
//read pattern and compare with the pattern show sent
mmc->update_sdly(mmc,sdly[i]);//update sdly
mmc_set_clock(mmc, mmc->clock);//make sdly efficiency
for(j=0;j<repeat_times;j++){
ret = sunxi_read_tuning(mmc->control_num,
TUNING_ADD,
TUNING_LEN,
rcv_pat);
if(ret != TUNING_LEN){
MMCINFO(" read failed\n");
//if read failedand block len>1,send stop for next try
//no care if it is successed
//if(TUNING_LEN>1){
// MMCINFO(" Send stop\n");
// mmc_send_manual_stop(mmc);
//}
break;
}
ret = memcmp(std_pat, rcv_pat, TUNING_LEN*512);
if(ret){
MMCINFO(" pattern compare fail\n");
break;
}
MMCDBG(" Pattern compare ok in sample ponit %d\n",sdly[i]);
}
if(j>=repeat_times){
break;
}
}
if(i>end_in){
//MMCINFO("Can not find sample point between %d-%d\n",sdly[start_in],sdly[end_in]);
tick_printf("[mmc]:Can not find sample point between [");
for(i=start_in;i<=end_in;i++){
printf("%d",sdly[i]);
}
printf("]\n");
ret = -1;
goto out;
}
*start_out = i;
/**********find end point************/
for(i++;i<=end_in;i++){
//read pattern and compare with the pattern show sent
mmc->update_sdly(mmc,sdly[i]);//update sdly
mmc_set_clock(mmc, mmc->clock);//make sdly efficiency
for(j=0;j<repeat_times;j++){
ret = sunxi_read_tuning(mmc->control_num,
TUNING_ADD,
TUNING_LEN,
rcv_pat);
if(ret != TUNING_LEN){
MMCINFO(" read failed\n");
//if read failedand block len>1,send stop for next try
//no care if it is successed
//if(TUNING_LEN>1){
// MMCINFO(" Send stop\n");
// mmc_send_manual_stop(mmc);
//}
break;
}
ret = memcmp(std_pat, rcv_pat, TUNING_LEN*512);
if(ret){
MMCINFO(" pattern compare fail\n");
break;
}
MMCDBG(" Pattern compare ok in sample ponit %d\n",sdly[i]);
}
if(j<repeat_times){
break;
}
}
if(i>end_in){
*end_out = end_in;
}else{
*end_out = i-1;
}
tick_printf("[mmc]:*************************delay win[");
for(i=*start_out;i<=*end_out;i++){
printf("%d",sdly[i]);
}
printf("]*************************\n");
ret = 0;
out:
free(rcv_pat);
return ret;
}
static void calc_real_dly(u32 pll_clk,u32 clk,s8 *real_delay)
{
int i = 0;
char sple_dly_real[8] ={1,2,3,4,5,6,7,0};
u32 delay0 = 0;
char sple_win_str[9] = {0};
/**********calc readlly delay 0**************/
/*calc really delay 0*/
delay0 = pll_clk/clk/2;
MMCDBG("delay0: %d, sclk %d,card clk %d\n",delay0,pll_clk,clk);
for(i=0;i<7;i++){
if(delay0<= sple_dly_real[i]){
break;
}
}
if(i<7){
memmove(sple_dly_real+i+1,sple_dly_real+i,7-i);
sple_dly_real[i] = 0;
}
for(i = 0;i<=7;i++){
sprintf(sple_win_str+i,"%d",sple_dly_real[i]);
}
MMCINFO("real sample win [%s]\n",sple_win_str);
memcpy(real_delay,sple_dly_real,8);
/**********calc readlly delay 0 end**************/
}
static int sunxi_exe_tuning(struct mmc *mmc)
{
int ret = 0;
int i = 0;
const char *std_pat = NULL;
s8 sple_dly_real[8] ={1,2,3,4,5,6,7,0};
s32 sple_start0 = 0;
s32 sple_end0 = 0;
u32 win0 = 0;
s32 sple_start1 = 0;
s32 sple_end1 = 0;
u32 win1 = 0;
//u32 f_max_bak = 0;
u32 tuning_freqs[] = {52*1000*1000,26*1000*1000};
s32 tuning_times = 0;
int suit_sdly = 0;
//decide tuning freq and times
if (IS_SD(mmc)) {
if (mmc->card_caps & MMC_MODE_HS){
tuning_freqs[1]= 25000000;
tuning_freqs[0]= 50000000;
tuning_times = 2;
}else{
tuning_freqs[0]= 25000000;
tuning_times = 1;
}
} else {
if (mmc->card_caps & MMC_MODE_HS) {
if (mmc->card_caps & MMC_MODE_HS_52MHz){
tuning_freqs[1]= 26000000;
tuning_freqs[0]= 52000000;
tuning_times = 2;
}else{
tuning_freqs[0]= 26000000;
tuning_times = 1;
}
} else{
tuning_freqs[0]= 20000000;
tuning_times = 1;
}
}
if(mmc->update_sdly==NULL){
MMCINFO("update_sdly not implement\n");
return -1;
}
if(mmc->bus_width == 4){
std_pat = tuning_blk_4b;
}else if(mmc->bus_width == 8){
std_pat = tuning_blk_8b;
}else if(mmc->bus_width == 1){
MMCINFO("Not support 1 bit tuning now\n");
ret = -1;
goto out;
}
//f_max_bak = mmc->f_max;
//mmc->f_max = 100*1000*1000;
//for(i=0;i<sizeof(tuning_freqs)/sizeof(tuning_freqs[0]);i++){
for(i=0;i<tuning_times;i++){
MMCDBG("**************************Start tuning in freq %d**************************\n",tuning_freqs[i]);
mmc_set_clock(mmc, tuning_freqs[i]);
calc_real_dly(mmc->pll_clock,mmc->clock,sple_dly_real);
ret = sunxi_get_sdly_win(mmc,0,7,&sple_start0,&sple_end0,sple_dly_real,std_pat,REPEAT_TIMES);
if(ret){
MMCDBG("Can not find sample point in win0\n");
MMCINFO("**************Failed to find sample point in freq %d(%d)**************\n",tuning_freqs[i],mmc->clock);
win0 = 0;
//continue;
//if we can not find sample point, we assume that there is something wrong not related to sample point
ret = -1;
goto out;
}else{
MMCDBG("find sample point in win0\n");
if(sple_end0==sple_start0){
win0 = 1;
}else{
win0 = sple_end0-sple_start0+1;
}
}
ret = sunxi_get_sdly_win(mmc,sple_end0+2,7,&sple_start1,&sple_end1,sple_dly_real,std_pat,REPEAT_TIMES);
if(ret){
MMCDBG("Can not find sample point in win1\n");
win1 =0;
}else{
MMCDBG("find sample point in win1\n");
if(sple_end1==sple_start1){
win1 = 1;
}else{
win1 = sple_end1-sple_start1+1;
}
}
if(win0>win1){
suit_sdly = sple_start0+(win0)/2;
}else{
suit_sdly = sple_start1+(win1)/2;
}
MMCINFO("!!!!!!!!!!!!Find suitable sample point %d in freq %d(%d)!!!!!!!!!!!!\n",sple_dly_real[suit_sdly],tuning_freqs[i],mmc->clock);
if(tuning_freqs[i]<=26000000){
mmc->sdly_tuning.sdly_25M = sple_dly_real[suit_sdly];
}else if(tuning_freqs[i]<=52000000){
mmc->sdly_tuning.sdly_50M = sple_dly_real[suit_sdly];
}else{
MMCINFO("The freq is over 52M,not be dealt with now\n");
ret = -1;
goto out;
}
mmc->update_sdly(mmc,sple_dly_real[suit_sdly]);//update sdly
}
// mmc->f_max = f_max_bak;
// mmc_set_clock(mmc, mmc->clock_after_init);//recover clock when init ok
//set clock for burn fireware
mmc_set_clock(mmc, tuning_freqs[0]);
MMCINFO("---------------mmc clock %d-----------\n", mmc->clock);
ret = 0;
out:
return ret;
}
int mmc_write_info(int dev_num,void *buffer,u32 buffer_size)
{
struct mmc *mmc = find_mmc_device(dev_num);
int work_mode = uboot_spare_head.boot_data.work_mode;
if(mmc==NULL){
MMCINFO("Can not find mmc\n");
return -1;
}
if(mmc->sample_mode ==AUTO_SAMPLE_MODE
&& work_mode!= WORK_MODE_BOOT){
if(sizeof(struct tuning_sdly)>buffer_size){
MMCINFO("size of tuning_sdly over %d\n",buffer_size);
return -1;
}
memcpy(buffer,(void *)&mmc->sdly_tuning,sizeof(sizeof(struct tuning_sdly)));
MMCINFO("write mmc info ok\n");
return 0;
}
return -1;
}
static int mmc_init_product(struct mmc *mmc)
{
int err;
//while((*(volatile unsigned int *)0) != 1);
if (mmc->has_init){
MMCINFO("Has init\n");
return 0;
}
retry:
err = mmc->init(mmc);
if (err){
MMCINFO("mmc->init error\n");
return err;
}
mmc_set_bus_width(mmc, 1);
mmc_set_clock(mmc, 1);
/* Reset the Card */
err = mmc_go_idle(mmc);
if (err){
MMCINFO("mmc go idle error\n");
return err;
}
/* The internal partition reset to user partition(0) at every CMD0*/
mmc->part_num = 0;
MMCINFO("************Try SD card %d************\n",mmc->control_num);
/* Test for SD version 2 */
err = mmc_send_if_cond(mmc);
if(err && !sunxi_need_rty(mmc)){
goto retry;
}
/* Now try to get the SD card's operating condition */
err = sd_send_op_cond(mmc);
if(err && !sunxi_need_rty(mmc)){
goto retry;
}
/* If the command timed out, we check for an MMC card */
if (err == -1){
if(!sunxi_need_rty(mmc)){
goto retry;
}
MMCINFO("*Try MMC card %d*\n",mmc->control_num);
err = mmc_send_op_cond(mmc);
if(err && !sunxi_need_rty(mmc)){
goto retry;
}
if (err) {
MMCINFO("Card did not respond to voltage select!\n");
MMCINFO("*SD/MMC %d init error!*\n",mmc->control_num);
return UNUSABLE_ERR;
}
}
err = mmc_startup(mmc);
if (err){
MMCINFO("*SD/MMC %d init error!*\n",mmc->control_num);
mmc->has_init = 0;
}
else{
mmc->has_init = 1;
//MMCINFO("************SD/MMC %d init OK!!!************\n",mmc->control_num);
}
if(err && !sunxi_need_rty(mmc)){
goto retry;
}
err = sunxi_write_tuning(mmc);
if(err){
MMCINFO("Write pattern failed\n");
return err;
}
err = sunxi_exe_tuning(mmc);
if(err){
return err;
}
init_part(&mmc->block_dev);
return err;
}
static int mmc_init_boot(struct mmc *mmc)
{
int err;
int work_mode = uboot_spare_head.boot_data.work_mode;
if (mmc->has_init){
MMCINFO("Has init\n");
return 0;
}
err = mmc->init(mmc);
if (err){
MMCINFO("mmc->init error\n");
return err;
}
mmc_set_bus_width(mmc, 1);
mmc_set_clock(mmc, 1);
/* Reset the Card */
err = mmc_go_idle(mmc);
if (err){
MMCINFO("mmc go idle error\n");
return err;
}
/* The internal partition reset to user partition(0) at every CMD0*/
mmc->part_num = 0;
MMCINFO("*Try SD card %d*\n",mmc->control_num);
/* Test for SD version 2 */
err = mmc_send_if_cond(mmc);
/* Now try to get the SD card's operating condition */
err = sd_send_op_cond(mmc);
/* If the command timed out, we check for an MMC card */
if (err == -1){
MMCINFO("*Try MMC card %d*\n",mmc->control_num);
err = mmc_send_op_cond(mmc);
if (err) {
MMCINFO("Card did not respond to voltage select!\n");
MMCINFO("***SD/MMC %d init error!!!***\n",mmc->control_num);
return UNUSABLE_ERR;
}
}
err = mmc_startup(mmc);
if (err){
MMCINFO("*SD/MMC %d init error!!*\n",mmc->control_num);
mmc->has_init = 0;
}
else{
mmc->has_init = 1;
//MMCINFO("************SD/MMC %d init OK!!!************\n",mmc->control_num);
}
if((mmc->sample_mode == AUTO_SAMPLE_MODE)
&&(work_mode == WORK_MODE_BOOT)){
u32 suit_sdly = 0;
struct tuning_sdly *sdly= (struct tuning_sdly *)uboot_spare_head.boot_data.sdcard_spare_data;
//MMCINFO("****************sdly:%d*************************\n",sdly->sdly_50M);
suit_sdly = sdly->sdly_50M;
if(script_parser_patch("mmc2_para","sdc_sdly_50M",&suit_sdly,1) == SCRIPT_PARSER_OK){
int rval = 0;
script_parser_fetch("mmc2_para","sdc_sdly_50M", &rval, 1);
MMCINFO("set kernel %s %d ok\n","sdc_sdly_50M",rval);
}else{
MMCINFO("set kernel %s failed\n","sdc_sdly_50M");
}
suit_sdly = sdly->sdly_25M;
if(script_parser_patch("mmc2_para","sdc_sdly_25M",&suit_sdly,1) == SCRIPT_PARSER_OK){
int rval = 0;
script_parser_fetch("mmc2_para","sdc_sdly_25M", &rval, 1);
MMCINFO("set kernel %s %d ok\n","sdc_sdly_25M",rval);
}else{
MMCINFO("set kernel %s failed\n","sdc_sdly_25M");
}
}
init_part(&mmc->block_dev);
return err;
}
int mmc_init(struct mmc *mmc)
{
int work_mode = uboot_spare_head.boot_data.work_mode;
int ret = 0;
#if defined(CONFIG_ARCH_SUN9IW1P1)
if(gd->securemode == SUNXI_SECURE_MODE_NO_SECUREOS)
{
mmc->block_dev.lun = 0x0;
mmc->block_dev.type = 0x0;
mmc->block_dev.blksz = 0x200;
//use max lba/capacity becauese we can not get capacity from sd,because we can not get rca.
//for eMMC,we can get capacity,but for compatible to sd,we use max too
mmc->block_dev.lba = 0xffffffff;
mmc->capacity = 0xffffffff;
//mmc->block_dev.part_type = 0x2;
//assume high capacity for we do not init card here
mmc->high_capacity = 1;
//mmc->b_max = (0x20<<4);//(0x10000>>5);
//mmc->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
mmc->read_bl_len = 0x200;
mmc->write_bl_len = 0x200;
//mmc->erase_grp_size = 0x1;
mmc->part_config = MMCPART_NOAVAILABLE;
mmc->has_init = 1;
return 0;
}
#endif
//while((*(volatile unsigned int *)0) != 1);
if((mmc->sample_mode == AUTO_SAMPLE_MODE)
&&(work_mode != WORK_MODE_BOOT)){
return mmc_init_product(mmc);
}
ret = mmc_init_boot(mmc);
if (mmc->drv_wipe_feature & DRV_PARA_DISABLE_EMMC_SANITIZE)
mmc->secure_feature &= (~EXT_CSD_SEC_SANITIZE);
else if (mmc->drv_wipe_feature & DRV_PARA_DISABLE_EMMC_SECURE_PURGE)
mmc->secure_feature &= (~EXT_CSD_SEC_ER_EN);
else if (mmc->drv_wipe_feature & DRV_PARA_DISABLE_EMMC_TRIM)
mmc->secure_feature &= (~EXT_CSD_SEC_GB_CL_EN);
//MMCINFO("========================================\n");
//MMCINFO("mmc->block_dev.lba: %d Sectors\n", mmc->block_dev.lba);
//MMCINFO("wr_blk_len: 0x%x Byte\n", mmc->write_bl_len);
MMCINFO("erase_grp_size:0x%xWrBlk * 0x%x = 0x%x Byte\n",
mmc->erase_grp_size, mmc->write_bl_len, mmc->erase_grp_size*mmc->write_bl_len);
//MMCINFO("erase_to: %d ms\n", mmc->erase_timeout);
//MMCINFO("trim_discard_to: %d ms\n", mmc->trim_discard_timeout);
//MMCINFO("secure_tirm_to: %d ms\n", mmc->secure_erase_timeout);
//MMCINFO("secure_erase_to: %d ms\n", mmc->secure_trim_timeout);
MMCDBG("support sanitze: %d\n",\
mmc->secure_feature & EXT_CSD_SEC_SANITIZE);
MMCDBG("support trim: %d\n", \
mmc->secure_feature & EXT_CSD_SEC_GB_CL_EN);
MMCDBG("support secure purge op: %d\n", \
mmc->secure_feature & EXT_CSD_SEC_ER_EN);
MMCDBG("secure removal type: 0x%x\n", \
mmc->secure_removal_type);
MMCINFO("secure_feature 0x%x\n", mmc->secure_feature);
MMCINFO("secure_removal_type 0x%x\n", mmc->secure_removal_type);
//MMCINFO("========================================\n\n");
#ifdef MMC_INTERNAL_TEST
if (((mmc->mmc_test&MMC_ITEST_WHEN_BOOT) && (work_mode == WORK_MODE_BOOT))
|| ((mmc->mmc_test&MMC_ITEST_WHEN_PRODUCT) && (work_mode != WORK_MODE_BOOT)) )
{
if (mmc->mmc_test & MMC_ITEST_RWC) {
ret = mmc_t_rwc(mmc, 1024*1024*2, 10);
if (ret) {
MMCINFO("%s: mmc_t_rwc fail\n", __FUNCTION__);
}
}
if (mmc->mmc_test & MMC_ITEST_MEMCPY) {
ret = mmc_t_memcpy();
if (ret) {
MMCINFO("%s: mmc_t_memcpy fail\n", __FUNCTION__);
}
}
if (mmc->mmc_test & MMC_ITEST_SEQ_W_SPD) {
/* from 1GB, len: 64MB, each: 64KB */
ret = mmc_t_seq_write_speed_test(mmc, 1024*1024*2, 64*1024*2, 128);
if (ret) {
MMCINFO("%s: mmc_t_write_speed_test fail\n", __FUNCTION__);
}
}
}
#endif
return ret;
}
/*
* CPU and board-specific MMC initializations. Aliased function
* signals caller to move on
*/
static int __def_mmc_init(bd_t *bis)
{
return -1;
}
int cpu_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
int board_mmc_init(bd_t *bis) __attribute__((weak, alias("__def_mmc_init")));
void print_mmc_devices(char separator)
{
struct mmc *m;
struct list_head *entry;
list_for_each(entry, &mmc_devices) {
m = list_entry(entry, struct mmc, link);
MMCINFO("%s: %d", m->name, m->block_dev.dev);
if (entry->next != &mmc_devices)
printf("%c ", separator);
}
printf("\n");
}
int get_mmc_num(void)
{
//return cur_dev_num;
return board_mmc_get_num();
}
int mmc_initialize(bd_t *bis)
{
// INIT_LIST_HEAD (&mmc_devices);
if (board_mmc_init(bis) < 0)
cpu_mmc_init(bis);
print_mmc_devices(',');
return 0;
}
int mmc_exit(void)
{
int err;
int sdc_no = 2;
struct mmc *mmc = find_mmc_device(sdc_no);
if(mmc == NULL){
MMCINFO(" mmc %s not find,so not exit\n",sdc_no);
return -1;
}
MMCINFO("mmc exit start\n");
#if defined(CONFIG_ARCH_SUN9IW1P1)
if(gd->securemode == SUNXI_SECURE_MODE_NO_SECUREOS)
{
MMCINFO("mmc not exit\n");
return 0;
}
#endif
err = mmc->init(mmc);
if (err){
MMCINFO("mmc->init error\n");
MMCINFO("mmc %d exit failed\n",mmc->control_num);
return err;
}
mmc_set_bus_width(mmc, 1);
mmc_set_clock(mmc, 1);
/* Reset the Card */
err = mmc_go_idle(mmc);
if (err){
MMCINFO("mmc go idle error\n");
MMCINFO("mmc %d exit failed\n",mmc->control_num);
return err;
}
/* The internal partition reset to user partition(0) at every CMD0*/
mmc->part_num = 0;
//MMCINFO("************Try SD card %d************\n",mmc->control_num);
/* Test for SD version 2 */
err = mmc_send_if_cond(mmc);
/* Now try to get the SD card's operating condition */
err = sd_send_op_cond(mmc);
/* If the command timed out, we check for an MMC card */
if (err == -1){
//MMCINFO("************Try MMC card %d************\n",mmc->control_num);
err = mmc_send_op_cond(mmc);
if (err) {
MMCINFO("Card did not respond to voltage select!\n");
MMCINFO("mmc %d exit failed\n",mmc->control_num);
return UNUSABLE_ERR;
}
}
/*
err = mmc_startup(mmc);
if (err){
MMCINFO("************SD/MMC %d init error!!!************\n",mmc->control_num);
mmc->has_init = 0;
}
else{
mmc->has_init = 1;
//MMCINFO("************SD/MMC %d init OK!!!************\n",mmc->control_num);
}
*/
sunxi_mmc_exit(sdc_no);
MMCINFO("mmc %d exit ok\n",mmc->control_num);
return err;
}