00001
00041 #include "dataflash.h"
00042 #include <appconfig.h>
00043
00044 #include <cfg/macros.h>
00045 #include <cfg/debug.h>
00046 #include <cfg/module.h>
00047 #include <drv/timer.h>
00048 #include <kern/kfile.h>
00049
00050 #if CONFIG_KERNEL
00051 #include <kern/proc.h>
00052 #endif
00053
00054 #include <string.h>
00055
00059 static const DataflashInfo mem_info[] =
00060 {
00061 {
00062
00063 .density_id = 0x07,
00064 .page_size = 264,
00065 .page_bits = 9,
00066 .page_cnt = 2048,
00067 .read_cmd = DFO_READ_FLASH_MEM_BYTE_B,
00068 },
00069 {
00070
00071 .density_id = 0x09,
00072 .page_size = 264,
00073 .page_bits = 9,
00074 .page_cnt = 4096,
00075 .read_cmd = DFO_READ_FLASH_MEM_BYTE_D,
00076 },
00077 {
00078
00079 .density_id = 0x0B,
00080 .page_size = 528,
00081 .page_bits = 10,
00082 .page_cnt = 4096,
00083 .read_cmd = DFO_READ_FLASH_MEM_BYTE_D,
00084 },
00085
00086 };
00087
00088 STATIC_ASSERT(countof(mem_info) == DFT_CNT);
00089
00094 INLINE void CS_TOGGLE(KFileDataflash *fd)
00095 {
00096 fd->setCS(false);
00097 fd->setCS(true);
00098 }
00099
00105 static void send_cmd(KFileDataflash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode)
00106 {
00107
00108
00109
00110
00111
00112 CS_TOGGLE(fd);
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 kfile_putc(opcode, fd->channel);
00133
00134
00135
00136
00137 kfile_putc((uint8_t)(page_addr >> (16 - mem_info[fd->dev].page_bits)), fd->channel);
00138 kfile_putc((uint8_t)((page_addr << (mem_info[fd->dev].page_bits - 8)) + (byte_addr >> 8)), fd->channel);
00139
00140
00141
00142
00143 kfile_putc((uint8_t)byte_addr, fd->channel);
00144 }
00145
00154 static void dataflash_reset(KFileDataflash *fd)
00155 {
00156 fd->setCS(false);
00157
00158 if (fd->setReset)
00159 {
00160 fd->setReset(true);
00161 timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH));
00162 fd->setReset(false);
00163 timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH));
00164 }
00165 }
00166
00167
00171 static uint8_t dataflash_stat(KFileDataflash *fd)
00172 {
00173
00174
00175
00176
00177 CS_TOGGLE(fd);
00178
00179 kfile_putc(DFO_READ_STATUS, fd->channel);
00180
00181 return kfile_getc(fd->channel);
00182 }
00183
00184
00190 static uint8_t dataflash_cmd(KFileDataflash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode)
00191 {
00192 uint8_t stat;
00193
00194 send_cmd(fd, page_addr, byte_addr, opcode);
00195
00196 CS_TOGGLE(fd);
00197
00198
00199
00200
00201
00202 while (!(dataflash_stat(fd) & BUSY_BIT))
00203 {
00204 #if CONFIG_KERNEL
00205 proc_switch();
00206 #endif
00207 }
00208
00209 stat = dataflash_stat(fd);
00210
00211 kfile_flush(fd->channel);
00212
00213
00214
00215 fd->setCS(false);
00216
00217 return stat;
00218 }
00219
00224 static void dataflash_readBlock(KFileDataflash *fd, dataflash_page_t page_addr, dataflash_offset_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflash_size_t len)
00225 {
00226 send_cmd(fd, page_addr, byte_addr, opcode);
00227
00228 if (opcode == DFO_READ_FLASH_MEM_BYTE_B)
00229 {
00230
00231
00232
00233 uint8_t dummy[] = { 0, 0, 0 };
00234 kfile_write(fd->channel, dummy, sizeof(dummy));
00235 }
00236
00237 kfile_putc(0, fd->channel);
00238 kfile_read(fd->channel, block, len);
00239 kfile_flush(fd->channel);
00240 fd->setCS(false);
00241 }
00242
00243
00251 static void dataflash_writeBlock(KFileDataflash *fd, dataflash_offset_t offset, DataFlashOpcode opcode, const uint8_t *block, dataflash_size_t len)
00252 {
00253 ASSERT(offset + len <= mem_info[fd->dev].page_size);
00254
00255 send_cmd(fd, 0x00, offset, opcode);
00256
00257 kfile_write(fd->channel, block, len);
00258 kfile_flush(fd->channel);
00259
00260 fd->setCS(false);
00261 }
00262
00263
00267 static void dataflash_loadPage(KFileDataflash *fd, dataflash_page_t page_addr)
00268 {
00269 dataflash_cmd(fd, page_addr, 0x00, DFO_MOV_MEM_TO_BUFF1);
00270 }
00271
00275 static int dataflash_flush(KFile *_fd)
00276 {
00277 KFileDataflash *fd = KFILEDATAFLASH(_fd);
00278 if (fd->page_dirty)
00279 {
00280 dataflash_cmd(fd, fd->current_page, 0x00, DFO_WRITE_BUFF1_TO_MEM_E);
00281
00282 fd->page_dirty = false;
00283
00284 kprintf("Flushing page <%ld>\n", fd->current_page);
00285 }
00286 return 0;
00287 }
00288
00289
00290
00294 static int dataflash_close(struct KFile *_fd)
00295 {
00296 dataflash_flush(_fd);
00297 TRACE;
00298 return 0;
00299 }
00300
00304 static KFile *dataflash_reopen(KFile *_fd)
00305 {
00306 KFileDataflash *fd = KFILEDATAFLASH(_fd);
00307 dataflash_close(_fd);
00308
00309 fd->current_page = 0;
00310 fd->fd.seek_pos = 0;
00311
00312
00313 dataflash_loadPage(fd, fd->current_page);
00314
00315 TRACE;
00316 return &fd->fd;
00317 }
00318
00319
00332 static size_t dataflash_read(struct KFile *_fd, void *buf, size_t size)
00333 {
00334 KFileDataflash *fd = KFILEDATAFLASH(_fd);
00335
00336 dataflash_offset_t byte_addr;
00337 dataflash_page_t page_addr;
00338 uint8_t *data = (uint8_t *)buf;
00339
00340
00341 ASSERT(fd->fd.seek_pos + size <= fd->fd.size);
00342 size = MIN((uint32_t)size, fd->fd.size - fd->fd.seek_pos);
00343
00344 kprintf("Reading at pos[%lu]\n", fd->fd.seek_pos);
00345
00346
00347
00348
00349 page_addr = fd->fd.seek_pos / mem_info[fd->dev].page_size;
00350 byte_addr = fd->fd.seek_pos % mem_info[fd->dev].page_size;
00351
00352 kprintf("[page-<%ld>, byte-<%ld>]", page_addr, byte_addr);
00353
00354
00355
00356
00357
00358 dataflash_flush(&fd->fd);
00359
00360
00361
00362
00363 dataflash_readBlock(fd, page_addr, byte_addr, mem_info[fd->dev].read_cmd, data, size);
00364
00365 fd->fd.seek_pos += size;
00366 kprintf("Read %ld bytes\n", size);
00367
00368 return size;
00369 }
00370
00382 static size_t dataflash_write(struct KFile *_fd, const void *_buf, size_t size)
00383 {
00384 KFileDataflash *fd = KFILEDATAFLASH(_fd);
00385
00386 dataflash_offset_t offset;
00387 dataflash_page_t new_page;
00388 size_t total_write = 0;
00389
00390 const uint8_t *data = (const uint8_t *) _buf;
00391
00392 ASSERT(fd->fd.seek_pos + size <= fd->fd.size);
00393 size = MIN((uint32_t)size, fd->fd.size - fd->fd.seek_pos);
00394
00395 kprintf("Writing at pos[%lu]\n", fd->fd.seek_pos);
00396
00397 while (size)
00398 {
00399
00400
00401
00402 new_page = fd->fd.seek_pos / mem_info[fd->dev].page_size;
00403 offset = fd->fd.seek_pos % mem_info[fd->dev].page_size;
00404
00405
00406 size_t wr_len = MIN(size, mem_info[fd->dev].page_size - offset);
00407
00408 kprintf(" [page-<%ld>, byte-<%ld>]",new_page, offset);
00409
00410 if (new_page != fd->current_page)
00411 {
00412
00413 dataflash_flush(&fd->fd);
00414
00415 dataflash_loadPage(fd, new_page);
00416
00417 fd->current_page = new_page;
00418 kprintf(" >> Load page: <%ld> ", new_page);
00419 }
00420
00421
00422
00423
00424 dataflash_writeBlock(fd, offset, DFO_WRITE_BUFF1, data, wr_len);
00425 fd->page_dirty = true;
00426
00427 data += wr_len;
00428 fd->fd.seek_pos += wr_len;
00429 size -= wr_len;
00430 total_write += wr_len;
00431 }
00432
00433 kprintf("written %lu bytes\n", total_write);
00434 return total_write;
00435 }
00436
00437 MOD_DEFINE(dataflash);
00438
00448 bool dataflash_init(KFileDataflash *fd, KFile *ch, DataflashType dev, dataflash_setCS_t *setCS, dataflash_setReset_t *setReset)
00449 {
00450 uint8_t stat;
00451
00452 MOD_CHECK(hw_dataflash);
00453
00454 ASSERT(fd);
00455 ASSERT(ch);
00456 ASSERT(setCS);
00457 ASSERT(dev < DFT_CNT);
00458
00459 memset(fd, 0, sizeof(*fd));
00460 DB(fd->fd._type = KFT_DATAFLASH);
00461 fd->dev = dev;
00462 fd->channel = ch;
00463 fd->setReset = setReset;
00464 fd->setCS = setCS;
00465
00466
00467 fd->fd.reopen = dataflash_reopen;
00468 fd->fd.close = dataflash_close;
00469 fd->fd.read = dataflash_read;
00470 fd->fd.write = dataflash_write;
00471 fd->fd.seek = kfile_genericSeek;
00472 fd->fd.flush = dataflash_flush;
00473
00474 dataflash_reset(fd);
00475
00476 stat = dataflash_stat(fd);
00477
00478
00479
00480
00481
00482
00483 if (GET_ID_DESITY_DEVICE(stat) != mem_info[fd->dev].density_id)
00484 return false;
00485
00486 fd->current_page = 0;
00487 fd->fd.seek_pos = 0;
00488 fd->fd.size = mem_info[fd->dev].page_size * mem_info[fd->dev].page_cnt;
00489
00490
00491 dataflash_loadPage(fd, fd->current_page);
00492 MOD_INIT(dataflash);
00493 return true;
00494 }