2010-05-15 19:42:17 +03:00
|
|
|
#pypp 0
|
|
|
|
// Iris: micro-kernel for a capability-based operating system.
|
|
|
|
// boot-programs/nand.ccp: NAND driver.
|
|
|
|
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include "devices.hh"
|
|
|
|
#define ARCH
|
|
|
|
#include "arch.hh"
|
2010-09-02 00:27:14 +03:00
|
|
|
|
2010-10-07 10:52:04 +03:00
|
|
|
#define debug Iris::debug
|
2010-09-02 00:27:14 +03:00
|
|
|
#define DELAY Iris::schedule
|
2010-08-22 23:03:06 +03:00
|
|
|
#include "nand.hh"
|
2010-10-07 10:52:04 +03:00
|
|
|
#undef debug
|
2010-05-15 19:42:17 +03:00
|
|
|
|
2010-09-02 00:27:14 +03:00
|
|
|
static unsigned *cache
|
|
|
|
static bool dirty
|
|
|
|
static unsigned current_block
|
2010-08-05 23:19:58 +03:00
|
|
|
|
2010-09-02 00:27:14 +03:00
|
|
|
static void sync ():
|
2010-10-10 11:46:12 +03:00
|
|
|
//Iris::debug ("erasing %x\n", current_block << block_bits)
|
2010-10-07 10:52:04 +03:00
|
|
|
erase (current_block << block_bits)
|
|
|
|
for unsigned p = 0; p < 1 << (block_bits - page_bits); ++p:
|
|
|
|
write ((current_block << block_bits) + (p << page_bits), (char *)&cache[p << (page_bits - 2)])
|
2010-08-05 23:19:58 +03:00
|
|
|
|
2010-09-02 00:27:14 +03:00
|
|
|
static void read_block (unsigned b):
|
2010-10-07 10:52:04 +03:00
|
|
|
if b == current_block:
|
|
|
|
return
|
|
|
|
if current_block != ~0 && dirty:
|
|
|
|
sync ()
|
|
|
|
current_block = b
|
|
|
|
//kdebug ("setting current block to ")
|
|
|
|
//kdebug_num (b)
|
|
|
|
//kdebug ("\n")
|
2010-09-02 00:27:14 +03:00
|
|
|
for unsigned p = 0; p < 1 << (block_bits - 9); ++p:
|
|
|
|
read ((b << block_bits) + (p << 9), (char *)&cache[p << (9 - 2)])
|
|
|
|
dirty = false
|
|
|
|
|
|
|
|
Iris::Num start ():
|
2010-08-22 23:03:06 +03:00
|
|
|
map_emc ()
|
|
|
|
map_gpio ()
|
2010-08-05 23:19:58 +03:00
|
|
|
|
2010-08-22 23:03:06 +03:00
|
|
|
// Arbitrary addresses where the pages are mapped.
|
|
|
|
command = (volatile char *)0x15000
|
|
|
|
address = (volatile char *)0x16000
|
|
|
|
data = (volatile char *)0x17000
|
2010-05-15 19:42:17 +03:00
|
|
|
|
|
|
|
Iris::Page data_page = Iris::my_memory.create_page ()
|
|
|
|
Iris::Page command_page = Iris::my_memory.create_page ()
|
|
|
|
Iris::Page address_page = Iris::my_memory.create_page ()
|
|
|
|
|
|
|
|
unsigned base = 0x18000000
|
|
|
|
data_page.alloc_physical (base, false, false)
|
|
|
|
command_page.alloc_physical (base + 0x8000, false, false)
|
|
|
|
address_page.alloc_physical (base + 0x10000, false, false)
|
|
|
|
|
|
|
|
Iris::my_memory.map (data_page, (unsigned)data)
|
|
|
|
Iris::my_memory.map (command_page, (unsigned)command)
|
|
|
|
Iris::my_memory.map (address_page, (unsigned)address)
|
|
|
|
|
|
|
|
Iris::free_cap (data_page)
|
|
|
|
Iris::free_cap (command_page)
|
|
|
|
Iris::free_cap (address_page)
|
|
|
|
|
|
|
|
reset ()
|
|
|
|
|
2010-09-02 00:27:14 +03:00
|
|
|
current_block = ~0
|
|
|
|
dirty = false
|
|
|
|
cache = (unsigned *)0x40000000
|
|
|
|
for unsigned p = 0; p < 1 << (block_bits - PAGE_BITS); ++p:
|
|
|
|
Iris::Page page = Iris::my_memory.create_page ()
|
|
|
|
page.set_flags (Iris::Page::PAYING | Iris::Page::FRAME)
|
2010-09-09 22:48:35 +03:00
|
|
|
Iris::my_memory.map (page, (unsigned)cache + (p << PAGE_BITS))
|
2010-09-02 00:27:14 +03:00
|
|
|
Iris::free_cap (page)
|
|
|
|
Iris::Page tmp = Iris::my_memory.create_page ()
|
|
|
|
tmp.set_flags (Iris::Page::PAYING)
|
|
|
|
unsigned *tmp_addr = (unsigned *)0x3ffff000
|
|
|
|
Iris::my_memory.map (tmp, (unsigned)tmp_addr)
|
|
|
|
|
|
|
|
Iris::Cap cap = Iris::my_receiver.create_capability (0)
|
2012-01-14 19:17:23 +02:00
|
|
|
Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ())
|
2010-09-02 00:27:14 +03:00
|
|
|
Iris::free_cap (cap)
|
|
|
|
|
|
|
|
Iris::my_parent.init_done ()
|
|
|
|
|
|
|
|
while true:
|
|
|
|
Iris::wait ()
|
|
|
|
switch Iris::recv.data[0].l:
|
|
|
|
case Iris::Block::GET_SIZE:
|
|
|
|
if size_bits > 32:
|
|
|
|
Iris::recv.reply.invoke (Iris::Num (0, 1 << (size_bits - 32)))
|
|
|
|
else:
|
|
|
|
Iris::recv.reply.invoke (1 << size_bits)
|
|
|
|
break
|
|
|
|
case Iris::Block::GET_ALIGN_BITS:
|
|
|
|
Iris::recv.reply.invoke (9)
|
|
|
|
break
|
|
|
|
case Iris::Block::GET_BLOCK:
|
|
|
|
unsigned row = Iris::recv.data[1].value () >> 9
|
|
|
|
unsigned block = row >> (block_bits - 9)
|
|
|
|
row &= (1 << (block_bits - 9)) - 1
|
|
|
|
unsigned offset = Iris::recv.data[0].h & 0xe00
|
|
|
|
unsigned size = Iris::recv.data[0].h >> 16
|
|
|
|
if size + offset >= 0x1000:
|
|
|
|
size = 0x1000 - offset
|
2010-10-07 10:52:04 +03:00
|
|
|
#if 0
|
|
|
|
kdebug ("get ")
|
|
|
|
kdebug_num (block)
|
|
|
|
kdebug (":")
|
|
|
|
kdebug_num (row)
|
|
|
|
kdebug ("+")
|
|
|
|
kdebug_num (size)
|
|
|
|
kdebug ("@")
|
|
|
|
kdebug_num (offset)
|
|
|
|
kdebug ("\n")
|
|
|
|
#endif
|
|
|
|
read_block (block)
|
2010-09-02 00:27:14 +03:00
|
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
|
|
Iris::Page page = Iris::get_arg ()
|
|
|
|
page.share (tmp)
|
|
|
|
tmp.set_flags (Iris::Page::FRAME)
|
|
|
|
for unsigned t = 0; t < size >> 2; ++t:
|
2010-10-07 10:52:04 +03:00
|
|
|
tmp_addr[(offset >> 2) + t] = cache[t + (row << (9 - 2))]
|
2010-09-02 00:27:14 +03:00
|
|
|
tmp.set_flags (0, Iris::Page::FRAME)
|
|
|
|
reply.invoke ()
|
|
|
|
Iris::free_cap (reply)
|
|
|
|
Iris::free_cap (page)
|
|
|
|
break
|
|
|
|
case Iris::WBlock::SET_BLOCK:
|
|
|
|
unsigned row = Iris::recv.data[1].value () >> 9
|
|
|
|
unsigned block = row >> (block_bits - 9)
|
2010-10-07 10:52:04 +03:00
|
|
|
row &= (1 << (block_bits - 9)) - 1
|
2010-09-02 00:27:14 +03:00
|
|
|
unsigned offset = Iris::recv.data[0].h & 0xe00
|
|
|
|
unsigned size = Iris::recv.data[0].h >> 16
|
|
|
|
if size + offset >= 0x1000:
|
|
|
|
size = 0x1000 - offset
|
2010-10-07 10:52:04 +03:00
|
|
|
#if 0
|
|
|
|
kdebug ("set ")
|
|
|
|
kdebug_num (block)
|
|
|
|
kdebug (":")
|
|
|
|
kdebug_num (row)
|
|
|
|
kdebug ("+")
|
|
|
|
kdebug_num (size)
|
|
|
|
kdebug ("@")
|
|
|
|
kdebug_num (offset)
|
|
|
|
kdebug ("\n")
|
|
|
|
#endif
|
|
|
|
//kdebug_num (current_block)
|
|
|
|
//kdebug ("/")
|
|
|
|
read_block (block)
|
2010-09-02 00:27:14 +03:00
|
|
|
Iris::Cap reply = Iris::get_reply ()
|
|
|
|
Iris::Page page = Iris::get_arg ()
|
|
|
|
page.share (tmp)
|
|
|
|
tmp.set_flags (Iris::Page::FRAME)
|
2010-10-07 10:52:04 +03:00
|
|
|
for unsigned t = 0; t < size; t += 4:
|
|
|
|
cache[(offset + t + (row << 9)) >> 2] = tmp_addr[(offset + t) >> 2]
|
2010-09-02 00:27:14 +03:00
|
|
|
tmp.set_flags (0, Iris::Page::FRAME)
|
|
|
|
reply.invoke ()
|
|
|
|
Iris::free_cap (reply)
|
|
|
|
Iris::free_cap (page)
|
|
|
|
dirty = true
|
2010-10-07 10:52:04 +03:00
|
|
|
//kdebug_num (current_block)
|
|
|
|
//kdebug ("!")
|
2010-09-02 00:27:14 +03:00
|
|
|
break
|
|
|
|
case Iris::WBlock::TRUNCATE:
|
|
|
|
default:
|
|
|
|
Iris::recv.reply.invoke (Iris::ERR_INVALID_OPERATION)
|
|
|
|
break
|