Exemple #1
0
int lc823450_sdc_trimsector(uint32_t ch, unsigned long addr, unsigned short cnt)
{
  int ret;

  _sdc_semtake(&_sdc_sem[ch]);

#ifdef CONFIG_LC823450_SDC_LOG
  mcinfo("++++ start ch=%d, addr=%ld, cnt=%d \n", ch, addr, cnt);
#endif

  lc823450_sdc_access_led(ch, addr);

#ifdef CONFIG_SCHED_INSTRUMENTATION_IO
  sched_add_bt((uint64_t)cnt);
#endif

  ret = SdDrEraseSeq(0x00000001, addr, cnt, _cfg[ch]);
  if (0 > ret)
    {
      mcinfo("ret=%d ch=%d add=%ld cnt=%d \n", ret, ch, addr, cnt);
    }

  _sdc_semgive(&_sdc_sem[ch]);

  mcinfo("----  end ret=%d \n", ret);
  return ret;
}
Exemple #2
0
int lc823450_sdc_changespeedmode(uint32_t ch, int mode)
{
  int ret;

  mcinfo("++++ ch=%d, mode=%d \n", ch, mode);
  _sdc_semtake(&_sdc_sem[ch]);

  ret = SdDrChangeSpeedMode(mode, _cfg[ch]);

  if (0 == ret)
    {
      switch (mode)
        {
          case 1: /* High Speed */
            modifyreg32(SDCTL,
                        SDCTL_ACSMODE0_MASK << (ch * 8),
                        SDCTL_ACSMODE0_HS << (ch * 8));
            break;

          case 4: /* DDR */
            modifyreg32(SDCTL,
                        SDCTL_ACSMODE0_MASK << (ch * 8),
                        SDCTL_ACSMODE0_MMCDDR << (ch * 8));
            break;
        }
    }

  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("----  end ret=%d \n", ret);
  return ret;
}
Exemple #3
0
static void fmuk66_mediachange(struct fmuk66_sdhc_state_s *sdhc)
{
	bool inserted;

	/* Get the current value of the card detect pin.  This pin is pulled up on
	 * board.  So low means that a card is present.
	 */

	inserted = !kinetis_gpioread(GPIO_SD_CARDDETECT);
	mcinfo("inserted: %s\n", inserted ? "Yes" : "No");

	/* Has the pin changed state? */

	if (inserted != sdhc->inserted) {
		mcinfo("Media change: %d->%d\n",  sdhc->inserted, inserted);

		/* Yes.. perform the appropriate action (this might need some debounce). */

		sdhc->inserted = inserted;
		sdhc_mediachange(sdhc->sdhc, inserted);

#ifdef CONFIG_FMUK66_SDHC_AUTOMOUNT
		/* Let the automounter know about the insertion event */

		fmuk66_automount_event(fmuk66_cardinserted());
#endif
	}
}
Exemple #4
0
int lc823450_sdc_getcid(uint32_t ch, char *cidstr, int length)
{
  uint8_t cid[16];
  int ret;

  mcinfo("++++ ch=%d \n", ch);
  _sdc_semtake(&_sdc_sem[ch]);

  ret = SdDrGetCid((UI_32 *)cid, _cfg[ch]);

  if (0 == ret && length >= (2 * sizeof(cid) + 1))
    {
      int i;

      for (i = 15; i >= 0; i--)
        {
          snprintf(cidstr, 3, "%02x", cid[i]);
          cidstr += 2;
        }

      *cidstr = '\0';
    }

  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("----  end ret=%d \n", ret);
  return ret;
}
Exemple #5
0
int lc823450_sdc_initialize(uint32_t ch)
{
  int ret;

  /* Only ES2 is supported */

  ASSERT(1 == cpu_ver);

  struct SdDrCfg_s *psd = _cfg[ch];

  psd->sysclk           = lc823450_get_systemfreq();
  psd->detecttime       = DET_TIME;

#ifdef CONFIG_LC823450_SDC_UHS1
  psd->setting          = SDDR_SD_SWITCH_18V;
#endif

  psd->deposinit        = sddep_os_init;
  psd->deposexit        = sddep_os_exit;
  psd->depsetclk        = sddep_set_clk;
  psd->depwait          = sddep_wait;
  psd->depwaitstatus    = sddep_wait_status;
  psd->depreaddata      = sddep_read;
  psd->depwritedata     = sddep_write;
  psd->depvoltageswitch = sddep_voltage_switch;

  switch (ch)
    {
      case 0:
        psd->dephwinit  = sddep0_hw_init;
        psd->dephwexit  = sddep0_hw_exit;
        psd->regbase    = SDIF0_BASE;
        psd->workbuf    = _work0;
        break;

#ifdef CONFIG_LC823450_SDIF_SDC
      case 1:
        psd->dephwinit  = sddep1_hw_init;
        psd->dephwexit  = sddep1_hw_exit;
        psd->regbase    = SDIF1_BASE;
        psd->workbuf    = _work1;
        break;
#endif

      default:
        ASSERT(false);
    }

  mcinfo("++++ start \n");
  _sdc_semtake(&_sdc_sem[ch]);
  ret = SdDrInitialize(_cfg[ch]);
  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("---- end ret=%d \n", ret);

  return ret;
}
Exemple #6
0
int lc823450_sdc_finalize(uint32_t ch)
{
  int ret;

  mcinfo("++++ start ch=%ld \n", ch);
  _sdc_semtake(&_sdc_sem[ch]);
  ret = SdDrFinalize(_cfg[ch]);
  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("---- end ret=%d \n", ret);

  return ret;
}
Exemple #7
0
int lc823450_sdc_setclock(uint32_t ch, uint32_t limitclk, uint32_t sysclk)
{
  int ret;

  mcinfo("++++ start ch=%ld limitClk=%ld sysClk=%ld\n", ch, limitClk, sysClk);
  _sdc_semtake(&_sdc_sem[ch]);
  ret = SdDrSetClock(limitclk, sysclk, _cfg[ch]);
  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("---- end ret=%d \n", ret);

  return ret;
}
Exemple #8
0
int lc823450_sdc_refmediatype(uint32_t ch)
{
  int ret;

  mcinfo("++++ start \n");
  _sdc_semtake(&_sdc_sem[ch]);
  ret = SdDrRefMediaType(_cfg[ch]);
  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("---- end ret=%d \n", ret);

  return ret;
}
Exemple #9
0
int lc823450_sdc_cachectl(uint32_t ch, int ctrl)
{
  int ret;

  mcinfo("++++ ch=%d, ctrl=%d \n", ch, ctrl);
  _sdc_semtake(&_sdc_sem[ch]);

  ret = SdDrCacheCtrl(ctrl, _cfg[ch]);

  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("----  end ret=%d \n", ret);
  return ret;
}
Exemple #10
0
int lc823450_sdc_getcardsize(uint32_t ch,
                             unsigned long *psecnum, unsigned long *psecsize)
{
  int ret;

  mcinfo("++++ start \n");
  _sdc_semtake(&_sdc_sem[ch]);

  ret = SdDrGetCardSize(psecnum, psecsize, _cfg[ch]);

  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("---- end ret=%d \n", ret);
  return ret;
}
Exemple #11
0
int k64_sdhc_initialize(void)
{
  int ret;

  /* Configure GPIO pins */

  kinetis_pinconfig(GPIO_SD_CARDDETECT);

  /* Attached the card detect interrupt (but don't enable it yet) */

  kinetis_pinirqattach(GPIO_SD_CARDDETECT, k64_cdinterrupt);

  /* Configure the write protect GPIO -- None */

  /* Mount the SDHC-based MMC/SD block driver */
  /* First, get an instance of the SDHC interface */

  mcinfo("Initializing SDHC slot %d\n", MMCSD_SLOTNO);

  g_sdhc.sdhc = sdhc_initialize(MMCSD_SLOTNO);
  if (!g_sdhc.sdhc)
    {
      mcerr("ERROR: Failed to initialize SDHC slot %d\n", MMCSD_SLOTNO);
      return -ENODEV;
    }

  /* Now bind the SDHC interface to the MMC/SD driver */

  mcinfo("Bind SDHC to the MMC/SD driver, minor=%d\n", MMSCD_MINOR);

  ret = mmcsd_slotinitialize(MMSCD_MINOR, g_sdhc.sdhc);
  if (ret != OK)
    {
      syslog(LOG_ERR, "ERROR: Failed to bind SDHC to the MMC/SD driver: %d\n", ret);
      return ret;
    }

  syslog(LOG_INFO, "Successfully bound SDHC to the MMC/SD driver\n");

  /* Handle the initial card state */

  k64_mediachange();

  /* Enable CD interrupts to handle subsequent media changes */

  kinetis_pinirqenable(GPIO_SD_CARDDETECT);
  return OK;
}
Exemple #12
0
bool fmuk66_cardinserted(void)
{
	bool inserted;

	/* Get the current value of the card detect pin.  This pin is pulled up on
	 * board.  So low means that a card is present.
	 */

	inserted = !kinetis_gpioread(GPIO_SD_CARDDETECT);
	mcinfo("inserted: %s\n", inserted ? "Yes" : "No");
	return inserted;
}
Exemple #13
0
int lc823450_sdc_identifycard(uint32_t ch)
{
  int ret;

  mcinfo("++++ start \n");
  _sdc_semtake(&_sdc_sem[ch]);

  ret = SdDrIdentifyCard(_cfg[ch]);

#ifdef CONFIG_LC823450_SDC_CACHE
  if (ch)
    {
      _sec_cache_enabled = 0;
      _sec_cache_add = 0xffffffff; /* invalid */
    }
#endif

  _sdc_semgive(&_sdc_sem[ch]);
  mcinfo("---- end ret=%d \n", ret);
  return ret;
}
Exemple #14
0
int lc823450_sdc_writesector(uint32_t ch,
                             unsigned long addr, unsigned short cnt,
                             void *pbuf, unsigned long type)
{
  int ret;

  _sdc_semtake(&_sdc_sem[ch]);

#ifdef CONFIG_LC823450_SDC_LOG
  mcinfo("++++ start ch=%d, addr=%ld, cnt=%d \n", ch, addr, cnt);
#endif

#ifdef CONFIG_LC823450_SDC_CACHE
  if (1 == ch && _sec_cache_enabled)
    {
      _sec_cache_add = 0xffffffff; /* invalid */
    }
#endif

  lc823450_sdc_access_led(ch, addr);

#ifdef CONFIG_SCHED_INSTRUMENTATION_IO
  sched_add_bo((uint64_t)cnt);
#endif

  ret = SdDrWriteSector(addr, cnt, pbuf, type, _cfg[ch]);

  if (0 > ret)
    {
      mcinfo("ret=%d ch=%d add=%ld cnt=%d \n", ret, ch, addr, cnt);
    }

  _sdc_semgive(&_sdc_sem[ch]);

  mcinfo("----  end ret=%d \n", ret);
  return ret;
}
Exemple #15
0
/*
 * @file sim-hlt-tpc.C
 * @brief HLT Conformal mapping tracker embedded into AliRoot simulation.
 *
 * Example macro to run the HLT Conformal mapping tracker embedded into
 * AliRoot simulation. The reconstruction is done from the TPC digits.
 *
 * Usage: aliroot -b -q sim-hlt-tpc.C | tee sim-hlt-tpc.log
 *
 * The chain to be run is defined within the macro. The input data is
 * read from the TPC.Digits.
 *
 * The following options can be specified comma separated in a string:
 * <pre>
 *   aliroot -b -q sim-hlt-tpc.C'("options")'
 *       CA      use the cellular automaton  tracker and track merger
 *       CM      use the conformal mapping tracker and track merger
 *       SORTED  use CF pre-sorting and corresponding sequential CF
 *               algorithm, by default the algorithm capable of reading
 *               unsorted data is used
 *       RAW     write raw data for all detectors
 *       RAWHLT  write raw data only for HLT
 *       MC      propagate the MC information
 * </pre>
 *
 * The macro asumes the data to be already simulated. If it should run
 * within the initial simulation, comment the corresponding functions
 * below (SetRunGeneration etc.)
 *
 * @author [email protected]
 * @ingroup alihlt_tpc
 */
