mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-04 23:19:41 +02:00
make more things work
This commit is contained in:
parent
431b38acb9
commit
906f487b01
138
boot-programs/buzzer.ccp
Normal file
138
boot-programs/buzzer.ccp
Normal file
@ -0,0 +1,138 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/buzzer.ccp: Piezo buzzer 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 DevBuzzer:
|
||||
static unsigned const pwm = 4
|
||||
Kernel::Cap event
|
||||
bool is_active, is_beeping
|
||||
public:
|
||||
DevBuzzer ():
|
||||
is_active = false
|
||||
is_beeping = false
|
||||
gpio_as_pwm4 ()
|
||||
tcu_stop_counter (pwm)
|
||||
tcu_select_extalclk (pwm)
|
||||
tcu_select_clk_div64 (pwm)
|
||||
tcu_enable_pwm_output (pwm)
|
||||
void stop ():
|
||||
if !is_beeping:
|
||||
return
|
||||
tcu_stop_counter (pwm)
|
||||
event.invoke ()
|
||||
is_active = false
|
||||
Kernel::free_cap (event)
|
||||
void beep (unsigned freq, unsigned ms, Kernel::Cap cb):
|
||||
stop ()
|
||||
event = cb
|
||||
unsigned full = JZ_EXTAL / 64 / freq
|
||||
tcu_set_full_data (pwm, full)
|
||||
tcu_set_half_data (pwm, full / 2)
|
||||
tcu_set_count (pwm, 0)
|
||||
tcu_start_counter (pwm)
|
||||
Kernel::my_receiver.set_alarm (ms * HZ / 1000)
|
||||
is_beeping = true
|
||||
|
||||
enum codes:
|
||||
BUZZER = 32
|
||||
|
||||
Kernel::Num start ():
|
||||
map_gpio ()
|
||||
map_tcu ()
|
||||
|
||||
DevBuzzer buzzer
|
||||
|
||||
Device dev = Kernel::my_receiver.create_capability (BUZZER)
|
||||
Kernel::my_parent.ocall (dev.copy (), Buzzer::ID)
|
||||
Kernel::free_cap (dev)
|
||||
unsigned user (~0)
|
||||
unsigned next_user (0)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
buzzer.stop ()
|
||||
break
|
||||
case 0:
|
||||
switch Kernel::recv.protected_data.l:
|
||||
case BUZZER:
|
||||
// Buzzer device control request.
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Device::CREATE_USER:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Keyboard cap = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, BUZZER))
|
||||
reply.invoke (0, 0, cap.copy ())
|
||||
Kernel::free_cap (cap)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Device::DESTROY_USER:
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
case Device::UNUSE:
|
||||
buzzer.stop ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
case Device::USE:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
user = Kernel::my_receiver.get_protected (Kernel::recv.arg).l
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid buzzer control command: ")
|
||||
kdebug_num (Kernel::recv.data[0].l)
|
||||
kdebug ("\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid buzzer request\n")
|
||||
break
|
||||
break
|
||||
case BUZZER:
|
||||
// Buzzer device user request.
|
||||
if Kernel::recv.protected_data.l != user:
|
||||
kdebug ("invalid user requesting buzzer\n")
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Buzzer::BEEP:
|
||||
// Volume is not used for this buzzer.
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
buzzer.beep (Kernel::recv.data[1].l, Kernel::recv.data[1].h, arg)
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (arg)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Buzzer::STOP:
|
||||
kdebug ("stop\n")
|
||||
buzzer.stop ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug ("other\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("unknown num: ")
|
||||
kdebug_num (Kernel::recv.protected_data.h)
|
||||
kdebug ("\n")
|
@ -36,7 +36,23 @@ namespace Kernel:
|
||||
Cap my_parent
|
||||
__recv_data_t recv
|
||||
|
||||
void print_caps ():
|
||||
// Assume __caps to be 16.
|
||||
bool used[16]
|
||||
for unsigned i = 0; i < 16; ++i:
|
||||
used[i] = true
|
||||
unsigned num = 0
|
||||
for list *i = __first_free_cap; i; i = i->next:
|
||||
used[i - __cap_admin] = false
|
||||
++num
|
||||
kdebug_num (num, 1)
|
||||
kdebug (":")
|
||||
for unsigned i = 0; i < 16; ++i:
|
||||
kdebug_char (used[i] ? '#' : '.')
|
||||
kdebug_char ('\n')
|
||||
|
||||
void free_slot (unsigned slot):
|
||||
//kdebug ("free slot\n")
|
||||
__slot_admin[slot].prev = NULL
|
||||
__slot_admin[slot].next = __first_free_slot
|
||||
if __slot_admin[slot].next:
|
||||
@ -44,6 +60,7 @@ namespace Kernel:
|
||||
__first_free_slot = &__slot_admin[slot]
|
||||
|
||||
void free_cap (Cap cap):
|
||||
//kdebug ("free cap\n")
|
||||
if cap.slot () != 0:
|
||||
kdebug ("trying to free capability from non-0 slot\n")
|
||||
return
|
||||
@ -55,6 +72,7 @@ namespace Kernel:
|
||||
__first_free_cap = l
|
||||
|
||||
unsigned alloc_slot ():
|
||||
//kdebug ("alloc slot\n")
|
||||
if !__first_free_slot:
|
||||
// Out of slots... Probably best to raise an exception. For now, just return NO_SLOT.
|
||||
kdebug ("out of slots!\n")
|
||||
@ -66,6 +84,7 @@ namespace Kernel:
|
||||
return ret - __slot_admin
|
||||
|
||||
Cap alloc_cap ():
|
||||
//kdebug ("alloc cap\n")
|
||||
if !__first_free_cap:
|
||||
// Out of caps... Probably best to raise an exception. For now, just return CAP_NONE
|
||||
kdebug ("out of capabilities!\n")
|
||||
|
@ -39,7 +39,7 @@ struct String : public Kernel::Cap:
|
||||
GET_SIZE = 0x2001
|
||||
GET_CHARS
|
||||
GET_PAGE
|
||||
_END_MARKER
|
||||
ID
|
||||
/// Get the size of the string.
|
||||
Kernel::Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
@ -61,10 +61,10 @@ struct String : public Kernel::Cap:
|
||||
struct WString : public String:
|
||||
WString (Kernel::Cap c = Kernel::Cap ()) : String (c):
|
||||
enum request:
|
||||
TRUNCATE = String::_END_MARKER
|
||||
TRUNCATE = String::ID
|
||||
SET_CHARS
|
||||
SET_PAGE
|
||||
_END_MARKER
|
||||
ID
|
||||
/// Set the size of the string. Strings may have a limit to this setting.
|
||||
void truncate (Kernel::Num size):
|
||||
call (CAP_MASTER_DIRECT | TRUNCATE, size)
|
||||
@ -75,17 +75,41 @@ struct WString : public String:
|
||||
void set_page (Kernel::Num idx, Kernel::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 Kernel::Cap:
|
||||
Device (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
CREATE_USER = WString::ID
|
||||
DESTROY_USER
|
||||
UNUSE
|
||||
USE
|
||||
ID
|
||||
// Create a new user for this device. It will not be the active user.
|
||||
// The provided storage must allow object creation; no other actions may be used by the terminal.
|
||||
Kernel::Cap create_user (Kernel::Memory storage):
|
||||
iocall (storage, CAP_MASTER_DIRECT | CREATE_USER)
|
||||
return Kernel::get_arg ()
|
||||
// Destroy a user. It must not be active.
|
||||
void destroy_user (Kernel::Cap user):
|
||||
ocall (user, CAP_MASTER_DIRECT | DESTROY_USER)
|
||||
// Make user inactive.
|
||||
void unuse (Kernel::Cap user):
|
||||
ocall (user, CAP_MASTER_DIRECT | UNUSE)
|
||||
// Make user active.
|
||||
void use (Kernel::Cap user):
|
||||
ocall (user, CAP_MASTER_DIRECT | USE)
|
||||
|
||||
// Keyboard interface.
|
||||
struct Keyboard : public Kernel::Cap:
|
||||
Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
SET_CB = WString::_END_MARKER
|
||||
SET_CB = Device::ID
|
||||
GET_KEYS
|
||||
_END_MARKER
|
||||
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, plus a ~0 to signal the end of such events.
|
||||
// Set the event callback. Currently pressed keys emit a key press event to the new callback immediately.
|
||||
void set_cb (Kernel::Cap cb):
|
||||
ocall (cb, CAP_MASTER_DIRECT | SET_CB)
|
||||
// Get a list of keys on this keyboard. The key codes start at zero with no gaps.
|
||||
@ -93,15 +117,29 @@ struct Keyboard : public Kernel::Cap:
|
||||
icall (CAP_MASTER_DIRECT | GET_KEYS)
|
||||
return List <String> (Kernel::get_arg ())
|
||||
|
||||
// Buzzer interface.
|
||||
struct Buzzer : public Kernel::Cap:
|
||||
Buzzer (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
BEEP = Keyboard::ID
|
||||
STOP
|
||||
ID
|
||||
// Emit a beep of specified frequency, time and volume. Volume may not be supported.
|
||||
void beep (unsigned freq, unsigned ms, unsigned volume, Kernel::Cap cb = Kernel::Cap ()):
|
||||
ocall (cb, Kernel::Num (CAP_MASTER_DIRECT | BEEP, volume), Kernel::Num (freq, ms))
|
||||
// Abort current beep, if any.
|
||||
void stop ():
|
||||
call (CAP_MASTER_DIRECT | STOP)
|
||||
|
||||
// Display interface.
|
||||
struct Display : public Kernel::Cap:
|
||||
Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
EOF_CB = Keyboard::_END_MARKER
|
||||
EOF_CB = Buzzer::ID
|
||||
CREATE_FB
|
||||
USE_FB
|
||||
GET_INFO
|
||||
_END_MARKER
|
||||
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 (Kernel::Cap cb):
|
||||
@ -129,10 +167,10 @@ struct Display : public Kernel::Cap:
|
||||
struct File : public Kernel::Cap:
|
||||
File (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
INFO = Display::_END_MARKER
|
||||
INFO = Display::ID
|
||||
CLOSE
|
||||
MAP_HANDLE
|
||||
_END_MARKER
|
||||
ID
|
||||
// Get information about the file.
|
||||
Kernel::Num get_info (unsigned type):
|
||||
return icall (Kernel::Num (CAP_MASTER_DIRECT | INFO, type))
|
||||
@ -148,13 +186,13 @@ struct File : public Kernel::Cap:
|
||||
struct Directory : public File:
|
||||
Directory (Kernel::Cap c = Kernel::Cap ()) : File (c):
|
||||
enum request:
|
||||
GET_SIZE = File::_END_MARKER
|
||||
GET_SIZE = File::ID
|
||||
GET_NAME
|
||||
GET_FILE
|
||||
GET_FILE_INFO
|
||||
CREATE_FILE
|
||||
DELETE_FILE
|
||||
_END_MARKER
|
||||
ID
|
||||
// Get the number of entries in this directory.
|
||||
Kernel::Num get_size ():
|
||||
return call (CAP_MASTER_DIRECT | GET_SIZE)
|
||||
@ -181,9 +219,9 @@ struct Directory : public File:
|
||||
struct Stream : public File:
|
||||
Stream (Kernel::Cap c = Kernel::Cap ()) : File (c):
|
||||
enum request:
|
||||
READ = Directory::_END_MARKER
|
||||
READ = Directory::ID
|
||||
WRITE
|
||||
_END_MARKER
|
||||
ID
|
||||
// Try to read size bytes. Returns the number of bytes successfully read.
|
||||
Kernel::Num read (Kernel::Num size):
|
||||
return icall (CAP_MASTER_DIRECT | READ, size)
|
||||
@ -195,10 +233,10 @@ struct Stream : public File:
|
||||
struct Seekable : public File:
|
||||
Seekable (Kernel::Cap c = Kernel::Cap ()) : File (c):
|
||||
enum request:
|
||||
READ = Stream::_END_MARKER
|
||||
READ = Stream::ID
|
||||
WRITE
|
||||
TRUNCATE
|
||||
_END_MARKER
|
||||
ID
|
||||
// Try to read size bytes from position idx. Returns the number of bytes successfully read.
|
||||
Kernel::Num read (Kernel::Num idx, unsigned size):
|
||||
return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, size), idx)
|
||||
|
@ -18,84 +18,114 @@
|
||||
|
||||
#include "devices.hh"
|
||||
#include "iris.hh"
|
||||
#include "init.hh"
|
||||
|
||||
static Keyboard kbd, tp
|
||||
static Display lcd
|
||||
static Kernel::Cap lockleds, pwm
|
||||
static Keyboard kbd, sysreq
|
||||
static Buzzer buzzer
|
||||
static Device kbd_dev, buz_dev
|
||||
static List <String> kbd_names
|
||||
static unsigned slot
|
||||
|
||||
// Event types.
|
||||
enum type:
|
||||
KBD = 0x10000
|
||||
TP
|
||||
MEMORY
|
||||
KBDDEV
|
||||
KBD
|
||||
KEYNAMES
|
||||
SYSREQ
|
||||
BUZDEV
|
||||
BUZZER
|
||||
|
||||
static void setup ():
|
||||
unsigned state = 0
|
||||
Kernel::Caps my_caps = Kernel::my_memory.create_caps (4 + 1)
|
||||
unsigned my_slot = my_caps.use ()
|
||||
unsigned slot = Kernel::alloc_slot ()
|
||||
Kernel::Caps caps = Kernel::my_memory.create_caps (32)
|
||||
slot = caps.use ()
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, MEMORY))
|
||||
Kernel::Cap driver_memory = Kernel::my_memory.create_memory ()
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Kernel::Caps caps = Kernel::get_arg ()
|
||||
switch Kernel::recv.data[0].value ():
|
||||
case Init::REGISTER_GPIO:
|
||||
caps.use (slot)
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
my_caps.set (i, Kernel::Cap (slot, i).copy ())
|
||||
kbd = Kernel::Cap (my_slot, 0)
|
||||
tp = Kernel::Cap (my_slot, 1)
|
||||
lockleds = Kernel::Cap (my_slot, 2)
|
||||
pwm = Kernel::Cap (my_slot, 3)
|
||||
Kernel::Cap arg = Kernel::get_arg ()
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Keyboard::ID:
|
||||
switch Kernel::recv.data[0].h:
|
||||
case 0:
|
||||
caps.set (KBDDEV, arg.copy ())
|
||||
kbd_dev = Kernel::Cap (slot, KBDDEV)
|
||||
break
|
||||
case Init::REGISTER_LCD:
|
||||
caps.use (slot)
|
||||
my_caps.set (4, Kernel::Cap (slot, 0).copy ())
|
||||
lcd = Kernel::Cap (my_slot, 4)
|
||||
case 1:
|
||||
caps.set (SYSREQ, arg.copy ())
|
||||
sysreq = Kernel::Cap (slot, SYSREQ)
|
||||
break
|
||||
default:
|
||||
kdebug ("unexpected keyboard\n")
|
||||
break
|
||||
break
|
||||
case Buzzer::ID:
|
||||
caps.set (BUZDEV, arg.copy ())
|
||||
buz_dev = Kernel::Cap (slot, BUZDEV)
|
||||
break
|
||||
default:
|
||||
Kernel::free_cap (reply)
|
||||
Kernel::free_cap (arg)
|
||||
kdebug ("unknown setup request for init\n")
|
||||
continue
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (caps)
|
||||
Kernel::free_cap (reply)
|
||||
if ++state == 2:
|
||||
Kernel::free_cap (arg)
|
||||
if ++state == 3:
|
||||
break
|
||||
Kernel::free_cap (my_caps)
|
||||
Kernel::free_slot (slot)
|
||||
Kernel::schedule ()
|
||||
Kernel::Cap kc = Kernel::my_receiver.create_capability (KBD)
|
||||
kbd.set_cb (kc)
|
||||
Kernel::Cap tc = Kernel::my_receiver.create_capability (TP)
|
||||
tp.set_cb (tc)
|
||||
pwm.call (1)
|
||||
// sysreq
|
||||
Kernel::Cap cb = Kernel::my_receiver.create_capability (SYSREQ)
|
||||
sysreq.set_cb (cb.copy ())
|
||||
// keyboard user
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, KBD))
|
||||
kbd = kbd_dev.create_user (driver_memory)
|
||||
kbd_dev.use (kbd)
|
||||
// keyboard callback
|
||||
Kernel::set_recv_arg (cb)
|
||||
Kernel::my_receiver.create_capability (KBD)
|
||||
kbd.set_cb (cb.copy ())
|
||||
// keyboard name list
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, KEYNAMES))
|
||||
kbd_names = kbd.get_keys ()
|
||||
// buzzer user
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, BUZZER))
|
||||
buzzer = buz_dev.create_user (driver_memory)
|
||||
buz_dev.use (buzzer)
|
||||
// clean up.
|
||||
Kernel::free_cap (cb)
|
||||
|
||||
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
|
||||
//char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":"
|
||||
char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$*T\nE& B=UDLR+-F^CA"
|
||||
|
||||
Kernel::Num start ():
|
||||
kdebug ("init started\n")
|
||||
setup ()
|
||||
kdebug ("init set up\n")
|
||||
while true:
|
||||
kdebug ("init waiting\n")
|
||||
Kernel::wait ()
|
||||
kdebug ("init done waiting\n")
|
||||
switch Kernel::recv.protected_data.value ():
|
||||
case SYSREQ:
|
||||
unsigned code = Kernel::recv.data[0].l
|
||||
kdebug ("\n\nSystem request ")
|
||||
if code & Keyboard::RELEASE:
|
||||
kdebug ("released.\n\n")
|
||||
else:
|
||||
kdebug ("pressed.\n\n")
|
||||
break
|
||||
case KBD:
|
||||
unsigned code = Kernel::recv.data[0].l
|
||||
if code & Keyboard::RELEASE:
|
||||
break
|
||||
kdebug_char (decode_kbd[code])
|
||||
if code == 0:
|
||||
Kernel::Caps ().print (~0)
|
||||
break
|
||||
case TP:
|
||||
unsigned leds = 0
|
||||
if Kernel::recv.data[0].l & 1:
|
||||
leds |= 0x1
|
||||
kdebug_char ('-')
|
||||
else:
|
||||
leds |= 0x4
|
||||
if !(Kernel::recv.data[0].l & Keyboard::RELEASE):
|
||||
leds |= 0x2
|
||||
lockleds.call (leds)
|
||||
kdebug_char ('+')
|
||||
buzzer.beep (2000, 100, 0)
|
||||
String name = kbd_names.get (code & ~Keyboard::RELEASE)
|
||||
unsigned size = name.get_size ().l
|
||||
char buffer[16]
|
||||
for unsigned i = 0; i < size; i += 16:
|
||||
name.get_chars (i, buffer)
|
||||
for unsigned k = 0; k < size - i && k < 16; ++k:
|
||||
kdebug_char (buffer[k])
|
||||
kdebug_char ('\n')
|
||||
Kernel::free_cap (name)
|
||||
break
|
||||
|
@ -1,60 +0,0 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/init.hhp: interface for init task.
|
||||
// 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/>.
|
||||
|
||||
#ifndef __INIT_HH
|
||||
#define __INIT_HH
|
||||
|
||||
#include "iris.hh"
|
||||
|
||||
struct Init : public Kernel::Cap:
|
||||
Init (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c):
|
||||
enum request:
|
||||
REGISTER_GPIO = 0x1000
|
||||
REGISTER_LCD
|
||||
enum protected_codes:
|
||||
GPIO_KEYBOARD = 32
|
||||
GPIO_TOUCHPAD
|
||||
GPIO_LOCKLEDS
|
||||
GPIO_PWM
|
||||
LCD_SET_EOF_CB
|
||||
LOG
|
||||
void register_gpio ():
|
||||
Kernel::Caps c = Kernel::my_memory.create_caps (4)
|
||||
unsigned slot = c.use ()
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, 0))
|
||||
Kernel::my_receiver.create_capability (GPIO_KEYBOARD)
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, 1))
|
||||
Kernel::my_receiver.create_capability (GPIO_TOUCHPAD)
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, 2))
|
||||
Kernel::my_receiver.create_capability (GPIO_LOCKLEDS)
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, 3))
|
||||
Kernel::my_receiver.create_capability (GPIO_PWM)
|
||||
ocall (c, CAP_MASTER_DIRECT | REGISTER_GPIO)
|
||||
Kernel::my_memory.destroy (c)
|
||||
Kernel::free_cap (c)
|
||||
Kernel::free_slot (slot)
|
||||
void register_lcd ():
|
||||
Kernel::Caps c = Kernel::my_memory.create_caps (1)
|
||||
unsigned slot = c.use ()
|
||||
Kernel::set_recv_arg (Kernel::Cap (slot, 0))
|
||||
Kernel::my_receiver.create_capability (LCD_SET_EOF_CB)
|
||||
ocall (c, CAP_MASTER_DIRECT | REGISTER_LCD)
|
||||
Kernel::my_memory.destroy (c)
|
||||
Kernel::free_cap (c)
|
||||
Kernel::free_slot (slot)
|
||||
#endif
|
366
boot-programs/nanonote-gpio.ccp
Normal file
366
boot-programs/nanonote-gpio.ccp
Normal file
@ -0,0 +1,366 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/nanonote-gpio.ccp: gpio devices on the nanonote.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "devices.hh"
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
//#define QI
|
||||
#define SCAN_INTERVAL HZ / 50
|
||||
|
||||
class DevKbd:
|
||||
static unsigned const NUM_COLS = 8
|
||||
static unsigned const NUM_ROWS = 8
|
||||
static unsigned const COLS_PORT = 2
|
||||
static unsigned const ROWS_PORT = 3
|
||||
static unsigned const ALL_COLS = 0x0003fc00
|
||||
static unsigned const ALL_ROWS = 0x05fc0000
|
||||
static unsigned const COLS[NUM_COLS]
|
||||
static unsigned const ROWS[NUM_ROWS]
|
||||
static unsigned const encode[NUM_ROWS][NUM_COLS]
|
||||
enum Keys:
|
||||
#ifdef QI
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z
|
||||
F1, F2, F3, F4, F5, F6, F7, F8
|
||||
TAB, BACKSLASH, QUOTE, COMMA, PERIOD, SLASH, EQUAL, SPACE
|
||||
ESCAPE, ENTER, BACKSPACE
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
CAPS, ARROW, QI, CTRL, VOLUP, VOLDOWN, SHIFT, ALT, FN
|
||||
#else
|
||||
N0, N1, N2, N3, N4, N5, N6, N7, N8, N9
|
||||
A, B, C, D, E, F, G, H, I, J, K, L, M
|
||||
N, O, P, Q, R, S, T, U, V, W, X, Y, Z
|
||||
F1, F2, F3, F4
|
||||
CAPS, TAB, ENTER, ESCAPE, MP3, SPACE, BACKSPACE, EQUALS
|
||||
UP, DOWN, LEFT, RIGHT
|
||||
VOLUP, VOLDOWN
|
||||
FN, SHIFT, CTRL, ALT
|
||||
#endif
|
||||
NUM_KEYS
|
||||
static char const *const names[NUM_KEYS]
|
||||
unsigned state[NUM_COLS]
|
||||
Kernel::Cap event
|
||||
bool is_active
|
||||
bool is_scanning
|
||||
public:
|
||||
unsigned size ():
|
||||
return NUM_KEYS
|
||||
unsigned get_name_size (unsigned n):
|
||||
if n >= NUM_KEYS:
|
||||
return 0
|
||||
unsigned ret = 0
|
||||
for char const *p = names[n]; *p; ++p:
|
||||
++ret
|
||||
return ret
|
||||
void send_name (unsigned n, Kernel::Cap c, Kernel::Num offset):
|
||||
if n >= NUM_KEYS:
|
||||
c.invoke (0, 0)
|
||||
return
|
||||
unsigned data[4]
|
||||
char *d = (char *)data
|
||||
if offset.value () < get_name_size (n):
|
||||
unsigned o = offset.l & ~3;
|
||||
unsigned p
|
||||
for p = 0; p < 16 && names[n][p + o]; ++p:
|
||||
*d++ = names[n][p + o]
|
||||
for ; p < 16; ++p:
|
||||
*d++ = 0
|
||||
c.invoke (Kernel::Num (data[0], data[1]), Kernel::Num (data[2], data[3]))
|
||||
bool scanning ():
|
||||
return is_scanning
|
||||
void inactive ():
|
||||
if is_active:
|
||||
Kernel::free_cap (event)
|
||||
is_active = false
|
||||
void check (unsigned col, unsigned rowdata):
|
||||
for unsigned r = 0; r < NUM_ROWS; ++r:
|
||||
if !((rowdata ^ state[col]) & (1 << ROWS[r])):
|
||||
continue
|
||||
unsigned code = encode[r][col]
|
||||
if rowdata & (1 << ROWS[r]):
|
||||
code |= Keyboard::RELEASE
|
||||
if is_active:
|
||||
event.invoke (code)
|
||||
state[col] = rowdata
|
||||
void delay ():
|
||||
for unsigned i = 0; i < 10000; ++i:
|
||||
gpio_set (0, 0)
|
||||
void scan ():
|
||||
unsigned r
|
||||
gpio_mask_irq (ROWS_PORT, ALL_ROWS)
|
||||
is_scanning = false
|
||||
if !is_active:
|
||||
return
|
||||
for unsigned c = 0; c < NUM_COLS; ++c:
|
||||
gpio_as_input (COLS_PORT, ALL_COLS & ~(1 << COLS[c]))
|
||||
gpio_as_output (COLS_PORT, 1 << COLS[c])
|
||||
if c > 0:
|
||||
check (c - 1, r)
|
||||
delay ()
|
||||
else:
|
||||
check (0, state[0])
|
||||
delay ()
|
||||
r = gpio_get_port (ROWS_PORT) & ALL_ROWS
|
||||
if r != ALL_ROWS:
|
||||
is_scanning = true
|
||||
gpio_as_output (COLS_PORT, ALL_COLS)
|
||||
check (NUM_COLS - 1, r)
|
||||
delay ()
|
||||
r = gpio_get_port (ROWS_PORT) & ALL_ROWS
|
||||
unsigned high = 0, low = 0
|
||||
for unsigned i = 0; i < NUM_ROWS; ++i:
|
||||
if r & (1 << ROWS[i]):
|
||||
low |= 1 << ROWS[i]
|
||||
else:
|
||||
high |= 1 << ROWS[i]
|
||||
gpio_as_interrupt (ROWS_PORT, high, true, true)
|
||||
gpio_as_interrupt (ROWS_PORT, low, false, true)
|
||||
gpio_unmask_irq (ROWS_PORT, ALL_ROWS)
|
||||
void active (Kernel::Cap cb):
|
||||
inactive ()
|
||||
event = cb
|
||||
is_active = true
|
||||
for unsigned c = 0; c < NUM_COLS; ++c:
|
||||
state[c] = ALL_ROWS
|
||||
scan ()
|
||||
DevKbd ():
|
||||
is_active = false
|
||||
gpio_as_gpio (COLS_PORT, ALL_COLS)
|
||||
gpio_as_gpio (ROWS_PORT, ALL_ROWS)
|
||||
gpio_clear (COLS_PORT, ALL_COLS)
|
||||
gpio_as_output (COLS_PORT, ALL_COLS)
|
||||
gpio_as_input (ROWS_PORT, ALL_ROWS)
|
||||
gpio_enable_pull (ROWS_PORT, ALL_ROWS)
|
||||
for unsigned i = 0; i < NUM_COLS; ++i:
|
||||
state[i] = ALL_ROWS
|
||||
scan ()
|
||||
|
||||
unsigned const DevKbd::COLS[NUM_COLS] = { 10, 11, 12, 13, 14, 15, 16, 17 }
|
||||
unsigned const DevKbd::ROWS[NUM_ROWS] = { 18, 19, 20, 21, 22, 23, 24, 26 }
|
||||
unsigned const DevKbd::encode[NUM_ROWS][NUM_COLS] = {
|
||||
#ifdef QI
|
||||
{ F1, F2, F3, F4, F5, F6, F7, ~0 },
|
||||
{ Q, W, E, R, T, Y, U, I },
|
||||
{ A, S, D, F, G, H, J, K },
|
||||
{ ESCAPE, Z, X, C, V, B, N, M },
|
||||
{ TAB, CAPS, BACKSLASH, QUOTE, COMMA, PERIOD, SLASH, UP },
|
||||
{ O, L, EQUAL, ARROW, SPACE, QI, CTRL, LEFT },
|
||||
{ F8, P, BACKSPACE, ENTER, VOLUP, VOLDOWN, DOWN, RIGHT },
|
||||
{ SHIFT, ALT, FN, ~0, ~0, ~0, ~0, ~0 }
|
||||
#else
|
||||
{ ESCAPE, TAB, F1, F2, F3, F4, MP3, ~0 },
|
||||
{ N1, N2, N3, N4, N5, N6, N7, N8 },
|
||||
{ Q, W, E, R, T, Y, U, I },
|
||||
{ A, S, D, F, G, H, J, K },
|
||||
{ Z, X, C, V, B, N, M, UP },
|
||||
{ N9, O, L, ALT, CAPS, SPACE, EQUALS, LEFT },
|
||||
{ BACKSPACE, N0, P, ENTER, VOLUP, VOLDOWN, DOWN, RIGHT },
|
||||
{ FN, SHIFT, CTRL, ~0, ~0, ~0, ~0, ~0 }
|
||||
#endif
|
||||
}
|
||||
char const *const DevKbd::names[NUM_KEYS] = {
|
||||
#ifdef QI
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
|
||||
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8",
|
||||
"tab", "\\", "'", ",", ".", "/", "=", "space",
|
||||
"escape", "enter", "backspace",
|
||||
"up", "down", "left", "right",
|
||||
"caps lock", "arrow", "qi", "left control", "volume up", "volume down", "left shift", "left alt", "fn"
|
||||
#else
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
|
||||
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
|
||||
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
|
||||
"f1", "f2", "f3", "f4",
|
||||
"caps lock", "tab", "enter", "escape", "mp3", "space", "backspace", "=",
|
||||
"up", "down", "left", "right",
|
||||
"volume up", "volume down",
|
||||
"fn", "left shift", "left control", "left alt"
|
||||
#endif
|
||||
}
|
||||
|
||||
class PowerButton:
|
||||
bool state, started
|
||||
Kernel::Cap cb
|
||||
public:
|
||||
void scan ():
|
||||
gpio_mask_irq (3, 1 << 29)
|
||||
bool s = gpio_get_port (3) & (1 << 29)
|
||||
if s != state:
|
||||
state = s
|
||||
cb.invoke (state ? Keyboard::RELEASE : 0)
|
||||
gpio_as_interrupt (3, 1 << 29, !state, true)
|
||||
gpio_unmask_irq (3, 1 << 29)
|
||||
PowerButton ():
|
||||
gpio_as_gpio (3, 29)
|
||||
state = true
|
||||
started = false
|
||||
void set_cb (Kernel::Cap c):
|
||||
if started:
|
||||
Kernel::free_cap (cb)
|
||||
else:
|
||||
started = true
|
||||
cb = c
|
||||
state = true
|
||||
scan ()
|
||||
|
||||
enum codes:
|
||||
KBD_DEV = 32
|
||||
KBD_LIST
|
||||
PWR
|
||||
|
||||
Kernel::Num start ():
|
||||
map_gpio ()
|
||||
map_tcu ()
|
||||
|
||||
DevKbd kbd
|
||||
PowerButton pwr
|
||||
|
||||
Device dev = Kernel::my_receiver.create_capability (KBD_DEV)
|
||||
Keyboard pw = Kernel::my_receiver.create_capability (PWR)
|
||||
Kernel::my_parent.ocall (dev.copy (), Kernel::Num (Keyboard::ID, 0))
|
||||
Kernel::my_parent.ocall (pw.copy (), Kernel::Num (Keyboard::ID, 1))
|
||||
Kernel::free_cap (dev)
|
||||
Kernel::free_cap (pw)
|
||||
if kbd.scanning ():
|
||||
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
unsigned user (~0)
|
||||
unsigned next_user (0)
|
||||
List <String> list = List <String> (Kernel::my_receiver.create_capability (KBD_LIST))
|
||||
Kernel::register_interrupt (IRQ_GPIO3)
|
||||
while true:
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.h:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
kbd.scan ()
|
||||
if kbd.scanning ():
|
||||
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
break
|
||||
case 0:
|
||||
switch Kernel::recv.protected_data.l:
|
||||
case IRQ_GPIO3:
|
||||
// Interrupt.
|
||||
pwr.scan ()
|
||||
kbd.scan ()
|
||||
if kbd.scanning ():
|
||||
Kernel::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
Kernel::register_interrupt (IRQ_GPIO3)
|
||||
break
|
||||
case PWR:
|
||||
// Power button request.
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Keyboard::SET_CB:
|
||||
pwr.set_cb (Kernel::get_arg ())
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
default:
|
||||
kdebug ("power button invalid request\n")
|
||||
break
|
||||
break
|
||||
case KBD_DEV:
|
||||
// Keyboard device control request.
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Device::CREATE_USER:
|
||||
kdebug ("create\n")
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
Keyboard cap = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, KBD_DEV))
|
||||
reply.invoke (0, 0, cap.copy ())
|
||||
Kernel::free_cap (cap)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Device::DESTROY_USER:
|
||||
kdebug ("destroy\n")
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
case Device::UNUSE:
|
||||
kdebug ("unuse\n")
|
||||
kbd.inactive ()
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
case Device::USE:
|
||||
kdebug ("use\n")
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
user = Kernel::my_receiver.get_protected (Kernel::recv.arg).l
|
||||
reply.invoke ()
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("other dev:")
|
||||
kdebug_num (Kernel::recv.data[0].l)
|
||||
kdebug ("\n")
|
||||
break
|
||||
break
|
||||
case KBD_LIST:
|
||||
// Keyboard name lookup.
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Kernel::Caps::GET:
|
||||
Kernel::Cap reply = Kernel::get_reply ()
|
||||
unsigned num = Kernel::recv.data[1].l
|
||||
Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (num, KBD_LIST))
|
||||
reply.invoke (kbd.get_name_size (num), 0, name.copy ())
|
||||
Kernel::free_cap (name)
|
||||
Kernel::free_cap (reply)
|
||||
break
|
||||
case Kernel::Caps::GET_SIZE:
|
||||
Kernel::recv.reply.invoke (kbd.size ())
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid list operation\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
break
|
||||
break
|
||||
case KBD_DEV:
|
||||
// Keyboard device user request.
|
||||
if Kernel::recv.protected_data.l != user:
|
||||
kdebug ("invalid user requesting\n")
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
switch Kernel::recv.data[0].l:
|
||||
case Keyboard::SET_CB:
|
||||
kdebug ("set cb\n")
|
||||
kbd.active (Kernel::get_arg ())
|
||||
Kernel::recv.reply.invoke ()
|
||||
break
|
||||
case Keyboard::GET_KEYS:
|
||||
kdebug ("get keys\n")
|
||||
Kernel::recv.reply.invoke (0, 0, list)
|
||||
break
|
||||
default:
|
||||
kdebug ("other\n")
|
||||
break
|
||||
break
|
||||
case KBD_LIST:
|
||||
switch Kernel::recv.data[0].l:
|
||||
case String::GET_SIZE:
|
||||
Kernel::recv.reply.invoke (kbd.get_name_size (Kernel::recv.protected_data.l))
|
||||
break
|
||||
case String::GET_CHARS:
|
||||
kbd.send_name (Kernel::recv.protected_data.l, Kernel::recv.reply, Kernel::recv.data[1])
|
||||
break
|
||||
default:
|
||||
kdebug ("invalid string operation\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("unknown num: ")
|
||||
kdebug_num (Kernel::recv.protected_data.h)
|
||||
kdebug ("\n")
|
@ -17,7 +17,6 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "devices.hh"
|
||||
#include "init.hh"
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
@ -130,6 +129,7 @@ class Udc:
|
||||
char configuration
|
||||
unsigned size
|
||||
char const *ptr
|
||||
bool rebooting
|
||||
bool vendor (Setup *s)
|
||||
bool get_descriptor (unsigned type, unsigned idx, unsigned len)
|
||||
bool handle_setup (Setup *s)
|
||||
@ -149,7 +149,6 @@ Udc::my_config const Udc::config_descriptor = {
|
||||
Udc::String <7> const Udc::s_manufacturer = { sizeof (String <7>), String <7>::Type, { 'I', 'n', 'g', 'e', 'n', 'i', 'c' } }
|
||||
Udc::String <22> const Udc::s_product = { sizeof (String <22>), String <22>::Type, { 'J', 'Z', '4', '7', '4', '0', ' ', 'U', 'S', 'B', ' ', 'B', 'o', 'o', 't', ' ', 'D', 'e', 'v', 'i', 'c', 'e'} }
|
||||
void Udc::init ():
|
||||
kdebug ("udc: init\n")
|
||||
state = IDLE
|
||||
configuration = 0
|
||||
size = 0
|
||||
@ -165,19 +164,16 @@ void Udc::init ():
|
||||
UDC_INDEX = 0
|
||||
|
||||
bool Udc::vendor (Setup *s):
|
||||
kdebug ("udc: vendor\n")
|
||||
if s->request_type & 0x80:
|
||||
kdebug ("udc: vendorsend\n")
|
||||
static char const *name = "abcdefgh"
|
||||
ptr = name
|
||||
size = 8
|
||||
state = TX
|
||||
rebooting = true
|
||||
return true
|
||||
kdebug ("udc: vendorrecv\n")
|
||||
return true
|
||||
|
||||
bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len):
|
||||
kdebug ("udc: getdesc\n")
|
||||
switch type:
|
||||
case Configuration::Type:
|
||||
if idx != 1:
|
||||
@ -268,7 +264,6 @@ bool Udc::handle_setup (Setup *s):
|
||||
return true
|
||||
|
||||
void Udc::interrupt ():
|
||||
kdebug ("udc: inter\n")
|
||||
unsigned i = UDC_INTRUSB
|
||||
if i & UDC_INTR_RESET:
|
||||
kdebug ("udc: reset\n")
|
||||
@ -276,7 +271,6 @@ void Udc::interrupt ():
|
||||
return
|
||||
i = UDC_INTRIN
|
||||
if i & (1 << 0):
|
||||
kdebug ("udc: ep0\n")
|
||||
// Interrupt on endpoint 0.
|
||||
unsigned csr = UDC_CSR0
|
||||
if csr & UDC_CSR0_SENTSTALL:
|
||||
@ -287,10 +281,10 @@ void Udc::interrupt ():
|
||||
state = IDLE
|
||||
switch state:
|
||||
case IDLE:
|
||||
kdebug ("udc: idle\n")
|
||||
if rebooting:
|
||||
Kernel::reboot ()
|
||||
if !(csr & UDC_CSR0_OUTPKTRDY):
|
||||
return
|
||||
kdebug ("udc: packet\n")
|
||||
union { unsigned d[2]; Setup s; } packet
|
||||
packet.d[0] = UDC_FIFO (0)
|
||||
packet.d[1] = UDC_FIFO (0)
|
||||
@ -327,30 +321,41 @@ void Udc::interrupt ():
|
||||
UDC_CSR0 = csr
|
||||
|
||||
void Udc::log (unsigned c):
|
||||
kdebug ("udc: log\n")
|
||||
kdebug ("udc: log ")
|
||||
kdebug_char (c)
|
||||
kdebug ("\n")
|
||||
|
||||
enum pdata:
|
||||
LOG = 32
|
||||
|
||||
Kernel::Num start ():
|
||||
map_udc ()
|
||||
map_gpio ()
|
||||
Udc udc
|
||||
|
||||
kdebug ("udc: start\n")
|
||||
udc.init ()
|
||||
kdebug ("udc: done init\n")
|
||||
Kernel::Cap logcap = Kernel::my_receiver.create_capability (Init::LOG)
|
||||
kdebug ("udc: made cap\n")
|
||||
Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG)
|
||||
__asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory")
|
||||
kdebug ("udc: registered cap\n")
|
||||
Kernel::register_interrupt (IRQ_UDC)
|
||||
kdebug ("udc: registered interrupt\n")
|
||||
//Kernel::my_receiver.set_alarm (HZ)
|
||||
while true:
|
||||
kdebug ("udc: waiting\n")
|
||||
Kernel::wait ()
|
||||
switch Kernel::recv.protected_data.l:
|
||||
case ~0:
|
||||
// alarm.
|
||||
Kernel::my_receiver.set_alarm (HZ)
|
||||
kdebug ("alarm; d =")
|
||||
unsigned mask[4] = { 0x00000000, 0xfe000000, 0x09c00000, 0x3dfc8055 }
|
||||
for unsigned i = 0; i < 4; ++i:
|
||||
kdebug (" ")
|
||||
kdebug_num (gpio_get_port (i) & mask[i])
|
||||
kdebug ("\n")
|
||||
break
|
||||
case IRQ_UDC:
|
||||
udc.interrupt ()
|
||||
Kernel::register_interrupt (IRQ_UDC)
|
||||
break
|
||||
case Init::LOG:
|
||||
case LOG:
|
||||
udc.log (Kernel::recv.data[0].l)
|
||||
break
|
||||
default:
|
||||
|
18
invoke.ccp
18
invoke.ccp
@ -168,6 +168,15 @@ static kCaps reply_caps, replied_caps
|
||||
static kReceiver *reply_target
|
||||
static Kernel::Num reply_protected
|
||||
|
||||
static void reply_num (Kernel::Num num):
|
||||
kCapability::Context c
|
||||
c.data[0] = num
|
||||
c.data[1] = 0
|
||||
if reply_target:
|
||||
reply_target->send_message (reply_protected, &c)
|
||||
else:
|
||||
dpanic (0, "nothing to reply to")
|
||||
|
||||
static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0):
|
||||
kCapability::Context c
|
||||
c.data[0] = Kernel::Num (num1, num2)
|
||||
@ -208,6 +217,13 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte
|
||||
case Kernel::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK:
|
||||
reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs)
|
||||
return
|
||||
case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK:
|
||||
if !c->arg.valid () || c->arg->target != receiver:
|
||||
dpanic (0, "wrong argument for get_protected")
|
||||
reply_num (~0)
|
||||
return
|
||||
reply_num (c->arg->protected_data)
|
||||
return
|
||||
case Kernel::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK:
|
||||
reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0)
|
||||
return
|
||||
@ -517,6 +533,8 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_
|
||||
kPage *page = (kPage *)c->arg->protected_data.l
|
||||
reply_num (page->frame & ~0xc0000000)
|
||||
return
|
||||
case Kernel::Thread::PRIV_REBOOT & REQUEST_MASK:
|
||||
arch_reboot ()
|
||||
case Kernel::Thread::PRIV_PANIC & REQUEST_MASK:
|
||||
panic (c->data[1].l, "panic requested by thread")
|
||||
reply_num (~0)
|
||||
|
7
iris.hhp
7
iris.hhp
@ -129,6 +129,7 @@ namespace Kernel:
|
||||
struct Page
|
||||
struct Memory
|
||||
|
||||
void print_caps ()
|
||||
unsigned alloc_slot ()
|
||||
Cap alloc_cap ()
|
||||
void free_slot (unsigned slot)
|
||||
@ -256,6 +257,7 @@ namespace Kernel:
|
||||
CREATE_CAPABILITY
|
||||
CREATE_CALL_CAPABILITY
|
||||
CREATE_ASYNC_CALL_CAPABILITY
|
||||
GET_PROTECTED
|
||||
GET_REPLY_PROTECTED_DATA
|
||||
SET_REPLY_PROTECTED_DATA
|
||||
GET_ALARM
|
||||
@ -272,6 +274,8 @@ namespace Kernel:
|
||||
Cap create_capability (Num protected_data):
|
||||
icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data)
|
||||
return get_arg ()
|
||||
Num get_protected (Kernel::Cap target):
|
||||
return ocall (target, CAP_MASTER_DIRECT | GET_PROTECTED)
|
||||
Num get_reply_protected_data ():
|
||||
return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA)
|
||||
void set_reply_protected_data (Num data):
|
||||
@ -309,6 +313,7 @@ namespace Kernel:
|
||||
// This is not an operation, but having this capability allows using the thread in Receiver::set_owner.
|
||||
SET_OWNER
|
||||
DBG_SEND
|
||||
PRIV_REBOOT
|
||||
PRIV_PANIC
|
||||
// These get/set_info are not arch-specific.
|
||||
enum info_type:
|
||||
@ -478,6 +483,8 @@ namespace Kernel:
|
||||
return get_arg ()
|
||||
inline void dbg_send (unsigned code, unsigned bits = 32):
|
||||
my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits))
|
||||
inline void reboot ():
|
||||
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT)
|
||||
inline void panic (unsigned code):
|
||||
my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code)
|
||||
|
||||
|
@ -263,6 +263,7 @@ void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address)
|
||||
kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly)
|
||||
void kPage_arch_update_mapping (kPage *page)
|
||||
void arch_register_interrupt (unsigned num, kReceiverP r)
|
||||
void arch_reboot ()
|
||||
|
||||
bool kMemory::map (kPage *page, unsigned address, bool readonly = false):
|
||||
return kMemory_arch_map (this, page, address, readonly)
|
||||
|
@ -289,3 +289,15 @@ void arch_register_interrupt (unsigned num, kReceiver *r):
|
||||
intc_unmask_irq (num)
|
||||
else:
|
||||
intc_mask_irq (num)
|
||||
|
||||
void arch_reboot ():
|
||||
// Wait for serial port to be done.
|
||||
while !(UART0_LSR & UARTLSR_TEMT):
|
||||
// Reboot.
|
||||
wdt_select_extalclk ()
|
||||
wdt_select_clk_div1 ()
|
||||
wdt_set_data (1)
|
||||
wdt_set_count (0)
|
||||
wdt_start ()
|
||||
// Wait for wdt to trigger reboot.
|
||||
while true:
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
load = 0x80000000
|
||||
|
||||
ARCH_CXXFLAGS = -DNUM_THREADS=2
|
||||
ARCH_CXXFLAGS = -DNUM_THREADS=4
|
||||
ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL
|
||||
CROSS = mipsel-linux-gnu-
|
||||
OBJDUMP = $(CROSS)objdump
|
||||
@ -28,7 +28,7 @@ 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
|
||||
boot_threads = init udc
|
||||
boot_threads = init udc nanonote-gpio buzzer
|
||||
|
||||
test: iris.raw nanonote-boot
|
||||
./nanonote-boot iris.raw 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8')
|
||||
@ -50,7 +50,7 @@ mips/entry.o: $(boot_threads)
|
||||
mips/init.o: TARGET_FLAGS = -I/usr/include
|
||||
$(boot_threads): TARGET_FLAGS = -I.
|
||||
$(boot_threads): LDFLAGS = -EL
|
||||
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): boot-programs/devices.hh boot-programs/init.hh
|
||||
$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): boot-programs/devices.hh
|
||||
lcd: boot-programs/charset.data
|
||||
|
||||
boot-programs/charset.data: boot-programs/charset
|
||||
@ -63,4 +63,4 @@ boot-programs/charset.data: boot-programs/charset
|
||||
iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources))
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
|
||||
ARCH_CLEAN_FILES = $(boot_sources) $(boot_threads) $(arch_headers) boot_programs/init.hh boot_programs/devices.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw
|
||||
ARCH_CLEAN_FILES = $(boot_sources) $(boot_threads) $(arch_headers) boot_programs/devices.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw
|
||||
|
@ -29,6 +29,7 @@ void board_init ():
|
||||
gpio_as_aic ()
|
||||
gpio_as_lcd_16bit ()
|
||||
gpio_as_msc ()
|
||||
setup_sdram ()
|
||||
// Set up keyboard: this breaks uart receive.
|
||||
gpio_as_gpio (3, 0x05fc0000)
|
||||
tcu_stop_counter (0)
|
||||
|
@ -117,7 +117,7 @@ static void __map_io (unsigned physical, unsigned mapping):
|
||||
#define map_intc() do { __map_io (INTC_PHYSICAL, INTC_BASE); } while (0)
|
||||
#define map_tcu() do { __map_io (TCU_PHYSICAL, TCU_BASE); } while (0)
|
||||
#define map_wdt() do { __map_io (WDT_PHYSICAL, WDT_BASE); } while (0)
|
||||
#define map_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (0)
|
||||
#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_uart0() do { __map_io (UART0_PHYSICAL, UART0_BASE); } while (0)
|
||||
@ -2322,7 +2322,7 @@ static void gpio_as_interrupt (unsigned p, unsigned pins, bool high, bool level)
|
||||
if high:
|
||||
GPIO_PXDIRS (p) = pins
|
||||
else:
|
||||
GPIO_PXDIRS (p) = pins
|
||||
GPIO_PXDIRC (p) = pins
|
||||
GPIO_PXFLGC (p) = pins
|
||||
|
||||
static void gpio_set (unsigned p, unsigned pins):
|
||||
@ -3577,4 +3577,103 @@ static void cim_enable_nongated_clock_mode ():
|
||||
|
||||
|
||||
|
||||
static void setup_sdram ():
|
||||
// SDRAM BANK Number: 1, 2
|
||||
unsigned CONFIG_NR_DRAM_BANKS = 1
|
||||
// CAS latency: 2 or 3
|
||||
unsigned SDRAM_CASL = 3
|
||||
// SDRAM Timings, unit: ns
|
||||
// RAS# Active Time
|
||||
unsigned SDRAM_TRAS = 45
|
||||
// RAS# to CAS# Delay
|
||||
unsigned SDRAM_RCD = 20
|
||||
// RAS# Precharge Time
|
||||
unsigned SDRAM_TPC = 20
|
||||
// Write Latency Time
|
||||
unsigned SDRAM_TRWL = 7
|
||||
// Refresh period: 4096 refresh cycles/64ms
|
||||
unsigned SDRAM_TREF = 15625
|
||||
unsigned dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns
|
||||
unsigned cas_latency_sdmr[2] = { EMC_SDMR_CAS_2, EMC_SDMR_CAS_3 }
|
||||
unsigned cas_latency_dmcr[2] = { 1 << EMC_DMCR_TCL_BIT, 2 << EMC_DMCR_TCL_BIT }
|
||||
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}
|
||||
|
||||
cpu_clk = 225000000
|
||||
gpio_as_sdram_32bit ()
|
||||
unsigned SDRAM_BW16 = 0
|
||||
unsigned SDRAM_BANK4 = 1
|
||||
unsigned SDRAM_ROW = 13
|
||||
unsigned SDRAM_COL = 9
|
||||
|
||||
mem_clk = cpu_clk * div[cpm_get_cdiv()] / div[cpm_get_mdiv()]
|
||||
EMC_BCR = 0
|
||||
EMC_RTCSR = 0
|
||||
unsigned SDRAM_ROW0 = 11
|
||||
unsigned SDRAM_COL0 = 8
|
||||
unsigned SDRAM_BANK40 = 0
|
||||
dmcr0 = ((SDRAM_ROW0-11)<<EMC_DMCR_RA_BIT) | ((SDRAM_COL0-8)<<EMC_DMCR_CA_BIT) | (SDRAM_BANK40<<EMC_DMCR_BA_BIT) | (SDRAM_BW16<<EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN | cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]
|
||||
// Basic DMCR value
|
||||
dmcr = ((SDRAM_ROW-11)<<EMC_DMCR_RA_BIT) | ((SDRAM_COL-8)<<EMC_DMCR_CA_BIT) | (SDRAM_BANK4<<EMC_DMCR_BA_BIT) | (SDRAM_BW16<<EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN | cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]
|
||||
// SDRAM timimg
|
||||
ns = 1000000000 / mem_clk
|
||||
tmp = SDRAM_TRAS / ns
|
||||
if tmp < 4:
|
||||
tmp = 4
|
||||
if tmp > 11:
|
||||
tmp = 11
|
||||
dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT)
|
||||
tmp = SDRAM_RCD/ns
|
||||
if tmp > 3:
|
||||
tmp = 3
|
||||
dmcr |= (tmp << EMC_DMCR_RCD_BIT)
|
||||
tmp = SDRAM_TPC/ns
|
||||
if tmp > 7:
|
||||
tmp = 7
|
||||
dmcr |= (tmp << EMC_DMCR_TPC_BIT)
|
||||
tmp = SDRAM_TRWL/ns
|
||||
if tmp > 3:
|
||||
tmp = 3
|
||||
dmcr |= (tmp << EMC_DMCR_TRWL_BIT)
|
||||
tmp = (SDRAM_TRAS + SDRAM_TPC)/ns
|
||||
if tmp > 14:
|
||||
tmp = 14
|
||||
dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT)
|
||||
|
||||
// SDRAM mode value
|
||||
sdmode = EMC_SDMR_BT_SEQ | EMC_SDMR_OM_NORMAL | EMC_SDMR_BL_4 | cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)];
|
||||
|
||||
// Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0
|
||||
EMC_DMCR = dmcr
|
||||
REG8(EMC_SDMR0|sdmode) = 0
|
||||
|
||||
// Wait for precharge, > 200us
|
||||
tmp = (cpu_clk / 1000000) * 1000
|
||||
volatile unsigned t = tmp
|
||||
while t--:
|
||||
|
||||
// Stage 2. Enable auto-refresh
|
||||
EMC_DMCR = dmcr | EMC_DMCR_RFSH
|
||||
|
||||
tmp = SDRAM_TREF/ns
|
||||
tmp = tmp/64 + 1
|
||||
if tmp > 0xff:
|
||||
tmp = 0xff
|
||||
EMC_RTCOR = tmp
|
||||
EMC_RTCNT = 0
|
||||
// Divisor is 64, CKO/64
|
||||
EMC_RTCSR = EMC_RTCSR_CKS_64
|
||||
|
||||
// Wait for number of auto-refresh cycles
|
||||
tmp = (cpu_clk / 1000000) * 1000
|
||||
t = tmp
|
||||
while t--:
|
||||
|
||||
// Stage 3. Mode Register Set
|
||||
EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET
|
||||
REG8(EMC_SDMR0|sdmode) = 0
|
||||
|
||||
// Set back to basic DMCR value
|
||||
EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -132,6 +132,13 @@ nanonote::nanonote (unsigned skip):
|
||||
if !find_device (skip):
|
||||
std::cerr << "unable to find NanoNote device.\n";
|
||||
throw "unable to find NanoNote device";
|
||||
// Get info will reset the device if it has already booted into Iris.
|
||||
get_cpu_info ()
|
||||
usb_close (handle)
|
||||
sleep (1)
|
||||
if !find_device (skip):
|
||||
std::cerr << "unable to find NanoNote device again.\n";
|
||||
throw "unable to find NanoNote device again";
|
||||
|
||||
void nanonote::get_cpu_info ():
|
||||
char buffer[8]
|
||||
@ -141,14 +148,12 @@ void nanonote::get_cpu_info ():
|
||||
cpu_info = std::string (buffer, 8)
|
||||
|
||||
void nanonote::request (requests r, unsigned data):
|
||||
std::cerr << "requesting " << r << " (data = " << std::hex << data << ")" << std::endl
|
||||
if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, r, (data >> 16) & 0xffff, data & 0xffff, NULL, 0, timeout) < 0:
|
||||
std::cerr << "unable to send control message to NanoNote: " << usb_strerror () << ".\n"
|
||||
throw "unable to send control message to NanoNote"
|
||||
|
||||
void nanonote::send_file (unsigned address, unsigned size, char const *data):
|
||||
request (VR_SET_DATA_ADDRESS, address)
|
||||
//request (VR_SET_DATA_LENGTH, size)
|
||||
char const *ptr = data
|
||||
while ptr - data < size:
|
||||
int ret = usb_bulk_write (handle, out_ep, ptr, size - (ptr - data), timeout)
|
||||
@ -158,20 +163,12 @@ void nanonote::send_file (unsigned address, unsigned size, char const *data):
|
||||
ptr += ret
|
||||
|
||||
void nanonote::boot (std::string const &data, unsigned load, unsigned start):
|
||||
get_cpu_info ()
|
||||
std::cerr << "info: " << cpu_info << std::endl
|
||||
send_file (stage1_load, stage1_size, stage1)
|
||||
request (VR_PROGRAM_START1, stage1_start)
|
||||
usleep (100)
|
||||
send_file (load, data.size (), data.data ())
|
||||
request (VR_FLUSH_CACHES)
|
||||
request (VR_PROGRAM_START2, start)
|
||||
sleep (1)
|
||||
get_cpu_info ()
|
||||
std::cerr << "info: ";
|
||||
for unsigned i = 0; i < cpu_info.size (); ++i:
|
||||
std::cerr << std::setfill ('0') << std::setw (2) << std::hex << (cpu_info[i] & 0xff);
|
||||
std::cerr << std::endl
|
||||
|
||||
int main (int argc, char **argv):
|
||||
if argc != 3:
|
||||
|
@ -20,15 +20,6 @@
|
||||
#define __KERNEL
|
||||
#include "jz4740.hh"
|
||||
|
||||
#define CONFIG_NR_DRAM_BANKS 1 // SDRAM BANK Number: 1, 2
|
||||
#define SDRAM_CASL 3 // CAS latency: 2 or 3
|
||||
// SDRAM Timings, unit: ns
|
||||
#define SDRAM_TRAS 45 // RAS# Active Time
|
||||
#define SDRAM_RCD 20 // RAS# to CAS# Delay
|
||||
#define SDRAM_TPC 20 // RAS# Precharge Time
|
||||
#define SDRAM_TRWL 7 // Write Latency Time
|
||||
#define SDRAM_TREF 15625 // Refresh period: 4096 refresh cycles/64ms
|
||||
|
||||
asm volatile (".set noreorder\n"
|
||||
"\t.globl __start\n"
|
||||
"\t.text\n"
|
||||
@ -51,102 +42,5 @@ extern "C":
|
||||
void start_cpp ()
|
||||
|
||||
void start_cpp ():
|
||||
unsigned dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns
|
||||
unsigned cas_latency_sdmr[2] = { EMC_SDMR_CAS_2, EMC_SDMR_CAS_3 }
|
||||
unsigned cas_latency_dmcr[2] = { 1 << EMC_DMCR_TCL_BIT, 2 << EMC_DMCR_TCL_BIT }
|
||||
int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}
|
||||
|
||||
cpu_clk = 225000000
|
||||
gpio_as_sdram_32bit ()
|
||||
unsigned SDRAM_BW16 = 0
|
||||
unsigned SDRAM_BANK4 = 1
|
||||
unsigned SDRAM_ROW = 13
|
||||
unsigned SDRAM_COL = 9
|
||||
|
||||
mem_clk = cpu_clk * div[cpm_get_cdiv()] / div[cpm_get_mdiv()]
|
||||
EMC_BCR = 0
|
||||
EMC_RTCSR = 0
|
||||
#define SDRAM_ROW0 11
|
||||
#define SDRAM_COL0 8
|
||||
#define SDRAM_BANK40 0
|
||||
dmcr0 = ((SDRAM_ROW0-11)<<EMC_DMCR_RA_BIT) | ((SDRAM_COL0-8)<<EMC_DMCR_CA_BIT) | (SDRAM_BANK40<<EMC_DMCR_BA_BIT) | (SDRAM_BW16<<EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN | cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]
|
||||
// Basic DMCR value
|
||||
dmcr = ((SDRAM_ROW-11)<<EMC_DMCR_RA_BIT) | ((SDRAM_COL-8)<<EMC_DMCR_CA_BIT) | (SDRAM_BANK4<<EMC_DMCR_BA_BIT) | (SDRAM_BW16<<EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN | cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)]
|
||||
// SDRAM timimg
|
||||
ns = 1000000000 / mem_clk
|
||||
tmp = SDRAM_TRAS / ns
|
||||
if tmp < 4:
|
||||
tmp = 4
|
||||
if tmp > 11:
|
||||
tmp = 11
|
||||
dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT)
|
||||
tmp = SDRAM_RCD/ns
|
||||
if tmp > 3:
|
||||
tmp = 3
|
||||
dmcr |= (tmp << EMC_DMCR_RCD_BIT)
|
||||
tmp = SDRAM_TPC/ns
|
||||
if tmp > 7:
|
||||
tmp = 7
|
||||
dmcr |= (tmp << EMC_DMCR_TPC_BIT)
|
||||
tmp = SDRAM_TRWL/ns
|
||||
if tmp > 3:
|
||||
tmp = 3
|
||||
dmcr |= (tmp << EMC_DMCR_TRWL_BIT)
|
||||
tmp = (SDRAM_TRAS + SDRAM_TPC)/ns
|
||||
if tmp > 14:
|
||||
tmp = 14
|
||||
dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT)
|
||||
|
||||
// SDRAM mode value
|
||||
sdmode = EMC_SDMR_BT_SEQ | EMC_SDMR_OM_NORMAL | EMC_SDMR_BL_4 | cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)];
|
||||
|
||||
// Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0
|
||||
EMC_DMCR = dmcr
|
||||
REG8(EMC_SDMR0|sdmode) = 0
|
||||
|
||||
// Wait for precharge, > 200us
|
||||
tmp = (cpu_clk / 1000000) * 1000
|
||||
volatile unsigned t = tmp
|
||||
while t--:
|
||||
|
||||
// Stage 2. Enable auto-refresh
|
||||
EMC_DMCR = dmcr | EMC_DMCR_RFSH
|
||||
|
||||
tmp = SDRAM_TREF/ns
|
||||
tmp = tmp/64 + 1
|
||||
if tmp > 0xff:
|
||||
tmp = 0xff
|
||||
EMC_RTCOR = tmp
|
||||
EMC_RTCNT = 0
|
||||
// Divisor is 64, CKO/64
|
||||
EMC_RTCSR = EMC_RTCSR_CKS_64
|
||||
|
||||
// Wait for number of auto-refresh cycles
|
||||
tmp = (cpu_clk / 1000000) * 1000
|
||||
t = tmp
|
||||
while t--:
|
||||
|
||||
// Stage 3. Mode Register Set
|
||||
EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET
|
||||
REG8(EMC_SDMR0|sdmode) = 0
|
||||
|
||||
// Set back to basic DMCR value
|
||||
EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET
|
||||
|
||||
setup_sdram ()
|
||||
// everything is ok now: return to boot loader to load stage 2.
|
||||
|
||||
pll_init ()
|
||||
cpm_start_all ()
|
||||
gpio_as_uart0 ()
|
||||
UART0_IER = 0
|
||||
UART0_FCR = 0
|
||||
UART0_MCR = 0
|
||||
UART0_SIRCR = 0
|
||||
UART0_UMR = 0
|
||||
UART0_UACR = 0
|
||||
UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1 | UARTLCR_DLAB
|
||||
unsigned uart_div = 3000000 / 16 / 9600
|
||||
UART0_DLHR = uart_div >> 8
|
||||
UART0_DLLR = uart_div
|
||||
UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1
|
||||
UART0_FCR = UARTFCR_UUE | UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS
|
||||
|
@ -27,7 +27,15 @@ thread0:
|
||||
thread1:
|
||||
.incbin "udc"
|
||||
|
||||
.balign 0x1000
|
||||
thread2:
|
||||
.incbin "nanonote-gpio"
|
||||
|
||||
.balign 0x1000
|
||||
thread3:
|
||||
.incbin "buzzer"
|
||||
|
||||
thread4:
|
||||
|
||||
// Everything from here may be freed after kernel initialization.
|
||||
init_start:
|
||||
@ -36,3 +44,5 @@ thread_start:
|
||||
.word thread0
|
||||
.word thread1
|
||||
.word thread2
|
||||
.word thread3
|
||||
.word thread4
|
||||
|
@ -77,6 +77,9 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag
|
||||
dbg_log_num (n)
|
||||
dbg_log_char ('\n')
|
||||
// If no log capability is registered, the machine just hangs.
|
||||
#ifdef USE_SERIAL
|
||||
arch_reboot ()
|
||||
#endif
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
void dbg_send (unsigned num, unsigned bits):
|
||||
|
26
plan
26
plan
@ -1,2 +1,28 @@
|
||||
caps zonder size limit?
|
||||
invoke ipc: try sync; try receiver memory; try caller memory; fail.
|
||||
|
||||
memories map:
|
||||
|
||||
top
|
||||
- lcd
|
||||
- keyboard
|
||||
- sound
|
||||
- led
|
||||
- udc
|
||||
- battery
|
||||
- beeper
|
||||
- msc
|
||||
- nand
|
||||
- filesystem
|
||||
- network
|
||||
- top session manager
|
||||
- - user session
|
||||
- - - program container
|
||||
- - - - driver emulation
|
||||
- - - - driver emulation
|
||||
- - - - program
|
||||
- - - program container
|
||||
- - - - driver emulation
|
||||
- - - - program
|
||||
- - user session
|
||||
...
|
||||
|
Loading…
Reference in New Issue
Block a user