mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-12-28 12:39:52 +02:00
add partial nand and sd/mmc drivers
This commit is contained in:
parent
8c7cac36e6
commit
6bf41032d8
6
Makefile
6
Makefile
@ -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
|
||||
|
201
devices.hhp
201
devices.hhp
@ -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.
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
199
source/nand.ccp
Normal 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
|
@ -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
184
source/sd+mmc.ccp
Normal 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")
|
Loading…
Reference in New Issue
Block a user