| 1 | #include <ioc.h> | 
|---|
| 2 | #include <defs.h> | 
|---|
| 3 |  | 
|---|
| 4 | #define in_reset        __attribute__((section (".reset"))) | 
|---|
| 5 | #define in_reset_data   __attribute__((section (".reset_data"))) | 
|---|
| 6 | #define in_unckdata     __attribute__((section (".unckdata"))) | 
|---|
| 7 |  | 
|---|
| 8 | in_unckdata   int volatile _ioc_lock    = 0; | 
|---|
| 9 | in_reset_data int volatile _ioc_done    = 0; | 
|---|
| 10 | in_reset_data int volatile _ioc_status; | 
|---|
| 11 |  | 
|---|
| 12 | #ifndef SOCLIB_IOC | 
|---|
| 13 | /*in_reset_data volatile unsigned int _ioc_init_ok = 0;*/ | 
|---|
| 14 |  | 
|---|
| 15 | static in_reset_data struct sdcard_dev  _sdcard_device; | 
|---|
| 16 | static in_reset_data struct spi_dev   * _spi_device   = ( struct spi_dev * )IOC_BASE; | 
|---|
| 17 | #endif | 
|---|
| 18 |  | 
|---|
| 19 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 20 | //  I/O BLOCK_DEVICE | 
|---|
| 21 | // The three functions below use the three variables _ioc_lock _ioc_done, | 
|---|
| 22 | // and _ioc_status for synchronsation. | 
|---|
| 23 | // - As the IOC component can be used by several programs running in parallel, | 
|---|
| 24 | // the _ioc_lock variable guaranties exclusive access to the device. | 
|---|
| 25 | // The _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock. | 
|---|
| 26 | // and set _ioc_lock to a non zero value. | 
|---|
| 27 | // The _ioc_write() and _ioc_read() functions are blocking, polling the _ioc_lock | 
|---|
| 28 | // variable until the device is available. | 
|---|
| 29 | // - When the tranfer is completed, the ISR routine activated by the IOC IRQ | 
|---|
| 30 | // set the _ioc_done variable to a non-zero value. Possible address errors detected | 
|---|
| 31 | // by the IOC peripheral are reported by the ISR in the _ioc_status variable. | 
|---|
| 32 | // The _ioc_completed() function is polling the _ioc_done variable, waiting for | 
|---|
| 33 | // tranfer conpletion. When the completion is signaled, the _ioc_completed() function | 
|---|
| 34 | // reset the _ioc_done variable to zero, and releases the _ioc_lock variable. | 
|---|
| 35 | // | 
|---|
| 36 | // In a multi-tasks environment, this polling policy must be replaced by a | 
|---|
| 37 | // descheduling policy for the requesting process. | 
|---|
| 38 | ////////////////////////////////////////////////////////////////////// | 
|---|
| 39 |  | 
|---|
| 40 | ////////////////////////////////////////////////////////////////////// | 
|---|
| 41 | //  _dcache_buf_invalidate() | 
|---|
| 42 | // Invalidate all cache lines corresponding to a memory buffer. | 
|---|
| 43 | // This is used by the block_device driver. | 
|---|
| 44 | ///////////////////////////////////////////////////////////////////////// | 
|---|
| 45 | //in_reset static void _dcache_buf_invalidate(const void * buffer, size_t size) | 
|---|
| 46 | //{ | 
|---|
| 47 | //    size_t i; | 
|---|
| 48 | //    size_t dcache_line_size; | 
|---|
| 49 | // | 
|---|
| 50 | //    // retrieve dcache line size from config register (bits 12:10) | 
|---|
| 51 | //    asm volatile("mfc0 %0, $16, 1" : "=r" (dcache_line_size)); | 
|---|
| 52 | // | 
|---|
| 53 | //    dcache_line_size = 2 << ((dcache_line_size>>10) & 0x7); | 
|---|
| 54 | // | 
|---|
| 55 | //    // iterate on lines to invalidate each one of them | 
|---|
| 56 | //    for ( i=0; i<size; i+=dcache_line_size ) | 
|---|
| 57 | //        asm volatile(" cache %0, %1" | 
|---|
| 58 | //                : | 
|---|
| 59 | //                :"i" (0x11), "R" (*((char*)buffer+i))); | 
|---|
| 60 | //} | 
|---|
| 61 |  | 
|---|
| 62 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 63 | //  _ioc_get_lock() | 
|---|
| 64 | // This blocking function is used by the _ioc_read() and _ioc_write() functions | 
|---|
| 65 | // to get _ioc_lock using LL/SC. | 
|---|
| 66 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 67 | in_reset void _ioc_get_lock() | 
|---|
| 68 | { | 
|---|
| 69 | register unsigned int   proctime; | 
|---|
| 70 | register unsigned int   delay; | 
|---|
| 71 | register unsigned int*  plock = (unsigned int*)&_ioc_lock; | 
|---|
| 72 |  | 
|---|
| 73 | asm volatile( | 
|---|
| 74 | "mfc0 %0, $9    \n" | 
|---|
| 75 | : "=r"(proctime) | 
|---|
| 76 | : /* No inputs */ | 
|---|
| 77 | ); | 
|---|
| 78 |  | 
|---|
| 79 | delay = (proctime & 0xF) << 4; | 
|---|
| 80 |  | 
|---|
| 81 | asm volatile ("_ioc_llsc:                   \n" | 
|---|
| 82 | "ll   $2,    0(%0)            \n" // $2 <= _ioc_lock | 
|---|
| 83 | "bnez $2,    _ioc_delay       \n" // random delay if busy | 
|---|
| 84 | "li   $3,    1                \n" // prepare argument for sc | 
|---|
| 85 | "sc   $3,    0(%0)            \n" // try to set _ioc_busy | 
|---|
| 86 | "bnez $3,    _ioc_ok          \n" // exit if atomic | 
|---|
| 87 | "_ioc_delay:                  \n" | 
|---|
| 88 | "move $4,    %1               \n" // $4 <= delay | 
|---|
| 89 | "_ioc_loop:                   \n" | 
|---|
| 90 | "addi $4,    $4,    -1        \n" // $4 <= $4 - 1 | 
|---|
| 91 | "beqz $4,    _ioc_loop        \n" // test end delay | 
|---|
| 92 | "j           _ioc_llsc        \n" // retry | 
|---|
| 93 | "_ioc_ok:                     \n" | 
|---|
| 94 | ::"r"(plock),"r"(delay):"$2","$3","$4"); | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | in_reset int _ioc_init() | 
|---|
| 98 | { | 
|---|
| 99 | #ifndef SOCLIB_IOC | 
|---|
| 100 | in_reset_data static char init_begin[] = "Initializing block device\n\r"; | 
|---|
| 101 | in_reset_data static char init_end[]   = "Finish block device initialization\n\r"; | 
|---|
| 102 |  | 
|---|
| 103 | unsigned char sdcard_rsp; | 
|---|
| 104 |  | 
|---|
| 105 | boot_puts(init_begin); | 
|---|
| 106 |  | 
|---|
| 107 | /** | 
|---|
| 108 | * Initializing the SPI controller | 
|---|
| 109 | */ | 
|---|
| 110 | spi_dev_config ( | 
|---|
| 111 | _spi_device   , | 
|---|
| 112 | 200000        , /**< SPI_clk: 200 Khz */ | 
|---|
| 113 | 50000000      , /**< Sys_clk: 50  Mhz */ | 
|---|
| 114 | 8             , /**< Charlen: 8       */ | 
|---|
| 115 | SPI_TX_NEGEDGE, | 
|---|
| 116 | SPI_RX_POSEDGE | 
|---|
| 117 | ); | 
|---|
| 118 |  | 
|---|
| 119 | /** | 
|---|
| 120 | * Initializing the SD Card | 
|---|
| 121 | */ | 
|---|
| 122 | if ( (sdcard_rsp = sdcard_dev_open(&_sdcard_device, _spi_device, 0)) ) | 
|---|
| 123 | return sdcard_rsp; | 
|---|
| 124 |  | 
|---|
| 125 | if ( (sdcard_rsp = sdcard_dev_set_blocklen(&_sdcard_device, 512)) ) | 
|---|
| 126 | return sdcard_rsp; | 
|---|
| 127 |  | 
|---|
| 128 | /** | 
|---|
| 129 | * Incrementing SDCARD clock frequency for normal function | 
|---|
| 130 | */ | 
|---|
| 131 | spi_dev_config ( | 
|---|
| 132 | _spi_device , | 
|---|
| 133 | 10000000    , /**< SPI_clkL 10 Mhz */ | 
|---|
| 134 | 50000000    , /**< Sys_clk: 50 Mhz */ | 
|---|
| 135 | -1          , /**< Charlen: 8      */ | 
|---|
| 136 | -1          , | 
|---|
| 137 | -1 | 
|---|
| 138 | ); | 
|---|
| 139 |  | 
|---|
| 140 | boot_puts(init_end); | 
|---|
| 141 | #endif | 
|---|
| 142 |  | 
|---|
| 143 | return 0; | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 147 | //  _ioc_completed() | 
|---|
| 148 | // This blocking function cheks completion of an I/O transfer and reports errors. | 
|---|
| 149 | // It returns 0 if the transfer is successfully completed. | 
|---|
| 150 | // It returns -1 if an error has been reported. | 
|---|
| 151 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 152 | in_reset int _ioc_completed() | 
|---|
| 153 | { | 
|---|
| 154 | unsigned int status = 0; | 
|---|
| 155 |  | 
|---|
| 156 | #ifdef SOCLIB_IOC | 
|---|
| 157 |  | 
|---|
| 158 | unsigned int * ioc_address = ( unsigned int * )VCIBD_BASE; | 
|---|
| 159 |  | 
|---|
| 160 | while ( 1 ) | 
|---|
| 161 | { | 
|---|
| 162 | status = ioread32(&ioc_address[BLOCK_DEVICE_STATUS]); | 
|---|
| 163 |  | 
|---|
| 164 | if (( status == BLOCK_DEVICE_READ_SUCCESS ) || | 
|---|
| 165 | ( status == BLOCK_DEVICE_READ_ERROR  )) | 
|---|
| 166 | break; | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | #endif | 
|---|
| 170 |  | 
|---|
| 171 | return status; | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 | ////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 175 | //  _ioc_write() | 
|---|
| 176 | // Transfer data from a memory buffer to a file on the block_device. | 
|---|
| 177 | // - lba    : first block index on the disk | 
|---|
| 178 | // - buffer : base address of the memory buffer | 
|---|
| 179 | // - count  : number of blocks to be transfered | 
|---|
| 180 | // The source buffer must be in user address space. | 
|---|
| 181 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 182 | in_reset int _ioc_write(size_t lba, void* buffer, size_t count) | 
|---|
| 183 | { | 
|---|
| 184 | // get the lock | 
|---|
| 185 | // _ioc_get_lock(); | 
|---|
| 186 |  | 
|---|
| 187 | #ifdef SOCLIB_IOC | 
|---|
| 188 |  | 
|---|
| 189 | unsigned int * ioc_address = ( unsigned int * )VCIBD_BASE; | 
|---|
| 190 |  | 
|---|
| 191 | // block_device configuration | 
|---|
| 192 | iowrite32( &ioc_address[BLOCK_DEVICE_BUFFER], | 
|---|
| 193 | ( unsigned int ) buffer ); | 
|---|
| 194 |  | 
|---|
| 195 | iowrite32( &ioc_address[BLOCK_DEVICE_COUNT], | 
|---|
| 196 | ( unsigned int ) count ); | 
|---|
| 197 |  | 
|---|
| 198 | iowrite32( &ioc_address[BLOCK_DEVICE_LBA], | 
|---|
| 199 | ( unsigned int ) lba ); | 
|---|
| 200 |  | 
|---|
| 201 | iowrite32( &ioc_address[BLOCK_DEVICE_IRQ_ENABLE], | 
|---|
| 202 | ( unsigned int ) 0 ); | 
|---|
| 203 |  | 
|---|
| 204 | iowrite32( &ioc_address[BLOCK_DEVICE_OP], | 
|---|
| 205 | ( unsigned int ) BLOCK_DEVICE_WRITE); | 
|---|
| 206 |  | 
|---|
| 207 | _ioc_completed(); | 
|---|
| 208 |  | 
|---|
| 209 | #else | 
|---|
| 210 | /* | 
|---|
| 211 | in_reset_data static char end_line[] = | 
|---|
| 212 | "\n\r"; | 
|---|
| 213 | in_reset_data static char error_init[] = | 
|---|
| 214 | "ERROR during initialization of block device. Code: "; | 
|---|
| 215 |  | 
|---|
| 216 | unsigned int sdcard_rsp; | 
|---|
| 217 |  | 
|---|
| 218 | if ( _ioc_init_ok == 0 ) | 
|---|
| 219 | { | 
|---|
| 220 | if (( sdcard_rsp = _ioc_init(&_sdcard_device, 0) )) | 
|---|
| 221 | { | 
|---|
| 222 | boot_puts(error_init); | 
|---|
| 223 | boot_putx(sdcard_rsp); | 
|---|
| 224 | boot_puts(end_line); | 
|---|
| 225 | } | 
|---|
| 226 |  | 
|---|
| 227 | _ioc_init_ok = 1; | 
|---|
| 228 | } | 
|---|
| 229 | */ | 
|---|
| 230 |  | 
|---|
| 231 | sdcard_dev_lseek(&_sdcard_device, lba); | 
|---|
| 232 | sdcard_dev_write(&_sdcard_device, buffer, count*512); | 
|---|
| 233 |  | 
|---|
| 234 | #endif | 
|---|
| 235 |  | 
|---|
| 236 | // _ioc_lock = 0; | 
|---|
| 237 |  | 
|---|
| 238 | return 0; | 
|---|
| 239 | } | 
|---|
| 240 |  | 
|---|
| 241 | /** | 
|---|
| 242 | *  _ioc_read() | 
|---|
| 243 | * | 
|---|
| 244 | * Transfer data from a file on the block device to a memory buffer. | 
|---|
| 245 | * | 
|---|
| 246 | * \param lba    : first block index on the disk | 
|---|
| 247 | * \param buffer : base address of the memory buffer | 
|---|
| 248 | * \param count  : number of blocks to be transfered | 
|---|
| 249 | * | 
|---|
| 250 | * \note This is a blocking function. The function returns once the transfer | 
|---|
| 251 | *       has finished | 
|---|
| 252 | */ | 
|---|
| 253 | in_reset int _ioc_read(size_t lba, void* buffer, size_t count) | 
|---|
| 254 | { | 
|---|
| 255 | // get the lock | 
|---|
| 256 | // _ioc_get_lock(); | 
|---|
| 257 |  | 
|---|
| 258 | #ifdef SOCLIB_IOC | 
|---|
| 259 |  | 
|---|
| 260 | unsigned int * ioc_address  = (unsigned int*)VCIBD_BASE; | 
|---|
| 261 |  | 
|---|
| 262 | // block_device configuration | 
|---|
| 263 | iowrite32( &ioc_address[BLOCK_DEVICE_BUFFER], | 
|---|
| 264 | ( unsigned int ) buffer ); | 
|---|
| 265 |  | 
|---|
| 266 | iowrite32( &ioc_address[BLOCK_DEVICE_COUNT], | 
|---|
| 267 | ( unsigned int ) count ); | 
|---|
| 268 |  | 
|---|
| 269 | iowrite32( &ioc_address[BLOCK_DEVICE_LBA], | 
|---|
| 270 | ( unsigned int ) lba ); | 
|---|
| 271 |  | 
|---|
| 272 | iowrite32( &ioc_address[BLOCK_DEVICE_IRQ_ENABLE], | 
|---|
| 273 | ( unsigned int ) 0 ); | 
|---|
| 274 |  | 
|---|
| 275 | iowrite32( &ioc_address[BLOCK_DEVICE_OP], | 
|---|
| 276 | ( unsigned int ) BLOCK_DEVICE_READ ); | 
|---|
| 277 |  | 
|---|
| 278 | _ioc_completed(); | 
|---|
| 279 |  | 
|---|
| 280 | #else | 
|---|
| 281 | in_reset_data static char error_read[] = | 
|---|
| 282 | "ERROR during read on the SDCARD device. Code: "; | 
|---|
| 283 | in_reset_data static char end_line[] = | 
|---|
| 284 | "\n\r"; | 
|---|
| 285 | /* | 
|---|
| 286 | in_reset_data static char error_init[] = | 
|---|
| 287 | "ERROR during initialization of block device. Code: "; | 
|---|
| 288 | */ | 
|---|
| 289 |  | 
|---|
| 290 | unsigned int sdcard_rsp; | 
|---|
| 291 |  | 
|---|
| 292 | /* | 
|---|
| 293 | if ( _ioc_init_ok == 0 ) | 
|---|
| 294 | { | 
|---|
| 295 | if (( sdcard_rsp = _ioc_init(&_sdcard_device, 0) )) | 
|---|
| 296 | { | 
|---|
| 297 | boot_puts(error_init); | 
|---|
| 298 | boot_putx(sdcard_rsp); | 
|---|
| 299 | boot_puts(end_line); | 
|---|
| 300 | } | 
|---|
| 301 |  | 
|---|
| 302 | _ioc_init_ok = 1; | 
|---|
| 303 | } | 
|---|
| 304 | */ | 
|---|
| 305 |  | 
|---|
| 306 | sdcard_dev_lseek(&_sdcard_device, lba); | 
|---|
| 307 |  | 
|---|
| 308 | if (( sdcard_rsp = sdcard_dev_read (&_sdcard_device, buffer, count*512) )) | 
|---|
| 309 | { | 
|---|
| 310 | boot_puts(error_read); | 
|---|
| 311 | boot_putx(sdcard_rsp); | 
|---|
| 312 | boot_puts(end_line); | 
|---|
| 313 | } | 
|---|
| 314 |  | 
|---|
| 315 | #endif | 
|---|
| 316 |  | 
|---|
| 317 | //_ioc_lock = 0; | 
|---|
| 318 | // | 
|---|
| 319 | //_dcache_buf_invalidate(buffer, count); | 
|---|
| 320 |  | 
|---|
| 321 | return 0; | 
|---|
| 322 | } | 
|---|
| 323 | #undef in_reset | 
|---|
| 324 | #undef in_reset_data | 
|---|
| 325 | #undef in_unckdata | 
|---|
| 326 |  | 
|---|
| 327 | /* | 
|---|
| 328 | * vim: tabstop=4 : shiftwidth=4 : expandtab | 
|---|
| 329 | */ | 
|---|