1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-29 21:12:25 +02: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 LD = $(CROSS)ld
OBJCOPY = $(CROSS)objcopy 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) iris_sources = panic.cc data.cc alloc.cc memory.cc invoke.cc schedule.cc $(arch_iris_sources)
BUILT_SOURCES = $(iris_sources) $(boot_sources) BUILT_SOURCES = $(iris_sources) $(boot_sources)
@ -59,7 +59,7 @@ clean:
debug: debug:
stty -F $(SERIAL) raw 9600 stty -F $(SERIAL) raw 9600
cat $(SERIAL) while : ; do cat $(SERIAL) ; done
.PHONY: clean .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: namespace Iris:
// Caplist interface. // Caplist interface.
template <typename _T> // template <typename _T> //
struct Caplist : public Iris::Caps: struct Caplist : public Caps:
Caplist (Iris::Caps c = Iris::Cap ()) : Iris::Caps (c): Caplist (Caps c = Cap ()) : Caps (c):
Caplist <_T> create (unsigned size, Iris::Memory mem = Iris::my_memory): Caplist <_T> create (unsigned size, Memory mem = my_memory):
return Caplist <_T> (mem.create_caps (size)) return Caplist <_T> (mem.create_caps (size))
void set (unsigned idx, _T value): void set (unsigned idx, _T value):
return Iris::Caps::set (idx, value) return Caps::set (idx, value)
_T get (unsigned idx): _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'). /// A block of data with a size and content. Any character can be stored in it (including '\0').
struct String : public Iris::Cap: struct String : public Cap:
String (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c): String (Cap c = Cap ()) : Cap (c):
enum request: enum request:
GET_SIZE = 0x2001 GET_SIZE = 0x2001
GET_CHARS GET_CHARS
GET_PAGE GET_PAGE
ID ID
/// Get the size of the string. /// Get the size of the string.
Iris::Num get_size (): Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE) return call (CAP_MASTER_DIRECT | GET_SIZE)
/// Get exactly 16 characters. The index must be word-aligned. /// 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) call (CAP_MASTER_DIRECT | GET_CHARS, idx)
unsigned *b = (unsigned *)buffer unsigned *b = (unsigned *)buffer
b[0] = Iris::recv.data[0].l b[0] = recv.data[0].l
b[1] = Iris::recv.data[0].h b[1] = recv.data[0].h
b[2] = Iris::recv.data[1].l b[2] = recv.data[1].l
b[3] = Iris::recv.data[1].h b[3] = recv.data[1].h
return buffer return buffer
/// Helper function for get_page. /// Helper function for get_page.
static Iris::Page _create_paying_page (): static Page _create_paying_page ():
Iris::Page ret = Iris::my_memory.create_page () Page ret = my_memory.create_page ()
ret.set_flags (Iris::Page::PAYING, Iris::Page::PAYING) ret.set_flags (Page::PAYING, Page::PAYING)
return ret 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. /// 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) ocall (ret, CAP_MASTER_DIRECT | GET_PAGE, idx)
return ret return ret
/// A writable String. /// A writable String.
struct WString : public String: struct WString : public String:
WString (Iris::Cap c = Iris::Cap ()) : String (c): WString (Cap c = Cap ()) : String (c):
enum request: enum request:
TRUNCATE = String::ID TRUNCATE = String::ID
SET_CHARS SET_CHARS
SET_PAGE SET_PAGE
ID ID
/// Set the size of the string. Strings may have a limit to this setting. /// 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) call (CAP_MASTER_DIRECT | TRUNCATE, size)
/// Set exactly 4 characters. The index must be word-aligned. /// Set exactly 4 characters. The index must be word-aligned.
void set_chars (Iris::Num idx, char buffer[4]): void set_chars (Num idx, char buffer[4]):
call (Iris::Num (CAP_MASTER_DIRECT | SET_CHARS, *(unsigned *)buffer), idx) 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. /// 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) ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx)
// Every process which wants to be switchable through a terminal must implement this interface. // Every process which wants to be switchable through a terminal must implement this interface.
struct Device : public Iris::Cap: struct Device : public Cap:
Device (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c): Device (Cap c = Cap ()) : Cap (c):
enum request: enum request:
RESET = WString::ID RESET = WString::ID
ID ID
@ -91,40 +91,49 @@ namespace Iris:
void reset (): void reset ():
call (CAP_MASTER_DIRECT | RESET) call (CAP_MASTER_DIRECT | RESET)
struct Elfrun : public Iris::Cap: struct Event : public Device:
Elfrun (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c): Event (Cap c = Cap ()) : Device (c):
enum request: 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 RUN_CAPS
ID ID
enum arg_pos: enum arg_pos:
PARENT_MEMORY PARENT_MEMORY
DATA DATA
PARENT PARENT
Iris::Caps run_string (Memory parent_memory, String data, Cap parent, unsigned num_slots = 8, unsigned num_caps = 32): 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 caps = my_memory.create_caps (3)
caps.set (PARENT_MEMORY, parent_memory) caps.set (PARENT_MEMORY, parent_memory)
caps.set (DATA, data) caps.set (DATA, data)
caps.set (PARENT, parent) caps.set (PARENT, parent)
iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Iris::Num (num_slots, num_caps)) iocall (caps.copy (), CAP_MASTER_DIRECT | RUN_STRING, Num (num_slots, num_caps))
Iris::Caps ret = Iris::get_arg () Caps ret = get_arg ()
Iris::my_memory.destroy (caps) my_memory.destroy (caps)
Iris::free_cap (caps) free_cap (caps)
return ret return ret
Iris::Caps run_caps (Memory parent_memory, Caps data, Cap parent, unsigned pages, unsigned num_slots = 8, unsigned num_caps = 32): 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 caps = my_memory.create_caps (3)
caps.set (PARENT_MEMORY, parent_memory) caps.set (PARENT_MEMORY, parent_memory)
caps.set (DATA, data) caps.set (DATA, data)
caps.set (PARENT, parent) caps.set (PARENT, parent)
iocall (caps.copy (), Iris::Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Iris::Num (num_slots, num_caps)) iocall (caps.copy (), Num (CAP_MASTER_DIRECT | RUN_CAPS, pages), Num (num_slots, num_caps))
Iris::Caps ret = Iris::get_arg () Caps ret = get_arg ()
Iris::my_memory.destroy (caps) my_memory.destroy (caps)
Iris::free_cap (caps) free_cap (caps)
return ret return ret
// Interface for talking to the parent process. // Interface for talking to the parent process.
struct Parent : public Iris::Cap: struct Parent : public Cap:
Parent (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c): Parent (Cap c = Cap ()) : Cap (c):
enum request: enum request:
GET_CAPABILITY = Elfrun::ID GET_CAPABILITY = Elfrun::ID
PROVIDE_CAPABILITY PROVIDE_CAPABILITY
@ -136,43 +145,39 @@ namespace Iris:
ID ID
// Get a handle. // Get a handle.
template <typename _T> _T get_capability (unsigned num = 0): template <typename _T> _T get_capability (unsigned num = 0):
icall (Iris::Num (CAP_MASTER_DIRECT | GET_CAPABILITY, num), _T::ID) icall (Num (CAP_MASTER_DIRECT | GET_CAPABILITY, num), _T::ID)
return Iris::get_arg () return get_arg ()
// Provide a device handle. // Provide a device handle.
template <typename _T> void provide_capability (Cap cap, unsigned num = 0): 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. // Wait until a device is used by the caller again.
template <typename _T> void wait (unsigned num = 0): 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. // 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) 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). // 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) icall (CAP_MASTER_DIRECT | PROVIDE_MEMORY, limit)
return Iris::get_arg () return get_arg ()
// Signal the parent that the initialisation phase is over. // 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) call (CAP_MASTER_DIRECT | INIT_DONE, stage)
// Exit the program. The parent does not reply, but kills the process. // 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) call (CAP_MASTER_DIRECT | EXIT, code)
// Keyboard interface. // Keyboard interface.
struct Keyboard : public Device: struct Keyboard : public Event:
Keyboard (Iris::Cap c = Iris::Cap ()) : Iris::Device (c): Keyboard (Cap c = Cap ()) : Event (c):
enum request: enum request:
SET_CB = Parent::ID GET_NUM_KEYS = Parent::ID
GET_NUM_KEYS
GET_KEYS GET_KEYS
ID ID
// At event: the callback is called with a keycode. One bit defines if it's a press or release event. // At event: the callback is called with a keycode. One bit defines if it's a press or release event.
enum constant: enum constant:
RELEASE = 1 << 31 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. // Get the number of keys on the keyboard.
unsigned get_num_keys (): unsigned get_num_keys ():
return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l return call (CAP_MASTER_DIRECT | GET_NUM_KEYS).l
@ -182,21 +187,21 @@ namespace Iris:
// Buzzer interface. // Buzzer interface.
struct Buzzer : public Device: struct Buzzer : public Device:
Buzzer (Iris::Cap c = Iris::Cap ()) : Iris::Device (c): Buzzer (Cap c = Cap ()) : Device (c):
enum request: enum request:
BEEP = Keyboard::ID BEEP = Keyboard::ID
STOP STOP
ID 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. // 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 ()): void beep (unsigned freq, unsigned ms, unsigned volume, Cap cb = Cap ()):
ocall (cb, Iris::Num (CAP_MASTER_DIRECT | BEEP, volume), Iris::Num (freq, ms)) ocall (cb, Num (CAP_MASTER_DIRECT | BEEP, volume), Num (freq, ms))
// Abort current beep, if any. // Abort current beep, if any.
void stop (): void stop ():
call (CAP_MASTER_DIRECT | STOP) call (CAP_MASTER_DIRECT | STOP)
// Display interface. // Display interface.
struct Display : public Device: struct Display : public Device:
Display (Iris::Cap c = Iris::Cap ()) : Iris::Device (c): Display (Cap c = Cap ()) : Device (c):
enum request: enum request:
SET_EOF_CB = Buzzer::ID SET_EOF_CB = Buzzer::ID
MAP_FB MAP_FB
@ -205,22 +210,22 @@ namespace Iris:
ID ID
// Register an end-of-frame callback. // 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. // 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) ocall (cb, CAP_MASTER_DIRECT | SET_EOF_CB)
// Map the framebuffer into memory. // Map the framebuffer into memory.
Iris::Caps map_fb (unsigned address, Iris::Memory mem = Iris::my_memory, bool use = true): Caps map_fb (unsigned address, Memory mem = my_memory, bool use = true):
iocall (mem, Iris::Num (CAP_MASTER_DIRECT | MAP_FB, use ? 1 : 0), address) iocall (mem, Num (CAP_MASTER_DIRECT | MAP_FB, use ? 1 : 0), address)
return Iris::get_arg () return get_arg ()
void unmap_fb (Iris::Caps caps): void unmap_fb (Caps caps):
ocall (caps, CAP_MASTER_DIRECT | UNMAP_FB) ocall (caps, CAP_MASTER_DIRECT | UNMAP_FB)
// Get information about the display. // Get information about the display.
void get_info (): void get_info ():
// TODO: Interface is to be designed. // 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. // Numerical setting, such as a display backlight.
struct Setting : public Iris::Device: struct Setting : public Device:
Setting (Iris::Cap c = Iris::Cap ()) : Iris::Device (c): Setting (Cap c = Cap ()) : Device (c):
enum request: enum request:
SET = Display::ID SET = Display::ID
GET_RANGE GET_RANGE
@ -238,8 +243,8 @@ namespace Iris:
// Seekable is not a class, it is identical to [W]String. // Seekable is not a class, it is identical to [W]String.
// Directory interface. // Directory interface.
struct Directory : public Iris::Cap: struct Directory : public Cap:
Directory (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c): Directory (Cap c = Cap ()) : Cap (c):
enum request: enum request:
GET_SIZE = Setting::ID GET_SIZE = Setting::ID
GET_NAME GET_NAME
@ -249,19 +254,19 @@ namespace Iris:
UNLOCK_RO UNLOCK_RO
ID ID
// Get the number of entries in this directory. // Get the number of entries in this directory.
Iris::Num get_size (): Num get_size ():
return call (CAP_MASTER_DIRECT | GET_SIZE) return call (CAP_MASTER_DIRECT | GET_SIZE)
// Get the filename. // Get the filename.
String get_name (Iris::Num idx): String get_name (Num idx):
icall (CAP_MASTER_DIRECT | GET_NAME, idx) icall (CAP_MASTER_DIRECT | GET_NAME, idx)
return Iris::get_arg () return get_arg ()
// Get the file. // 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) icall (CAP_MASTER_DIRECT | GET_FILE_RO, idx)
return Iris::get_arg () return get_arg ()
// Get file info. TODO: define possible types. // Get file info. TODO: define possible types.
Iris::Num get_file_info (Iris::Num idx, unsigned type): Num get_file_info (Num idx, unsigned type):
return icall (Iris::Num (CAP_MASTER_DIRECT | GET_FILE_INFO, type), idx) 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. // Lock the directory for reading. Multiple read locks can exist simultaneously, but no write lock can be present.
void lock_ro (): void lock_ro ():
call (CAP_MASTER_DIRECT | LOCK_RO) call (CAP_MASTER_DIRECT | LOCK_RO)
@ -269,7 +274,7 @@ namespace Iris:
void unlock_ro (): void unlock_ro ():
call (CAP_MASTER_DIRECT | UNLOCK_RO) call (CAP_MASTER_DIRECT | UNLOCK_RO)
struct WDirectory : public Directory: struct WDirectory : public Directory:
WDirectory (Iris::Cap c = Iris::Cap ()) : Directory (c): WDirectory (Cap c = Cap ()) : Directory (c):
enum request: enum request:
GET_FILE = Directory::ID GET_FILE = Directory::ID
CREATE_FILE CREATE_FILE
@ -278,15 +283,15 @@ namespace Iris:
UNLOCK UNLOCK
ID ID
// Get the file. // Get the file.
Iris::Cap get_file (Iris::Num idx): Cap get_file (Num idx):
icall (CAP_MASTER_DIRECT | GET_FILE, 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. // 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) 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. // 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) call (CAP_MASTER_DIRECT | DELETE_FILE, idx)
// Lock the directory. Write operations can only be done when the directory is locked. // Lock the directory. Write operations can only be done when the directory is locked.
void lock (): void lock ():
@ -297,34 +302,34 @@ namespace Iris:
// A filesystem turns a String into a Directory. // A filesystem turns a String into a Directory.
struct Filesystem : public Device: struct Filesystem : public Device:
Filesystem (Iris::Cap c = Iris::Cap ()) : Device (c): Filesystem (Cap c = Cap ()) : Device (c):
enum request: enum request:
USE_DEVICE = WDirectory::ID USE_DEVICE = WDirectory::ID
USE_DEVICE_RO USE_DEVICE_RO
ID ID
WDirectory use_device (WString dev): WDirectory use_device (WString dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE) ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE)
return Iris::get_arg () return get_arg ()
Directory use_device_ro (String dev): Directory use_device_ro (String dev):
ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO) ocall (dev, CAP_MASTER_DIRECT | USE_DEVICE_RO)
return Iris::get_arg () return get_arg ()
// Stream interface. // Stream interface.
struct Stream : public Iris::Cap: struct Stream : public Cap:
Stream (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c): Stream (Cap c = Cap ()) : Cap (c):
enum request: enum request:
READ = Filesystem::ID READ = Filesystem::ID
WRITE WRITE
ID ID
// Try to read size bytes. Returns the number of bytes successfully read. // Try to read size bytes. Returns the number of bytes successfully read.
Iris::Num read (Iris::Num size, bool block): Num read (Num size, bool block):
return icall (Iris::Num (CAP_MASTER_DIRECT | READ, block), size) return icall (Num (CAP_MASTER_DIRECT | READ, block), size)
// Try to write size bytes. Returns the number of bytes successfully written. // 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) return ocall (s, CAP_MASTER_DIRECT | WRITE, size)
struct UI : public Iris::Cap: struct UI : public Cap:
UI (Iris::Cap c = Iris::Cap ()) : Iris::Cap (c): UI (Cap c = Cap ()) : Cap (c):
enum request: enum request:
GET_STATE = Stream::ID GET_STATE = Stream::ID
EVENT EVENT
@ -332,16 +337,16 @@ namespace Iris:
ID ID
enum constant: enum constant:
INPUT = 1 << 31 INPUT = 1 << 31
void get_state (Iris::Cap cap): void get_state (Cap cap):
ocall (cap, CAP_MASTER_DIRECT | GET_STATE) ocall (cap, CAP_MASTER_DIRECT | GET_STATE)
void event (unsigned code, unsigned value = 0): 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 (): void exit ():
call (CAP_MASTER_DIRECT | EXIT) call (CAP_MASTER_DIRECT | EXIT)
// Block device interface. // Block device interface.
struct Block_device : public WString: 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. // TODO: to be designed.

