mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-19 07:42:47 +02:00
185 lines
6.0 KiB
COBOL
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")
|