⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc_protocol.c

📁 spi driver code one marve
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Core MMC driver functions * * Copyright (c) 2002 Hewlett-Packard Company *    * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: *   * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. *   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Many thanks to Alessandro Rubini and Jonathan Corbet! * * Author:  Andrew Christian *          6 May 2002  *(C) Copyright 2006 Marvell International Ltd.   * All Rights Reserved  *//* * mmc_protocol.c - MMC protocol driver * * Copyright (C) 2006 Intel Corporation * * 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 <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/list.h>#include <linux/sysctl.h>#include <linux/mm.h>#include <asm/scatterlist.h>#include <linux/mmc/mss_core.h>#include <linux/mmc/mmc_protocol.h>/* internal functions */#define KBPS 1#define MBPS 1000static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 };static u32 ts_mul[] = { 0,    1000, 1200, 1300, 1500, 2000, 2500, 3000, 			3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 };static u32 mmc_tran_speed(u8 ts){	u32 clock = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3];	dbg("MMC clock is %d\n", clock);	return clock;}static int mmc_unpack_r1(struct mss_cmd *cmd, struct mmc_response_r1 *r1, struct mmc_card *mmc_card){	u8 *buf = cmd->response;	mmc_card->errno = MMC_ERROR_NONE;	r1->cmd    = unstuff_bits(buf, 40, 8, 6);	r1->status = unstuff_bits(buf, 8, 32, 6);	if (R1_STATUS(r1->status)) {		if (r1->status & R1_OUT_OF_RANGE)			mmc_card->errno = MMC_ERROR_OUT_OF_RANGE;		if (r1->status & R1_ADDRESS_ERROR)		  	mmc_card->errno = MMC_ERROR_ADDRESS;		if (r1->status & R1_BLOCK_LEN_ERROR)		    	mmc_card->errno = MMC_ERROR_BLOCK_LEN;		if (r1->status & R1_ERASE_SEQ_ERROR)		    	mmc_card->errno = MMC_ERROR_ERASE_SEQ;		if (r1->status & R1_ERASE_PARAM)			mmc_card->errno = MMC_ERROR_ERASE_PARAM;		if (r1->status & R1_WP_VIOLATION)		 	mmc_card->errno = MMC_ERROR_WP_VIOLATION;		if (r1->status & R1_LOCK_UNLOCK_FAILED)			mmc_card->errno = MMC_ERROR_LOCK_UNLOCK_FAILED;		if (r1->status & R1_COM_CRC_ERROR)		  	mmc_card->errno = MMC_ERROR_COM_CRC;		if (r1->status & R1_ILLEGAL_COMMAND)		    	mmc_card->errno = MMC_ERROR_ILLEGAL_COMMAND;		if (r1->status & R1_CARD_ECC_FAILED)		    	mmc_card->errno = MMC_ERROR_CARD_ECC_FAILED;		if (r1->status & R1_CC_ERROR)	     		mmc_card->errno = MMC_ERROR_CC;		if (r1->status & R1_ERROR)	  		mmc_card->errno = MMC_ERROR_GENERAL;		if (r1->status & R1_UNDERRUN)	     		mmc_card->errno = MMC_ERROR_UNDERRUN;		if (r1->status & R1_OVERRUN)      			mmc_card->errno = MMC_ERROR_OVERRUN;		if (r1->status & R1_CID_CSD_OVERWRITE)		      	mmc_card->errno = MMC_ERROR_CID_CSD_OVERWRITE;	}	if (buf[0] != cmd->opcode)	       	mmc_card->errno = MMC_ERROR_HEADER_MISMATCH;	/* This should be last - it's the least dangerous error */	if (R1_CURRENT_STATE(r1->status) != mmc_card->state ) {		dbg("state dismatch:r1->status:%x,state:%x\n",				R1_CURRENT_STATE(r1->status),mmc_card->state);		mmc_card->errno = MMC_ERROR_STATE_MISMATCH;	}	dbg("mmc card error %d", mmc_card->errno);	if (mmc_card->errno)		return MSS_ERROR_RESP_UNPACK;	return 0;}static int mmc_unpack_r3(struct mss_cmd *cmd, struct mmc_response_r3 *r3, struct mmc_card *mmc_card){	u8 *buf = cmd->response;	mmc_card->errno = MMC_ERROR_NONE;	r3->cmd = unstuff_bits(buf, 40, 8, 6);	r3->ocr = unstuff_bits(buf, 8, 32, 6);	if (r3->cmd != 0x3f) {  		mmc_card->errno = MMC_ERROR_HEADER_MISMATCH;		return MSS_ERROR_RESP_UNPACK;	}	return 0;}/** *  Fast I/O, support for CEATA devices. */static int mmc_unpack_r4( struct mss_cmd *cmd, struct mmc_response_r4 *r4, struct mmc_card *mmc_card){	u8 *buf = cmd->response;	mmc_card->errno = MMC_ERROR_NONE;	r4->cmd			= unstuff_bits(buf, 40, 8, 6);	r4->rca			= unstuff_bits(buf, 24, 16, 6);	r4->status		= unstuff_bits(buf, 23, 1, 6);	r4->reg_addr		= unstuff_bits(buf, 16, 7, 6);	r4->read_reg_contents	= unstuff_bits(buf, 8, 8, 6);		if (r4->cmd != 0x27) {		mmc_card->errno = MMC_ERROR_HEADER_MISMATCH;		return MSS_ERROR_RESP_UNPACK;	}	return 0 ;}/** *  Interrupt request. not supported temporarily. */static int mmc_unpack_r5(struct mss_cmd *cmd, struct mmc_response_r5 *r5, struct mmc_card *mmc_card){	u8 *buf = cmd->response;	mmc_card->errno = MMC_ERROR_NONE;		r5->cmd		= unstuff_bits(buf, 40, 8, 6);	r5->rca		= unstuff_bits(buf, 24, 16, 6);	r5->irq_data	= unstuff_bits(buf, 8, 16, 6);		if (r5->cmd != 0x28) {		mmc_card->errno = MMC_ERROR_HEADER_MISMATCH;		return MSS_ERROR_RESP_UNPACK;	}	return 0 ;}static int mmc_unpack_cid(struct mss_cmd *cmd, struct mmc_cid *cid, struct mmc_card *mmc_card){	u8 *buf = cmd->response;	mmc_card->errno = MMC_ERROR_NONE;	if (buf[0] != 0x3f)  {	       mmc_card->errno = MMC_ERROR_HEADER_MISMATCH;	       return MSS_ERROR_RESP_UNPACK;	}	buf = buf + 1;		cid->mid	= unstuff_bits(buf, 120, 8, 16);	cid->oid	= unstuff_bits(buf, 104, 16, 16);	cid->pnm[0]	= unstuff_bits(buf, 96, 8, 16);	cid->pnm[1]	= unstuff_bits(buf, 88, 8, 16);	cid->pnm[2]	= unstuff_bits(buf, 80, 8, 16);	cid->pnm[3]	= unstuff_bits(buf, 72, 8, 16);	cid->pnm[4]	= unstuff_bits(buf, 64, 8, 16);	cid->pnm[5]	= unstuff_bits(buf, 56, 8, 16);		cid->pnm[6]	= 0;	cid->prv	= unstuff_bits(buf, 48, 8, 16);	cid->psn	= unstuff_bits(buf, 16, 32, 16);	cid->mdt	= unstuff_bits(buf, 8, 8, 16);	#if 0	DEBUG(" mid=%d oid=%d pnm=%s prv=%d.%d psn=%08x mdt=%d/%d\n",	      cid->mid, cid->oid, cid->pnm, 	      (cid->prv>>4), (cid->prv&0xf), 	      cid->psn, cid->mdt&&0xf, ((cid->mdt>>4)&0xff)+2000);#endif      	return 0;}static int mmc_unpack_csd(struct mss_cmd *cmd, struct mmc_csd *csd, struct mmc_card *mmc_card){	u8 *buf = cmd->response;		mmc_card->errno = MMC_ERROR_NONE;	if (buf[0] != 0x3f)  {		mmc_card->errno = MMC_ERROR_HEADER_MISMATCH;		return MSS_ERROR_RESP_UNPACK;	}	buf = buf + 1;		csd->csd_structure      = unstuff_bits(buf, 126, 2, 16);	csd->spec_vers          = unstuff_bits(buf, 122, 4, 16);	csd->taac               = unstuff_bits(buf, 112, 8, 16);	csd->nsac               = unstuff_bits(buf, 104, 8, 16);	csd->tran_speed         = unstuff_bits(buf, 96, 8, 16);	csd->ccc                = unstuff_bits(buf, 84, 12, 16);;	csd->read_bl_len        = unstuff_bits(buf, 80, 4, 16);	csd->read_bl_partial    = unstuff_bits(buf, 79, 1, 16);	csd->write_blk_misalign = unstuff_bits(buf, 78, 1, 16);	csd->read_blk_misalign  = unstuff_bits(buf, 77, 1, 16);	csd->dsr_imp            = unstuff_bits(buf, 76, 1, 16);	csd->c_size             = unstuff_bits(buf, 62, 12, 16);	csd->vdd_r_curr_min     = unstuff_bits(buf, 59, 3, 16);	csd->vdd_r_curr_max     = unstuff_bits(buf, 56, 3, 16);	csd->vdd_w_curr_min     = unstuff_bits(buf, 53, 3, 16);	csd->vdd_w_curr_max     = unstuff_bits(buf, 50, 3, 16);	csd->c_size_mult        = unstuff_bits(buf, 47, 3, 16);	switch (csd->csd_structure ) {		case CSD_STRUCT_1_0:		case CSD_STRUCT_1_1:			csd->erase.v22.sector_size    = 				unstuff_bits(buf, 42, 5, 16);			csd->erase.v22.erase_grp_size = 				unstuff_bits(buf, 37, 5, 6);		break;		case CSD_STRUCT_1_2:		default:			csd->erase.v31.erase_grp_size = 				unstuff_bits(buf, 42, 5, 16);			csd->erase.v31.erase_grp_mult = 				unstuff_bits(buf, 37, 5, 16);;		break;	}	csd->wp_grp_size        = unstuff_bits(buf, 32, 5, 16);	csd->wp_grp_enable      = unstuff_bits(buf, 31, 1, 16);	csd->default_ecc        = unstuff_bits(buf, 29, 2, 16);	csd->r2w_factor         = unstuff_bits(buf, 26, 3, 16);	csd->write_bl_len       = unstuff_bits(buf, 22, 4, 16);	csd->write_bl_partial   = unstuff_bits(buf, 21, 1, 16);	csd->file_format_grp    = unstuff_bits(buf, 16, 1, 16);	csd->copy               = unstuff_bits(buf, 14, 1, 16);	csd->perm_write_protect = unstuff_bits(buf, 13, 1, 16);	csd->tmp_write_protect  = unstuff_bits(buf, 12, 1, 16);	csd->file_format        = unstuff_bits(buf, 10, 2, 16);	csd->ecc                = unstuff_bits(buf, 8, 2, 16);#if 0	printk("csd_structure=%d  spec_vers=%d  taac=%02x  nsac=%02x  tran_speed=%02x\n"	      "  ccc=%04x  read_bl_len=%d  read_bl_partial=%d  write_blk_misalign=%d\n"	      "  read_blk_misalign=%d  dsr_imp=%d  c_size=%d  vdd_r_curr_min=%d\n"	      "  vdd_r_curr_max=%d  vdd_w_curr_min=%d  vdd_w_curr_max=%d  c_size_mult=%d\n"	      "  wp_grp_size=%d  wp_grp_enable=%d  default_ecc=%d  r2w_factor=%d\n"	      "  write_bl_len=%d  write_bl_partial=%d  file_format_grp=%d  copy=%d\n"	      "  perm_write_protect=%d  tmp_write_protect=%d  file_format=%d  ecc=%d\n",	      csd->csd_structure, csd->spec_vers, 	      csd->taac, csd->nsac, csd->tran_speed,	      csd->ccc, csd->read_bl_len, 	      csd->read_bl_partial, csd->write_blk_misalign,	      csd->read_blk_misalign, csd->dsr_imp, 	      csd->c_size, csd->vdd_r_curr_min,	      csd->vdd_r_curr_max, csd->vdd_w_curr_min, 	      csd->vdd_w_curr_max, csd->c_size_mult,	      csd->wp_grp_size, csd->wp_grp_enable,	      csd->default_ecc, csd->r2w_factor, 	      csd->write_bl_len, csd->write_bl_partial,	      csd->file_format_grp, csd->copy, 	      csd->perm_write_protect, csd->tmp_write_protect,	      csd->file_format, csd->ecc);	switch ( csd->csd_structure ) {	case CSD_STRUCT_1_0:	case CSD_STRUCT_1_1:		printk(" V22 sector_size=%d erase_grp_size=%d\n", 		      csd->erase.v22.sector_size, 		      csd->erase.v22.erase_grp_size);		break;	case CSD_STRUCT_1_2:	default:		printk(" V31 erase_grp_size=%d erase_grp_mult=%d\n", 		      csd->erase.v31.erase_grp_size,		      csd->erase.v31.erase_grp_mult);		break;			}#endif	return MSS_ERROR_NONE;}static int mmc_unpack_ext_csd(u8 *buf, struct mmc_ext_csd *ext_csd){	ext_csd->s_cmd_set = buf[504];	ext_csd->sec_count = ((u32)buf[212]) << 24 | ((u32)buf[213]) << 16 | ((u32)buf[214]) << 8 | ((u32)buf[215]) ;	ext_csd->min_perf_w_8_52 = buf[210];	ext_csd->min_perf_r_8_52 = buf[209];	ext_csd->min_perf_w_26_4_52 = buf[208];	ext_csd->min_perf_r_26_4_52 = buf[207];	ext_csd->min_perf_w_4_26 = buf[206];	ext_csd->min_perf_r_4_26 = buf[205];	ext_csd->pwr_cl_26_360 = buf[203];	ext_csd->pwr_cl_52_360 = buf[202];	ext_csd->pwr_cl_26_195 = buf[201];	ext_csd->pwr_cl_52_195 = buf[200];	ext_csd->card_type = buf[196];	ext_csd->csd_structure = buf[194];	ext_csd->ext_csd_rev = buf[192];	ext_csd->cmd_set = buf[191];	ext_csd->cmd_set_rev = buf[189];	ext_csd->power_class = buf[187];	ext_csd->hs_timing = buf[185];	ext_csd->erased_mem_cont = buf[183];#if 0	DEBUG("s_cmd_set:%d, sec_count:%d, min_perf_w_8_52:%d,\n"	"min_perf_r_8_52:%d, min_perf_w_26_4_52:%d, min_perf_r_26_4_52:%d\n"	"min_perf_w_4_26:%d, min_perf_r_4_26:%d, pwr_cl_26_360:%d, "	"pwr_cl_52_360:%d, pwr_cl_26_195:%d, pwr_cl_52_195:%d, card_type:%d\n"	"csd_structure:%d, ext_csd_rev:%d, cmd_set:%d, cmd_set_rev:%d\n"	"power_class:%d, hs_timing:%d, erased_mem_cont:%d\n", ext_csd->s_cmd_set,ext_csd->sec_count,ext_csd->min_perf_w_8_52, ext_csd->min_perf_r_8_52,ext_csd->min_perf_w_26_4_52,ext_csd->min_perf_r_26_4_52, ext_csd->min_perf_w_4_26, ext_csd->min_perf_r_4_26, ext_csd->pwr_cl_26_360, ext_csd->pwr_cl_52_360, ext_csd->pwr_cl_26_195, ext_csd->pwr_cl_52_195, ext_csd->card_type, ext_csd->csd_structure, ext_csd->ext_csd_rev, ext_csd->cmd_set, ext_csd->cmd_set_rev, ext_csd->power_class, ext_csd->hs_timing, ext_csd->erased_mem_cont); #endif	return 0;}#ifdef CONFIG_MMC_CEATAstatic int mmc_unpack_ceata(u8 *buf, struct mmc_ceata *ceata){/*	memcpy(ceata->sn, buf + 20, 20);	memcpy(ceata->fw_ver, buf + 46, 8);	memcpy(ceata->model_number, buf + 54, 40);	ceata->major_ver = buf[160] << 8 | buf[161];	ceata->max_lba = ((u64)buf[200] << 56) | ((u64)buf[201] << 48) | 		((u64)buf[202] << 40) | ((u64)buf[203] << 32) | 		((u64)buf[204] << 24) | ((u64)buf[205] << 16) | 		((u64)buf[206] << 8) | (u64)(buf[207]);	ceata->feature = buf[512] << 8 | buf[513];	dbg("max_lbr : 0x%llx", ceata->max_lba);*/	return 0;}#endif/** *  The blocks requested by the kernel may or may not match what we can do.   *  Unfortunately, filesystems play fast and loose with block sizes, so we're  * stuck with this . */static void mmc_fix_request_block_len(struct mss_card *card, int action, struct mss_rw_arg *arg){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -