mirror of
git://projects.qi-hardware.com/iris.git
synced 2025-04-21 12:27:27 +03:00
add partial nand and sd/mmc drivers
This commit is contained in:
@@ -12,11 +12,12 @@ enum Outs:
|
||||
ALARM
|
||||
NUM_OUTS
|
||||
|
||||
static UI <NUM_INS, NUM_OUTS> ui
|
||||
static UI <NUM_INS, NUM_OUTS>::in <unsigned> total_time
|
||||
static UI <NUM_INS, NUM_OUTS>::in_event do_start
|
||||
static UI <NUM_INS, NUM_OUTS>::out <unsigned> current_time
|
||||
static UI <NUM_INS, NUM_OUTS>::out_event do_alarm
|
||||
typedef UI <NUM_INS, NUM_OUTS> ui_t
|
||||
static ui_t ui
|
||||
static ui_t::in <unsigned> total_time
|
||||
static ui_t::in_event do_start
|
||||
static ui_t::out <unsigned> current_time
|
||||
static ui_t::out_event do_alarm
|
||||
|
||||
static bool ticking
|
||||
|
||||
@@ -56,7 +57,8 @@ Iris::Num start ():
|
||||
switch Iris::recv.protected_data.l:
|
||||
case ~0:
|
||||
// alarm.
|
||||
current_time = current_time - 1
|
||||
if current_time:
|
||||
current_time = current_time - 1
|
||||
if !current_time:
|
||||
do_alarm ()
|
||||
ticking = false
|
||||
|
||||
@@ -137,7 +137,7 @@ extern "C":
|
||||
Iris::recv.reply = Iris::alloc_cap ()
|
||||
Iris::recv.arg = Iris::alloc_cap ()
|
||||
Iris::Num ret = start ()
|
||||
Iris::my_parent.invoke (~0, ret)
|
||||
Iris::my_parent.exit (ret)
|
||||
Iris::my_memory.destroy (Iris::my_thread)
|
||||
// The program no longer exists. If it somehow does, generate an address fault.
|
||||
while true:
|
||||
|
||||
@@ -25,6 +25,7 @@ enum ins:
|
||||
static Iris::Display display
|
||||
static Iris::Buzzer buzzer
|
||||
static unsigned *framebuffer
|
||||
static unsigned alarming
|
||||
|
||||
enum PD:
|
||||
UI
|
||||
@@ -151,38 +152,57 @@ static void draw_time (bool upper, unsigned time):
|
||||
draw_num (upper, 3, time / 10)
|
||||
draw_num (upper, 4, time % 10)
|
||||
|
||||
static void beep ():
|
||||
buzzer.beep (4 * 440, 1000, ~0)
|
||||
static void do_alarm ():
|
||||
static unsigned tune[] = { 4, 6, 6, 5, 7, 7 }
|
||||
if ++alarming > sizeof (tune) / sizeof (*tune):
|
||||
alarming = 1
|
||||
buzzer.beep (tune[alarming - 1] * 220, 300, ~0)
|
||||
Iris::my_receiver.set_alarm (HZ / 3)
|
||||
|
||||
Iris::Num start ():
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
display = Iris::my_parent.get_capability <Iris::Display> ()
|
||||
Iris::Setting bright = Iris::my_parent.get_capability <Iris::Setting> ()
|
||||
Iris::Keyboard keyboard = Iris::my_parent.get_capability <Iris::Keyboard> ()
|
||||
buzzer = Iris::my_parent.get_capability <Iris::Buzzer> ()
|
||||
Iris::UI app = Iris::my_parent.get_capability <Iris::UI> ()
|
||||
Iris::Cap cb = Iris::my_receiver.create_capability (UI)
|
||||
|
||||
framebuffer = (unsigned *)0x15000
|
||||
Iris::Caps fb = display.map_fb ((unsigned)framebuffer)
|
||||
bright.set (bright.get_range ())
|
||||
|
||||
unsigned screen_max = bright.get_range ()
|
||||
bright.set (0)
|
||||
bool screen_on = false
|
||||
|
||||
Iris::Cap cb = Iris::my_receiver.create_capability (UI)
|
||||
app.get_state (cb.copy ())
|
||||
Iris::free_cap (cb)
|
||||
|
||||
cb = Iris::my_receiver.create_capability (KBD)
|
||||
keyboard.set_cb (cb.copy ())
|
||||
Iris::free_cap (cb)
|
||||
|
||||
draw_num (false, 2, 10)
|
||||
draw_num (true, 2, 10)
|
||||
|
||||
unsigned total_time = 0
|
||||
alarming = 0
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case ~0:
|
||||
// Alarm.
|
||||
if alarming:
|
||||
do_alarm ()
|
||||
break
|
||||
case UI:
|
||||
switch Iris::recv.data[0].l:
|
||||
case CURRENT_TIME:
|
||||
draw_time (false, Iris::recv.data[1].l)
|
||||
break
|
||||
case ALARM:
|
||||
beep ()
|
||||
do_alarm ()
|
||||
break
|
||||
case TOTAL_TIME | Iris::UI::INPUT:
|
||||
total_time = Iris::recv.data[1].l
|
||||
@@ -194,6 +214,7 @@ Iris::Num start ():
|
||||
case KBD:
|
||||
if Iris::recv.data[0].l & Iris::Keyboard::RELEASE:
|
||||
break
|
||||
alarming = 0
|
||||
switch Iris::recv.data[0].l:
|
||||
case Key::VOLUME_UP:
|
||||
total_time += 60
|
||||
@@ -236,3 +257,11 @@ Iris::Num start ():
|
||||
break
|
||||
case Key::ENTER:
|
||||
app.event (START)
|
||||
break
|
||||
case Key::BACKSPACE:
|
||||
screen_on = !screen_on
|
||||
if screen_on:
|
||||
bright.set (screen_max)
|
||||
else:
|
||||
bright.set (0)
|
||||
break
|
||||
|
||||
@@ -269,6 +269,7 @@ static Type types[] = {
|
||||
{ "String", 6, Iris::String::ID },
|
||||
{ "WString", 7, Iris::WString::ID },
|
||||
{ "Device", 6, Iris::Device::ID },
|
||||
{ "Event", 5, Iris::Event::ID },
|
||||
{ "Parent", 6, Iris::Parent::ID },
|
||||
{ "Keyboard", 8, Iris::Keyboard::ID },
|
||||
{ "Buzzer", 6, Iris::Buzzer::ID },
|
||||
|
||||
199
source/nand.ccp
Normal file
199
source/nand.ccp
Normal file
@@ -0,0 +1,199 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// boot-programs/nand.ccp: NAND driver.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "devices.hh"
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
// The following defines are taken from mtd/nand.h in the Linux source.
|
||||
|
||||
// Standard NAND flash commands
|
||||
#define CMD_READ0 0
|
||||
#define CMD_READ1 1
|
||||
#define CMD_RNDOUT 5
|
||||
#define CMD_PAGEPROG 0x10
|
||||
#define CMD_READOOB 0x50
|
||||
#define CMD_ERASE1 0x60
|
||||
#define CMD_STATUS 0x70
|
||||
#define CMD_STATUS_MULTI 0x71
|
||||
#define CMD_SEQIN 0x80
|
||||
#define CMD_RNDIN 0x85
|
||||
#define CMD_READID 0x90
|
||||
#define CMD_ERASE2 0xd0
|
||||
#define CMD_RESET 0xff
|
||||
|
||||
// Extended commands for large page devices
|
||||
#define CMD_READSTART 0x30
|
||||
#define CMD_RNDOUTSTART 0xE0
|
||||
#define CMD_CACHEDPROG 0x15
|
||||
|
||||
// Extended commands for AG-AND device
|
||||
// Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
|
||||
// there is no way to distinguish that from NAND_CMD_READ0
|
||||
// until the remaining sequence of commands has been completed
|
||||
// so add a high order bit and mask it off in the command.
|
||||
#define CMD_DEPLETE1 0x100
|
||||
#define CMD_DEPLETE2 0x38
|
||||
#define CMD_STATUS_MULTI 0x71
|
||||
#define CMD_STATUS_ERROR 0x72
|
||||
// multi-bank error status (banks 0-3)
|
||||
#define CMD_STATUS_ERROR0 0x73
|
||||
#define CMD_STATUS_ERROR1 0x74
|
||||
#define CMD_STATUS_ERROR2 0x75
|
||||
#define CMD_STATUS_ERROR3 0x76
|
||||
#define CMD_STATUS_RESET 0x7f
|
||||
#define CMD_STATUS_CLEAR 0xff
|
||||
|
||||
#define CMD_NONE -1
|
||||
|
||||
// Status bits
|
||||
#define STATUS_FAIL 0x01
|
||||
#define STATUS_FAIL_N1 0x02
|
||||
#define STATUS_TRUE_READY 0x20
|
||||
#define STATUS_READY 0x40
|
||||
#define STATUS_WP 0x80
|
||||
|
||||
static volatile char *command
|
||||
static volatile char *address
|
||||
static volatile char *data
|
||||
|
||||
static unsigned page_bits
|
||||
static unsigned redundant_bits
|
||||
static unsigned block_bits
|
||||
static unsigned word_size
|
||||
|
||||
static void unbusy ():
|
||||
while !(gpio_get_port (2) & (1 << 30)):
|
||||
Iris::schedule ()
|
||||
|
||||
static void reset ():
|
||||
Iris::Page data_page = Iris::my_memory.create_page ()
|
||||
Iris::Page command_page = Iris::my_memory.create_page ()
|
||||
Iris::Page address_page = Iris::my_memory.create_page ()
|
||||
|
||||
unsigned base = 0x18000000
|
||||
data_page.alloc_physical (base, false, false)
|
||||
command_page.alloc_physical (base + 0x8000, false, false)
|
||||
address_page.alloc_physical (base + 0x10000, false, false)
|
||||
|
||||
Iris::my_memory.map (data_page, (unsigned)data)
|
||||
Iris::my_memory.map (command_page, (unsigned)command)
|
||||
Iris::my_memory.map (address_page, (unsigned)address)
|
||||
|
||||
Iris::free_cap (data_page)
|
||||
Iris::free_cap (command_page)
|
||||
Iris::free_cap (address_page)
|
||||
|
||||
// Set up.
|
||||
gpio_as_nand ()
|
||||
EMC_NFCSR = EMC_NFCSR_NFE1 | EMC_NFCSR_NFCE1
|
||||
|
||||
// Reset nand.
|
||||
*command = CMD_RESET
|
||||
unbusy ()
|
||||
|
||||
*command = CMD_READID
|
||||
*address = 0
|
||||
unsigned d = *data
|
||||
//unsigned maker = d
|
||||
d = *data
|
||||
//unsigned device = d
|
||||
d = *data
|
||||
//unsigned internal_chip_number = 1 << (d & 0x3)
|
||||
//unsigned cell_type = 2 << ((d >> 2) & 0x3)
|
||||
//unsigned simultaneously_programmed_pages = 1 << ((d >> 4) & 0x3)
|
||||
//bool can_interleave_program_between_chips = d & 0x40
|
||||
//bool can_cache_program = d & 0x80
|
||||
d = *data
|
||||
page_bits = 10 + (d & 3)
|
||||
kdebug ("page bits: ")
|
||||
kdebug_num (page_bits)
|
||||
kdebug ("\n")
|
||||
redundant_bits = (d & 4 ? 4 : 3)
|
||||
block_bits = 64 + ((d >> 4) & 3)
|
||||
word_size = (d & 0x40 ? 16 : 8)
|
||||
//unsigned serial_access_minimum = (d & 0x80 ? 25 : 50)
|
||||
d = *data
|
||||
//unsigned num_planes = 1 << ((d >> 2) & 3)
|
||||
//unsigned plane_bits = 26 + ((d >> 4) & 7)
|
||||
|
||||
static void read (unsigned a, char *buffer):
|
||||
unsigned column = a & ((1 << page_bits) - 1)
|
||||
unsigned row = a >> page_bits
|
||||
kdebug ("reading: ")
|
||||
kdebug_num (a)
|
||||
kdebug ("/")
|
||||
kdebug_num (row)
|
||||
kdebug ("/")
|
||||
kdebug_num (column)
|
||||
kdebug (": ")
|
||||
*command = CMD_READ0
|
||||
*address = column
|
||||
*address = column >> 8
|
||||
*address = row
|
||||
*address = row >> 8
|
||||
*address = row >> 16
|
||||
*command = CMD_READSTART
|
||||
EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_ERST
|
||||
// Wait for nand to be ready.
|
||||
unbusy ()
|
||||
for unsigned t = 0; t < 0x200; ++t:
|
||||
buffer[t] = *data
|
||||
char error[9]
|
||||
unsigned errcol = (1 << page_bits) + (column >> 5)
|
||||
*command = CMD_RNDOUT
|
||||
*address = errcol
|
||||
*address = errcol >> 8
|
||||
*command = CMD_RNDOUTSTART
|
||||
for unsigned t = 0; t < 9; ++t:
|
||||
error[t] = *data
|
||||
EMC_NFPAR (0) = ((unsigned *)error)[0]
|
||||
EMC_NFPAR (1) = ((unsigned *)error)[1]
|
||||
EMC_NFPAR (2) = error[9]
|
||||
EMC_NFECR = EMC_NFECR_ECCE | EMC_NFECR_RS | EMC_NFECR_RS_DECODING | EMC_NFECR_PRDY
|
||||
while !(EMC_NFINTS & EMC_NFINTS_DECF):
|
||||
Iris::schedule ()
|
||||
// delay...
|
||||
//Iris::schedule ()
|
||||
unsigned errs = (EMC_NFINTS & EMC_NFINTS_ERRCNT_MASK) >> EMC_NFINTS_ERRCNT_BIT
|
||||
|
||||
Iris::Num start ():
|
||||
for unsigned i = 0; i < 30; ++i:
|
||||
Iris::schedule ()
|
||||
map_emc ()
|
||||
map_gpio ()
|
||||
|
||||
command = (volatile char *)0x15000
|
||||
address = (volatile char *)0x16000
|
||||
data = (volatile char *)0x17000
|
||||
|
||||
reset ()
|
||||
|
||||
char buffer[0x200]
|
||||
|
||||
// Send nand contents to serial port.
|
||||
for unsigned a = 0; a < 0x4000; a += 0x200:
|
||||
read (a, buffer)
|
||||
//for unsigned s = 0; s < 0x10; ++s:
|
||||
for unsigned t = 0; t < 0x10; ++t:
|
||||
kdebug (" ")
|
||||
kdebug_num (buffer[0 * 0x20 + t], 2)
|
||||
kdebug ("\n")
|
||||
//kdebug ("\n")
|
||||
// Exit.
|
||||
return 0
|
||||
@@ -165,22 +165,24 @@ unsigned const DevKbd::keys[NUM_KEYS] = {
|
||||
#endif
|
||||
}
|
||||
|
||||
class PowerButton:
|
||||
class Event:
|
||||
bool state, started
|
||||
unsigned pin
|
||||
Iris::Cap cb
|
||||
public:
|
||||
void scan ():
|
||||
if !started:
|
||||
return
|
||||
gpio_mask_irq (3, 1 << 29)
|
||||
bool s = gpio_get_port (3) & (1 << 29)
|
||||
gpio_mask_irq (3, 1 << pin)
|
||||
bool s = gpio_get_port (3) & (1 << pin)
|
||||
if s != state:
|
||||
state = s
|
||||
cb.invoke (state ? Iris::Keyboard::RELEASE : 0)
|
||||
gpio_as_interrupt (3, 1 << 29, !state, true)
|
||||
gpio_unmask_irq (3, 1 << 29)
|
||||
PowerButton ():
|
||||
gpio_as_gpio (3, 29)
|
||||
gpio_as_interrupt (3, 1 << pin, !state, true)
|
||||
gpio_unmask_irq (3, 1 << pin)
|
||||
Event (unsigned p):
|
||||
pin = p
|
||||
gpio_as_gpio (3, pin)
|
||||
state = true
|
||||
started = false
|
||||
void set_cb (Iris::Cap c):
|
||||
@@ -195,19 +197,24 @@ class PowerButton:
|
||||
enum codes:
|
||||
KBD_DEV = 32
|
||||
PWR
|
||||
SDMMC
|
||||
|
||||
Iris::Num start ():
|
||||
map_gpio ()
|
||||
|
||||
DevKbd kbd
|
||||
PowerButton pwr
|
||||
Event pwr (29)
|
||||
Event sdmmc (0)
|
||||
|
||||
Iris::Device dev = Iris::my_receiver.create_capability (KBD_DEV)
|
||||
Iris::Keyboard dev = Iris::my_receiver.create_capability (KBD_DEV)
|
||||
Iris::Keyboard pw = Iris::my_receiver.create_capability (PWR)
|
||||
Iris::Event sm = Iris::my_receiver.create_capability (SDMMC)
|
||||
Iris::my_parent.provide_capability <Iris::Keyboard> (dev.copy (), 0)
|
||||
Iris::my_parent.provide_capability <Iris::Keyboard> (pw.copy (), 1)
|
||||
Iris::my_parent.provide_capability <Iris::Event> (sm.copy ())
|
||||
Iris::free_cap (dev)
|
||||
Iris::free_cap (pw)
|
||||
Iris::free_cap (sm)
|
||||
Iris::my_parent.init_done ()
|
||||
if kbd.scanning ():
|
||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
@@ -225,6 +232,7 @@ Iris::Num start ():
|
||||
// Interrupt.
|
||||
pwr.scan ()
|
||||
kbd.scan ()
|
||||
sdmmc.scan ()
|
||||
if kbd.scanning ():
|
||||
Iris::my_receiver.set_alarm (SCAN_INTERVAL)
|
||||
Iris::register_interrupt (IRQ_GPIO3)
|
||||
@@ -235,7 +243,7 @@ Iris::Num start ():
|
||||
case Iris::Device::RESET:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Keyboard::SET_CB:
|
||||
case Iris::Event::SET_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
kbd.active (Iris::get_arg ())
|
||||
reply.invoke ()
|
||||
@@ -256,7 +264,7 @@ Iris::Num start ():
|
||||
case Iris::Device::RESET:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Keyboard::SET_CB:
|
||||
case Iris::Event::SET_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
pwr.set_cb (Iris::get_arg ())
|
||||
reply.invoke ()
|
||||
@@ -268,6 +276,23 @@ Iris::Num start ():
|
||||
kdebug ("\n")
|
||||
break
|
||||
break
|
||||
case SDMMC:
|
||||
switch Iris::recv.data[0].l:
|
||||
case Iris::Device::RESET:
|
||||
Iris::recv.reply.invoke ()
|
||||
break
|
||||
case Iris::Event::SET_CB:
|
||||
Iris::Cap reply = Iris::get_reply ()
|
||||
sdmmc.set_cb (Iris::get_arg ())
|
||||
reply.invoke ()
|
||||
Iris::free_cap (reply)
|
||||
break
|
||||
default:
|
||||
kdebug ("SdMmc gpio invalid request\n")
|
||||
kdebug_num (Iris::recv.data[0].l)
|
||||
kdebug ("\n")
|
||||
break
|
||||
break
|
||||
default:
|
||||
kdebug ("keyboard unknown num: ")
|
||||
kdebug_num (Iris::recv.protected_data.h)
|
||||
|
||||
184
source/sd+mmc.ccp
Normal file
184
source/sd+mmc.ccp
Normal file
@@ -0,0 +1,184 @@
|
||||
#pypp 0
|
||||
// Iris: micro-kernel for a capability-based operating system.
|
||||
// source/sd+mmc.ccp: sd+mmc driver.
|
||||
// Copyright 2009 Bas Wijnen <wijnen@debian.org>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "devices.hh"
|
||||
#define ARCH
|
||||
#include "arch.hh"
|
||||
|
||||
class Mmc:
|
||||
static unsigned const PORT = 3
|
||||
static unsigned const PIN = 2
|
||||
bool check_sdio ()
|
||||
void check_sdmem ()
|
||||
void check_mmc ()
|
||||
public:
|
||||
void reset ()
|
||||
void detect ()
|
||||
void release ()
|
||||
void interrupt ()
|
||||
|
||||
void Mmc::reset ():
|
||||
// Enable slow clock to msc.
|
||||
CPM_MSCCDR = ~0
|
||||
cpm_start_msc ()
|
||||
// Enable msc pins.
|
||||
gpio_as_msc ()
|
||||
// Disable power to card.
|
||||
gpio_as_gpio (PORT, 1 << PIN)
|
||||
gpio_as_output (PORT, 1 << PIN)
|
||||
gpio_disable_pull (PORT, 1 << PIN)
|
||||
gpio_set (PORT, 1 << PIN)
|
||||
|
||||
// Stop the clock.
|
||||
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP
|
||||
while MSC_STAT & MSC_STAT_CLK_EN:
|
||||
Iris::schedule ()
|
||||
|
||||
// Initialize registers.
|
||||
MSC_CLKRT = MSC_CLKRT_CLK_RATE_DIV_128
|
||||
MSC_RESTO = 64
|
||||
MSC_RDTO = ~0
|
||||
MSC_BLKLEN = 0x200
|
||||
MSC_NOB = 0
|
||||
MSC_IMASK = ~0
|
||||
MSC_ARG = 0
|
||||
|
||||
// Reset controller and inserted devices.
|
||||
MSC_STRPCL = MSC_STRPCL_RESET
|
||||
while MSC_STAT & MSC_STAT_IS_RESETTING:
|
||||
Iris::schedule ()
|
||||
|
||||
// Start the clock.
|
||||
MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START
|
||||
// Set cards, if any, to idle.
|
||||
MSC_CMD = 0
|
||||
MSC_CMDAT = MSC_CMDAT_RESPONSE_NONE
|
||||
msc_start_op ()
|
||||
while !msc_ireg_end_cmd_res ():
|
||||
Iris::schedule ()
|
||||
msc_ireg_clear_end_cmd_res ()
|
||||
|
||||
// Reset SDIO device, if any.
|
||||
MSC_CMD = 52
|
||||
MSC_ARG = 0x88000C08
|
||||
MSC_CMDAT = MSC_CMDAT_RESPONSE_R5
|
||||
msc_start_op ()
|
||||
while !msc_ireg_end_cmd_res ():
|
||||
Iris::schedule ()
|
||||
msc_ireg_clear_end_cmd_res ()
|
||||
|
||||
bool Mmc::check_sdio ():
|
||||
// 2. Send CMD5 (IO_SEND_OP_CMD) to validate voltage.
|
||||
// 3. If the response is correct and the number of IO functions > 0, then continue, else go to check SDMEM.
|
||||
// 4. If C-bit in the response is ready (the initialization has finished), go to 6.
|
||||
// 5. Send CMD5 (IO_SEND_OP_CMD) to validate voltage, then go to 4.
|
||||
// 6. If memory-present-bit in the response is true, then it is a combo card (SDIO + Memory), else
|
||||
// it is only a SDIO card.
|
||||
// 7. If it is a combo card, go to check SDMEM to initialize the memory part.
|
||||
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let the card publish a RCA. The RCA is returned
|
||||
// from the response.
|
||||
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
|
||||
// 10. Go to check MMC, because we can assure that there is no SDMEM card.
|
||||
return false
|
||||
|
||||
void Mmc::check_sdmem ():
|
||||
// 2. Send CMD55. Here the default RCA 0x0000 is used for CMD55.
|
||||
// 3. If the response is correct (CMD55 has response), then continue, else go to check MMC.
|
||||
// 4. Send ACMD41 (SD_SEND_OP_CMD) to validate voltage (the general OCR value is 0x00FF8000).
|
||||
// 5. If the initialization has finished, go to 7. (The response is the OCR register and it includes a status information bit (bit [31]). This status bit is set if the card power up procedure has been finished. As long as the card is busy, the corresponding bit[31] is set to LOW.)
|
||||
// 6. Send CMD55 and ACMD41 to validate voltage, and then go to 5.
|
||||
// 7. Send CMD2 (ALL_SEND_CID) to get the card CID.
|
||||
// 8. Send CMD3 (SET_RELATIVE_ADDR) to let card publish a RCA. The RCA is returned from the response.
|
||||
// 9. If do not accept the new RCA, go to 8, else record the new RCA.
|
||||
// 10. Go to check MMC.
|
||||
|
||||
void Mmc::check_mmc ():
|
||||
// 1. SEND CMD1 (SEND_OP_CMD) TO VALIDATE VOLTAGE (THE GENERAL OCR VALUE IS 0X00FF88000).
|
||||
// 2. IF THE RESPONSE IS CORRECT, THEN CONTINUE, ELSE GOTO 9.
|
||||
// 3. IF THE INITIALIZATION HAS FINISHED, GO TO 5. (THE RESPONSE IS THE OCR REGISTER AND IT INCLUDES A STATUS INFORMATION BIT (BIT [31]). THIS STATUS BIT IS SET IF THE CARD POWER UP PROCEDURE HAS BEEN FINISHED. AS LONG AS THE CARD IS BUSY, THE CORRESPONDING BIT[31] IS SET TO LOW.)
|
||||
// 4. Send CMD1 (SEND_OP_CMD) to validate voltage, and then go to 3.
|
||||
// 5. Send CMD2 (ALL_SEND_CID) to get the card CID.
|
||||
// 6. If the response timeout occurs, goto 9.
|
||||
// 7. Send CMD3 (SET_RELATIVE_ADDR) to assign the card a RCA.
|
||||
// 8. If there are other MMC cards, then go to 5.
|
||||
|
||||
void Mmc::detect ():
|
||||
kdebug ("mmc detect\n")
|
||||
gpio_clear (PORT, 1 << PIN)
|
||||
if check_sdio ():
|
||||
check_sdmem ()
|
||||
check_mmc ()
|
||||
|
||||
void Mmc::release ():
|
||||
kdebug ("mmc release\n")
|
||||
gpio_set (PORT, 1 << PIN)
|
||||
|
||||
void Mmc::interrupt ():
|
||||
kdebug ("mmc interrupt\n")
|
||||
|
||||
|
||||
enum types:
|
||||
DETECT
|
||||
REQUEST
|
||||
|
||||
Iris::Num start ():
|
||||
map_msc ()
|
||||
map_gpio ()
|
||||
map_cpm ()
|
||||
|
||||
Mmc mmc
|
||||
mmc.reset ()
|
||||
|
||||
Iris::Event detect = Iris::my_parent.get_capability <Iris::Event> ()
|
||||
Iris::Cap cap = Iris::my_receiver.create_capability (DETECT)
|
||||
detect.set_cb (cap.copy ())
|
||||
cap.invoke (~0)
|
||||
Iris::free_cap (cap)
|
||||
|
||||
// Get a message from the queue. This is either the "there is no card" message, or the message we just sent.
|
||||
Iris::wait ()
|
||||
if Iris::recv.data[0].l != ~0:
|
||||
// If it was "there is no card", the message we sent is still in the queue.
|
||||
Iris::wait ()
|
||||
else:
|
||||
// Otherwise, there is a card.
|
||||
mmc.detect ()
|
||||
|
||||
cap = Iris::my_receiver.create_capability (REQUEST)
|
||||
Iris::my_parent.provide_capability <Iris::WString> (cap.copy ())
|
||||
Iris::free_cap (cap)
|
||||
|
||||
Iris::my_parent.init_done ()
|
||||
|
||||
while true:
|
||||
Iris::wait ()
|
||||
switch Iris::recv.protected_data.l:
|
||||
case DETECT:
|
||||
if Iris::recv.data[0].l:
|
||||
mmc.detect ()
|
||||
else:
|
||||
mmc.release ()
|
||||
break
|
||||
case IRQ_MSC:
|
||||
mmc.interrupt ()
|
||||
break
|
||||
case REQUEST:
|
||||
kdebug ("sd+mmc request\n")
|
||||
break
|
||||
default:
|
||||
Iris::panic (0, "unexpected request source for sd+mmc")
|
||||
Reference in New Issue
Block a user