View File

@ -5,6 +5,8 @@
driver driver_gpio = "gpio.elf" driver driver_gpio = "gpio.elf"
program alarm = "alarm.elf" program alarm = "alarm.elf"
program gui = "gui.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 <name> / <type> [, <index>] = <cap> prepare to accept a capability from a named program.
receive driver_lcd / Display = display receive driver_lcd / Display = display
@ -12,7 +14,9 @@
receive driver_buzzer / Buzzer = buzzer receive driver_buzzer / Buzzer = buzzer
receive driver_gpio / Keyboard , 0 = keyboard receive driver_gpio / Keyboard , 0 = keyboard
receive driver_gpio / Keyboard , 1 = sysreq receive driver_gpio / Keyboard , 1 = sysreq
receive driver_gpio / Event = sdmmc_gpio
receive alarm / UI = ui receive alarm / UI = ui
receive sdmmc / WString = sdmmc
# sysreq <cap> use a capability as the system request keyboard. # sysreq <cap> use a capability as the system request keyboard.
sysreq sysreq sysreq sysreq
@ -23,6 +27,7 @@
give gui / Setting = display_bright give gui / Setting = display_bright
give gui / Buzzer = buzzer give gui / Buzzer = buzzer
give gui / Keyboard = keyboard give gui / Keyboard = keyboard
give sdmmc / Event = sdmmc_gpio
# include <file> include a file as another config file. # 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 arch_iris_sources = mips/interrupts.cc mips/arch.cc
boot_sources = mips/init.cc mips/nanonote/board.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 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 all: test

