1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-06-28 18:59:51 +03:00

add partial nand and sd/mmc drivers

This commit is contained in:
Bas Wijnen 2010-05-15 18:42:17 +02:00
parent 8c7cac36e6
commit 6bf41032d8
13 changed files with 584 additions and 132 deletions

View File

@ -23,7 +23,7 @@ CC = $(CROSS)gcc
LD = $(CROSS)ld
OBJCOPY = $(CROSS)objcopy
headers = kernel.hh iris.hh ui.hh $(arch_headers)
headers = kernel.hh iris.hh devices.hh ui.hh $(arch_headers)
iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
BUILT_SOURCES = $(iris_sources) $(boot_sources)
@ -59,7 +59,7 @@ clean:
debug:
stty -F $(SERIAL) raw 9600
cat $(SERIAL)
while : ; do cat $(SERIAL) ; done
.PHONY: clean
.PRECIOUS: iris.hh kernel.hh ui.hh boot-programs/crt0.o
.PRECIOUS: $(headers) boot-programs/crt0.o source/crt0.o

View File

@ -24,66 +24,66 @@
namespace Iris:
// Caplist interface.
template <typename _T> //
struct Caplist : public Iris::Caps:
Caplist (Iris::Caps c = Iris::Cap ()) : Iris::Caps (c):
Caplist <_T> create (unsigned size, Iris::Memory mem = Iris::my_memory):
struct Caplist : public Caps:
Caplist (Caps c = Cap ()) : Caps (c):
Caplist <_T> create (unsigned size, Memory mem = my_memory):
return Caplist <_T> (mem.create_caps (size))
void set (unsigned idx, _T value):
return Iris::Caps::set (idx, value)
return Caps::set (idx, value)
_T get (unsigned idx):
return _T (Iris::Caps::get (idx))
return _T (Caps::get (idx))
/// A block of data with a size and content. Any character can be stored in it (including '\0').
struct String : public Iris::Cap:
String (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
struct String : public Cap:
String (Cap c = Cap ()) : Cap (c):
enum request:
GET_SIZE = 0x2001
GET_CHARS
GET_PAGE
ID
/// Get the size of the string.
Iris::Num get_size ():
Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
/// Get exactly 16 characters. The index must be word-aligned.
char *get_chars (Iris::Num idx, char buffer[16]):
char *get_chars (Num idx, char buffer[16]):
call (CAP_MASTER_DIRECT | GET_CHARS, idx)
unsigned *b = (unsigned *)buffer
b[0] = Iris::recv.data[0].l
b[1] = Iris::recv.data[0].h
b[2] = Iris::recv.data[1].l
b[3] = Iris::recv.data[1].h
b[0] = recv.data[0].l
b[1] = recv.data[0].h
b[2] = recv.data[1].l
b[3] = recv.data[1].h
return buffer
/// Helper function for get_page.
static Iris::Page _create_paying_page ():
Iris::Page ret = Iris::my_memory.create_page ()
ret.set_flags (Iris::Page::PAYING, Iris::Page::PAYING)
static Page _create_paying_page ():
Page ret = my_memory.create_page ()
ret.set_flags (Page::PAYING, Page::PAYING)
return ret
/// Get a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned.
Cap get_page (Iris::Num idx, Iris::Page ret = _create_paying_page ()):
Cap get_page (Num idx, Page ret = _create_paying_page ()):
ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
return ret
/// A writable String.
struct WString : public String:
WString (Iris::Cap c = Iris::Cap ()) : String (c):
WString (Cap c = Cap ()) : String (c):
enum request:
TRUNCATE = String::ID
SET_CHARS
SET_PAGE
ID
/// Set the size of the string. Strings may have a limit to this setting.
void truncate (Iris::Num size):
void truncate (Num size):
call (CAP_MASTER_DIRECT | TRUNCATE, size)
/// Set exactly 4 characters. The index must be word-aligned.
void set_chars (Iris::Num idx, char buffer[4]):
call (Iris::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
void set_chars (Num idx, char buffer[4]):
call (Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx)
/// Overwrite a page from the string. This need not be implemented for strings smaller than PAGE_SIZE. The index must be page-aligned. The caller may lose the frame in the transaction.
void set_page (Iris::Num idx, Iris::Page page):
void set_page (Num idx, Page page):
ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
// Every process which wants to be switchable through a terminal must implement this interface.
struct Device : public Iris::Cap:
Device (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
struct Device : public Cap:
Device (Cap c = Cap ()) : Cap (c):
enum request:
RESET = WString::ID
ID
@ -91,40 +91,49 @@ namespace Iris:
void reset ():
call (CAP_MASTER_DIRECT | RESET)
struct Elfrun : public Iris::Cap:
Elfrun (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
struct Event : public Device:
Event (Cap c = Cap ()) : Device (c):
enum request:
RUN_STRING = Device::ID
SET_CB = Device::ID
ID
// Set the event callback. Pending event emit to the new callback immediately.
void set_cb (Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
struct Elfrun : public Cap:
Elfrun (Cap c = Cap ()) : Cap (c):
enum request:
RUN_STRING = Event::ID
RUN_CAPS
ID
enum arg_pos:
PARENT_MEMORY
DATA
PARENT
Iris::Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
Iris::Caps caps = Iris::my_memory.create_caps (3)
Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32):
Caps caps = my_memory.create_caps (3)
caps.set (PARENT_MEMORY, parent_memory)
caps.set (DATA, data)
caps.set (PARENT, parent)
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Iris::Num (num_slots, num_caps))
Iris::Caps ret = Iris::get_arg ()
Iris::my_memory.destroy (caps)
Iris::free_cap (caps)
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Num (num_slots, num_caps))
Caps ret = get_arg ()
my_memory.destroy (caps)
free_cap (caps)
return ret
Iris::Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
Iris::Caps caps = Iris::my_memory.create_caps (3)
Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32):
Caps caps = my_memory.create_caps (3)
caps.set (PARENT_MEMORY, parent_memory)
caps.set (DATA, data)
caps.set (PARENT, parent)
iocall (caps.copy (), Iris::Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Iris::Num (num_slots, num_caps))
Iris::Caps ret = Iris::get_arg ()
Iris::my_memory.destroy (caps)
Iris::free_cap (caps)
iocall (caps.copy (), Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Num (num_slots, num_caps))
Caps ret = get_arg ()
my_memory.destroy (caps)
free_cap (caps)
return ret
// Interface for talking to the parent process.
struct Parent : public Iris::Cap:
Parent (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
struct Parent : public Cap:
Parent (Cap c = Cap ()) : Cap (c):
enum request:
GET_CAPABILITY = Elfrun::ID
PROVIDE_CAPABILITY
@ -136,43 +145,39 @@ namespace Iris:
ID
// Get a handle.
template <typename _T> _T get_capability (unsigned num = 0):
icall (Iris::Num (CAP_MASTER_DIRECT | GET_CAPABILITY, num), _T::ID)
return Iris::get_arg ()
icall (Num (CAP_MASTER_DIRECT | GET_CAPABILITY, num), _T::ID)
return get_arg ()
// Provide a device handle.
template <typename _T> void provide_capability (Cap cap, unsigned num = 0):
ocall (cap, Iris::Num (CAP_MASTER_DIRECT | PROVIDE_CAPABILITY, num), _T::ID)
ocall (cap, Num (CAP_MASTER_DIRECT | PROVIDE_CAPABILITY, num), _T::ID)
// Wait until a device is used by the caller again.
template <typename _T> void wait (unsigned num = 0):
call (Iris::Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
call (Num (CAP_MASTER_DIRECT | WAIT, num), _T::ID)
// Get memory paid for by another thread, which cannot be inspected or changed by that thread. The memory can be inspected and changed by the user (owning both threads). The call will fail when the threads are not owned by the same user.
Iris::Memory get_memory (Iris::Cap target):
Memory get_memory (Cap target):
iocall (target, CAP_MASTER_DIRECT | GET_MEMORY)
return Iris::get_arg ()
return get_arg ()
// Get a handle that another thread can use to call get_memory on. The actual limit on the created memory is floor(limit, thread address space limit).
Iris::Cap provide_memory (unsigned limit):
Cap provide_memory (unsigned limit):
icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
return Iris::get_arg ()
return get_arg ()
// Signal the parent that the initialisation phase is over.
void init_done (Iris::Num stage = 0):
void init_done (Num stage = 0):
call (CAP_MASTER_DIRECT | INIT_DONE, stage)
// Exit the program. The parent does not reply, but kills the process.
void exit (Iris::Num code):
void exit (Num code):
call (CAP_MASTER_DIRECT | EXIT, code)
// Keyboard interface.
struct Keyboard : public Device:
Keyboard (Iris::Cap c = Iris::Cap ()) : Iris::Device (c):
struct Keyboard : public Event:
Keyboard (Cap c = Cap ()) : Event (c):
enum request:
SET_CB = Parent::ID
GET_NUM_KEYS
GET_NUM_KEYS = Parent::ID
GET_KEYS
ID
// At event: the callback is called with a keycode. One bit defines if it's a press or release event.
enum constant:
RELEASE = 1 << 31
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
void set_cb (Iris::Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
// Get the number of keys on the keyboard.
unsigned get_num_keys ():
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
@ -182,21 +187,21 @@ namespace Iris:
// Buzzer interface.
struct Buzzer : public Device:
Buzzer (Iris::Cap c = Iris::Cap ()) : Iris::Device (c):
Buzzer (Cap c = Cap ()) : Device (c):
enum request:
BEEP = Keyboard::ID
STOP
ID
// Emit a beep of specified frequency, time and volume. Volume may not be supported. If an other beep is in progress, it is aborted.
void beep (unsigned freq, unsigned ms, unsigned volume, Iris::Cap cb = Iris::Cap ()):
ocall (cb, Iris::Num (CAP_MASTER_DIRECT | BEEP, volume), Iris::Num (freq, ms))
void beep (unsigned freq, unsigned ms, unsigned volume, Cap cb = Cap ()):
ocall (cb, Num (CAP_MASTER_DIRECT | BEEP, volume), Num (freq, ms))
// Abort current beep, if any.
void stop ():
call (CAP_MASTER_DIRECT | STOP)
// Display interface.
struct Display : public Device:
Display (Iris::Cap c = Iris::Cap ()) : Iris::Device (c):
Display (Cap c = Cap ()) : Device (c):
enum request:
SET_EOF_CB = Buzzer::ID
MAP_FB
@ -205,22 +210,22 @@ namespace Iris:
ID
// Register an end-of-frame callback.
// At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events.
void set_eof_cb (Iris::Cap cb):
void set_eof_cb (Cap cb):
ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
// Map the framebuffer into memory.
Iris::Caps map_fb (unsigned address, Iris::Memory mem = Iris::my_memory, bool use = true):
iocall (mem, Iris::Num (CAP_MASTER_DIRECT | MAP_FB, use ? 1 : 0), address)
return Iris::get_arg ()
void unmap_fb (Iris::Caps caps):
Caps map_fb (unsigned address, Memory mem = my_memory, bool use = true):
iocall (mem, Num (CAP_MASTER_DIRECT | MAP_FB, use ? 1 : 0), address)
return get_arg ()
void unmap_fb (Caps caps):
ocall (caps, CAP_MASTER_DIRECT | UNMAP_FB)
// Get information about the display.
void get_info ():
// TODO: Interface is to be designed.
Iris::panic (0, "using undefined interface Display::get_info ()")
panic (0, "using undefined interface Display::get_info ()")
// Numerical setting, such as a display backlight.
struct Setting : public Iris::Device:
Setting (Iris::Cap c = Iris::Cap ()) : Iris::Device (c):
struct Setting : public Device:
Setting (Cap c = Cap ()) : Device (c):
enum request:
SET = Display::ID
GET_RANGE
@ -238,8 +243,8 @@ namespace Iris:
// Seekable is not a class, it is identical to [W]String.
// Directory interface.
struct Directory : public Iris::Cap:
Directory (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
struct Directory : public Cap:
Directory (Cap c = Cap ()) : Cap (c):
enum request:
GET_SIZE = Setting::ID
GET_NAME
@ -249,19 +254,19 @@ namespace Iris:
UNLOCK_RO
ID
// Get the number of entries in this directory.
Iris::Num get_size ():
Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE)
// Get the filename.
String get_name (Iris::Num idx):
String get_name (Num idx):
icall (CAP_MASTER_DIRECT | GET_NAME, idx)
return Iris::get_arg ()
return get_arg ()
// Get the file.
Iris::Cap get_file_ro (Iris::Num idx):
Cap get_file_ro (Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
return Iris::get_arg ()
return get_arg ()
// Get file info. TODO: define possible types.
Iris::Num get_file_info (Iris::Num idx, unsigned type):
return icall (Iris::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
Num get_file_info (Num idx, unsigned type):
return icall (Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx)
// Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
void lock_ro ():
call (CAP_MASTER_DIRECT | LOCK_RO)
@ -269,7 +274,7 @@ namespace Iris:
void unlock_ro ():
call (CAP_MASTER_DIRECT | UNLOCK_RO)
struct WDirectory : public Directory:
WDirectory (Iris::Cap c = Iris::Cap ()) : Directory (c):
WDirectory (Cap c = Cap ()) : Directory (c):
enum request:
GET_FILE = Directory::ID
CREATE_FILE
@ -278,15 +283,15 @@ namespace Iris:
UNLOCK
ID
// Get the file.
Iris::Cap get_file (Iris::Num idx):
Cap get_file (Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE, idx)
return Iris::get_arg ()
return get_arg ()
// Create a new file. After this, any index may map to a different file.
Iris::Cap create_file (String name):
Cap create_file (String name):
icall (CAP_MASTER_DIRECT | CREATE_FILE)
return Iris::get_arg ()
return get_arg ()
// Delete a file. After this, any index may map to a different file.
void delete_file (Iris::Num idx):
void delete_file (Num idx):
call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Lock the directory. Write operations can only be done when the directory is locked.
void lock ():
@ -297,34 +302,34 @@ namespace Iris:
// A filesystem turns a String into a Directory.
struct Filesystem : public Device:
Filesystem (Iris::Cap c = Iris::Cap ()) : Device (c):
Filesystem (Cap c = Cap ()) : Device (c):
enum request:
USE_DEVICE = WDirectory::ID
USE_DEVICE_RO
ID
WDirectory use_device (WString dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
return Iris::get_arg ()
return get_arg ()
Directory use_device_ro (String dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
return Iris::get_arg ()
return get_arg ()
// Stream interface.
struct Stream : public Iris::Cap:
Stream (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
struct Stream : public Cap:
Stream (Cap c = Cap ()) : Cap (c):
enum request:
READ = Filesystem::ID
WRITE
ID
// Try to read size bytes. Returns the number of bytes successfully read.
Iris::Num read (Iris::Num size, bool block):
return icall (Iris::Num (CAP_MASTER_DIRECT | READ, block), size)
Num read (Num size, bool block):
return icall (Num (CAP_MASTER_DIRECT | READ, block), size)
// Try to write size bytes. Returns the number of bytes successfully written.
Iris::Num write (String s, Iris::Num size):
Num write (String s, Num size):
return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
struct UI : public Iris::Cap:
UI (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c):
struct UI : public Cap:
UI (Cap c = Cap ()) : Cap (c):
enum request:
GET_STATE = Stream::ID
EVENT
@ -332,16 +337,16 @@ namespace Iris:
ID
enum constant:
INPUT = 1 << 31
void get_state (Iris::Cap cap):
void get_state (Cap cap):
ocall (cap, CAP_MASTER_DIRECT | GET_STATE)
void event (unsigned code, unsigned value = 0):
call (Iris::Num (CAP_MASTER_DIRECT | EVENT, code), value)
call (Num (CAP_MASTER_DIRECT | EVENT, code), value)
void exit ():
call (CAP_MASTER_DIRECT | EXIT)
// Block device interface.
struct Block_device : public WString:
Block_device (Iris::Cap c = Iris::Cap ()) : WString (c):
Block_device (Cap c = Cap ()) : WString (c):
// TODO: to be designed.

View File

@ -5,6 +5,8 @@
driver driver_gpio = "gpio.elf"
program alarm = "alarm.elf"
program gui = "gui.elf"
#driver nand = "nand.elf"
driver sdmmc = "sd+mmc.elf"
# receive <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
receive driver_lcd / Display = display
@ -12,7 +14,9 @@
receive driver_buzzer / Buzzer = buzzer
receive driver_gpio / Keyboard , 0 = keyboard
receive driver_gpio / Keyboard , 1 = sysreq
receive driver_gpio / Event = sdmmc_gpio
receive alarm / UI = ui
receive sdmmc / WString = sdmmc
# sysreq <cap> use a capability as the system request keyboard.
sysreq sysreq
@ -23,6 +27,7 @@
give gui / Setting = display_bright
give gui / Buzzer = buzzer
give gui / Keyboard = keyboard
give sdmmc / Event = sdmmc_gpio
# include <file> include a file as another config file.

View File

@ -27,9 +27,9 @@ LDFLAGS = --omagic -Ttext $(load)
arch_iris_sources = mips/interrupts.cc mips/arch.cc
boot_sources = mips/init.cc mips/nanonote/board.cc
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh devices.hh
arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh
boot_threads = bootinit udc
programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm gui
programs = init gpio lcd bsquare ball buzzer metronome elfrun alarm gui nand sd+mmc
all: test

View File

@ -46,6 +46,13 @@ void board_init ():
// Use some gpio pins for lcd.
gpio_as_gpio (2, (1 << 21) | (1 << 22) | (1 << 23))
gpio_as_output (2, (1 << 21) | (1 << 22) | (1 << 23))
// And some for sd/mmc.
gpio_as_gpio (3, (1 << 0) | (1 << 2))
gpio_as_output (3, 1 << 2)
gpio_as_input (3, 1 << 0)
gpio_disable_pull (3, (1 << 0) | (1 << 2))
// Disable power to sd/mmc by default.
gpio_set (3, 1 << 2)
// Set up keyboard: this breaks uart receive.
gpio_as_gpio (3, 0x05fc0000)
// Set up timed interrupts.

View File

@ -120,6 +120,7 @@ static void __map_io (unsigned physical, unsigned mapping):
#define map_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (1)
#define map_gpio() do { __map_io (GPIO_PHYSICAL, GPIO_BASE); } while (0)
#define map_aic() do { __map_io (AIC_PHYSICAL, AIC_BASE); } while (0)
#define map_msc() do { __map_io (MSC_PHYSICAL, MSC_BASE); } while (0)
#define map_uart0() do { __map_io (UART0_PHYSICAL, UART0_BASE); } while (0)
#define map_i2c() do { __map_io (I2C_PHYSICAL, I2C_BASE); } while (0)
#define map_ssi() do { __map_io (SSI_PHYSICAL, SSI_BASE); } while (0)
@ -3140,14 +3141,8 @@ static void msc_set_cmdat_res_format(unsigned r):
#define msc_rd_rxfifo() ( MSC_RXFIFO )
#define msc_wr_txfifo(v) ( MSC_TXFIFO = v )
static void msc_reset():
MSC_STRPCL = MSC_STRPCL_RESET
while MSC_STAT & MSC_STAT_IS_RESETTING:
#define msc_start_clk() (MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START)
#define msc_stop_clk() (MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP)
#define MMC_CLK 19169200
#define SD_CLK 24576000

View File

@ -12,11 +12,12 @@ enum Outs:
ALARM
NUM_OUTS
static UI <NUM_INS, NUM_OUTS> ui
static UI <NUM_INS, NUM_OUTS>::in <unsigned> total_time
static UI <NUM_INS, NUM_OUTS>::in_event do_start
static UI <NUM_INS, NUM_OUTS>::out <unsigned> current_time
static UI <NUM_INS, NUM_OUTS>::out_event do_alarm
typedef UI <NUM_INS, NUM_OUTS> ui_t
static ui_t ui
static ui_t::in <unsigned> total_time
static ui_t::in_event do_start
static ui_t::out <unsigned> current_time
static ui_t::out_event do_alarm
static bool ticking
@ -56,7 +57,8 @@ Iris::Num start ():
switch Iris::recv.protected_data.l:
case ~0:
// alarm.
current_time = current_time - 1
if current_time:
current_time = current_time - 1
if !current_time:
do_alarm ()
ticking = false

View File

@ -137,7 +137,7 @@ extern "C":
Iris::recv.reply = Iris::alloc_cap ()
Iris::recv.arg = Iris::alloc_cap ()
Iris::Num ret = start ()
Iris::my_parent.invoke (~0, ret)
Iris::my_parent.exit (ret)
Iris::my_memory.destroy (Iris::my_thread)
// The program no longer exists. If it somehow does, generate an address fault.
while true:

View File

@ -25,6 +25,7 @@ enum ins:
static Iris::Display display
static Iris::Buzzer buzzer
static unsigned *framebuffer
static unsigned alarming
enum PD:
UI
@ -151,38 +152,57 @@ static void draw_time (bool upper, unsigned time):
draw_num (upper, 3, time / 10)
draw_num (upper, 4, time % 10)
static void beep ():
buzzer.beep (4 * 440, 1000, ~0)
static void do_alarm ():
static unsigned tune[] = { 4, 6, 6, 5, 7, 7 }
if ++alarming > sizeof (tune) / sizeof (*tune):
alarming = 1
buzzer.beep (tune[alarming - 1] * 220, 300, ~0)
Iris::my_receiver.set_alarm (HZ / 3)
Iris::Num start ():
Iris::my_parent.init_done ()
display = Iris::my_parent.get_capability <Iris::Display> ()
Iris::Setting bright = Iris::my_parent.get_capability <Iris::Setting> ()
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
Iris::UI app = Iris::my_parent.get_capability <Iris::UI> ()
Iris::Cap cb = Iris::my_receiver.create_capability (UI)
framebuffer = (unsigned *)0x15000
Iris::Caps fb = display.map_fb ((unsigned)framebuffer)
bright.set (bright.get_range ())
unsigned screen_max = bright.get_range ()
bright.set (0)
bool screen_on = false
Iris::Cap cb = Iris::my_receiver.create_capability (UI)
app.get_state (cb.copy ())
Iris::free_cap (cb)
cb = Iris::my_receiver.create_capability (KBD)
keyboard.set_cb (cb.copy ())
Iris::free_cap (cb)
draw_num (false, 2, 10)
draw_num (true, 2, 10)
unsigned total_time = 0
alarming = 0
while true:
Iris::wait ()
switch Iris::recv.protected_data.l:
case ~0:
// Alarm.
if alarming:
do_alarm ()
break
case UI:
switch Iris::recv.data[0].l:
case CURRENT_TIME:
draw_time (false, Iris::recv.data[1].l)
break
case ALARM:
beep ()
do_alarm ()
break
case TOTAL_TIME | Iris::UI::INPUT:
total_time = Iris::recv.data[1].l
@ -194,6 +214,7 @@ Iris::Num start ():
case KBD:
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
break
alarming = 0
switch Iris::recv.data[0].l:
case Key::VOLUME_UP:
total_time += 60
@ -236,3 +257,11 @@ Iris::Num start ():
break
case Key::ENTER:
app.event (START)
break
case Key::BACKSPACE:
screen_on = !screen_on
if screen_on:
bright.set (screen_max)
else:
bright.set (0)
break

View File

@ -269,6 +269,7 @@ static Type types[] = {
{ "String", 6, Iris::String::ID },
{ "WString", 7, Iris::WString::ID },
{ "Device", 6, Iris::Device::ID },
{ "Event", 5, Iris::Event::ID },
{ "Parent", 6, Iris::Parent::ID },
{ "Keyboard", 8, Iris::Keyboard::ID },
{ "Buzzer", 6, Iris::Buzzer::ID },

199
source/nand.ccp Normal file
View File

@ -0,0 +1,199 @@
#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"
// The following defines are taken from mtd/nand.h in the Linux source.
// Standard NAND flash commands
#define CMD_READ0 0
#define CMD_READ1 1
#define CMD_RNDOUT 5
#define CMD_PAGEPROG 0x10
#define CMD_READOOB 0x50
#define CMD_ERASE1 0x60
#define CMD_STATUS 0x70
#define CMD_STATUS_MULTI 0x71
#define CMD_SEQIN 0x80
#define CMD_RNDIN 0x85
#define CMD_READID 0x90
#define CMD_ERASE2 0xd0
#define CMD_RESET 0xff
// Extended commands for large page devices
#define CMD_READSTART 0x30
#define CMD_RNDOUTSTART 0xE0
#define CMD_CACHEDPROG 0x15
// Extended commands for AG-AND device
// Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
// there is no way to distinguish that from NAND_CMD_READ0
// until the remaining sequence of commands has been completed
// so add a high order bit and mask it off in the command.
#define CMD_DEPLETE1 0x100
#define CMD_DEPLETE2 0x38
#define CMD_STATUS_MULTI 0x71
#define CMD_STATUS_ERROR 0x72
// multi-bank error status (banks 0-3)
#define CMD_STATUS_ERROR0 0x73
#define CMD_STATUS_ERROR1 0x74
#define CMD_STATUS_ERROR2 0x75
#define CMD_STATUS_ERROR3 0x76
#define CMD_STATUS_RESET 0x7f
#define CMD_STATUS_CLEAR 0xff
#define CMD_NONE -1
// Status bits
#define STATUS_FAIL 0x01
#define STATUS_FAIL_N1 0x02
#define STATUS_TRUE_READY 0x20
#define STATUS_READY 0x40
#define STATUS_WP 0x80
static volatile char *command
static volatile char *address
static volatile char *data
static unsigned page_bits
static unsigned redundant_bits
static unsigned block_bits
static unsigned word_size
static void unbusy ():
while !(gpio_get_port (2) & (1 << 30)):
Iris::schedule ()
static void reset ():
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)
// Set up.
gpio_as_nand ()
EMC_NFCSR = EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1
// Reset nand.
*command = CMD_RESET
unbusy ()
*command = CMD_READID
*address = 0
unsigned d = *data
//unsigned maker = d
d = *data
//unsigned device = d
d = *data
//unsigned internal_chip_number = 1 << (d & 0x3)
//unsigned cell_type = 2 << ((d >> 2) & 0x3)
//unsigned simultaneously_programmed_pages = 1 << ((d >> 4) & 0x3)
//bool can_interleave_program_between_chips = d & 0x40
//bool can_cache_program = d & 0x80
d = *data
page_bits = 10 + (d & 3)
kdebug ("page bits: ")
kdebug_num (page_bits)
kdebug ("\n")
redundant_bits = (d & 4 ? 4 : 3)
block_bits = 64 + ((d >> 4) & 3)
word_size = (d & 0x40 ? 16 : 8)
//unsigned serial_access_minimum = (d & 0x80 ? 25 : 50)
d = *data
//unsigned num_planes = 1 << ((d >> 2) & 3)
//unsigned plane_bits = 26 + ((d >> 4) & 7)
static void read (unsigned a, char *buffer):
unsigned column = a & ((1 << page_bits) - 1)
unsigned row = a >> page_bits
kdebug ("reading: ")
kdebug_num (a)
kdebug ("/")
kdebug_num (row)
kdebug ("/")
kdebug_num (column)
kdebug (": ")
*command = CMD_READ0
*address = column
*address = column >> 8
*address = row
*address = row >> 8
*address = row >> 16
*command = CMD_READSTART
EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_ERST
// Wait for nand to be ready.
unbusy ()
for unsigned t = 0; t < 0x200; ++t:
buffer[t] = *data
char error[9]
unsigned errcol = (1 << page_bits) + (column >> 5)
*command = CMD_RNDOUT
*address = errcol
*address = errcol >> 8
*command = CMD_RNDOUTSTART
for unsigned t = 0; t < 9; ++t:
error[t] = *data
EMC_NFPAR (0) = ((unsigned *)error)[0]
EMC_NFPAR (1) = ((unsigned *)error)[1]
EMC_NFPAR (2) = error[9]
EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY
while !(EMC_NFINTS & EMC_NFINTS_DECF):
Iris::schedule ()
// delay...
//Iris::schedule ()
unsigned errs = (EMC_NFINTS & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT
Iris::Num start ():
for unsigned i = 0; i < 30; ++i:
Iris::schedule ()
map_emc ()
map_gpio ()
command = (volatile char *)0x15000
address = (volatile char *)0x16000
data = (volatile char *)0x17000
reset ()
char buffer[0x200]
// Send nand contents to serial port.
for unsigned a = 0; a < 0x4000; a += 0x200:
read (a, buffer)
//for unsigned s = 0; s < 0x10; ++s:
for unsigned t = 0; t < 0x10; ++t:
kdebug (" ")
kdebug_num (buffer[0 * 0x20 + t], 2)
kdebug ("\n")
//kdebug ("\n")
// Exit.
return 0

View File

@ -165,22 +165,24 @@ unsigned const DevKbd::keys[NUM_KEYS] = {
#endif
}
class PowerButton:
class Event:
bool state, started
unsigned pin
Iris::Cap cb
public:
void scan ():
if !started:
return
gpio_mask_irq (3, 1 << 29)
bool s = gpio_get_port (3) & (1 << 29)
gpio_mask_irq (3, 1 << pin)
bool s = gpio_get_port (3) & (1 << pin)
if s != state:
state = s
cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
gpio_as_interrupt (3, 1 << 29, !state, true)
gpio_unmask_irq (3, 1 << 29)
PowerButton ():
gpio_as_gpio (3, 29)
gpio_as_interrupt (3, 1 << pin, !state, true)
gpio_unmask_irq (3, 1 << pin)
Event (unsigned p):
pin = p
gpio_as_gpio (3, pin)
state = true
started = false
void set_cb (Iris::Cap c):
@ -195,19 +197,24 @@ class PowerButton:
enum codes:
KBD_DEV = 32
PWR
SDMMC
Iris::Num start ():
map_gpio ()
DevKbd kbd
PowerButton pwr
Event pwr (29)
Event sdmmc (0)
Iris::Device dev = Iris::my_receiver.create_capability (KBD_DEV)
Iris::Keyboard dev = Iris::my_receiver.create_capability (KBD_DEV)
Iris::Keyboard pw = Iris::my_receiver.create_capability (PWR)
Iris::Event sm = Iris::my_receiver.create_capability (SDMMC)
Iris::my_parent.provide_capability <Iris::Keyboard> (dev.copy (), 0)
Iris::my_parent.provide_capability <Iris::Keyboard> (pw.copy (), 1)
Iris::my_parent.provide_capability <Iris::Event> (sm.copy ())
Iris::free_cap (dev)
Iris::free_cap (pw)
Iris::free_cap (sm)
Iris::my_parent.init_done ()
if kbd.scanning ():
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
@ -225,6 +232,7 @@ Iris::Num start ():
// Interrupt.
pwr.scan ()
kbd.scan ()
sdmmc.scan ()
if kbd.scanning ():
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
Iris::register_interrupt (IRQ_GPIO3)
@ -235,7 +243,7 @@ Iris::Num start ():
case Iris::Device::RESET:
Iris::recv.reply.invoke ()
break
case Iris::Keyboard::SET_CB:
case Iris::Event::SET_CB:
Iris::Cap reply = Iris::get_reply ()
kbd.active (Iris::get_arg ())
reply.invoke ()
@ -256,7 +264,7 @@ Iris::Num start ():
case Iris::Device::RESET:
Iris::recv.reply.invoke ()
break
case Iris::Keyboard::SET_CB:
case Iris::Event::SET_CB:
Iris::Cap reply = Iris::get_reply ()
pwr.set_cb (Iris::get_arg ())
reply.invoke ()
@ -268,6 +276,23 @@ Iris::Num start ():
kdebug ("\n")
break
break
case SDMMC:
switch Iris::recv.data[0].l:
case Iris::Device::RESET:
Iris::recv.reply.invoke ()
break
case Iris::Event::SET_CB:
Iris::Cap reply = Iris::get_reply ()
sdmmc.set_cb (Iris::get_arg ())
reply.invoke ()
Iris::free_cap (reply)
break
default:
kdebug ("SdMmc gpio invalid request\n")
kdebug_num (Iris::recv.data[0].l)
kdebug ("\n")
break
break
default:
kdebug ("keyboard unknown num: ")
kdebug_num (Iris::recv.protected_data.h)

184
source/sd+mmc.ccp Normal file
View File

@ -0,0 +1,184 @@
#pypp 0
// Iris: micro-kernel for a capability-based operating system.
// source/sd+mmc.ccp: sd+mmc 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"
class Mmc:
static unsigned const PORT = 3
static unsigned const PIN = 2
bool check_sdio ()
void check_sdmem ()
void check_mmc ()
public:
void reset ()
void detect ()
void release ()
void interrupt ()
void Mmc::reset ():
// Enable slow clock to msc.
CPM_MSCCDR = ~0
cpm_start_msc ()
// Enable msc pins.
gpio_as_msc ()
// Disable power to card.
gpio_as_gpio (PORT, 1 << PIN)
gpio_as_output (PORT, 1 << PIN)
gpio_disable_pull (PORT, 1 << PIN)
gpio_set (PORT, 1 << PIN)
// Stop the clock.
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
while MSC_STAT & MSC_STAT_CLK_EN:
Iris::schedule ()
// Initialize registers.
MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_128
MSC_RESTO = 64
MSC_RDTO = ~0
MSC_BLKLEN = 0x200
MSC_NOB = 0
MSC_IMASK = ~0
MSC_ARG = 0
// Reset controller and inserted devices.
MSC_STRPCL = MSC_STRPCL_RESET
while MSC_STAT & MSC_STAT_IS_RESETTING:
Iris::schedule ()
// Start the clock.
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
// Set cards, if any, to idle.
MSC_CMD = 0
MSC_CMDAT = MSC_CMDAT_RESPONSE_NONE
msc_start_op ()
while !msc_ireg_end_cmd_res ():
Iris::schedule ()
msc_ireg_clear_end_cmd_res ()
// Reset SDIO device, if any.
MSC_CMD = 52
MSC_ARG = 0x88000C08
MSC_CMDAT = MSC_CMDAT_RESPONSE_R5
msc_start_op ()
while !msc_ireg_end_cmd_res ():
Iris::schedule ()
msc_ireg_clear_end_cmd_res ()
bool Mmc::check_sdio ():
// 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
// 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
// 4. If C-bit in the response is ready (the initialization has finished), go to 6.
// 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
// 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else
// it is only a SDIO card.
// 7. If it is a combo card, go to check SDMEM to initialize the memory part.
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned
// from the response.
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
// 10. Go to check MMC, because we can assure that there is no SDMEM card.
return false
void Mmc::check_sdmem ():
// 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
// 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
// 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
// 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
// 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
// 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
// 10. Go to check MMC.
void Mmc::check_mmc ():
// 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
// 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
// 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
// 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
// 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
// 6. If the response timeout occurs, goto 9.
// 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
// 8. If there are other MMC cards, then go to 5.
void Mmc::detect ():
kdebug ("mmc detect\n")
gpio_clear (PORT, 1 << PIN)
if check_sdio ():
check_sdmem ()
check_mmc ()
void Mmc::release ():
kdebug ("mmc release\n")
gpio_set (PORT, 1 << PIN)
void Mmc::interrupt ():
kdebug ("mmc interrupt\n")
enum types:
DETECT
REQUEST
Iris::Num start ():
map_msc ()
map_gpio ()
map_cpm ()
Mmc mmc
mmc.reset ()
Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
Iris::Cap cap = Iris::my_receiver.create_capability (DETECT)
detect.set_cb (cap.copy ())
cap.invoke (~0)
Iris::free_cap (cap)
// Get a message from the queue. This is either the "there is no card" message, or the message we just sent.
Iris::wait ()
if Iris::recv.data[0].l != ~0:
// If it was "there is no card", the message we sent is still in the queue.
Iris::wait ()
else:
// Otherwise, there is a card.
mmc.detect ()
cap = Iris::my_receiver.create_capability (REQUEST)
Iris::my_parent.provide_capability <Iris::WString> (cap.copy ())
Iris::free_cap (cap)
Iris::my_parent.init_done ()
while true:
Iris::wait ()
switch Iris::recv.protected_data.l:
case DETECT:
if Iris::recv.data[0].l:
mmc.detect ()
else:
mmc.release ()
break
case IRQ_MSC:
mmc.interrupt ()
break
case REQUEST:
kdebug ("sd+mmc request\n")
break
default:
Iris::panic (0, "unexpected request source for sd+mmc")