123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292 |
- /*
- * Copyright (C) 2017 ALLWINNERTECH TECHNOLOGY CO., LTD. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name of ALLWINNERTECH TECHNOLOGY CO., LTD. nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "stdint.h"
- #include "sys/param.h"
- #include "sys/endian.h"
- #include "hal_sdhost.h"
- #include "sdmmc.h"
- #include "sdio.h"
- #include "_sd_define.h"
- #include "_core.h"
- #include "_sdio.h"
- #ifdef CONFIG_USE_SDIO
- //inline int mmc_io_rw_direct(struct mmc_card *card, int32_t write, uint32_t fn, uint32_t addr, uint8_t in, uint8_t *out);
- #define SDIO_MIN(a, b) MIN(a, b)
- /*
- * Calculate the maximum byte mode transfer size
- */
- static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
- {
- unsigned mval = func->card->host->max_blk_size;
- //if (mmc_blksz_for_byte_mode(func->card))
- // mval = min(mval, func->cur_blksize);
- //else
- mval = SDIO_MIN(mval, func->max_blksize);
- //if (mmc_card_broken_byte_mode_512(func->card))
- return SDIO_MIN(mval, 511u);
- return SDIO_MIN(mval, 512u); /* maximum size for byte mode */
- }
- #ifdef CONFIG_SDIO_USE_FUNS
- static int32_t cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, uint32_t size)
- {
- uint32_t i, nr_strings;
- char **buffer, *string;
- /* Find all null-terminated (including zero length) strings in
- the TPLLV1_INFO field. Trailing garbage is ignored. */
- buf += 2;
- size -= 2;
- nr_strings = 0;
- for (i = 0; i < size; i++) {
- if (buf[i] == 0xff)
- break;
- if (buf[i] == 0)
- nr_strings++;
- }
- if (nr_strings == 0)
- return 0;
- size = i;
- buffer = HAL_Malloc(sizeof(char *) * nr_strings + size);
- SDC_Memset(buffer, 0, sizeof(char *) * nr_strings + size);
- if (!buffer)
- return -1;
- string = (char*)(buffer + nr_strings);
- for (i = 0; i < nr_strings; i++) {
- buffer[i] = string;
- strcpy(string, (char *)buf);
- string += strlen(string) + 1;
- buf += strlen((char *)buf) + 1;
- }
- if (func) {
- func->num_info = nr_strings;
- func->info = (const char**)buffer;
- } else {
- card->num_info = nr_strings;
- card->info = (const int8_t **)buffer;
- }
- return 0;
- }
- static int32_t cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, unsigned size)
- {
- uint32_t vendor, device;
- /* TPLMID_MANF */
- vendor = buf[0] | (buf[1] << 8);
- /* TPLMID_CARD */
- device = buf[2] | (buf[3] << 8);
- if (func) {
- func->vendor = vendor;
- func->device = device;
- } else {
- card->cis.vendor = vendor;
- card->cis.device = device;
- }
- return 0;
- }
- static const unsigned char speed_val[16] =
- { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
- static const uint32_t speed_unit[8] =
- { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
- typedef int32_t (tpl_parse_t)(struct mmc_card *, struct sdio_func *, const unsigned char *, unsigned);
- struct cis_tpl {
- unsigned char code;
- unsigned char min_size;
- tpl_parse_t *parse;
- };
- static int32_t cis_tpl_parse(struct mmc_card *card, struct sdio_func *func,
- const char *tpl_descr,
- const struct cis_tpl *tpl, int32_t tpl_count,
- uint8_t code, const uint8_t *buf, uint32_t size)
- {
- int32_t i, ret = 0;
- /* look for a matching code in the table */
- for (i = 0; i < tpl_count; i++, tpl++) {
- if (tpl->code == code)
- break;
- }
- if (i < tpl_count) {
- if (size >= tpl->min_size) {
- if (tpl->parse)
- ret = tpl->parse(card, func, buf, size);
- else
- ret = 0; /* known tuple, not parsed */
- } else {
- /* invalid tuple */
- ret = -1;
- }
- if (ret) {
- SD_LOGW("%s: bad %s tuple 0x%02x (%u bytes)\n",
- __func__, tpl_descr, (unsigned int)code, (unsigned int)size);
- }
- } else {
- /* warn about unknown tuples */
- SD_LOGW("%s: queuing unknown CIS tuple 0x%02x (%u bytes)\n",
- __func__, (unsigned int)code, (unsigned int)size);
- }
- return ret;
- }
- static int32_t cistpl_funce_common(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, unsigned size)
- {
- /* Only valid for the common CIS (function 0) */
- if (func)
- return -1;
- /* TPLFE_FN0_BLK_SIZE */
- card->cis.blksize = buf[1] | (buf[2] << 8);
- /* TPLFE_MAX_TRAN_SPEED */
- card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] *
- speed_unit[buf[3] & 7];
- return 0;
- }
- static int32_t cistpl_funce_func(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, uint32_t size)
- {
- uint32_t vsn;
- uint32_t min_size;
- /* Only valid for the individual function's CIS (1-7) */
- if (!func)
- return -1;
- /*
- * This tuple has a different length depending on the SDIO spec
- * version.
- */
- vsn = func->card->cccr.sdio_vsn;
- min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
- if (size < min_size)
- return -1;
- /* TPLFE_MAX_BLK_SIZE */
- func->max_blksize = buf[12] | (buf[13] << 8);
- /* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */
- #ifdef CONFIG_MMC_ERASE
- if (vsn > SDIO_SDIO_REV_1_00)
- func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10;
- else
- func->enable_timeout = jiffies_to_msecs(HZ);
- #endif
- return 0;
- }
- /*
- * Known TPLFE_TYPEs table for CISTPL_FUNCE tuples.
- *
- * Note that, unlike PCMCIA, CISTPL_FUNCE tuples are not parsed depending
- * on the TPLFID_FUNCTION value of the previous CISTPL_FUNCID as on SDIO
- * TPLFID_FUNCTION is always hardcoded to 0x0C.
- */
- static const struct cis_tpl cis_tpl_funce_list[] = {
- { (unsigned char)0x00, (unsigned char)4, (tpl_parse_t *)cistpl_funce_common },
- { (unsigned char)0x01, (unsigned char)0, (tpl_parse_t *)cistpl_funce_func },
- { (unsigned char)0x04, (unsigned char)(1+1+6), NULL/* CISTPL_FUNCE_LAN_NODE_ID */ },
- };
- static int32_t cistpl_funce(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, unsigned size)
- {
- if (size < 1)
- return -1;
- return cis_tpl_parse(card, func, "CISTPL_FUNCE",
- cis_tpl_funce_list,
- HAL_ARRAY_SIZE(cis_tpl_funce_list),
- buf[0], buf, size);
- }
- /* Known TPL_CODEs table for CIS tuples */
- static const struct cis_tpl cis_tpl_list[] = {
- { 0x15, 3, (tpl_parse_t *)cistpl_vers_1 },
- { 0x20, 4, (tpl_parse_t *)cistpl_manfid },
- { 0x21, 2, NULL/* cistpl_funcid */ },
- { 0x22, 0, (tpl_parse_t *)cistpl_funce },
- };
- static int32_t sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
- {
- int32_t ret;
- struct sdio_func_tuple *this, **prev;
- uint32_t i, ptr = 0;
- /*
- * Note that this works for the common CIS (function number 0) as
- * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
- * have the same offset.
- */
- for (i = 0; i < 3; i++) {
- uint8_t x, fn;
- if (func)
- fn = func->num;
- else
- fn = 0;
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
- if (ret)
- return ret;
- ptr |= x << (i * 8);
- }
- if (func)
- prev = &func->tuples;
- else
- prev = &card->tuples;
- if (*prev) {
- SD_LOGE("%s,%d no prev found\n", __func__, __LINE__);
- return -1;
- }
- do {
- uint8_t tpl_code, tpl_link;
- ret = mmc_io_rw_direct(card, 0, FN0, ptr++, 0, &tpl_code);
- if (ret)
- break;
- /* 0xff means we're done */
- if (tpl_code == 0xff)
- break;
- /* null entries have no link field or data */
- if (tpl_code == 0x00)
- continue;
- ret = mmc_io_rw_direct(card, 0, FN0, ptr++, 0, &tpl_link);
- if (ret)
- break;
- /* a size of 0xff also means we're done */
- if (tpl_link == 0xff)
- break;
- this = HAL_Malloc(sizeof(*this) + tpl_link);
- if (!this)
- return -1;
- for (i = 0; i < tpl_link; i++) {
- ret = mmc_io_rw_direct(card, 0, FN0, ptr + i, 0, &this->data[i]);
- if (ret)
- break;
- }
- if (ret) {
- HAL_Free(this);
- break;
- }
- /* Try to parse the CIS tuple */
- ret = cis_tpl_parse(card, func, "CIS",
- cis_tpl_list, HAL_ARRAY_SIZE(cis_tpl_list),
- tpl_code, this->data, tpl_link);
- if (ret == -1) {
- /*
- * The tuple is unknown or known but not parsed.
- * Queue the tuple for the function driver.
- */
- this->next = NULL;
- this->code = tpl_code;
- this->size = tpl_link;
- *prev = this;
- prev = &this->next;
- /* keep on analyzing tuples */
- ret = 0;
- } else {
- /*
- * We don't need the tuple anymore if it was
- * successfully parsed by the SDIO core or if it is
- * not going to be queued for a driver.
- */
- HAL_Free(this);
- }
- ptr += tpl_link;
- } while (!ret);
- /*
- * Link in all unknown tuples found in the common CIS so that
- * drivers don't have to go digging in two places.
- */
- if (func)
- *prev = card->tuples;
- return ret;
- }
- int32_t sdio_read_common_cis(struct mmc_card *card)
- {
- return sdio_read_cis(card, NULL);
- }
- void sdio_free_common_cis(struct mmc_card *card)
- {
- struct sdio_func_tuple *tuple, *victim;
- tuple = card->tuples;
- while (tuple) {
- victim = tuple;
- tuple = tuple->next;
- HAL_Free(victim);
- }
- card->tuples = NULL;
- }
- void sdio_free_func_cis(struct sdio_func *func)
- {
- struct sdio_func_tuple *tuple, *victim;
- tuple = func->tuples;
- while (tuple && tuple != func->card->tuples) {
- victim = tuple;
- tuple = tuple->next;
- HAL_Free(victim);
- }
- func->tuples = NULL;
- }
- int sdio_read_func_cis(struct sdio_func *func)
- {
- int ret;
- ret = sdio_read_cis(func->card, func);
- if (ret)
- return ret;
- /*
- * Since we've linked to tuples in the card structure,
- * we must make sure we have a reference to it.
- */
- // get_device(&func->card->dev);
- /*
- * Vendor/device id is optional for function CIS, so
- * copy it from the card structure as needed.
- */
- if (func->vendor == 0) {
- func->vendor = func->card->cis.vendor;
- func->device = func->card->cis.device;
- }
- return 0;
- }
- static int32_t sdio_read_fbr(struct sdio_func *func)
- {
- int32_t ret;
- unsigned char data;
- //if (mmc_card_nonstd_func_interface(func->card)) {
- // func->class = SDIO_CLASS_NONE;
- // return 0;
- //}
- ret = mmc_io_rw_direct(func->card, 0, FN0,
- SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);
- if (ret)
- goto out;
- data &= 0x0f;
- if (data == 0x0f) {
- ret = mmc_io_rw_direct(func->card, 0, FN0,
- SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data);
- if (ret)
- goto out;
- }
- func->class = data;
- out:
- return ret;
- }
- #endif
- static int32_t mmc_send_io_op_cond(struct mmc_card *card, uint32_t ocr, uint32_t *rocr)
- {
- struct mmc_command cmd = {0};
- uint32_t i, err = 0;
- cmd.opcode = SD_IO_SEND_OP_COND;
- cmd.arg = ocr;
- cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
- for (i = 1000; i; i--) {
- err = mmc_wait_for_cmd(card->host, &cmd);
- if (err)
- break;
- /* if we're just probing, do a single pass */
- if (ocr == 0)
- break;
- /* otherwise wait until reset completes */
- if (cmd.resp[0] & MMC_CARD_BUSY)
- break;
- err = -1;
- mmc_mdelay(1);
- }
- if (rocr)
- *rocr = cmd.resp[0];
- return err;
- }
- int32_t
- mmc_io_rw_direct_host(struct mmc_host *host, int32_t write, uint32_t fn,
- uint32_t addr, uint8_t in, uint8_t *out)
- {
- struct mmc_command cmd = {0};
- int32_t err;
- uint32_t temp;
- if (!host) {
- SD_LOGE_RAW(ROM_ERR_MASK, "%s,%d no host exist!\n", __func__, __LINE__);
- return -1;
- }
- if (fn > 7) {
- SDC_LOGE("%s,%d wrong fn:%ld!\n", __func__, __LINE__, HAL_PR_SZ_L(fn));
- return -1;
- }
- SDC_LOGD("%s,fun %ld, raw %d ,addr %lx,wrte data %x\n", write?"Write":"Read", HAL_PR_SZ_L(fn), (write && out)?1:0, HAL_PR_SZ_L(addr), in);
- /* sanity check */
- if (addr & ~0x1FFFF)
- return -1;
- cmd.opcode = SD_IO_RW_DIRECT;
- cmd.arg = write ? 0x80000000 : 0x00000000;
- cmd.arg |= fn << 28;
- cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
- cmd.arg |= addr << 9;
- cmd.arg |= in;
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(host, &cmd);
- if (err)
- return err;
- temp = cmd.resp[0];
- if (temp & 0xcf00) {
- SDC_LOGE("CMD52 %s Operation Error:%s%s%s%s%s !\n",
- write ? "wirte" : "read",
- temp&0x8000 ? " CMDCRCErr" : "",
- temp&0x4000 ? " ILLEGALCmd" : "",
- temp&0x800 ? " GenERR" : "",
- temp&0x200 ? " FucNumErr" : "",
- temp&0x100 ? " ArgOutRange" : "");
- }
- if (cmd.resp[0] & R5_ERROR)
- return -1;
- if (cmd.resp[0] & R5_FUNCTION_NUMBER)
- return -1;
- if (cmd.resp[0] & R5_OUT_OF_RANGE)
- return -1;
- if (out) {
- *out = cmd.resp[0] & 0xFF;
- }
- return 0;
- }
- int mmc_io_rw_direct(struct mmc_card *card, int32_t write, uint32_t fn, uint32_t addr, uint8_t in, uint8_t *out)
- {
- if (!card) {
- SD_LOGE_RAW(ROM_ERR_MASK, "%s,%d no card exist!\n", __func__, __LINE__);
- return -1;
- }
- return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
- }
- /**
- * SDIO Spec: CMD53 is 48 bit long. read or write multiple I/O registers with a
- * single command
- * ----------------------------------------------------------------------------
- * S|D|CMDIND|R|FUN|BLOCK MODE|OP CODE|REGISTER ADDRESS|BYTE/BLOCK COUNT|CRC7|E
- * ----------------------------------------------------------------------------
- * @ret : RET_OK, RET_FAIL
- */
- int32_t
- mmc_io_rw_extended(struct mmc_card *card, uint8_t write, uint8_t fn, uint32_t addr, uint32_t incr_addr,
- const void *buf, uint32_t blocks, uint32_t blksz)
- {
- struct mmc_request mrq;
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct scatterlist sg = {0};
- int32_t ret;
- if (fn > 7) {
- SD_LOGE("%s,%d err fn:%d\n", __func__, __LINE__, fn);
- return -1;
- }
- SDC_WARN_ON(blksz == 0);
- /* sanity check */
- if (addr & ~0x1FFFF)
- return -1;
- cmd.opcode = SD_IO_RW_EXTENDED; /* cmd53 --index */
- cmd.arg = write ? 0x80000000 : 0x00000000; /* write/read --flag */
- cmd.arg |= fn << 28; /* function number */
- cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; /* incrementing address */
- cmd.arg |= addr << 9;
- if (blocks == 0 )
- cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
- else
- cmd.arg |= 0x08000000| blocks; /* block mode */
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
- data.blksz = blksz;
- data.blocks = blocks ? blocks : 1;
- data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
- sg.buffer = (void *)buf;
- sg.len = data.blksz * data.blocks;
- mrq.cmd = &cmd;
- mrq.data = &data;
- SD_LOGD("starting %s CMD%ld add %lx,arg 0x%08lx flags %lx\n", write?"Write":"Read", HAL_PR_SZ_L(cmd.opcode), HAL_PR_SZ_L(addr), HAL_PR_SZ_L(cmd.arg), HAL_PR_SZ_L(cmd.flags));
- SD_LOGD("blksz %ld blocks %ld flags %lx\n", HAL_PR_SZ_L(data.blksz), HAL_PR_SZ_L(data.blocks), HAL_PR_SZ_L(data.flags));
- ret = mmc_wait_for_req(card->host, &mrq);
- if (ret) {
- SD_LOGE("SDC write operation failed\n");
- }
- if (cmd.resp[0] & R5_ERROR)
- return -1;
- if (cmd.resp[0] & R5_FUNCTION_NUMBER)
- return -1;
- if (cmd.resp[0] & R5_OUT_OF_RANGE)
- return -1;
- // printf("%s,%d,%x\n", __FUNCTION__,__LINE__, sg.buffer);
- return ret;
- }
- /**
- * read/write IO memory in Block/Stream mode with fixed/increaming address
- * This will split an arbitrarily sized data transfer into several IO_RW_EXTENDED commands.
- * @func_num: function number
- * @write: IOMEM_WR:write, IOMEM_RD:read
- * @addr: address of register read from or write to
- * @incr_addr: 1: in, 0: not, used for fifio
- * @buf: pointer to data buffer
- * @size: block counter(block mode)/byte counter(byte mode)
- * @ret: RET_OK, RET_FAIL
- */
- static int32_t
- sdio_io_rw_ext_helper(struct mmc_card *card, uint8_t func_num, int32_t write, uint32_t addr,
- uint32_t incr_addr, uint8_t *buf, uint32_t size)
- {
- uint32_t remainder = size;
- int32_t ret = -1;
- uint32_t blocks;
- int32_t fn_bsize;
- uint8_t *buf_tmp = buf;
- /* Do the bulk of the transfer using block mode (if supported). */
- //if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
- fn_bsize = card->fn_bsize[func_num];
- /* Do the bulk of the transfer using block mode (if supported). */
- while (remainder >= fn_bsize) {
- blocks = remainder / fn_bsize;
- size = blocks * fn_bsize;
- ret = mmc_io_rw_extended(card, write, func_num, addr, incr_addr, buf, blocks, fn_bsize);
- if (ret) {
- SD_LOGE("%s,%d %s IO%x [%lx] SZ:%ld Err:%ld !!\n", __func__, __LINE__,
- write?"W":"R", func_num, HAL_PR_SZ_L(addr), HAL_PR_SZ_L(size), HAL_PR_SZ_L(ret));
- return ret;
- }
- remainder -= size;
- buf += size;
- if (incr_addr)
- addr += size;
- }
- /* Write the remainder using byte mode. */
- while (remainder > 0) {
- size = SDIO_MIN(remainder, 512);
- ret = mmc_io_rw_extended(card, write, func_num, addr, incr_addr, buf, 0, size);
- if (ret) {
- SD_LOGE("%s,%d %s IO%x [%lx] SZ:%ld Err:%ld !!\n", __func__, __LINE__,
- write?"W":"R", func_num, HAL_PR_SZ_L(addr), HAL_PR_SZ_L(size), HAL_PR_SZ_L(ret));
- return ret;
- }
- remainder -= size;
- buf += size;
- if (incr_addr)
- addr += size;
- }
- // printf("%s,%d,%x %x,%x\n", __FUNCTION__,__LINE__, buf_tmp,(uint32_t)buf_tmp, (uint32_t)buf);
- return ret;
- }
- /**
- * sdio_readb - read a single byte from a SDIO function
- * @func_num: SDIO function to access
- * @addr: address to read
- * @err_ret: optional status value from transfer
- *
- * Reads a single byte from the address space of a given SDIO
- * function. If there is a problem reading the address, 0xff
- * is returned and @err_ret will contain the error code.
- */
- uint8_t sdio_readb(struct mmc_card *card, uint32_t func_num, uint32_t addr, int32_t *err_ret)
- {
- int32_t ret;
- uint8_t val;
- if (err_ret)
- *err_ret = 0;
- ret = mmc_io_rw_direct_host(card->host, 0, func_num, addr, 0, &val);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
- return 0xFF;
- }
- return val;
- }
- /**
- * sdio_writeb - write a single byte to a SDIO function
- * @func_num: SDIO function to access
- * @b: byte to write
- * @addr: address to write to
- * @err_ret: optional status value from transfer
- *
- * Writes a single byte to the address space of a given SDIO
- * function. @err_ret will contain the status of the actual
- * transfer.
- */
- void sdio_writeb(struct mmc_card *card, uint32_t func_num, const uint8_t b, uint32_t addr, int32_t *err_ret)
- {
- int32_t ret;
- ret = mmc_io_rw_direct_host(card->host, 1, func_num, addr, b, NULL);
- if (err_ret)
- *err_ret = ret;
- }
- /**
- * sdio_readw - read a 16 bit integer from a SDIO function
- * @func: SDIO function to access
- * @addr: address to read
- * @err_ret: optional status value from transfer
- *
- * Reads a 16 bit integer from the address space of a given SDIO
- * function. If there is a problem reading the address, 0xffff
- * is returned and @err_ret will contain the error code.
- */
- uint16_t sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret)
- {
- int ret;
- if (err_ret)
- *err_ret = 0;
- ret = sdio_memcpy_fromio(func->card, func->num,func->tmpbuf, addr, 2);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
- return 0xFFFF;
- }
- //return le16_to_cpup((__le16 *)func->tmpbuf);
- return le16toh( *((uint16_t *)func->tmpbuf));
- }
- //EXPORT_SYMBOL_GPL(sdio_readw);
- /**
- * sdio_writew - write a 16 bit integer to a SDIO function
- * @func: SDIO function to access
- * @b: integer to write
- * @addr: address to write to
- * @err_ret: optional status value from transfer
- *
- * Writes a 16 bit integer to the address space of a given SDIO
- * function. @err_ret will contain the status of the actual
- * transfer.
- */
- void sdio_writew(struct sdio_func *func, uint16_t b, unsigned int addr, int *err_ret)
- {
- int ret;
- //*(__le16 *)func->tmpbuf = cpu_to_le16(b);
- *(int16_t *)func->tmpbuf = cpu_to_le16(b);
- ret = sdio_memcpy_toio(func->card, func->num, addr, func->tmpbuf, 2);
- if (err_ret)
- *err_ret = ret;
- }
- //EXPORT_SYMBOL_GPL(sdio_writew);
- /**
- * sdio_readl - read a 32 bit integer from a SDIO function
- * @func: SDIO function to access
- * @addr: address to read
- * @err_ret: optional status value from transfer
- *
- * Reads a 32 bit integer from the address space of a given SDIO
- * function. If there is a problem reading the address,
- * 0xffffffff is returned and @err_ret will contain the error
- * code.
- */
- uint32_t sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret)
- {
- int ret;
- if (err_ret)
- *err_ret = 0;
- ret = sdio_memcpy_fromio(func->card, func->num,func->tmpbuf, addr, 4);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
- return 0xFFFFFFFF;
- }
- //return le32_to_cpup((__le32 *)func->tmpbuf);
- return le32toh(*((uint32_t *)func->tmpbuf));
- }
- //EXPORT_SYMBOL_GPL(sdio_readl);
- /**
- * sdio_writel - write a 32 bit integer to a SDIO function
- * @func: SDIO function to access
- * @b: integer to write
- * @addr: address to write to
- * @err_ret: optional status value from transfer
- *
- * Writes a 32 bit integer to the address space of a given SDIO
- * function. @err_ret will contain the status of the actual
- * transfer.
- */
- void sdio_writel(struct sdio_func *func, uint32_t b, unsigned int addr, int *err_ret)
- {
- int ret;
- //*(__le32 *)func->tmpbuf = cpu_to_le32(b);
- *(int32_t *)func->tmpbuf = cpu_to_le32(b);
- ret = sdio_memcpy_toio(func->card, func->num, addr, func->tmpbuf, 4);
- if (err_ret)
- *err_ret = ret;
- }
- //EXPORT_SYMBOL_GPL(sdio_writel);
- /**
- * sdio_enable_func - enables a SDIO function for usage
- * @func: SDIO function to enable
- *
- * Powers up and activates a SDIO function so that register
- * access is possible.
- */
- int32_t sdio_enable_func(struct mmc_card *card, uint32_t func_num)
- {
- uint8_t dat;
- mmc_io_rw_direct_host(card->host, 0, FN0, SDIO_CCCR_IOEx, 0, &dat);
- dat |= (1 << func_num); /* keep the value of other FN's IO enb state */
- mmc_io_rw_direct_host(card->host, 1, FN0, SDIO_CCCR_IOEx, dat, &dat);
- if (!(dat & (1 << func_num))) {
- SD_LOGE("%s,%d IO%ld Enable failed !!\n", __func__, __LINE__, HAL_PR_SZ_L(func_num));
- return -1;
- }
- SD_LOGD("IO%ld is enabled !!\n", HAL_PR_SZ_L(func_num));
- mmc_io_rw_direct_host(card->host, 0, FN0, SDIO_CCCR_IORx, 0, &dat);
- if (!(dat & (1 << func_num))) {
- SD_LOGD("%s,%d IO%ld is not ready !!\n", __func__, __LINE__, HAL_PR_SZ_L(func_num));
- return -1;
- }
- SD_LOGD("IO%ld is ready !!\n", HAL_PR_SZ_L(func_num));
- return 0;
- }
- /**
- * Disable IOx's Function.
- * @io_num: 1~7
- */
- int32_t sdio_disable_func(struct mmc_card *card, uint32_t func_num)
- {
- uint8_t dat;
- mmc_io_rw_direct_host(card->host, 0, FN0, SDIO_CCCR_IOEx, 0, &dat);
- dat &= ~(1 << func_num); /* keep the value of other FN's IO enb state */
- mmc_io_rw_direct_host(card->host, 1, FN0, SDIO_CCCR_IOEx, dat, &dat);
- if (dat & (1 << func_num)) {
- SD_LOGE("%s,%d IO%ld Disable failed !!\n", __func__, __LINE__, HAL_PR_SZ_L(func_num));
- return -1;
- }
- SD_LOGD("IO%ld is Disabled !!\n", HAL_PR_SZ_L(func_num));
- return 0;
- }
- int32_t sdio_set_block_size(struct mmc_card *card, uint32_t fn_num, uint32_t blksz)
- {
- int32_t ret;
- #if 0
- if ((blksz == 0) || card->fn_bsize[fn_num] == blksz) {
- SD_LOGW("block size has beed set to %d !!\n", blksz);
- return -1;
- }
- #endif
- if ((blksz == 0)) {
- SD_LOGW("block size has beed set to %ld !!\n", HAL_PR_SZ_L(blksz));
- return -1;
- }
- /* sdio block size set in FN0 CCIA */
- sdio_writeb(card, FN0, blksz & 0xff, SDIO_FBR_BASE(fn_num) + SDIO_FBR_BLKSIZE, &ret);
- if (ret)
- return ret;
- sdio_writeb(card, FN0, (blksz >> 8) & 0xff, SDIO_FBR_BASE(fn_num) + SDIO_FBR_BLKSIZE + 1, &ret);
- if (ret)
- return ret;
- card->fn_bsize[fn_num] = blksz;
- SD_LOGD("sdio FN%ld set block size to %ld\n", HAL_PR_SZ_L(fn_num), HAL_PR_SZ_L(blksz));
- return 0;
- }
- /*
- * Test if the card supports high-speed mode and, if so, switch to it.
- */
- static int32_t mmc_sdio_switch_hs(struct mmc_card *card, uint32_t enable)
- {
- int32_t ret;
- uint8_t speed;
- if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
- return 0;
- if (!card->cccr.high_speed)
- return 0;
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_SPEED, 0, &speed);
- if (ret)
- return ret;
- if (!(speed & SDIO_SPEED_SHS)) {
- SD_LOGE("%s not support high speed mode!\n", __func__);
- return -1;
- }
- if (enable) {
- speed |= SDIO_SPEED_EHS;
- } else {
- speed &= ~SDIO_SPEED_EHS;
- }
- ret = mmc_io_rw_direct(card, 1, FN0, SDIO_CCCR_SPEED, speed, NULL);
- if(ret)
- return ret;
- return 1;
- }
- uint32_t mmc_sdio_get_max_clock(struct mmc_card *card)
- {
- unsigned max_dtr;
- if (mmc_card_highspeed(card)) {
- /*
- * The SDIO specification doesn't mention how
- * the CIS transfer speed register relates to
- * high-speed, but it seems that 50 MHz is
- * mandatory.
- */
- max_dtr = 50000000;
- } else {
- max_dtr = card->cis.max_dtr;
- }
- #ifdef CONFIG_USE_SDIO_COMBO
- if (card->type == MMC_TYPE_SD_COMBO)
- max_dtr = min(max_dtr, mmc_sd_get_max_clock(card));
- #endif
- return max_dtr;
- }
- #ifdef CONFIG_SDIO_USE_FUNS
- /*
- * Allocate and initialise a new SDIO function structure.
- */
- struct sdio_func *sdio_alloc_func(struct mmc_card *card)
- {
- struct sdio_func *func;
- func = HAL_Malloc(sizeof(struct sdio_func));
- if (!func)
- return NULL;
- SDC_Memset(func, 0, sizeof(struct sdio_func));
- func->card = card;
- return func;
- }
- /*
- * Register a new SDIO function with the driver model.
- */
- int32_t sdio_add_func(struct sdio_func *func, uint32_t id)
- {
- // fprintf(func->name, "%s:%d", id, func->num);
- sdio_func_set_present(func);
- return 0;
- }
- /*
- * Unregister a SDIO function with the driver model, and
- * (eventually) free it.
- * This function can be called through error paths where sdio_add_func() was
- * never executed (because a failure occurred at an earlier point).
- */
- void sdio_remove_func(struct sdio_func *func)
- {
- if (!sdio_func_present(func))
- return;
- }
- static int32_t sdio_init_func(struct mmc_card *card, uint32_t fn)
- {
- int32_t ret;
- struct sdio_func *func;
- if (fn > SDIO_MAX_FUNCS) {
- SD_LOGE("%s,%d wrong fn:%ld!\n", __func__, __LINE__, HAL_PR_SZ_L(fn));
- return -1;
- }
- func = sdio_alloc_func(card);
- if (!func)
- return -1;
- func->num = fn;
- if (!(card->quirks & MMC_QUIRK_NONSTD_SDIO)) {
- ret = sdio_read_fbr(func);
- if (ret)
- goto fail;
- ret = sdio_read_func_cis(func);
- if (ret)
- goto fail;
- } else {
- func->vendor = func->card->cis.vendor;
- func->device = func->card->cis.device;
- func->max_blksize = func->card->cis.blksize;
- }
- card->sdio_func[fn - 1] = func;
- printf("func address %p\n",func);
- return 0;
- fail:
- /*
- * It is okay to remove the function here even though we hold
- * the host lock as we haven't registered the device yet.
- */
- sdio_remove_func(func);
- return ret;
- }
- /*
- * Host is being removed. Free up the current card.
- */
- int mmc_sdio_remove(struct mmc_host *host)
- {
- int i;
- if (!host) {
- SD_LOGE_RAW(ROM_ERR_MASK, "%s,%d no host exist!\n", __func__, __LINE__);
- return -1;
- }
- if (!host->card) {
- SDC_LOGE("%s,%d no card exist!\n", __func__, __LINE__);
- return -1;
- }
- for (i = 0;i < host->card->sdio_funcs;i++) {
- if (host->card->sdio_func[i]) {
- sdio_remove_func(host->card->sdio_func[i]);
- host->card->sdio_func[i] = NULL;
- }
- }
- //mmc_remove_card(host->card); /* do nothing */
- host->card = NULL;
- return 0;
- }
- #endif
- static int32_t sdio_read_cccr(struct mmc_card *card, uint32_t ocr)
- {
- int32_t ret;
- int32_t cccr_vsn;
- int32_t uhs = ocr & R4_18V_PRESENT;
- uint8_t data;
- uint8_t speed;
- SDC_Memset(&card->cccr, 0, sizeof(struct sdio_cccr));
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_CCCR, 0, &data);
- if (ret)
- goto out;
- cccr_vsn = data & 0x0f;
- if (cccr_vsn > SDIO_CCCR_REV_3_00) {
- SD_LOGW("%s: unrecognised CCCR structure version %ld\n",
- __func__, HAL_PR_SZ_L(cccr_vsn));
- return -1;
- }
- card->cccr.sdio_vsn = (data & 0xf0) >> 4;
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_CAPS, 0, &data);
- if (ret)
- goto out;
- if (data & SDIO_CCCR_CAP_SMB)
- card->cccr.multi_block = 1;
- if (data & SDIO_CCCR_CAP_LSC)
- card->cccr.low_speed = 1;
- if (data & SDIO_CCCR_CAP_4BLS)
- card->cccr.wide_bus = 1;
- if (cccr_vsn >= SDIO_CCCR_REV_1_10) {
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_POWER, 0, &data);
- if (ret)
- goto out;
- if (data & SDIO_POWER_SMPC)
- card->cccr.high_power = 1;
- }
- if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_SPEED, 0, &speed);
- if (ret)
- goto out;
- card->scr.sda_spec3 = 0;
- card->sw_caps.sd3_bus_mode = 0;
- card->sw_caps.sd3_drv_type = 0;
- if (cccr_vsn >= SDIO_CCCR_REV_3_00 && uhs) {
- card->scr.sda_spec3 = 1;
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_UHS, 0, &data);
- if (ret)
- goto out;
- if (card->host->caps &
- (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50)) {
- if (data & SDIO_UHS_DDR50)
- card->sw_caps.sd3_bus_mode |= SD_MODE_UHS_DDR50;
- if (data & SDIO_UHS_SDR50)
- card->sw_caps.sd3_bus_mode |= SD_MODE_UHS_SDR50;
- if (data & SDIO_UHS_SDR104)
- card->sw_caps.sd3_bus_mode |= SD_MODE_UHS_SDR104;
- }
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_DRIVE_STRENGTH, 0, &data);
- if (ret)
- goto out;
- if (data & SDIO_DRIVE_SDTA)
- card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_A;
- if (data & SDIO_DRIVE_SDTC)
- card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
- if (data & SDIO_DRIVE_SDTD)
- card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
- }
- /* if no uhs mode ensure we check for high speed */
- if (!card->sw_caps.sd3_bus_mode) {
- if (speed & SDIO_SPEED_SHS) {
- card->cccr.high_speed = 1;
- card->sw_caps.hs_max_dtr = 50000000;
- } else {
- card->cccr.high_speed = 0;
- card->sw_caps.hs_max_dtr = 25000000;
- }
- }
- }
- out:
- SD_LOGD("%s high_speed:%d sda_spec3:%d sd3_drv_type:%lx sd3_bus_mode:%lx\n",
- __func__, card->cccr.high_speed, card->scr.sda_spec3,
- HAL_PR_SZ_L(card->sw_caps.sd3_drv_type), HAL_PR_SZ_L(card->sw_caps.sd3_bus_mode));
- return ret;
- }
- static int32_t sdio_enable_wide(struct mmc_card *card)
- {
- int32_t ret;
- uint8_t ctrl;
- if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
- return 0;
- if (card->cccr.low_speed && !card->cccr.wide_bus)
- return 0;
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_IF, 0, &ctrl);
- if (ret)
- return ret;
- ctrl |= SDIO_BUS_WIDTH_4BIT;
- ret = mmc_io_rw_direct(card, 1, FN0, SDIO_CCCR_IF, ctrl, NULL);
- if (!ret && card->type == MMC_TYPE_SDIO)
- card->bus_width = MMC_BUS_WIDTH_4;
- return ret;
- }
- /*
- * If desired, disconnect the pull-up resistor on CD/DAT[3] (pin 1)
- * of the card. This may be required on certain setups of boards,
- * controllers and embedded sdio device which do not need the card's
- * pull-up. As a result, card detection is disabled and power is saved.
- */
- static int32_t sdio_disable_cd(struct mmc_card *card)
- {
- int32_t ret;
- uint8_t ctrl;
- if (!mmc_card_disable_cd(card))
- return 0;
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_IF, 0, &ctrl);
- if (ret)
- return ret;
- ctrl |= SDIO_BUS_CD_DISABLE;
- return mmc_io_rw_direct(card, 1, FN0, SDIO_CCCR_IF, ctrl, NULL);
- }
- /*
- * Devices that remain active during a system suspend are
- * put back into 1-bit mode. called by mmc_sdio_suspend(host).
- */
- #ifdef CONFIG_SD_PM
- static int32_t sdio_disable_wide(struct mmc_card *card)
- {
- int32_t ret;
- uint8_t ctrl;
- if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
- return 0;
- if (card->cccr.low_speed && !card->cccr.wide_bus)
- return 0;
- ret = mmc_io_rw_direct(card, 0, FN0, SDIO_CCCR_IF, 0, &ctrl);
- if (ret)
- return ret;
- if (!(ctrl & SDIO_BUS_WIDTH_4BIT))
- return 0;
- ctrl &= ~SDIO_BUS_WIDTH_4BIT;
- ctrl |= SDIO_BUS_ASYNC_INT;
- ret = mmc_io_rw_direct(card, 1, FN0, SDIO_CCCR_IF, ctrl, NULL);
- if (ret)
- return ret;
- HAL_SDC_Set_BusWidth(card->host, MMC_BUS_WIDTH_1);
- return 0;
- }
- #endif
- static int32_t sdio_enable_4bit_bus(struct mmc_card *card)
- {
- int32_t err = 0;
- if (card->type == MMC_TYPE_SDIO)
- return sdio_enable_wide(card);
- #ifdef CONFIG_USE_SDIO_COMBO
- if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
- err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
- return err;
- } else
- return 0;
- err = sdio_enable_wide(card);
- if (err <= 0)
- mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
- #endif
- return err;
- }
- /*
- * Enable SDIO/combo card's high-speed mode. Return 0/1 if [not]supported.
- */
- static int32_t sdio_enable_hs(struct mmc_card *card)
- {
- int32_t ret;
- ret = mmc_sdio_switch_hs(card, 1);
- if (ret <= 0 || card->type == MMC_TYPE_SDIO)
- return ret;
- #ifdef CONFIG_USE_SDIO_COMBO
- ret = mmc_sd_switch_hs(card);
- if (ret <= 0)
- mmc_sdio_switch_hs(card, 0);
- #endif
- return ret;
- }
- /*----------------------------------------------------------------------------------------------*\
- Function : This function gets the CIS adress present on the SDIO card
- Argumennt : pointer to controller structure
- Return : 0, -1
- \*----------------------------------------------------------------------------------------------*/
- /*
- static uint32_t sdio_get_cisptr(struct mmc_card *card)
- {
- uint32_t fn;
- uint8_t dat;
- for (fn=0; fn<=card->io_num; fn++) {
- sdio_ioreg_read(card, FN0, FN_CIS_POINTER_0_REG(fn), &dat);
- card->cisptr[fn] = dat;
- sdio_ioreg_read(card, FN0, FN_CIS_POINTER_1_REG(fn), &dat);
- card->cisptr[fn] |= (uint32_t)dat << 8;
- sdio_ioreg_read(card, FN0, FN_CIS_POINTER_2_REG(fn), &dat);
- card->cisptr[fn] |= (uint32_t)dat << 16;
- SD_LOGD("Card CIS Addr = %x, fn = %d\n", card->cisptr[fn], fn);
- }
- return 0;
- }
- */
- #if 0
- /*--------------------------------------------------------------*\
- @function : uint32_t sdio_read_cisinfo(uint8_t* buf)
- @brief : this function read CIS infomation of card
- @arguments: buf - pointer to data buffer
- @return : 0, -1
- \*--------------------------------------------------------------*/
- int32_t sdio_read_cisinfo(struct mmc_card *card, uint8_t* buf)
- {
- uint32_t i;
- int32_t ret=0;
- /* Read the Tuple Data */
- for (i = 0; i < SIZE_OF_TUPLE; i++) {
- ret = sdio_ioreg_read(card, FN0, card->cisptr[FN0]+i, buf+i);
- if (ret==-1)
- return ret;
- }
- return ret;
- }
- /*--------------------------------------------------------------*\
- @function : uint32_t sdio_read_manfid(uint32_t func_num)
- @brief : this function read Manufacturer identification of card
- @arguments: func_num - pointer to data buffer
- @return : 0, -1
- \*--------------------------------------------------------------*/
- int32_t sdio_read_manfid(struct mmc_card *card, uint32_t func_num)
- {
- uint32_t offset = 0;
- uint32_t manfid, card_id;
- int32_t ret=0;
- uint8_t tuple, link, datah, datal;
- do {
- ret = sdio_ioreg_read(card, func_num, card->cisptr[func_num]+offset, &tuple);
- if (ret == -1)
- return ret;
- if (tuple == CISTPL_MANFID) {
- offset += 2;
- ret = sdio_ioreg_read(card, func_num, card->cisptr[func_num]+offset, &datal);
- if (ret == -1)
- return ret;
- offset++;
- ret = sdio_ioreg_read(card, func_num, card->cisptr[func_num]+offset, &datah);
- if (ret == -1)
- return ret;
- manfid = (uint32_t)datal | (uint32_t)datah << 8;
- offset++;
- ret = sdio_ioreg_read(card, func_num, card->cisptr[func_num]+offset, &datal);
- if (ret == -1)
- return ret;
- offset++;
- ret = sdio_ioreg_read(card, func_num, card->cisptr[func_num]+offset, &datah);
- if (ret == -1)
- return ret;
- card_id = (uint32_t)datal | (uint32_t)datah << 8;
- card->manfid = (card_id<<16)|manfid;
- SD_LOGD("Card id = %08x manfid = %08x\n", card_id, manfid);
- return manfid;
- }
- ret = sdio_ioreg_read(card, func_num, card->cisptr[func_num]+offset+1, &link);
- if (ret == -1)
- return ret;
- offset += link + 2;
- } while(tuple != CISTPL_END);
- return 0;
- }
- int32_t sdio_get_vendor_id(struct mmc_card *card)
- {
- return (sdio_read_manfid(card, FN0));
- }
- #endif
- int
- sdio_memcpy_fromio(struct mmc_card *card, unsigned int func_num, void *dst, unsigned int addr, int count)
- {
- return sdio_io_rw_ext_helper(card, func_num, 0, addr, 1, dst, count);
- }
- int
- sdio_memcpy_toio(struct mmc_card *card, unsigned int func_num, unsigned int addr, const void *src, int count)
- {
- return sdio_io_rw_ext_helper(card, func_num, 1, addr, 1, (uint8_t *)src, count);
- }
- #ifdef CONFIG_SDIO_IRQ_SUPPORT
- #if 0
- /*-----------------------------------*\
- Read IOx's Interrupt Pending
- Argument: io_num - 1~7
- Return: 1-pending, 0-not pending
- \*-----------------------------------*/
- int32_t sdio_intx_pend_rd(struct mmc_card *card, uint32_t io_num)
- {
- uint8_t dat;
- //func_num uses default value 0
- mmc_io_rw_direct_host(card->host, 0, FN0, INT_PENDING_REG, 0, &dat);
- if (dat & INT(io_num)) {
- SD_LOGE("IO%x Interrupt is pending !!\n", io_num);
- return 0;
- }
- SD_LOGD("IO%x Interrupt is not pending !!\n", io_num);
- return -1;
- }
- /* IOx's Abort *\
- \* io_num: 1~7 */
- int32_t sdio_iox_abort(struct mmc_card *card, uint32_t io_num)
- {
- mmc_io_rw_direct_host(card->host, 0, FN0, IO_ABORT_REG, AS(io_num), NULL);
- return 0;
- }
- /**
- * sdio_claim_irq - claim the IRQ for a SDIO function
- * @func: SDIO function
- * @handler: IRQ handler callback
- *
- * Claim and activate the IRQ for the given SDIO function. The provided
- * handler will be called when that IRQ is asserted. The host is always
- * claimed already when the handler is called so the handler must not
- * call sdio_claim_host() nor sdio_release_host().
- */
- int sdio_claim_irq(struct mmc_card *card, unsigned int func_num, sdio_irq_handler_t *handler)
- {
- int32_t ret;
- uint8_t reg;
- if (!card) {
- SD_LOGE_RAW(ROM_ERR_MASK, "%s,%d\n", __func__, __LINE__);
- return -1;
- }
- SD_LOGN("SDIO: Enabling IRQ for %d...\n", func_num);
- if (card->irq_handler) {
- SD_LOGE("SDIO: IRQ for %d already in use.\n", func_num);
- return -EBUSY;
- }
- reg = sdio_readb(card, FN0, SDIO_CCCR_IENx, &ret);
- if (ret)
- return ret;
- reg |= 1 << func_num;
- reg |= 1; /* Master interrupt enable */
- sdio_writeb(card, FN0, reg, SDIO_CCCR_IENx, &ret);
- if (ret)
- return ret;
- card->irq_handler = handler;
- return ret;
- }
- /**
- * sdio_release_irq - release the IRQ for a SDIO function
- * @func: SDIO function
- *
- * Disable and release the IRQ for the given SDIO function.
- */
- int sdio_release_irq(struct mmc_card *card, unsigned int func_num)
- {
- int ret;
- uint8_t reg;
- if (!card) {
- SD_LOGE_RAW(ROM_ERR_MASK, "%s,%d\n", __func__, __LINE__);
- return -1;
- }
- SD_LOGN("SDIO: Disabling IRQ for %d...\n", func_num);
- if (card->irq_handler)
- card->irq_handler = NULL;
- reg = sdio_readb(card, FN0, SDIO_CCCR_IENx, &ret);
- if (ret)
- return ret;
- reg &= ~(1 << func_num);
- /* Disable master interrupt with the last function interrupt */
- if (!(reg & 0xFE))
- reg = 0;
- sdio_writeb(card, FN0, reg, SDIO_CCCR_IENx, &ret);
- if (ret)
- return ret;
- return 0;
- }
- #endif
- #endif
- /*
- * Fetch CID from card.
- */
- #ifdef CONFIG_USE_SDIO_COMBO
- int32_t mmc_sd_get_cid(struct mmc_host *host, uint32_t ocr, uint32_t *cid, uint32_t *rocr)
- {
- int32_t err;
- /*
- * Since we're changing the OCR value, we seem to
- * need to tell some cards to go back to the idle
- * state. We wait 1ms to give cards time to
- * respond.
- */
- mmc_go_idle(host);
- /*
- * If SD_SEND_IF_COND indicates an SD 2.0
- * compliant card and we should set bit 30
- * of the ocr to indicate that we can handle
- * block-addressed SDHC cards.
- */
- err = mmc_send_if_cond(host, ocr);
- if (!err)
- ocr |= SD_OCR_CCS;
- /*
- * If the host supports one of UHS-I modes, request the card
- * to switch to 1.8V signaling level.
- */
- if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
- ocr |= SD_OCR_S18R;
- /* If the host can supply more than 150mA, XPC should be set to 1. */
- if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
- MMC_CAP_SET_XPC_180))
- ocr |= SD_OCR_XPC;
- try_again:
- err = mmc_send_app_op_cond(host, ocr, rocr);
- if (err)
- return err;
- /*
- * In case CCS and S18A in the response is set, start Signal Voltage
- * Switch procedure. SPI mode doesn't support CMD11.
- */
- if (rocr && ((*rocr & 0x41000000) == 0x41000000)) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
- if (err) {
- ocr &= ~SD_OCR_S18R;
- goto try_again;
- }
- }
- err = mmc_all_send_cid(host, cid);
- return err;
- }
- #endif
- /*--------------------------------------------------------------*\
- @function : uint32_t sdio_enumerate(uint32_t smc_no)
- @brief : this function enumerates and initializes SDIO card
- @arguments: smc_no - number of the smc channel selected
- @return : 0, -1
- \*--------------------------------------------------------------*/
- int32_t mmc_sdio_init_card(struct mmc_card *card)
- {
- int32_t err;
- //struct mmc_host *host = card->host;
- /* The initialization should be done at 3.3 V I/O voltage. */
- //mmc_set_signal_voltage();
- err = mmc_send_io_op_cond(card, card->ocr.ocr & 0xFF8000, &card->ocr.ocr);
- if (err)
- return err;
- #ifdef CONFIG_USE_SDIO_COMBO
- if ((card->ocr.ocr & R4_MEMORY_PRESENT) &&
- mmc_sd_get_cid(host, host->ocr & card->ocr.ocr, card->raw_cid, NULL) == 0) {
- card->type = MMC_TYPE_SD_COMBO;
- SD_LOGW("SDIO Combo Card(With I/O & Memory) !!\n");
- /* if with memory in it, allocate memory space for storing memory portion information */
- //card->mem_info_p = (SDMMCInfo *)HAL_Malloc(sizeof(SDMMCInfo));
- /* relative operations for memory portion */
- } else
- #endif
- {
- card->type = MMC_TYPE_SDIO;
- SD_LOGD("Standard SDIO Card with IO portion only !!\n");
- }
- /*
- * If the host and card support UHS-I mode request the card
- * to switch to 1.8V signaling level. No 1.8v signalling if
- * UHS mode is not enabled to maintain compatibilty and some
- * systems that claim 1.8v signalling in fact do not support
- * it.
- */
- #ifdef SD_SUPPORT_VERSION3
- if ((card->ocr.ocr & R4_18V_PRESENT) &&
- (card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50))) {
- err = mmc_set_signal_voltage(card->host, MMC_SIGNAL_VOLTAGE_180, true);
- if (err) {
- card->ocr.ocr &= ~R4_18V_PRESENT;
- card->host->ocr &= ~R4_18V_PRESENT;
- }
- err = 0;
- } else {
- card->ocr.ocr &= ~R4_18V_PRESENT;
- card->host->ocr &= ~R4_18V_PRESENT;
- }
- #endif
- /* CMD3, Ask the card to publish a new Relative Card Address (RCA) */
- err = mmc_send_relative_addr(card->host, &card->rca);
- if (err) {
- SD_LOGW("SD public RCA failed\n");
- return err;
- }
- SD_LOGD("Card RCA %lx\n", HAL_PR_SZ_L(card->rca));
- HAL_SDC_Update_Clk(card->host, 25000000);
- /*
- * Read CSD, before selecting the card
- */
- #ifdef CONFIG_USE_SDIO_COMBO
- if (card->type == MMC_TYPE_SD_COMBO) {
- err = mmc_sd_get_csd(host, card);
- if (err)
- return err;
- mmc_decode_cid(card);
- }
- #endif
- /* CMD7, Select card, as all following commands rely on that. */
- err = mmc_select_card(card, 1);
- if (err) {
- SD_LOGE("Card Select Error!!\n");
- return -1;
- }
- #ifdef CONFIG_USE_MMC_QUIRK
- if (card->quirks & MMC_QUIRK_NONSTD_SDIO) {
- /*
- * This is non-standard SDIO device, meaning it doesn't
- * have any CIA (Common I/O area) registers present.
- * It's host's responsibility to fill cccr and cis
- * structures in init_card().
- */
- mmc_set_clock(host, card->cis.max_dtr);
- if (card->cccr.high_speed) {
- mmc_card_set_highspeed(card);
- mmc_set_timing(card->host, MMC_TIMING_SD_HS);
- }
- goto finish;
- }
- #endif
- /*
- * Read the common registers.
- */
- err = sdio_read_cccr(card, card->ocr.ocr);
- if (err)
- goto remove;
- /*
- * Read the common CIS tuples.
- */
- #ifdef CONFIG_SDIO_USE_FUNS
- err = sdio_read_common_cis(card);
- if (err)
- goto remove;
- #endif
- #ifdef CONFIG_USE_MMC_QUIRK
- mmc_fixup_device(card, NULL);
- #endif
- /*
- * If needed, disconnect card detection pull-up resistor.
- */
- err = sdio_disable_cd(card);
- if (err)
- goto remove;
- /* Initialization sequence for UHS-I cards */
- /* Only if card supports 1.8v and UHS signaling */
- #ifdef SD_SUPPORT_VERSION3
- if ((card->ocr.ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) {
- err = mmc_sdio_init_uhs_card(card);
- if (err)
- goto remove;
- /* Card is an ultra-high-speed card */
- mmc_card_set_uhs(card);
- } else
- #endif
- {
- /*
- * Switch to high-speed (if supported).
- */
- err = sdio_enable_hs(card);
- if (err > 0) {
- mmc_card_set_highspeed(card);
- SD_LOGN("sdio highspeed \n");
- } else if (err)
- goto remove;
- /*
- * Change to the card's maximum speed.
- */
- HAL_SDC_Update_Clk(card->host, mmc_sdio_get_max_clock(card));
- /*
- * Switch to wider bus (if supported).
- */
- err = sdio_enable_4bit_bus(card);
- if (!err) {
- /* sd Host Controller Register SDXC_REG_WIDTH */
- HAL_SDC_Set_BusWidth(card->host, MMC_BUS_WIDTH_4);
- SD_LOGN("%s bus width type:%d\n", __func__, MMC_BUS_WIDTH_4);
- } else if (err)
- goto remove;
- }
- #ifdef CONFIG_USE_MMC_QUIRK
- finish:
- #endif
- card->host->card = card;
- return 0;
- remove:
- card->host->card = NULL;
- #ifdef CONFIG_SDIO_USE_FUNS
- sdio_free_func_cis((struct sdio_func *)card->sdio_func);
- sdio_free_common_cis(card);
- #endif
- return err;
- }
- uint32_t sdio_reset(struct mmc_host *host)
- {
- int32_t ret;
- uint8_t abort;
- /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
- ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
- if (ret)
- abort = 0x08;
- else
- abort |= 0x08;
- ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
- return ret;
- }
- /**
- * sdio_set_host_pm_flags - set wanted host power management capabilities
- * @func: SDIO function attached to host
- *
- * Set a capability bitmask corresponding to wanted host controller
- * power management features for the upcoming suspend state.
- * This must be called, if needed, each time the suspend method of
- * the function driver is called, and must contain only bits that
- * were returned by sdio_get_host_pm_caps().
- * The host doesn't need to be claimed, nor the function active,
- * for this information to be set.
- */
- static int32_t sdio_set_host_pm_flags(sdio_t *card, uint32_t flags)
- {
- #ifdef CONFIG_SD_PM
- struct mmc_host *host = card->host;
- if (flags & ~host->pm_caps)
- return -1;
- /* function suspend methods are serialized, hence no lock needed */
- host->pm_flags |= flags;
- #endif
- return 0;
- }
- int32_t sdio_pm(sdio_t *card, int32_t suspend)
- {
- int32_t ret = 0;
- if (suspend) {
- /* Notify SDIO that ALLWINNERTECH will remain powered during suspend */
- ret = sdio_set_host_pm_flags(card, MMC_PM_KEEP_POWER);
- if (ret)
- SD_LOGE("Error setting SDIO pm flags: %ld\n", HAL_PR_SZ_L(ret));
- }
- return ret;
- }
- #ifdef CONFIG_SD_PM
- /*
- * SDIO suspend. We need to suspend all functions separately.
- * Therefore all registered functions must have drivers with suspend
- * and resume methods. Failing that we simply remove the whole card.
- */
- static int mmc_sdio_suspend(struct mmc_host *host)
- {
- int32_t i, err = 0;
- struct mmc_card *card;
- card = host->card;
- card->suspend = 1;
- #ifdef CONFIG_SDIO_USE_FUNS
- for (i = 0; i < host->card->sdio_funcs; i++) {
- struct sdio_func *func = host->card->sdio_func[i];
- if (func && sdio_func_present(func) && func->dev.driver) {
- err = sdio_bus_pm_suspend(&func->dev);
- sdio_disable_func(host->card, FN1);
- if (err)
- break;
- }
- }
- while (err && --i >= 0) {
- struct sdio_func *func = host->card->sdio_func[i];
- if (func && sdio_func_present(func) && func->dev.driver) {
- sdio_bus_pm_resume(&func->dev);
- }
- }
- #else
- (void)i;
- #endif
- if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
- mmc_claim_host(host);
- sdio_disable_wide(host->card);
- mmc_release_host(host);
- }
- return err;
- }
- int mmc_sdio_resume(struct mmc_host *host)
- {
- int32_t i, err = 0;
- struct mmc_card *card;
- if (!host) {
- SDC_LOGE_RAW(ROM_ERR_MASK, "%s,%d no host exist!\n", __func__, __LINE__);
- return -1;
- }
- if (!host->card) {
- SDC_LOGE("%s,%d no card exist!\n", __func__, __LINE__);
- return -1;
- }
- card = host->card;
- /* Basic card reinitialization. */
- mmc_claim_host(host);
- /* No need to reinitialize powered-resumed nonremovable cards */
- if (!mmc_card_keep_power(host)) {
- err = mmc_sdio_init_card(host->card);
- } else if (mmc_card_wake_sdio_irq(host)) {
- /* We may have switched to 1-bit mode during suspend */
- err = sdio_enable_4bit_bus(host->card);
- if (!err) {
- HAL_SDC_Set_BusWidth(host->card->host, MMC_BUS_WIDTH_4);
- SDC_LOGN("%s bus width type:%d\n", __func__, MMC_BUS_WIDTH_4);
- err = 0;
- }
- }
- #ifdef CONFIG_SDIO_IRQ_SUPPORT
- if (!err && host->sdio_irqs)
- wake_up_process(host->sdio_irq_thread);
- #endif
- mmc_release_host(host);
- #ifdef CONFIG_SDIO_USE_FUNS
- /*
- * If the card looked to be the same as before suspending, then
- * we proceed to resume all card functions. If one of them returns
- * an error then we simply return that error to the core and the
- * card will be redetected as new. It is the responsibility of
- * the function driver to perform further tests with the extra
- * knowledge it has of the card to confirm the card is indeed the
- * same as before suspending (same MAC address for network cards,
- * etc.) and return an error otherwise.
- */
- for (i = 0; !err && i < host->card->sdio_funcs; i++) {
- struct sdio_func *func = host->card->sdio_func[i];
- if (func && sdio_func_present(func) && func->dev.driver) {
- err = sdio_bus_pm_resume(&func->dev);
- sdio_enable_func(host->card, FN1);
- }
- }
- #else
- (void)i;
- #endif
- card->suspend = 0;
- return err;
- }
- static const struct mmc_bus_ops sdio_bus_ops = {
- .suspend = mmc_sdio_suspend,
- .resume = mmc_sdio_resume,
- };
- #endif
- /*
- * Starting point for SDIO card init.
- */
- int mmc_attach_sdio(struct mmc_card *card, struct mmc_host *host)
- {
- int err = -1;
- int32_t funcs;
- int i;
- if (!host) {
- SD_LOGE("%s,%d no host exist!\n", __func__, __LINE__);
- return -1;
- }
- /* CMD5 arg=0; get card support Voltage */
- err = mmc_send_io_op_cond(card, 0, &card->ocr.ocr);
- if (err)
- return err;
- SD_LOGD("card ocr:%lx\n", HAL_PR_SZ_L(card->ocr.ocr));
- /*
- * Sanity check the voltages that the card claims to
- * support.
- */
- if (card->ocr.ocr & 0x7F) {
- SD_LOGW("card claims to support voltages below the defined range."
- "These will be ignored.\n");
- card->ocr.ocr &= ~0x7F;
- }
- /* Detect and init the card. */
- err = mmc_sdio_init_card(card);
- if (err)
- return err;
- funcs = (card->ocr.ocr >> 28) & 0x7;
- SD_LOGD("Number of I/O Functions: %02lx\n", HAL_PR_SZ_L(funcs));
- /*
- * Initialize (but don't add) all present functions.
- */
- #ifdef CONFIG_SDIO_USE_FUNS
- card->sdio_funcs = 0;
- // for (int i = 0; i < card->io_num; i++, card->sdio_funcs++) {
- // for (int i = 0; i < funcs; i++, card->sdio_funcs++) {
- for (i = 0; i < funcs; i++, card->sdio_funcs++) {
- err = sdio_init_func(host->card, i + 1);
- if (err)
- goto remove;
- }
- #endif
- /*
- * First add the card to the driver model...
- */
- mmc_release_host(host);
- if(host->caps&MMC_CAP_SDIO_IRQ){
- int ret = OS_SemaphoreCreateBinary(&host->sdio_irq_signal);
- SDC_BUG_ON(ret!=OS_OK);
- }
- mmc_add_card(host->card);
- /*
- * ...then the SDIO functions.
- */
- #ifdef CONFIG_SDIO_USE_FUNS
- // for (int i = 0; i < funcs; i++) {
- for (i = 0; i < funcs; i++) {
- err = sdio_add_func(host->card->sdio_func[i], i);
- if (err)
- goto remove_added;
- }
- #else
- (void)funcs;
- #endif
- card->fn_bsize[1] = 512;
- mmc_claim_host(host);
- #ifdef CONFIG_SD_PM
- if (!card->suspend) {
- mmc_attach_bus(host, &sdio_bus_ops);
- }
- #endif
- return 0;
- #ifdef CONFIG_SDIO_USE_FUNS
- remove_added:
- /* Remove without lock if the device has been added. */
- mmc_sdio_remove(host);
- #endif
- card->host->card = NULL;
- mmc_claim_host(host);
- #ifdef CONFIG_SDIO_USE_FUNS
- remove:
- /* And with lock if it hasn't been added. */
- mmc_release_host(host);
- if (host->card) {
- mmc_sdio_remove(host);
- card->host->card = NULL;
- }
- mmc_claim_host(host);
- #else
- card->host->card = NULL;
- #endif
- SD_LOGE("%s: error %d whilst initialising SDIO card\n", __func__, err);
- return err;
- }
- void mmc_deattach_sdio(struct mmc_card *card, struct mmc_host *host)
- {
- if (!card) {
- SD_LOGE_RAW(ROM_ERR_MASK, "%s,%d\n", __func__, __LINE__);
- return ;
- }
- #ifdef CONFIG_SD_PM
- if (!card->suspend) {
- mmc_detach_bus(card->host);
- }
- #endif
- if(host->caps&MMC_CAP_SDIO_IRQ){
- int ret = OS_SemaphoreDelete(&host->sdio_irq_signal);
- SDC_BUG_ON(ret!=OS_OK);
- }
- }
- /**
- * sdio_align_size - pads a transfer size to a more optimal value
- * @card: SDIO card
- * @sz: original transfer size
- *
- * Pads the original data size with a number of extra bytes in
- * order to avoid controller bugs and/or performance hits
- * (e.g. some controllers revert to PIO for certain sizes).
- *
- * If possible, it will also adjust the size so that it can be
- * handled in just a single request.
- *
- * Returns the improved size, which might be unmodified.
- */
- //unsigned int sdio_align_size(struct mmc_card *card, unsigned int sz)
- unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
- {
- #ifdef CONFIG_SDIO_USE_FUNS
- unsigned int orig_sz;
- unsigned int blk_sz, byte_sz;
- unsigned chunk_sz;
- orig_sz = sz;
- #endif
- /* Do a first check with the controller, in case it
- * wants to increase the size up to a point where it
- * might need more than one block.
- */
- //sz = mmc_align_data_size(card, sz);
- sz = mmc_align_data_size(func->card, sz);
- #ifdef CONFIG_SDIO_USE_FUNS
- /*
- * If we can still do this with just a byte transfer, then
- * we're done.
- */
- if (sz <= sdio_max_byte_size(func))
- return sz;
- if (func->card->cccr.multi_block) {
- /*
- * Check if the transfer is already block aligned
- */
- if ((sz % func->cur_blksize) == 0) {
- return sz;
- }
- /*
- * Realign it so that it can be done with one request,
- * and recheck if the controller still likes it.
- */
- blk_sz = ((sz + func->cur_blksize - 1) /
- func->cur_blksize) * func->cur_blksize;
- blk_sz = mmc_align_data_size(func->card, blk_sz);
- /*
- * This value is only good if it is still just
- * one request.
- */
- if ((blk_sz % func->cur_blksize) == 0)
- return blk_sz;
- /*
- * We failed to do one request, but at least try to
- * pad the remainder properly.
- */
- byte_sz = mmc_align_data_size(func->card,
- sz % func->cur_blksize);
- if (byte_sz <= sdio_max_byte_size(func)) {
- blk_sz = sz / func->cur_blksize;
- return blk_sz * func->cur_blksize + byte_sz;
- }
- } else {
- /*
- * We need multiple requests, so first check that the
- * controller can handle the chunk size;
- */
- chunk_sz = mmc_align_data_size(func->card,
- sdio_max_byte_size(func));
- if (chunk_sz == sdio_max_byte_size(func)) {
- /*
- * Fix up the size of the remainder (if any)
- */
- byte_sz = orig_sz % chunk_sz;
- if (byte_sz) {
- byte_sz = mmc_align_data_size(func->card,
- byte_sz);
- }
- return (orig_sz / chunk_sz) * chunk_sz + byte_sz;
- }
- }
- /* The controller is simply incapable of transferring the size
- * we want in decent manner, so just return the original size.
- */
- return orig_sz;
- #endif
- return sz;
- }
- #ifdef SDIO_EXCLUSIVE_HOST
- /**
- * sdio_claim_host - exclusively claim a bus for a certain SDIO function
- * @card: SDIO that will be accessed
- *
- * Claim a bus for a set of operations. The SDIO function given
- * is used to figure out which bus is relevant.
- */
- void sdio_claim_host(struct mmc_card *card)
- {
- HAL_SDC_Claim_Host(card->host);
- }
- /**
- * sdio_release_host - release a bus for a certain SDIO function
- * @card: SDIO that was accessed
- *
- * Release a bus, allowing others to claim the bus for their
- * operations.
- */
- void sdio_release_host(struct mmc_card *card)
- {
- HAL_SDC_Release_Host(card->host);
- }
- #endif
- #endif /* CONFIG_USE_SDIO */
|