1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-19 07:42:47 +02:00
iris/source/sd+mmc.ccp
2010-05-15 18:42:17 +02:00

185 lines
6.0 KiB
COBOL

#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")