View File

@ -46,6 +46,13 @@ void board_init ():
// Use some gpio pins for lcd. // Use some gpio pins for lcd.
gpio_as_gpio (2, (1 << 21) | (1 << 22) | (1 << 23)) gpio_as_gpio (2, (1 << 21) | (1 << 22) | (1 << 23))
gpio_as_output (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. // Set up keyboard: this breaks uart receive.
gpio_as_gpio (3, 0x05fc0000) gpio_as_gpio (3, 0x05fc0000)
// Set up timed interrupts. // 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_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (1)
#define map_gpio() do { __map_io (GPIO_PHYSICAL, GPIO_BASE); } while (0) #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_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_uart0() do { __map_io (UART0_PHYSICAL, UART0_BASE); } while (0)
#define map_i2c() do { __map_io (I2C_PHYSICAL, I2C_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) #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_rd_rxfifo() ( MSC_RXFIFO )
#define msc_wr_txfifo(v) ( MSC_TXFIFO = v ) #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_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 MMC_CLK 19169200
#define SD_CLK 24576000 #define SD_CLK 24576000

View File

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

View File

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

View File

@ -25,6 +25,7 @@ enum ins:
static Iris::Display display static Iris::Display display
static Iris::Buzzer buzzer static Iris::Buzzer buzzer
static unsigned *framebuffer static unsigned *framebuffer
static unsigned alarming
enum PD: enum PD:
UI UI
@ -151,38 +152,57 @@ static void draw_time (bool upper, unsigned time):
draw_num (upper, 3, time / 10) draw_num (upper, 3, time / 10)
draw_num (upper, 4, time % 10) draw_num (upper, 4, time % 10)
static void beep (): static void do_alarm ():
buzzer.beep (4 * 440, 1000, ~0) 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::Num start ():
Iris::my_parent.init_done () Iris::my_parent.init_done ()
display = Iris::my_parent.get_capability <Iris::Display> () display = Iris::my_parent.get_capability <Iris::Display> ()
Iris::Setting bright = Iris::my_parent.get_capability <Iris::Setting> () Iris::Setting bright = Iris::my_parent.get_capability <Iris::Setting> ()
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> () Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
buzzer = Iris::my_parent.get_capability <Iris::Buzzer> () buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
Iris::UI app = Iris::my_parent.get_capability <Iris::UI> () Iris::UI app = Iris::my_parent.get_capability <Iris::UI> ()
Iris::Cap cb = Iris::my_receiver.create_capability (UI)
framebuffer = (unsigned *)0x15000 framebuffer = (unsigned *)0x15000
Iris::Caps fb = display.map_fb ((unsigned)framebuffer) 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 ()) app.get_state (cb.copy ())
Iris::free_cap (cb) Iris::free_cap (cb)
cb = Iris::my_receiver.create_capability (KBD) cb = Iris::my_receiver.create_capability (KBD)
keyboard.set_cb (cb.copy ()) keyboard.set_cb (cb.copy ())
Iris::free_cap (cb) Iris::free_cap (cb)
draw_num (false, 2, 10) draw_num (false, 2, 10)
draw_num (true, 2, 10) draw_num (true, 2, 10)
unsigned total_time = 0 unsigned total_time = 0
alarming = 0
while true: while true:
Iris::wait () Iris::wait ()
switch Iris::recv.protected_data.l: switch Iris::recv.protected_data.l:
case ~0:
// Alarm.
if alarming:
do_alarm ()
break
case UI: case UI:
switch Iris::recv.data[0].l: switch Iris::recv.data[0].l:
case CURRENT_TIME: case CURRENT_TIME:
draw_time (false, Iris::recv.data[1].l) draw_time (false, Iris::recv.data[1].l)
break break
case ALARM: case ALARM:
beep () do_alarm ()
break break
case TOTAL_TIME | Iris::UI::INPUT: case TOTAL_TIME | Iris::UI::INPUT:
total_time = Iris::recv.data[1].l total_time = Iris::recv.data[1].l
@ -194,6 +214,7 @@ Iris::Num start ():
case KBD: case KBD:
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE: if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
break break
alarming = 0
switch Iris::recv.data[0].l: switch Iris::recv.data[0].l:
case Key::VOLUME_UP: case Key::VOLUME_UP:
total_time += 60 total_time += 60
@ -236,3 +257,11 @@ Iris::Num start ():
break break
case Key::ENTER: case Key::ENTER:
app.event (START) 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 }, { "String", 6, Iris::String::ID },
{ "WString", 7, Iris::WString::ID }, { "WString", 7, Iris::WString::ID },
{ "Device", 6, Iris::Device::ID }, { "Device", 6, Iris::Device::ID },
{ "Event", 5, Iris::Event::ID },
{ "Parent", 6, Iris::Parent::ID }, { "Parent", 6, Iris::Parent::ID },
{ "Keyboard", 8, Iris::Keyboard::ID }, { "Keyboard", 8, Iris::Keyboard::ID },
{ "Buzzer", 6, Iris::Buzzer::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 #endif
} }
class PowerButton: class Event:
bool state, started bool state, started
unsigned pin
Iris::Cap cb Iris::Cap cb
public: public:
void scan (): void scan ():
if !started: if !started:
return return
gpio_mask_irq (3, 1 << 29) gpio_mask_irq (3, 1 << pin)
bool s = gpio_get_port (3) & (1 << 29) bool s = gpio_get_port (3) & (1 << pin)
if s != state: if s != state:
state = s state = s
cb.invoke (state ? Iris::Keyboard::RELEASE : 0) cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
gpio_as_interrupt (3, 1 << 29, !state, true) gpio_as_interrupt (3, 1 << pin, !state, true)
gpio_unmask_irq (3, 1 << 29) gpio_unmask_irq (3, 1 << pin)
PowerButton (): Event (unsigned p):
gpio_as_gpio (3, 29) pin = p
gpio_as_gpio (3, pin)
state = true state = true
started = false started = false
void set_cb (Iris::Cap c): void set_cb (Iris::Cap c):
@ -195,19 +197,24 @@ class PowerButton:
enum codes: enum codes:
KBD_DEV = 32 KBD_DEV = 32
PWR PWR
SDMMC
Iris::Num start (): Iris::Num start ():
map_gpio () map_gpio ()
DevKbd kbd 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::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> (dev.copy (), 0)
Iris::my_parent.provide_capability <Iris::Keyboard> (pw.copy (), 1) 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 (dev)
Iris::free_cap (pw) Iris::free_cap (pw)
Iris::free_cap (sm)
Iris::my_parent.init_done () Iris::my_parent.init_done ()
if kbd.scanning (): if kbd.scanning ():
Iris::my_receiver.set_alarm (SCAN_INTERVAL) Iris::my_receiver.set_alarm (SCAN_INTERVAL)
@ -225,6 +232,7 @@ Iris::Num start ():
// Interrupt. // Interrupt.
pwr.scan () pwr.scan ()
kbd.scan () kbd.scan ()
sdmmc.scan ()
if kbd.scanning (): if kbd.scanning ():
Iris::my_receiver.set_alarm (SCAN_INTERVAL) Iris::my_receiver.set_alarm (SCAN_INTERVAL)
Iris::register_interrupt (IRQ_GPIO3) Iris::register_interrupt (IRQ_GPIO3)
@ -235,7 +243,7 @@ Iris::Num start ():
case Iris::Device::RESET: case Iris::Device::RESET:
Iris::recv.reply.invoke () Iris::recv.reply.invoke ()
break break
case Iris::Keyboard::SET_CB: case Iris::Event::SET_CB:
Iris::Cap reply = Iris::get_reply () Iris::Cap reply = Iris::get_reply ()
kbd.active (Iris::get_arg ()) kbd.active (Iris::get_arg ())
reply.invoke () reply.invoke ()
@ -256,7 +264,7 @@ Iris::Num start ():
case Iris::Device::RESET: case Iris::Device::RESET:
Iris::recv.reply.invoke () Iris::recv.reply.invoke ()
break break
case Iris::Keyboard::SET_CB: case Iris::Event::SET_CB:
Iris::Cap reply = Iris::get_reply () Iris::Cap reply = Iris::get_reply ()
pwr.set_cb (Iris::get_arg ()) pwr.set_cb (Iris::get_arg ())
reply.invoke () reply.invoke ()
@ -268,6 +276,23 @@ Iris::Num start ():
kdebug ("\n") kdebug ("\n")
break break
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: default:
kdebug ("keyboard unknown num: ") kdebug ("keyboard unknown num: ")
kdebug_num (Iris::recv.protected_data.h) 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")