From 6bf41032d80d1c11ca1414f4b8a4d26547c7ee10 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Sat, 15 May 2010 18:42:17 +0200 Subject: [PATCH] add partial nand and sd/mmc drivers --- Makefile | 6 +- devices.hhp | 201 ++++++++++++++++++------------------ init.config | 5 + mips/nanonote/Makefile.arch | 4 +- mips/nanonote/board.ccp | 7 ++ mips/nanonote/jz4740.hhp | 7 +- source/alarm.ccp | 14 +-- source/crt0.ccp | 2 +- source/gui.ccp | 39 ++++++- source/init.ccp | 1 + source/nand.ccp | 199 +++++++++++++++++++++++++++++++++++ source/nanonote-gpio.ccp | 47 +++++++-- source/sd+mmc.ccp | 184 +++++++++++++++++++++++++++++++++ 13 files changed, 584 insertions(+), 132 deletions(-) create mode 100644 source/nand.ccp create mode 100644 source/sd+mmc.ccp diff --git a/Makefile b/Makefile index a42b81f..30c167b 100644 --- a/Makefile +++ b/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 diff --git a/devices.hhp b/devices.hhp index 140903e..b547d33 100644 --- a/devices.hhp +++ b/devices.hhp @@ -24,66 +24,66 @@ namespace Iris: // Caplist interface. template // - 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 _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 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 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. diff --git a/init.config b/init.config index 2f5dbe1..75bce62 100644 --- a/init.config +++ b/init.config @@ -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 / [, ] = 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 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 include a file as another config file. diff --git a/mips/nanonote/Makefile.arch b/mips/nanonote/Makefile.arch index 9fca787..e1bd759 100644 --- a/mips/nanonote/Makefile.arch +++ b/mips/nanonote/Makefile.arch @@ -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 diff --git a/mips/nanonote/board.ccp b/mips/nanonote/board.ccp index 8fd1732..57fa3b3 100644 --- a/mips/nanonote/board.ccp +++ b/mips/nanonote/board.ccp @@ -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. diff --git a/mips/nanonote/jz4740.hhp b/mips/nanonote/jz4740.hhp index dbad377..1355c94 100644 --- a/mips/nanonote/jz4740.hhp +++ b/mips/nanonote/jz4740.hhp @@ -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 diff --git a/source/alarm.ccp b/source/alarm.ccp index 028ba4b..9acf385 100644 --- a/source/alarm.ccp +++ b/source/alarm.ccp @@ -12,11 +12,12 @@ enum Outs: ALARM NUM_OUTS -static UI ui -static UI ::in total_time -static UI ::in_event do_start -static UI ::out current_time -static UI ::out_event do_alarm +typedef UI ui_t +static ui_t ui +static ui_t::in total_time +static ui_t::in_event do_start +static ui_t::out 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 diff --git a/source/crt0.ccp b/source/crt0.ccp index 66dbb6b..7db7b5f 100644 --- a/source/crt0.ccp +++ b/source/crt0.ccp @@ -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: diff --git a/source/gui.ccp b/source/gui.ccp index 199ca17..dcaa6e5 100644 --- a/source/gui.ccp +++ b/source/gui.ccp @@ -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::Setting bright = Iris::my_parent.get_capability () Iris::Keyboard keyboard = Iris::my_parent.get_capability () buzzer = Iris::my_parent.get_capability () Iris::UI app = Iris::my_parent.get_capability () - 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 diff --git a/source/init.ccp b/source/init.ccp index 1ce4064..91691af 100644 --- a/source/init.ccp +++ b/source/init.ccp @@ -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 }, diff --git a/source/nand.ccp b/source/nand.ccp new file mode 100644 index 0000000..af969e9 --- /dev/null +++ b/source/nand.ccp @@ -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 +// +// 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 . + +#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 diff --git a/source/nanonote-gpio.ccp b/source/nanonote-gpio.ccp index 2a7256c..281cd5b 100644 --- a/source/nanonote-gpio.ccp +++ b/source/nanonote-gpio.ccp @@ -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 (dev.copy (), 0) Iris::my_parent.provide_capability (pw.copy (), 1) + Iris::my_parent.provide_capability (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) diff --git a/source/sd+mmc.ccp b/source/sd+mmc.ccp new file mode 100644 index 0000000..9d9bc96 --- /dev/null +++ b/source/sd+mmc.ccp @@ -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 +// +// 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 . + +#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::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 (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")