/**************************************************************************//** * @file sdGlue.c * @version V3.00 * @brief N9H20 series SIC driver source file. Driver for FMI devices SD layer glue code. * * SPDX-License-Identifier: Apache-2.0 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved. *****************************************************************************/ #ifdef ECOS #include "stdlib.h" #include "string.h" #include "drv_api.h" #include "diag.h" #include "wbtypes.h" #include "wbio.h" #else #include <stdio.h> #include <stdlib.h> #include <string.h> #include "wblib.h" #endif #include "N9H20_SIC.h" #include "fmi.h" #include "N9H20_NVTFAT.h" DISK_DATA_T SD_DiskInfo0; DISK_DATA_T SD_DiskInfo1; DISK_DATA_T SD_DiskInfo2; FMI_SD_INFO_T *pSD0 = NULL; FMI_SD_INFO_T *pSD1 = NULL; FMI_SD_INFO_T *pSD2 = NULL; UINT8 pSD0_offset = 0; UINT8 pSD1_offset = 0; UINT8 pSD2_offset = 0; PDISK_T *pDisk_SD0 = NULL; PDISK_T *pDisk_SD1 = NULL; PDISK_T *pDisk_SD2 = NULL; INT32 g_SD0_card_detect = FALSE; // default is DISABLE SD0 card detect feature. extern INT fsPhysicalDiskConnected(PDISK_T *pDisk); static INT sd_disk_init(PDISK_T *lDisk) { return 0; } static INT sd_disk_ioctl(PDISK_T *lDisk, INT control, VOID *param) { return 0; } static INT sd_disk_read(PDISK_T *pDisk, UINT32 sector_no, INT number_of_sector, UINT8 *buff) { int status; fmiSD_CardSel(0); // enable SD outpw(REG_FMICR, FMI_SD_EN); status = fmiSD_Read_in(pSD0, sector_no, number_of_sector, (unsigned int)buff); if (status != Successful) return status; return FS_OK; } static INT sd_disk_write(PDISK_T *pDisk, UINT32 sector_no, INT number_of_sector, UINT8 *buff, BOOL IsWait) { int status; fmiSD_CardSel(0); // enable SD outpw(REG_FMICR, FMI_SD_EN); status = fmiSD_Write_in(pSD0, sector_no, number_of_sector, (unsigned int)buff); if (status != Successful) return status; return FS_OK; } static INT sd_disk_init0(PDISK_T *lDisk) { return 0; } static INT sd_disk_ioctl0(PDISK_T *lDisk, INT control, VOID *param) { return 0; } static INT sd_disk_read0(PDISK_T *pDisk, UINT32 sector_no, INT number_of_sector, UINT8 *buff) { return sd_disk_read(pDisk, sector_no, number_of_sector, buff); } static INT sd_disk_write0(PDISK_T *pDisk, UINT32 sector_no, INT number_of_sector, UINT8 *buff, BOOL IsWait) { return sd_disk_write(pDisk, sector_no, number_of_sector, buff, IsWait); } static INT sd_disk_init1(PDISK_T *lDisk) { return 0; } static INT sd_disk_ioctl1(PDISK_T *lDisk, INT control, VOID *param) { return 0; } static INT sd_disk_read1(PDISK_T *pDisk, UINT32 sector_no, INT number_of_sector, UINT8 *buff) { int status; fmiSD_CardSel(1); // enable SD outpw(REG_FMICR, FMI_SD_EN); status = fmiSD_Read_in(pSD1, sector_no, number_of_sector, (unsigned int)buff); if (status != Successful) return status; return FS_OK; } static INT sd_disk_write1(PDISK_T *pDisk, UINT32 sector_no, INT number_of_sector, UINT8 *buff, BOOL IsWait) { int status; fmiSD_CardSel(1); // enable SD outpw(REG_FMICR, FMI_SD_EN); status = fmiSD_Write_in(pSD1, sector_no, number_of_sector, (unsigned int)buff); if (status != Successful) return status; return FS_OK; } static INT sd_disk_init2(PDISK_T *lDisk) { return 0; } static INT sd_disk_ioctl2(PDISK_T *lDisk, INT control, VOID *param) { return 0; } static INT sd_disk_read2(PDISK_T *pDisk, UINT32 sector_no, INT number_of_sector, UINT8 *buff) { int status; fmiSD_CardSel(2); // enable SD outpw(REG_FMICR, FMI_SD_EN); status = fmiSD_Read_in(pSD2, sector_no, number_of_sector, (unsigned int)buff); if (status != Successful) return status; return FS_OK; } static INT sd_disk_write2(PDISK_T *pDisk, UINT32 sector_no, INT number_of_sector, UINT8 *buff, BOOL IsWait) { int status; fmiSD_CardSel(2); // enable SD outpw(REG_FMICR, FMI_SD_EN); status = fmiSD_Write_in(pSD2, sector_no, number_of_sector, (unsigned int)buff); if (status != Successful) return status; return FS_OK; } STORAGE_DRIVER_T _SDDiskDriver = { sd_disk_init, sd_disk_read, sd_disk_write, sd_disk_ioctl }; STORAGE_DRIVER_T _SD0DiskDriver = { sd_disk_init0, sd_disk_read0, sd_disk_write0, sd_disk_ioctl0 }; STORAGE_DRIVER_T _SD1DiskDriver = { sd_disk_init1, sd_disk_read1, sd_disk_write1, sd_disk_ioctl1 }; STORAGE_DRIVER_T _SD2DiskDriver = { sd_disk_init2, sd_disk_read2, sd_disk_write2, sd_disk_ioctl2 }; static int sd0_ok = 0; static int sd1_ok = 0; static int sd2_ok = 0; INT fmiSD_CardSel(INT cardSel) { if (cardSel==0) { outpw(REG_GPEFUN, (inpw(REG_GPEFUN)&(~0x0000FFF0)) | 0x0000aaa0); // SD0_CLK/CMD/DAT0_3 pins selected outpw(REG_SDCR, inpw(REG_SDCR) & (~SDCR_SDPORT)); // SD_0 port selected } else if (cardSel==1) { outpw(REG_GPBFUN, (inpw(REG_GPBFUN)&(~0x00000FFF)) | 0x00000AAA); // SD1_CLK_CMD_DAT0_3 pins selected outpw(REG_SDCR, (inpw(REG_SDCR) & (~0x60000000)) | 0x20000000); // SD_1 port selected } else if (cardSel==2) { outpw(REG_GPEFUN, (inpw(REG_GPEFUN)&(~0x000F0000)) | 0x00050000); // SD2_DAT0_1 pins selected outpw(REG_GPDFUN, (inpw(REG_GPDFUN)&(~0x0003FC00)) | 0x00015400); // SD2_CLK/CMD/DAT2_3 pins selected outpw(REG_SDCR, (inpw(REG_SDCR) & (~0x60000000)) | 0x40000000); // SD_2 port selected } else return 1; // wrong SD card select //--- 2014/2/26, Reset SD controller and DMAC to keep clean status for next access. // Reset DMAC engine and interrupt satus outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_SWRST | DMAC_EN); while(inpw(REG_DMACCSR) & DMAC_SWRST); outpw(REG_DMACCSR, inpw(REG_DMACCSR) | DMAC_EN); outpw(REG_DMACISR, WEOT_IF | TABORT_IF); // clear all interrupt flag // Reset FMI engine and interrupt status outpw(REG_FMICR, FMI_SWRST); while(inpw(REG_FMICR) & FMI_SWRST); outpw(REG_FMIISR, FMI_DAT_IF); // clear all interrupt flag // Reset SD engine and interrupt status outpw(REG_FMICR, FMI_SD_EN); outpw(REG_SDCR, inpw(REG_SDCR) | SDCR_SWRST); while(inpw(REG_SDCR) & SDCR_SWRST); outpw(REG_SDISR, 0xFFFFFFFF); // clear all interrupt flag return 0; } /*----------------------------------------------------------------------------- * Get SD card status for SD port 0 and assign the status to global value pSD0->bIsCardInsert. * Return: 0 is SD card inserted; * FMI_NO_SD_CARD is SD card removed. *---------------------------------------------------------------------------*/ INT fmiSD_CardStatus() { if (g_SD0_card_detect) { if (inpw(REG_SDISR) & SDISR_CD_Card) // CD pin status { pSD0->bIsCardInsert = FALSE; return FMI_NO_SD_CARD; } else { pSD0->bIsCardInsert = TRUE; return 0; } } else { pSD0->bIsCardInsert = TRUE; // always report card inserted. return 0; } } INT fmiInitSDDevice(INT cardSel) /* int sd_init_onedisk(INT i) */ { PDISK_T *pDisk; DISK_DATA_T* pSDDisk; FMI_SD_INFO_T *pSD_temp = NULL; int volatile rate, i; //Reset FMI outpw(REG_FMICR, FMI_SWRST); // Start reset FMI controller. while(inpw(REG_FMICR)&FMI_SWRST); // enable SD outpw(REG_FMICR, FMI_SD_EN); outpw(REG_SDCR, inpw(REG_SDCR) | SDCR_SWRST); // SD software reset while(inpw(REG_SDCR) & SDCR_SWRST); outpw(REG_SDCR, inpw(REG_SDCR) & ~0xFF); // disable SD clock ouput if (cardSel == 0) { if(sd0_ok == 1) return(0); pSDDisk = &SD_DiskInfo0; } else if (cardSel == 1) { if(sd1_ok == 1) return(0); pSDDisk = &SD_DiskInfo1; } else if (cardSel == 2) { if(sd2_ok == 1) return(0); pSDDisk = &SD_DiskInfo2; } // enable SD-0/1/2 pin? if (fmiSD_CardSel(cardSel)) return FMI_NO_SD_CARD; //Enable SD-0 card detectipn pin if (cardSel==0) { if (g_SD0_card_detect) outpw(REG_GPAFUN, inpw(REG_GPAFUN) | MF_GPA1); // GPA1 for SD-0 card detection outpw(REG_SDIER, inpw(REG_SDIER) | SDIER_CDSRC); // SD card detection source from GPIO but not DAT3 } // Disable FMI/SD host interrupt outpw(REG_FMIIER, 0); // outpw(REG_SDCR, (inpw(REG_SDCR) & ~SDCR_SDNWR) | (0x01 << 24)); // set SDNWR = 1 outpw(REG_SDCR, (inpw(REG_SDCR) & ~SDCR_SDNWR) | (0x09 << 24)); // set SDNWR = 9 outpw(REG_SDCR, (inpw(REG_SDCR) & ~SDCR_BLKCNT) | (0x01 << 16)); // set BLKCNT = 1 outpw(REG_SDCR, inpw(REG_SDCR) & ~SDCR_DBW); // SD 1-bit data bus outpw(REG_SDTMOUT,0xFFFFFF); pSD_temp = malloc(sizeof(FMI_SD_INFO_T)+4); if (pSD_temp == NULL) return FMI_NO_MEMORY; memset((char *)pSD_temp, 0, sizeof(FMI_SD_INFO_T)+4); if (cardSel==0) { pSD0_offset = (UINT32)pSD_temp %4; pSD0 = (FMI_SD_INFO_T *)((UINT32)pSD_temp + pSD0_offset); } else if (cardSel==1) { pSD1_offset = (UINT32)pSD_temp %4; pSD1 = (FMI_SD_INFO_T *)((UINT32)pSD_temp + pSD1_offset); } else if (cardSel==2) { pSD2_offset = (UINT32)pSD_temp %4; pSD2 = (FMI_SD_INFO_T *)((UINT32)pSD_temp + pSD2_offset); } outpw(REG_SDIER, inpw(REG_SDIER) | SDIER_CDSRC); // select GPIO detect outpw(REG_SDIER, inpw(REG_SDIER) | SDIER_CD_IEN); // enable card detect interrupt if (cardSel==0) { if (fmiSD_CardStatus() == FMI_NO_SD_CARD) { if (pSD0 != NULL) { free((FMI_SD_INFO_T *)((UINT32)pSD0 - pSD0_offset)); pSD0 = 0; } free((FMI_SD_INFO_T *)((UINT32)pSD0 - pSD0_offset)); sysprintf("ERROR: fmiInitSDDevice(): SD port %d has no card ! REG_SDISR = 0x%08X\n", cardSel, inpw(REG_SDISR)); return FMI_NO_SD_CARD; } if (fmiSD_Init(pSD0) < 0) return FMI_SD_INIT_ERROR; /* divider */ if (pSD0->uCardType == FMI_TYPE_MMC) rate = _fmi_uFMIReferenceClock / MMC_FREQ; else if (pSD0->uCardType == FMI_TYPE_MMC_SECTOR_MODE) rate = _fmi_uFMIReferenceClock / EMMC_FREQ; else rate = _fmi_uFMIReferenceClock / SD_FREQ; if (pSD0->uCardType == FMI_TYPE_MMC) { if ((_fmi_uFMIReferenceClock % MMC_FREQ) > 0) rate ++; } else if (pSD0->uCardType == FMI_TYPE_MMC_SECTOR_MODE) { if ((_fmi_uFMIReferenceClock % EMMC_FREQ) > 0) rate ++; } else { if ((_fmi_uFMIReferenceClock % SD_FREQ) > 0) rate ++; } } else if (cardSel==1) { // SD-1 no card detect pSD1->bIsCardInsert = TRUE; // SD-1 initial if (fmiSD_Init(pSD1) < 0) return FMI_SD_INIT_ERROR; /* divider */ if (pSD1->uCardType == FMI_TYPE_MMC) rate = _fmi_uFMIReferenceClock / MMC_FREQ; else if (pSD1->uCardType == FMI_TYPE_MMC_SECTOR_MODE) rate = _fmi_uFMIReferenceClock / EMMC_FREQ; else rate = _fmi_uFMIReferenceClock / SD_FREQ; if (pSD1->uCardType == FMI_TYPE_MMC) { if ((_fmi_uFMIReferenceClock % MMC_FREQ) > 0) rate ++; } else if (pSD1->uCardType == FMI_TYPE_MMC_SECTOR_MODE) { if ((_fmi_uFMIReferenceClock % EMMC_FREQ) > 0) rate ++; } else { if ((_fmi_uFMIReferenceClock % SD_FREQ) > 0) rate ++; } } else if (cardSel==2) { // SD-2 no card detect pSD2->bIsCardInsert = TRUE; // SD-2 initial if (fmiSD_Init(pSD2) < 0) return FMI_SD_INIT_ERROR; /* divider */ if (pSD2->uCardType == FMI_TYPE_MMC) rate = _fmi_uFMIReferenceClock / MMC_FREQ; else if (pSD2->uCardType == FMI_TYPE_MMC_SECTOR_MODE) rate = _fmi_uFMIReferenceClock / EMMC_FREQ; else rate = _fmi_uFMIReferenceClock / SD_FREQ; if (pSD2->uCardType == FMI_TYPE_MMC) { if ((_fmi_uFMIReferenceClock % MMC_FREQ) > 0) rate ++; } else if (pSD2->uCardType == FMI_TYPE_MMC_SECTOR_MODE) { if ((_fmi_uFMIReferenceClock % EMMC_FREQ) > 0) rate ++; } else { if ((_fmi_uFMIReferenceClock % SD_FREQ) > 0) rate ++; } } for(i=0; i<100; i++); outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_S) | (0x03 << 19)); // SD clock from UPLL outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_N0) | (0x01 << 16)); // SD clock divided by 2 if (rate % 2) { rate /= 2; rate &= 0xFF; } else { rate /= 2; rate &= 0xFF; rate--; } outpw(REG_CLKDIV2, (inpw(REG_CLKDIV2) & ~SD_N1) | (rate << 24)); // SD clock divider for(i=0; i<1000; i++); /* init SD interface */ if (cardSel==0) { fmiGet_SD_info(pSD0, pSDDisk); if (fmiSelectCard(pSD0)) return FMI_SD_SELECT_ERROR; } else if (cardSel==1) { fmiGet_SD_info(pSD1, pSDDisk); if (fmiSelectCard(pSD1)) return FMI_SD_SELECT_ERROR; } else if (cardSel==2) { fmiGet_SD_info(pSD2, pSDDisk); if (fmiSelectCard(pSD2)) return FMI_SD_SELECT_ERROR; } /* * Create physical disk descriptor */ pDisk = malloc(sizeof(PDISK_T)); if (pDisk == NULL) return FMI_NO_MEMORY; memset((char *)pDisk, 0, sizeof(PDISK_T)); /* read Disk information */ pDisk->szManufacture[0] = '\0'; strcpy(pDisk->szProduct, (char *)pSDDisk->product); strcpy(pDisk->szSerialNo, (char *)pSDDisk->serial); pDisk->nDiskType = DISK_TYPE_SD_MMC; pDisk->nPartitionN = 0; pDisk->ptPartList = NULL; pDisk->nSectorSize = 512; pDisk->uTotalSectorN = pSDDisk->totalSectorN; pDisk->uDiskSize = pSDDisk->diskSize; /* create relationship between UMAS device and file system hard disk device */ if (cardSel==0) pDisk->ptDriver = &_SD0DiskDriver; else if (cardSel==1) pDisk->ptDriver = &_SD1DiskDriver; else if (cardSel==2) pDisk->ptDriver = &_SD2DiskDriver; #ifdef DEBUG printf("SD disk found: size=%d MB\n", (int)pDisk->uDiskSize / 1024); #endif if (cardSel==0) { pDisk_SD0 = pDisk; } else if (cardSel==1) { pDisk_SD1 = pDisk; } else if (cardSel==2) { pDisk_SD2 = pDisk; } fsPhysicalDiskConnected(pDisk); if (cardSel == 0) sd0_ok = 1; else if (cardSel == 1) sd1_ok = 1; else if (cardSel == 2) sd2_ok = 1; return pDisk->uTotalSectorN; } INT fmiSD_Read(UINT32 uSector, UINT32 uBufcnt, UINT32 uDAddr) { int status=0; // enable SD outpw(REG_FMICR, FMI_SD_EN); status = fmiSD_Read_in(pSD0, uSector, uBufcnt, uDAddr); return status; } INT fmiSD_Write(UINT32 uSector, UINT32 uBufcnt, UINT32 uSAddr) { int status=0; // enable SD outpw(REG_FMICR, FMI_SD_EN); status = fmiSD_Write_in(pSD0, uSector, uBufcnt, uSAddr); return status; } VOID sicSdClose_sel(INT cardSel) { if (cardSel==0) { sd0_ok = 0; //--- 2014/12/4, MUST free pDisk_SD0 BEFORE free pSD0 // because pSD0 could be used within fsUnmountPhysicalDisk(). if (pDisk_SD0 != NULL) { fsUnmountPhysicalDisk(pDisk_SD0); free(pDisk_SD0); pDisk_SD0 = NULL; } if (pSD0 != NULL) { free((FMI_SD_INFO_T *)((UINT32)pSD0 - pSD0_offset)); pSD0 = 0; } } else if (cardSel==1) { sd1_ok = 0; if (pDisk_SD1 != NULL) { fsUnmountPhysicalDisk(pDisk_SD1); free(pDisk_SD1); pDisk_SD1 = NULL; } if (pSD1 != NULL) { free((FMI_SD_INFO_T *)((UINT32)pSD1 - pSD1_offset)); pSD1 = 0; } } else if (cardSel==2) { sd2_ok = 0; if (pDisk_SD2 != NULL) { fsUnmountPhysicalDisk(pDisk_SD2); free(pDisk_SD2); pDisk_SD2 = NULL; } if (pSD2 != NULL) { free((FMI_SD_INFO_T *)((UINT32)pSD2 - pSD2_offset)); pSD2 = 0; } } } VOID sicSdClose(void) { sicSdClose_sel(0); } VOID sicSdClose0(void) { sicSdClose_sel(0); } VOID sicSdClose1(void) { sicSdClose_sel(1); } VOID sicSdClose2(void) { sicSdClose_sel(2); } /*-----------------------------------------------------------------------------------*/ /* Function: */ /* sicSdOpen */ /* */ /* Parameters: */ /* sdPortNo SD port number(port0 or port1). */ /* */ /* Returns: */ /* >0 Total sector. */ /* FMI_NO_SD_CARD No SD card insert. */ /* FMI_SD_INIT_ERROR Card initial and identify error. */ /* FMI_SD_SELECT_ERROR Select card from identify mode to stand-by mode error. */ /* */ /* Side effects: */ /* None. */ /* */ /* Description: */ /* This function initial SD from identification to stand-by mode. */ /* */ /*-----------------------------------------------------------------------------------*/ INT sicSdOpen_sel(INT cardSel) { return fmiInitSDDevice(cardSel); } INT sicSdOpen(void) { return fmiInitSDDevice(0); } INT sicSdOpen0(void) { return fmiInitSDDevice(0); } INT sicSdOpen1(void) { return fmiInitSDDevice(1); } INT sicSdOpen2(void) { return fmiInitSDDevice(2); }