sim_hlt_tpc(const char* options="CA")
{
  // this is just a tool to switch the logging systems
  AliHLTLogging log;
  //log.SwitchAliLog(0);

  ///////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  //
  // scanning the options
  //
  bool bUseCA=true;   // use the CA tracker and merger
  bool bCFSort=false; // CF pre-sorting and sequential CF algorithm
  bool bRawData=false;// raw data for all detectors
  bool bRawHLTData=false; // raw data only for HLT
  bool bPropagateMC=false;
  TString tsOptions=options;
  TObjArray* pTokens=tsOptions.Tokenize(",");
  if (pTokens) {
    for (int n=0; n<pTokens->GetEntries(); n++) {
      TString arg=((TObjString*)pTokens->At(n))->GetString();
      if (arg.CompareTo("ca", TString::kIgnoreCase)==0) {
	bUseCA=true;
      } else if (arg.CompareTo("cm", TString::kIgnoreCase)==0) {
	bUseCA=false;
      } else if (arg.CompareTo("sorted", TString::kIgnoreCase)==0) {
	bCFSort=true;
      } else if (arg.CompareTo("unsorted", TString::kIgnoreCase)==0) {
	bCFSort=false;
      } else if (arg.CompareTo("raw", TString::kIgnoreCase)==0) {
	bRawData=true;
      } else if (arg.CompareTo("rawhlt", TString::kIgnoreCase)==0) {
	bRawHLTData=true;
      } else if (arg.CompareTo("mc", TString::kIgnoreCase)==0) {
	bPropagateMC=true;
      } else {
	cout << "unknown argument: " << arg << endl;
	return 0;
      }
    }
    delete pTokens;
  }
  // summary
  cout << "using " << bUseCA?"CA":"CM" << " tracker" << endl;
  
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  //
  // init the HLT system in order to define the analysis chain below
  //
  AliHLTSystem* gHLT=AliHLTPluginBase::GetInstance();

  ///////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  //
  // define the analysis chain
  //

  // load TPCParam from OCDB
  const char* cdbEntry="TPC/Calib/Parameters";
  AliCDBManager* pMan=AliCDBManager::Instance();
  AliTPCParam* pTPCParam=NULL;
  if (pMan) {
    if (!pMan->IsDefaultStorageSet()) {
      pMan->SetDefaultStorage("local://$ALICE_ROOT/OCDB");
      pMan->SetRun(0);
    }
    AliCDBEntry *pEntry = pMan->Get(cdbEntry);
    if (pEntry && 
	pEntry->GetObject() &&
	(pTPCParam=dynamic_cast<AliTPCParam*>(pEntry->GetObject()))) {
    } else {
      HLTWarning("can not load AliTPCParam from CDB entry %s", cdbEntry);
    }
  }

  int iMinSlice=0; 
  int iMaxSlice=35;
  int iMinPart=0;
  int iMaxPart=5;
  TString mergerInput;
  TString writerInput;
  TString sinkClusterInput;
  for (int slice=iMinSlice; slice<=iMaxSlice; slice++) {
    TString trackerInput;
    for (int part=iMinPart; part<=iMaxPart; part++) {
      TString arg, publisher, cf;

      // digit publisher components
      arg.Form("-slice %d -partition %d", slice, part);
      publisher.Form("DP_%02d_%d", slice, part);
      AliHLTConfiguration pubconf(publisher.Data(), "TPCDigitPublisher", NULL , arg.Data());

      // cluster finder components
      arg="-timebins ";
      if (pTPCParam) arg+=pTPCParam->GetMaxTBin()+1;
      else arg+=446; // old simulated data
      if (bCFSort) arg+=" -sorted ";
      if (bPropagateMC) arg+=" -do-mc ";
      cf.Form("CF_%02d_%d", slice, part);
      AliHLTConfiguration cfconf(cf.Data(), "TPCClusterFinderUnpacked", publisher.Data(), arg.Data());
      if (trackerInput.Length()>0) trackerInput+=" ";
      trackerInput+=cf;
      if (sinkClusterInput.Length()>0) sinkClusterInput+=" ";
      sinkClusterInput+=cf;
    }

    TString tracker;
    // tracker finder components
    tracker.Form("TR_%02d", slice);
    if (bUseCA) {
      AliHLTConfiguration trackerconf(tracker.Data(), "TPCCATracker", trackerInput.Data(), "");
    } else {
      AliHLTConfiguration trackerconf(tracker.Data(), "TPCSliceTracker", trackerInput.Data(), "-pp-run");
    }

    //add all trackers to writer input. Include if you would like all slice tracks written.
    //if (writerInput.Length()>0) writerInput+=" ";
    //writerInput+=tracker;

    // add all clusterfinders to the writer input
    if (writerInput.Length()>0) writerInput+=" ";
    writerInput+=trackerInput;

    if (mergerInput.Length()>0) mergerInput+=" ";
    mergerInput+=tracker;

  }

  // GlobalMerger component
  if (bUseCA) {
    AliHLTConfiguration mergerconf("globalmerger","TPCCAGlobalMerger",mergerInput.Data(),"");
  } else {
    AliHLTConfiguration mergerconf("globalmerger","TPCGlobalMerger",mergerInput.Data(),"");
  }

  TString converterInput="globalmerger";

  // collector for the MC information to be propagated from CFs to ESDConverter
  if (bPropagateMC){
    AliHLTConfiguration mcinfo("mcinfo", "BlockFilter"   , sinkClusterInput.Data(), "-datatype 'CLMCINFO' 'TPC '");  
    AliHLTConfiguration mcTrackMarker("mcTrackMarker","TPCTrackMCMarker","globalmerger mcinfo","" );
    converterInput+=" mcTrackMarker";
  }

  if (writerInput.Length()>0) writerInput+=" ";
  writerInput+="globalmerger";


  //////////////////////////////////////////////////////////////////////////////////////////
  //
  // output section
  //

  //////////////////////////////////////////////////////////////////////////////////////////
  // sink1: id=sink-writeall write all blocks
  AliHLTConfiguration sink1("sink-writeall", "FileWriter"   , writerInput.Data(), "-specfmt -subdir=event_%d -blcknofmt=_0x%x -idfmt=_0x%08x");


  //////////////////////////////////////////////////////////////////////////////////////////
  // sink2: id=sink-esd-file write ESD using the TPCEsdWriter
  AliHLTConfiguration sink2("sink-esd-file", "TPCEsdWriter"   , converterInput.Data(), "-datafile AliHLTESDs.root");


  //////////////////////////////////////////////////////////////////////////////////////////
  // sink3: id=sink-esd add ESD to HLTOUT using the TPCEsdConverter

  // the esd converter configuration
  AliHLTConfiguration sink3("sink-esd", "TPCEsdConverter"   , converterInput.Data(), "");

  //////////////////////////////////////////////////////////////////////////////////////////
  // sink4: id=sink-clusters add cluster data blocks to HLTOUT
  AliHLTConfiguration sink4("sink-clusters", "BlockFilter"   , sinkClusterInput.Data(), "-datatype 'CLUSTERS' 'TPC '");

  ///////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////
  //
  // Init and run the HLT simulation
  // All but HLT simulation is switched off
  //
  AliSimulation sim;
 
  // switch of simulation and data generation
  // comment all that stuff to also simulate the events and data
  sim.SetRunGeneration(kFALSE);
  sim.SetMakeDigits("");
  sim.SetMakeSDigits("");
  sim.SetMakeDigitsFromHits("");
  //sim.SetMakeTrigger("");
  sim.SetRunQA(":");

  // the normal simulation sets the specific storage for the GRP entry
  if (gSystem->AccessPathName("GRP/GRP/Data")) {
    cerr << "*********************************************************" << endl;
    cerr << "error: no GRP entry found in the currect directory, simulation might be incomplete. Skip setting specific storage for GRP entry" << endl;
    cerr << "*********************************************************" << endl << endl;
  } else {
    sim.SetSpecificStorage("GRP/GRP/Data",
			   Form("local://%s",gSystem->pwd()));
  }

  TString rawDataSelection="HLT";
  if (bRawData) rawDataSelection="ALL";
  if (bRawHLTData || bRawData) sim.SetWriteRawData(rawDataSelection, "raw.root", kTRUE);

  // set the options for the HLT simulation
  sim.SetRunHLT("libAliHLTUtil.so libAliHLTTPC.so loglevel=0x7c "
		"chains=sink-esd,sink-clusters");
  sim.Run();
}
Exemple #16
0
int fmuk66_sdhc_initialize(void)
{
	int ret;
	struct fmuk66_sdhc_state_s   *sdhc = &g_sdhc;
	/* Configure GPIO pins */

	VDD_3V3_SD_CARD_EN(true);

	kinetis_pinconfig(GPIO_SD_CARDDETECT);

	/* Attached the card detect interrupt (but don't enable it yet) */

	kinetis_pinirqattach(GPIO_SD_CARDDETECT, fmuk66_cdinterrupt, sdhc);

	/* Configure the write protect GPIO -- None */

	/* Mount the SDHC-based MMC/SD block driver */
	/* First, get an instance of the SDHC interface */

	mcinfo("Initializing SDHC slot %d\n", CONFIG_NSH_MMCSDSLOTNO);

	sdhc->sdhc = sdhc_initialize(CONFIG_NSH_MMCSDSLOTNO);

	if (!sdhc->sdhc) {
		mcerr("ERROR: Failed to initialize SDHC slot %d\n", CONFIG_NSH_MMCSDSLOTNO);
		return -ENODEV;
	}

//   Testing done on SanDISK HC all failed sd_bench with Drive/Slew other than default and _PIN_OUTPUT_FAST|_PIN_OUTPUT_HIGHDRIVE
//	_PIN_OUTPUT_FAST|_PIN_OUTPUT_HIGHDRIVE    Square noisy, pass SanDISK HC
//  _PIN_OUTPUT_FAST|_PIN_OUTPUT_LOWDRIVE     Square noisy, pass SanDISK HC
//  _PIN_OUTPUT_HIGHDRIVE|_PIN_OUTPUT_SLOW    sinusoidal fail SanDISK HC pass SanDISK HC1
//  _PIN_OUTPUT_LOWDRIVE|_PIN_OUTPUT_SLOW     sinusoidal fail SanDISK HC pass SanDISK HC1
//                       _PIN_OUTPUT_SLOW     sinusoidal fail SanDISK HC pass SanDISK HC1

	// This up dating of the driver setting is for EMI issue with GPS and FCC
	// With this setting the clock is sinusoidal N.B. sd_bench fails on SanDISK HC, but
	// Passes SanDISK **HC1** - use HC1 or Kingston cards!

	kinetis_pinconfig(PIN_SDHC0_DCLK | _PIN_OUTPUT_HIGHDRIVE | _PIN_OUTPUT_SLOW);

	/* Now bind the SDHC interface to the MMC/SD driver */

	mcinfo("Bind SDHC to the MMC/SD driver, minor=%d\n", CONFIG_NSH_MMCSDMINOR);

	ret = mmcsd_slotinitialize(CONFIG_NSH_MMCSDMINOR, sdhc->sdhc);

	if (ret != OK) {
		syslog(LOG_ERR, "ERROR: Failed to bind SDHC to the MMC/SD driver: %d\n", ret);
		return ret;
	}

	syslog(LOG_ERR, "Successfully bound SDHC to the MMC/SD driver\n");

	/* Handle the initial card state */

	fmuk66_mediachange(sdhc);

	/* Enable CD interrupts to handle subsequent media changes */

	kinetis_pinirqenable(GPIO_SD_CARDDETECT);
	return OK;
}
Exemple #17
0
int lc823450_sdc_readsector(uint32_t ch,
                            unsigned long addr, unsigned short cnt,
                            void *pbuf, unsigned long type)
{
  int ret = 0;
  int i = 0;

  _sdc_semtake(&_sdc_sem[ch]);

#ifdef CONFIG_LC823450_SDC_LOG
  mcinfo("++++ start ch=%d, addr=%ld, cnt=%d \n", ch, addr, cnt);
#endif

#ifdef CONFIG_LC823450_SDC_CACHE
  if (ch && _sec_cache_enabled && 1 == cnt && addr == _sec_cache_add)
    {
      memcpy(pbuf, _sec_cache, sizeof(_sec_cache));
      goto errout_with_semaphore;
    }
#endif

  lc823450_sdc_access_led(ch, addr);

#ifdef CONFIG_SCHED_INSTRUMENTATION_IO
  sched_add_bi((uint64_t)cnt);
#endif

  for (i = 0; i < 5; i++)
    {
#ifdef CONFIG_LC823450_SDIF_PATCH
      ret = fixedSdDrReadSector(addr, cnt, pbuf, type, _cfg[ch]);
#else
      ret = SdDrReadSector(addr, cnt, pbuf, type, _cfg[ch]);
#endif
      if (0 == ret)
        {
          break;
        }

      mcinfo("ret=%d ch=%d add=%ld cnt=%d i=%d \n",
             ret, ch, addr, cnt, i);
    }

#ifdef CONFIG_LC823450_SDC_CACHE
  if (ch)
    {
      if (0 == addr)
        {
          uint8_t *p = (pbuf + 0x1c2); /* partition id */
          if (0x7 == *p)
            {
              mcinfo("exFAT (NTFS) detected \n");
              _sec_cache_enabled = 1;
            }
        }

      if (_sec_cache_enabled)
        {
          if (1 == cnt && 0 == ret)
            {
              memcpy(_sec_cache, pbuf, sizeof(_sec_cache));
              _sec_cache_add = addr;
            }
          else
            {
              _sec_cache_add = 0xffffffff; /* invalid */
            }
        }
    }

errout_with_semaphore:
#endif
  _sdc_semgive(&_sdc_sem[ch]);

  mcinfo("----  end ret=%d \n", ret);
  return ret;
}