1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-06-28 23:29:50 +03:00
iris/source/nand.ccp

181 lines
5.4 KiB
COBOL

#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"
#define debug Iris::debug
#define DELAY Iris::schedule
#include "nand.hh"
#undef debug
static unsigned *cache
static bool dirty
static unsigned current_block
static void sync ():
//Iris::debug ("erasing %x\n", current_block << block_bits)
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)])
static void read_block (unsigned b):
if b == current_block:
return
if current_block != ~0 && dirty:
sync ()
current_block = b
//kdebug ("setting current block to ")
//kdebug_num (b)
//kdebug ("\n")
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 ():
map_emc ()
map_gpio ()
// Arbitrary addresses where the pages are mapped.
command = (volatile char *)0x15000
address = (volatile char *)0x16000
data = (volatile char *)0x17000
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 ()
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)
Iris::my_memory.map (page, (unsigned)cache + (p << PAGE_BITS))
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)
Iris::my_parent.provide_capability <Iris::WBlock> (cap.copy ())
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
#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)
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:
tmp_addr[(offset >> 2) + t] = cache[t + (row << (9 - 2))]
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)
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
#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)
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; t += 4:
cache[(offset + t + (row << 9)) >> 2] = tmp_addr[(offset + t) >> 2]
tmp.set_flags (0, Iris::Page::FRAME)
reply.invoke ()
Iris::free_cap (reply)
Iris::free_cap (page)
dirty = true
//kdebug_num (current_block)
//kdebug ("!")
break
case Iris::WBlock::TRUNCATE:
default:
Iris::recv.reply.invoke (Iris::ERR_INVALID_OPERATION)
break