/* * 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 #include #include #include #include #include #include #include #include "mmc_def.h" #include #include #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<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<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< 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<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>= 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 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;jcontrol_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;jcontrol_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(jend_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;ipll_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; }