Advantech / Mbed OS pelion-example-common
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers NuSDBlockDevice.cpp Source File

NuSDBlockDevice.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2015-2016 Nuvoton
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 /* Nuvoton mbed enabled targets which support SD card of SD bus mode */
00018 #if TARGET_NUVOTON
00019 
00020 #include "NuSDBlockDevice.h"
00021 #include "PeripheralPins.h"
00022 #include "mbed_debug.h"
00023 #include "nu_modutil.h"
00024 #include "mbed_critical.h"
00025 #include "mbed_toolchain.h"
00026 
00027 /* SD DMA compatible buffer if user buffer doesn't meet requirements
00028  * 
00029  * SD DMA buffer location requires to be:
00030  * (1) Word-aligned
00031  * (2) Located in 0x2xxxxxxx/0x3xxxxxxx region. Check linker files to ensure global/static
00032  *     variables are placed in this region.
00033  *
00034  * SD DMA buffer size DMA_BUF_SIZE must be a multiple of 512-byte block size.
00035  * Its value is estimated to trade memory footprint off against performance.
00036  *
00037  */
00038 #define DMA_BUFF_SIZE       512
00039 MBED_ALIGN(4) static uint8_t dma_buff[DMA_BUFF_SIZE];
00040 
00041 /* Check if specified buffer is SD DMA-compatible */
00042 static bool sd_dma_buff_compat(const void *buff, size_t buff_size, size_t size_aligned_to);
00043 
00044 #if TARGET_NUMAKER_PFM_NUC472
00045 #define NU_SDH_DAT0         PF_5
00046 #define NU_SDH_DAT1         PF_4
00047 #define NU_SDH_DAT2         PF_3
00048 #define NU_SDH_DAT3         PF_2
00049 #define NU_SDH_CMD          PF_7
00050 #define NU_SDH_CLK          PF_8
00051 #define NU_SDH_CDn          PF_6
00052 
00053 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487
00054 #define NU_SDH_DAT0         PE_2
00055 #define NU_SDH_DAT1         PE_3
00056 #define NU_SDH_DAT2         PB_4
00057 #define NU_SDH_DAT3         PB_5
00058 #define NU_SDH_CMD          PE_7
00059 #define NU_SDH_CLK          PE_6
00060 #define NU_SDH_CDn          PD_13
00061 
00062 #elif TARGET_NUMAKER_PFM_M2351
00063 #define NU_SDH_DAT0         PE_2
00064 #define NU_SDH_DAT1         PE_3
00065 #define NU_SDH_DAT2         PE_4
00066 #define NU_SDH_DAT3         PE_5
00067 #define NU_SDH_CMD          PE_7
00068 #define NU_SDH_CLK          PE_6
00069 #define NU_SDH_CDn          PD_13
00070 
00071 #endif
00072 
00073 #if TARGET_NUMAKER_PFM_NUC472
00074 extern DISK_DATA_T SD_DiskInfo0;
00075 extern DISK_DATA_T SD_DiskInfo1;
00076 extern SD_INFO_T SD0,SD1;
00077 extern int sd0_ok,sd1_ok;
00078 
00079 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487
00080 extern int SDH_ok;
00081 extern SDH_INFO_T SD0, SD1;
00082 
00083 #elif TARGET_NUMAKER_PFM_M2351
00084 extern int SDH_ok;
00085 extern SDH_INFO_T SD0;
00086 
00087 #endif
00088 
00089 
00090 static const struct nu_modinit_s sdh_modinit_tab[] = {
00091 #if TARGET_NUMAKER_PFM_NUC472
00092     {SD_0_0, SDH_MODULE, CLK_CLKSEL0_SDHSEL_PLL, CLK_CLKDIV0_SDH(2), SDH_RST, SD_IRQn, NULL},
00093     {SD_0_1, SDH_MODULE, CLK_CLKSEL0_SDHSEL_PLL, CLK_CLKDIV0_SDH(2), SDH_RST, SD_IRQn, NULL},
00094 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487
00095     {SD_0, SDH0_MODULE, CLK_CLKSEL0_SDH0SEL_HCLK, CLK_CLKDIV0_SDH0(2), SDH0_RST, SDH0_IRQn, NULL},
00096     {SD_1, SDH1_MODULE, CLK_CLKSEL0_SDH1SEL_HCLK, CLK_CLKDIV3_SDH1(2), SDH1_RST, SDH1_IRQn, NULL},
00097 #elif TARGET_NUMAKER_PFM_M2351
00098     {SD_0, SDH0_MODULE, CLK_CLKSEL0_SDH0SEL_HCLK, CLK_CLKDIV0_SDH0(2), SDH0_RST, SDH0_IRQn, NULL},
00099 #endif
00100 
00101     {NC, 0, 0, 0, 0, (IRQn_Type) 0, NULL}
00102 };
00103 
00104 
00105 
00106 #define SD_BLOCK_DEVICE_ERROR_WOULD_BLOCK        -5001  /*!< operation would block */
00107 #define SD_BLOCK_DEVICE_ERROR_UNSUPPORTED        -5002  /*!< unsupported operation */
00108 #define SD_BLOCK_DEVICE_ERROR_PARAMETER          -5003  /*!< invalid parameter */
00109 #define SD_BLOCK_DEVICE_ERROR_NO_INIT            -5004  /*!< uninitialized */
00110 #define SD_BLOCK_DEVICE_ERROR_NO_DEVICE          -5005  /*!< device is missing or not connected */
00111 #define SD_BLOCK_DEVICE_ERROR_WRITE_PROTECTED    -5006  /*!< write protected */
00112 
00113 
00114 NuSDBlockDevice::NuSDBlockDevice() :
00115     _sectors(0),
00116     _dbg(false),
00117     _sdh_modinit(NULL),
00118     _sdh((SDName) NC),
00119     _sdh_base(NULL),
00120 #if TARGET_NUMAKER_PFM_NUC472
00121     _sdh_port((uint32_t) -1),
00122 #endif
00123     _sdh_irq_thunk(this, &NuSDBlockDevice::_sdh_irq),
00124     _sd_dat0(NU_SDH_DAT0),
00125     _sd_dat1(NU_SDH_DAT1),
00126     _sd_dat2(NU_SDH_DAT2),
00127     _sd_dat3(NU_SDH_DAT3),
00128     _sd_cmd(NU_SDH_CMD),
00129     _sd_clk(NU_SDH_CLK),
00130     _sd_cdn(NU_SDH_CDn),
00131     _is_initialized(false),
00132     _init_ref_count(0)
00133 {
00134 }
00135 
00136 NuSDBlockDevice::NuSDBlockDevice(PinName sd_dat0, PinName sd_dat1, PinName sd_dat2, PinName sd_dat3,
00137     PinName sd_cmd, PinName sd_clk, PinName sd_cdn) :
00138     _sectors(0),
00139     _dbg(false),
00140     _sdh_modinit(NULL),
00141     _sdh((SDName) NC),
00142     _sdh_base(NULL),
00143 #if TARGET_NUMAKER_PFM_NUC472
00144     _sdh_port((uint32_t) -1),
00145 #endif
00146     _sdh_irq_thunk(this, &NuSDBlockDevice::_sdh_irq),
00147     _is_initialized(false),
00148     _init_ref_count(0)
00149 {
00150     _sd_dat0 = sd_dat0;
00151     _sd_dat1 = sd_dat1;
00152     _sd_dat2 = sd_dat2;
00153     _sd_dat3 = sd_dat3;
00154     _sd_cmd = sd_cmd;
00155     _sd_clk = sd_clk;
00156     _sd_cdn = sd_cdn;
00157 }
00158 
00159 NuSDBlockDevice::~NuSDBlockDevice()
00160 {
00161     if (_is_initialized) {
00162         deinit();
00163     }
00164 }
00165 
00166 int NuSDBlockDevice::init()
00167 {
00168     _lock.lock();
00169     int err = BD_ERROR_OK;
00170     
00171     do {
00172         if (_is_initialized) {
00173             _init_ref_count ++;
00174             break;
00175         } else {
00176             _init_ref_count = 0;
00177         }
00178     
00179         err = _init_sdh();
00180         if (err != BD_ERROR_OK) {
00181             break;
00182         }
00183         
00184 #if TARGET_NUMAKER_PFM_NUC472
00185         SD_Open(_sdh_port | CardDetect_From_GPIO);
00186         SD_Probe(_sdh_port);
00187 
00188         switch (_sdh_port) {
00189         case SD_PORT0:
00190             _is_initialized = sd0_ok && (SD0.CardType != SD_TYPE_UNKNOWN);
00191             break;
00192     
00193         case SD_PORT1:
00194             _is_initialized = sd1_ok && (SD1.CardType != SD_TYPE_UNKNOWN);
00195             break;
00196         }
00197     
00198 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487
00199         MBED_ASSERT(_sdh_modinit != NULL);
00200         
00201         NVIC_SetVector(_sdh_modinit->irq_n, _sdh_irq_thunk.entry());
00202         NVIC_EnableIRQ(_sdh_modinit->irq_n);
00203 
00204         SDH_Open(_sdh_base, CardDetect_From_GPIO);
00205         SDH_Probe(_sdh_base);
00206     
00207         switch (NU_MODINDEX(_sdh)) {
00208         case 0:
00209             _is_initialized = SDH_ok && (SD0.CardType != SDH_TYPE_UNKNOWN);
00210             break;
00211     
00212         case 1:
00213             _is_initialized = SDH_ok && (SD1.CardType != SDH_TYPE_UNKNOWN);
00214             break;
00215         }
00216 
00217 #elif TARGET_NUMAKER_PFM_M2351
00218         MBED_ASSERT(_sdh_modinit != NULL);
00219         
00220         NVIC_SetVector(_sdh_modinit->irq_n, _sdh_irq_thunk.entry());
00221         NVIC_EnableIRQ(_sdh_modinit->irq_n);
00222 
00223         SDH_Open(_sdh_base, CardDetect_From_GPIO);
00224         SDH_Probe(_sdh_base);
00225     
00226         switch (NU_MODINDEX(_sdh)) {
00227         case 0:
00228             _is_initialized = SDH_ok && (SD0.CardType != SDH_TYPE_UNKNOWN);
00229             break;
00230         }
00231 #endif
00232 
00233         if (_is_initialized) {
00234             _init_ref_count = 1;
00235         } else {
00236             debug_if(_dbg, "Fail to initialize card\n");
00237             err = BD_ERROR_DEVICE_ERROR;
00238         }
00239         debug_if(_dbg, "init card = %d\n", _is_initialized);
00240         _sectors = _sd_sectors();
00241     
00242     } while (0);
00243 
00244     _lock.unlock();
00245     
00246     return err;
00247 }
00248 
00249 int NuSDBlockDevice::deinit()
00250 {
00251     _lock.lock();
00252     int err = BD_ERROR_OK;
00253 
00254     do {
00255         if (_is_initialized && _init_ref_count > 1) {
00256             _init_ref_count --;
00257             break;
00258         } else if (! _is_initialized) {
00259             _init_ref_count = 0;
00260             break;
00261         }
00262 
00263         if (_sdh_modinit) {
00264 #if defined(DOMAIN_NS) && DOMAIN_NS
00265             CLK_DisableModuleClock_S(_sdh_modinit->clkidx);
00266 #else
00267             CLK_DisableModuleClock(_sdh_modinit->clkidx);
00268 #endif
00269         }
00270     
00271 #if TARGET_NUMAKER_PFM_NUC472
00272         // TODO
00273 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487
00274         // TODO
00275 #elif TARGET_NUMAKER_PFM_M2351
00276         // TODO
00277 #endif
00278 
00279         _is_initialized = false;
00280         _init_ref_count = 0;
00281     } while (0);
00282 
00283     _lock.unlock();
00284     
00285     return err;
00286 }
00287 
00288 int NuSDBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
00289 {
00290     if (! is_valid_program(addr, size)) {
00291         return SD_BLOCK_DEVICE_ERROR_PARAMETER;
00292     }
00293 
00294     _lock.lock();
00295     int err = BD_ERROR_OK;
00296     
00297     do {
00298         if (! _is_initialized) {
00299             err = SD_BLOCK_DEVICE_ERROR_NO_INIT;
00300             break;
00301         }
00302 
00303         /* Check if user buffer is SD DMA-compatible */
00304         if (sd_dma_buff_compat(b, static_cast<size_t>(size), 512)) {
00305             /* User buffer is DMA-compatible. We can transfer directly. */
00306 #if TARGET_NUMAKER_PFM_NUC472
00307             if (SD_Write(_sdh_port, (uint8_t*)b, addr / 512, size / 512) != 0) {
00308 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 || TARGET_NUMAKER_PFM_M2351
00309             if (SDH_Write(_sdh_base, (uint8_t*)b, addr / 512, size / 512) != 0) {
00310 #endif
00311                 err = BD_ERROR_DEVICE_ERROR;
00312             }
00313         } else {
00314             /* User buffer is not SD DMA-compatible. We must transfer via DMA intermediate buffer. */
00315             const uint8_t *b_pos = static_cast<const uint8_t *>(b);
00316             bd_addr_t addr_pos = addr;
00317             bd_size_t rmn = size;
00318 
00319             while (rmn) {
00320                 size_t todo_size = (rmn >= DMA_BUFF_SIZE) ? DMA_BUFF_SIZE : static_cast<size_t>(rmn);
00321                 memcpy(dma_buff, b_pos, todo_size);
00322 
00323 #if TARGET_NUMAKER_PFM_NUC472
00324                 if (SD_Write(_sdh_port, const_cast<uint8_t*>(dma_buff), static_cast<uint32_t>(addr_pos / 512), static_cast<uint32_t>(todo_size / 512)) != 0) {
00325 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 || TARGET_NUMAKER_PFM_M2351
00326                 if (SDH_Write(_sdh_base, const_cast<uint8_t*>(dma_buff), static_cast<uint32_t>(addr_pos / 512), static_cast<uint32_t>(todo_size / 512)) != 0) {
00327 #endif
00328                     err = BD_ERROR_DEVICE_ERROR;
00329                     break;
00330                 }
00331             
00332                 b_pos += todo_size;
00333                 addr_pos += todo_size;
00334                 rmn -= todo_size;
00335             }
00336         }
00337     } while (0);
00338     
00339     _lock.unlock();
00340     
00341     return err;
00342 }
00343 
00344 int NuSDBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
00345 {
00346     if (! is_valid_read(addr, size)) {
00347         return SD_BLOCK_DEVICE_ERROR_PARAMETER;
00348     }
00349 
00350     _lock.lock();
00351     int err = BD_ERROR_OK;
00352     
00353     do {
00354         if (! _is_initialized) {
00355             err = SD_BLOCK_DEVICE_ERROR_NO_INIT;
00356             break;
00357         }
00358 
00359         /* Check if user buffer is SD DMA-compatible */
00360         if (sd_dma_buff_compat(b, static_cast<size_t>(size), 512)) {
00361             /* User buffer is SD DMA-compatible. We can transfer directly. */
00362 #if TARGET_NUMAKER_PFM_NUC472
00363             if (SD_Read(_sdh_port, (uint8_t*)b, addr / 512, size / 512) != 0) {
00364 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 || TARGET_NUMAKER_PFM_M2351
00365             if (SDH_Read(_sdh_base, (uint8_t*)b, addr / 512, size / 512) != 0) {
00366 #endif
00367                 err = BD_ERROR_DEVICE_ERROR;
00368             }
00369         } else {
00370             /* User buffer is not SD DMA-compatible. We must transfer via DMA intermediate buffer. */
00371             uint8_t *b_pos = static_cast<uint8_t *>(b);
00372             bd_addr_t addr_pos = addr;
00373             bd_size_t rmn = size;
00374             
00375             while (rmn) {
00376                 size_t todo_size = (rmn >= DMA_BUFF_SIZE) ? DMA_BUFF_SIZE : static_cast<size_t>(rmn);
00377 
00378 #if TARGET_NUMAKER_PFM_NUC472
00379                 if (SD_Read(_sdh_port, static_cast<uint8_t*>(dma_buff), static_cast<uint32_t>(addr_pos / 512), static_cast<uint32_t>(todo_size / 512)) != 0) {
00380 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487 || TARGET_NUMAKER_PFM_M2351
00381                 if (SDH_Read(_sdh_base, static_cast<uint8_t*>(dma_buff), static_cast<uint32_t>(addr_pos / 512), static_cast<uint32_t>(todo_size / 512)) != 0) {
00382 #endif
00383                     err = BD_ERROR_DEVICE_ERROR;
00384                     break;
00385                 }
00386 
00387                 memcpy(b_pos, dma_buff, todo_size);
00388 
00389                 b_pos += todo_size;
00390                 addr_pos += todo_size;
00391                 rmn -= todo_size;
00392             }
00393         }
00394     } while (0);
00395     
00396     _lock.unlock();
00397     
00398     return err;
00399 }
00400 
00401 int NuSDBlockDevice::erase(bd_addr_t addr, bd_size_t size)
00402 {
00403     if (! _is_initialized) {
00404         return SD_BLOCK_DEVICE_ERROR_NO_INIT;
00405     }
00406 
00407     return BD_ERROR_OK;
00408 }
00409 
00410 bd_size_t NuSDBlockDevice::get_read_size() const
00411 {
00412     return 512;
00413 }
00414 
00415 bd_size_t NuSDBlockDevice::get_program_size() const
00416 {
00417     return 512;
00418 }
00419 
00420 bd_size_t NuSDBlockDevice::get_erase_size() const
00421 {
00422     return 512;
00423 }
00424 
00425 bd_size_t NuSDBlockDevice::get_erase_size(bd_addr_t addr) const
00426 {
00427     return 512;
00428 }
00429 
00430 bd_size_t NuSDBlockDevice::size() const
00431 {
00432     if (! _is_initialized) {
00433         return SD_BLOCK_DEVICE_ERROR_NO_INIT;
00434     }
00435 
00436     return 512 * _sectors;
00437 }
00438 
00439 void NuSDBlockDevice::debug(bool dbg)
00440 {
00441     _dbg = dbg;
00442 }
00443 
00444 int NuSDBlockDevice::_init_sdh()
00445 {
00446     debug_if(_dbg, "SD MPF Setting & Enable SD IP Clock\n");
00447         
00448     // Check if all pins belong to the same SD module
00449     // Merge SD DAT0/1/2/3
00450     uint32_t sd_dat0_mod = pinmap_peripheral(_sd_dat0, PinMap_SD_DAT0);
00451     uint32_t sd_dat1_mod = pinmap_peripheral(_sd_dat1, PinMap_SD_DAT1);
00452     uint32_t sd_dat2_mod = pinmap_peripheral(_sd_dat2, PinMap_SD_DAT2);
00453     uint32_t sd_dat3_mod = pinmap_peripheral(_sd_dat3, PinMap_SD_DAT3);
00454     uint32_t sd_dat01_mod = (SDName) pinmap_merge(sd_dat0_mod, sd_dat1_mod);
00455     uint32_t sd_dat23_mod = (SDName) pinmap_merge(sd_dat2_mod, sd_dat3_mod);
00456     uint32_t sd_dat0123_mod = (SDName) pinmap_merge(sd_dat01_mod, sd_dat23_mod);
00457     // Merge SD CMD/CLK/CDn
00458     uint32_t sd_cmd_mod = pinmap_peripheral(_sd_cmd, PinMap_SD_CMD);
00459     uint32_t sd_clk_mod = pinmap_peripheral(_sd_clk, PinMap_SD_CLK);
00460     uint32_t sd_cdn_mod = pinmap_peripheral(_sd_cdn, PinMap_SD_CD);
00461     uint32_t sd_cmdclk_mod = (SDName) pinmap_merge(sd_cmd_mod, sd_clk_mod);
00462     uint32_t sd_cmdclkcdn_mod = (SDName) pinmap_merge(sd_cmdclk_mod, sd_cdn_mod);
00463     // Merge SD DAT0/1/2/3 and SD CMD/CLK/CDn
00464     uint32_t sd_mod = (SDName) pinmap_merge(sd_dat0123_mod, sd_cmdclkcdn_mod);
00465     
00466     if (sd_mod == (uint32_t) NC) {
00467         debug("SD pinmap error\n");
00468         return BD_ERROR_DEVICE_ERROR;
00469     }
00470     
00471     _sdh_modinit = get_modinit(sd_mod, sdh_modinit_tab);
00472     MBED_ASSERT(_sdh_modinit != NULL);
00473     MBED_ASSERT(_sdh_modinit->modname == sd_mod);
00474     
00475     
00476     // Configure SD multi-function pins
00477     pinmap_pinout(_sd_dat0, PinMap_SD_DAT0);
00478     pinmap_pinout(_sd_dat1, PinMap_SD_DAT1);
00479     pinmap_pinout(_sd_dat2, PinMap_SD_DAT2);
00480     pinmap_pinout(_sd_dat3, PinMap_SD_DAT3);
00481     pinmap_pinout(_sd_cmd, PinMap_SD_CMD);
00482     pinmap_pinout(_sd_clk, PinMap_SD_CLK);
00483     pinmap_pinout(_sd_cdn, PinMap_SD_CD);
00484     
00485     // Configure SD IP clock 
00486 #if defined(DOMAIN_NS) && DOMAIN_NS
00487     SYS_UnlockReg_S();
00488 #else
00489     SYS_UnlockReg();
00490 #endif
00491     
00492     // Determine SDH port dependent on passed-in pins
00493     _sdh = (SDName) sd_mod;
00494     _sdh_base = (SDH_T *) NU_MODBASE(_sdh);
00495 #if TARGET_NUMAKER_PFM_NUC472
00496     switch (NU_MODSUBINDEX(_sdh)) {
00497     case 0:
00498         _sdh_port = SD_PORT0;
00499         break;
00500         
00501     case 1:
00502         _sdh_port = SD_PORT1;
00503         break;
00504     }
00505 #endif
00506 
00507 #if defined(DOMAIN_NS) && DOMAIN_NS
00508     SYS_ResetModule_S(_sdh_modinit->rsetidx);
00509 #else
00510     SYS_ResetModule(_sdh_modinit->rsetidx);
00511 #endif
00512 
00513 #if defined(DOMAIN_NS) && DOMAIN_NS
00514     CLK_SetModuleClock_S(_sdh_modinit->clkidx, _sdh_modinit->clksrc, _sdh_modinit->clkdiv);
00515 #else
00516     CLK_SetModuleClock(_sdh_modinit->clkidx, _sdh_modinit->clksrc, _sdh_modinit->clkdiv);
00517 #endif
00518 
00519 #if defined(DOMAIN_NS) && DOMAIN_NS
00520     CLK_EnableModuleClock_S(_sdh_modinit->clkidx);
00521 #else
00522     CLK_EnableModuleClock(_sdh_modinit->clkidx);
00523 #endif
00524 
00525 #if defined(DOMAIN_NS) && DOMAIN_NS
00526     SYS_LockReg_S();
00527 #else
00528     SYS_LockReg();
00529 #endif
00530 
00531     return BD_ERROR_OK;
00532 }
00533 
00534 uint32_t NuSDBlockDevice::_sd_sectors()
00535 {
00536     _lock.lock();
00537    
00538 #if TARGET_NUMAKER_PFM_NUC472
00539     switch (_sdh_port) {
00540     case SD_PORT0:
00541         _sectors = SD_DiskInfo0.totalSectorN;
00542         break;
00543     case SD_PORT1:
00544         _sectors = SD_DiskInfo1.totalSectorN;
00545         break;
00546     }
00547     
00548 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487
00549     switch (NU_MODINDEX(_sdh)) {
00550     case 0:
00551         _sectors = SD0.totalSectorN;
00552         break;
00553     case 1:
00554         _sectors = SD1.totalSectorN;
00555         break;
00556     }
00557     
00558 #elif TARGET_NUMAKER_PFM_M2351
00559     switch (NU_MODINDEX(_sdh)) {
00560     case 0:
00561         _sectors = SD0.totalSectorN;
00562         break;
00563     }
00564 
00565 #endif
00566 
00567     _lock.unlock();
00568     
00569     return _sectors;
00570 }
00571 
00572 void NuSDBlockDevice::_sdh_irq()
00573 {
00574 #if TARGET_NUMAKER_PFM_NUC472
00575     // TODO: Support IRQ
00576     
00577 #elif TARGET_NUMAKER_PFM_M487 || TARGET_NUMAKER_IOT_M487
00578     // FMI data abort interrupt
00579     if (_sdh_base->GINTSTS & SDH_GINTSTS_DTAIF_Msk) {
00580         _sdh_base->GINTSTS = SDH_GINTSTS_DTAIF_Msk;
00581         /* ResetAllEngine() */
00582         _sdh_base->GCTL |= SDH_GCTL_GCTLRST_Msk;
00583     }
00584 
00585     //----- SD interrupt status
00586     if (_sdh_base->INTSTS & SDH_INTSTS_BLKDIF_Msk) {
00587         // block down
00588         extern uint8_t volatile _SDH_SDDataReady;
00589         _SDH_SDDataReady = TRUE;
00590         _sdh_base->INTSTS = SDH_INTSTS_BLKDIF_Msk;
00591     }
00592     
00593     // NOTE: On M487, there are two SDH instances which each support port 0 and don't support port 1.
00594     //       Port 0 (support): INTEN.CDIEN0, INTEN.CDSRC0, INTSTS.CDIF0, INTSTS.CDSTS0
00595     //       Port 1 (no support): INTEN.CDIEN1, INTEN.CDSRC1, INTSTS.CDIF1, INTSTS.CDSTS1
00596     if (_sdh_base->INTSTS & SDH_INTSTS_CDIF_Msk) { // port 0 card detect
00597         _sdh_base->INTSTS = SDH_INTSTS_CDIF_Msk;
00598         // TBD: Support PnP
00599     }
00600 
00601     // CRC error interrupt
00602     if (_sdh_base->INTSTS & SDH_INTSTS_CRCIF_Msk) {
00603         _sdh_base->INTSTS = SDH_INTSTS_CRCIF_Msk;      // clear interrupt flag
00604     }
00605 
00606     if (_sdh_base->INTSTS & SDH_INTSTS_DITOIF_Msk) {
00607         _sdh_base->INTSTS = SDH_INTSTS_DITOIF_Msk;
00608     }
00609 
00610     // Response in timeout interrupt
00611     if (_sdh_base->INTSTS & SDH_INTSTS_RTOIF_Msk) {
00612         _sdh_base->INTSTS |= SDH_INTSTS_RTOIF_Msk;
00613     }
00614     
00615 #elif TARGET_NUMAKER_PFM_M2351
00616     // FMI data abort interrupt
00617     if (_sdh_base->GINTSTS & SDH_GINTSTS_DTAIF_Msk) {
00618         _sdh_base->GINTSTS = SDH_GINTSTS_DTAIF_Msk;
00619         /* ResetAllEngine() */
00620         _sdh_base->GCTL |= SDH_GCTL_GCTLRST_Msk;
00621     }
00622 
00623     //----- SD interrupt status
00624     if (_sdh_base->INTSTS & SDH_INTSTS_BLKDIF_Msk) {
00625         // block down
00626         extern uint8_t volatile g_u8SDDataReadyFlag;
00627         g_u8SDDataReadyFlag = TRUE;
00628         _sdh_base->INTSTS = SDH_INTSTS_BLKDIF_Msk;
00629     }
00630     
00631     if (_sdh_base->INTSTS & SDH_INTSTS_CDIF_Msk) {      // port 0 card detect
00632         _sdh_base->INTSTS = SDH_INTSTS_CDIF_Msk;
00633         // TBD: Support PnP
00634     }
00635 
00636     // CRC error interrupt
00637     if (_sdh_base->INTSTS & SDH_INTSTS_CRCIF_Msk) {
00638         _sdh_base->INTSTS = SDH_INTSTS_CRCIF_Msk;       // clear interrupt flag
00639     }
00640 
00641     if (_sdh_base->INTSTS & SDH_INTSTS_DITOIF_Msk) {
00642         _sdh_base->INTSTS = SDH_INTSTS_DITOIF_Msk;
00643     }
00644 
00645     // Response in timeout interrupt
00646     if (_sdh_base->INTSTS & SDH_INTSTS_RTOIF_Msk) {
00647         _sdh_base->INTSTS |= SDH_INTSTS_RTOIF_Msk;
00648     }
00649 
00650 #endif
00651 }
00652 
00653 static bool sd_dma_buff_compat(const void *buff, size_t buff_size, size_t size_aligned_to)
00654 {
00655     uint32_t buff_ = (uint32_t) buff;
00656 
00657     return (((buff_ & 0x03) == 0) &&                                        // Word-aligned buffer base address
00658         ((buff_size & (size_aligned_to - 1)) == 0) &&                       // 'size_aligned_to'-aligned buffer size
00659 #if TARGET_NUMAKER_PFM_M2351 && (defined(DOMAIN_NS) && DOMAIN_NS)
00660         (((buff_ >> 28) == 0x3) && (buff_size <= (0x40000000 - buff_))));   // 0x30000000-0x3FFFFFFF
00661 #else        
00662         (((buff_ >> 28) == 0x2) && (buff_size <= (0x30000000 - buff_))));   // 0x20000000-0x2FFFFFFF
00663 #endif
00664 }
00665 
00666 const char *NuSDBlockDevice::get_type() const
00667 {
00668     return "NUSD";
00669 }
00670 
00671 #endif  /* TARGET_NUVOTON */